Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 3 additions & 26 deletions scripts/build-externals/esbuild-config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -177,21 +177,6 @@ function createStubPlugin(stubMap = STUB_MAP) {
}
}

// Shared dependencies that exist as standalone bundle files in dist/external/.
// These must be marked external in bundles that would otherwise inline them,
// so that at runtime they resolve to the existing bundle wrappers.
const SHARED_EXTERNAL_DEPS = [
'debug',
'has-flag',
'p-map',
'signal-exit',
'spdx-correct',
'spdx-expression-parse',
'supports-color',
'which',
'yoctocolors-cjs',
]

/**
* Get package-specific esbuild options.
*
Expand All @@ -209,12 +194,6 @@ export function getPackageSpecificOptions(packageName) {
} else if (packageName === 'zod') {
// Zod has localization files we don't need.
opts.external = [...(opts.external || []), './locales/*']
} else if (packageName === 'debug') {
// Mark supports-color as external - it exists as a standalone bundle wrapper.
opts.external = [...(opts.external || []), 'supports-color']
} else if (packageName === 'pico-pack') {
// Mark p-map as external - it has its own standalone bundle.
opts.external = [...(opts.external || []), 'p-map']
} else if (packageName === 'external-pack') {
// Inquirer packages have heavy dependencies we can exclude.
opts.external = [...(opts.external || []), 'rxjs/operators']
Expand All @@ -223,10 +202,6 @@ export function getPackageSpecificOptions(packageName) {
opts.footer = {
js: 'if (module.exports && module.exports.default && Object.keys(module.exports).length === 1) { module.exports = module.exports.default; }',
}
} else if (packageName === 'npm-pack') {
// Mark shared deps as external - they exist as standalone bundle wrappers.
// This eliminates ~100KB of duplication in the npm-pack bundle.
opts.external = [...(opts.external || []), ...SHARED_EXTERNAL_DEPS]
} else if (packageName === '@socketregistry/packageurl-js') {
// packageurl-js imports from socket-lib, creating a circular dependency.
// Mark socket-lib imports as external to avoid bundling issues.
Expand Down Expand Up @@ -256,6 +231,8 @@ export function getEsbuildConfig(entryPoint, outfile, packageOpts = {}) {
entryPoints: [entryPoint],
bundle: true,
platform: 'node',
// Intentionally conservative: node18 ensures maximum compatibility
// for bundled externals consumed by downstream packages.
target: 'node18',
format: 'cjs',
outfile,
Expand Down Expand Up @@ -296,7 +273,7 @@ export function getEsbuildConfig(entryPoint, outfile, packageOpts = {}) {
keepNames: true,
// Additional optimizations:
pure: ['console.log', 'console.debug', 'console.warn'],
drop: ['debugger', 'console'],
drop: ['debugger'],
ignoreAnnotations: false,
// Define compile-time constants for dead code elimination.
define: {
Expand Down
10 changes: 7 additions & 3 deletions scripts/build-externals/orchestrator.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import { promises as fs } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

import { getDefaultLogger } from '@socketsecurity/lib-stable/logger'

import { bundlePackage } from './bundler.mjs'
import { externalPackages, scopedPackages } from './config.mjs'
import { ensureDir } from './copy-files.mjs'

const logger = getDefaultLogger()

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const rootDir = path.resolve(__dirname, '..', '..')
const distExternalDir = path.join(rootDir, 'dist', 'external')
Expand Down Expand Up @@ -84,7 +88,7 @@ async function bundleAllPackages(options = {}) {
}
} catch {
if (!quiet) {
console.log(` Skipping optional package ${scope}/${name}`)
logger.log(` Skipping optional package ${scope}/${name}`)
}
}
} else {
Expand Down Expand Up @@ -123,7 +127,7 @@ async function bundleAllPackages(options = {}) {
}
} catch {
if (!quiet) {
console.log(` Skipping optional package ${scope}/${pkg}`)
logger.log(` Skipping optional package ${scope}/${pkg}`)
}
}
} else {
Expand Down Expand Up @@ -226,7 +230,7 @@ async function fixNodeGypStrings(dir, options = {}) {
await fs.writeFile(filePath, fixed, 'utf8')

if (!quiet) {
console.log(
logger.log(
` Fixed node-gyp string in ${path.relative(path.join(dir, '..', '..'), filePath)}`,
)
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/fix/commonjs-exports.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { getDefaultLogger } from '@socketsecurity/lib-stable/logger'
const logger = getDefaultLogger()

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const distDir = path.resolve(__dirname, '..', 'dist')
const distDir = path.resolve(__dirname, '..', '..', 'dist')

/**
* Process files in a directory and fix CommonJS exports.
Expand Down
4 changes: 2 additions & 2 deletions scripts/fix/path-aliases.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { getDefaultLogger } from '@socketsecurity/lib-stable/logger'
const logger = getDefaultLogger()

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const distDir = path.resolve(__dirname, '..', 'dist')
const _srcDir = path.resolve(__dirname, '..', 'src')
const distDir = path.resolve(__dirname, '..', '..', 'dist')
const _srcDir = path.resolve(__dirname, '..', '..', 'src')

// Map of path aliases to their actual directories
const pathAliases = {
Expand Down
5 changes: 4 additions & 1 deletion scripts/test/cover.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ const buildResult = await spawn('node', ['scripts/build/main.mjs'], {
},
})
if (buildResult.code !== 0) {
throw new Error('Build with source maps failed')
logger.error('Build with source maps failed')
process.exitCode = 1
// eslint-disable-next-line unicorn/no-process-exit
process.exit()
}

// Run vitest with coverage enabled, capturing output
Expand Down
2 changes: 1 addition & 1 deletion scripts/test/filter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getDefaultLogger } from '@socketsecurity/lib-stable/logger'

const logger = getDefaultLogger()
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const projectRoot = path.resolve(__dirname, '..')
const projectRoot = path.resolve(__dirname, '..', '..')

// Find all coverage JSON files
const coverageDir = path.join(projectRoot, 'coverage')
Expand Down
9 changes: 7 additions & 2 deletions scripts/test/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,13 @@ async function runIsolatedTests(options) {
cwd: rootPath,
env: {
...process.env,
NODE_OPTIONS:
`${process.env.NODE_OPTIONS || ''} --max-old-space-size=${process.env.CI ? 8192 : 4096} --unhandled-rejections=warn`.trim(),
NODE_OPTIONS: [
...(process.env.NODE_OPTIONS || '')
.split(/\s+/)
.filter(opt => opt && !opt.startsWith('--max-old-space-size')),
`--max-old-space-size=${process.env.CI ? 8192 : 4096}`,
'--unhandled-rejections=warn',
].join(' '),
VITEST: '1',
},
stdio: 'inherit',
Expand Down
5 changes: 4 additions & 1 deletion scripts/validate/no-extraneous-dependencies.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,7 @@ async function main() {
}
}

main()
main().catch(error => {
logger.fail(`Validation failed: ${error.message}`)
process.exitCode = 1
})
4 changes: 1 addition & 3 deletions src/abort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,5 @@ export function createTimeoutSignal(ms: number): AbortSignal {
if (ms <= 0) {
throw new TypeError('timeout must be a positive number')
}
const controller = new AbortController()
setTimeout(() => controller.abort(), ms)
return controller.signal
return AbortSignal.timeout(Math.ceil(ms))
}
2 changes: 1 addition & 1 deletion src/ansi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const ANSI_REGEX = /\x1b\[[0-9;]*m/g
export function ansiRegex(options?: { onlyFirst?: boolean }): RegExp {
const { onlyFirst } = options ?? {}
// Valid string terminator sequences are BEL, ESC\, and 0x9c.
const ST = '(?:\\u0007\\u001B\\u005C|\\u009C)'
const ST = '(?:\\u0007|\\u001B\\u005C|\\u009C)'
// OSC sequences only: ESC ] ... ST (non-greedy until the first ST).
const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`
// CSI and related: ESC/C1, optional intermediates, optional params (supports ; and :) then final byte.
Expand Down
7 changes: 1 addition & 6 deletions src/argv/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,5 @@ export function getPositionalArgs(startIndex = 2): string[] {
* Check if a specific flag is present in argv.
*/
export function hasFlag(flag: string, argv = process.argv): boolean {
const flagVariants = [
`--${flag}`,
// Short flag.
`-${flag.charAt(0)}`,
]
return flagVariants.some(variant => argv.includes(variant))
return argv.includes(`--${flag}`)
}
15 changes: 12 additions & 3 deletions src/cache-with-ttl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,18 @@ export function createTtlCache(options?: TtlCacheOptions): TtlCache {
// Check persistent cache.
const cacheEntry = await cacache.safeGet(fullKey)
if (cacheEntry) {
const entry = JSON.parse(
cacheEntry.data.toString('utf8'),
) as TtlCacheEntry<T>
let entry: TtlCacheEntry<T>
try {
entry = JSON.parse(cacheEntry.data.toString('utf8')) as TtlCacheEntry<T>
} catch {
// Corrupted cache entry, treat as miss and remove.
try {
await cacache.remove(fullKey)
} catch {
// Ignore removal errors.
}
return undefined
}
if (!isExpired(entry)) {
// Update in-memory cache.
if (opts.memoize) {
Expand Down
67 changes: 26 additions & 41 deletions src/dlx/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import { getDefaultLogger } from '../logger'
import { getSocketDlxDir } from '../paths/socket'
import { processLock } from '../process-lock'

const fs = getFs()
const path = getPath()
const logger = getDefaultLogger()

/**
Expand Down Expand Up @@ -148,8 +150,7 @@ export class DlxManifest {

constructor(options: DlxManifestOptions = {}) {
this.manifestPath =
options.manifestPath ??
getPath().join(getSocketDlxDir(), MANIFEST_FILE_NAME)
options.manifestPath ?? path.join(getSocketDlxDir(), MANIFEST_FILE_NAME)
this.lockPath = `${this.manifestPath}.lock`
}

Expand All @@ -159,7 +160,7 @@ export class DlxManifest {
*/
private readManifest(): Record<string, ManifestEntry | StoreRecord> {
try {
if (!getFs().existsSync(this.manifestPath)) {
if (!fs.existsSync(this.manifestPath)) {
return Object.create(null)
}

Expand Down Expand Up @@ -191,7 +192,7 @@ export class DlxManifest {
data: Record<string, ManifestEntry | StoreRecord>,
): Promise<void> {
// Ensure directory exists.
const manifestDir = getPath().dirname(this.manifestPath)
const manifestDir = path.dirname(this.manifestPath)
try {
safeMkdirSync(manifestDir, { recursive: true })
} catch (error) {
Expand All @@ -205,22 +206,13 @@ export class DlxManifest {
const tempPath = `${this.manifestPath}.tmp`

try {
getFs().writeFileSync(tempPath, content, 'utf8')
getFs().writeFileSync(this.manifestPath, content, 'utf8')

// Clean up temp file.
try {
if (getFs().existsSync(tempPath)) {
getFs().unlinkSync(tempPath)
}
} catch {
// Cleanup failed, not critical.
}
fs.writeFileSync(tempPath, content, 'utf8')
fs.renameSync(tempPath, this.manifestPath)
} catch (error) {
// Clean up temp file on error.
try {
if (getFs().existsSync(tempPath)) {
getFs().unlinkSync(tempPath)
if (fs.existsSync(tempPath)) {
fs.unlinkSync(tempPath)
}
} catch {
// Best effort cleanup.
Expand All @@ -235,20 +227,22 @@ export class DlxManifest {
async clear(name: string): Promise<void> {
await processLock.withLock(this.lockPath, async () => {
try {
if (!getFs().existsSync(this.manifestPath)) {
if (!fs.existsSync(this.manifestPath)) {
return
}

const content = getFs().readFileSync(this.manifestPath, 'utf8')
const content = fs.readFileSync(this.manifestPath, 'utf8')
if (!content.trim()) {
return
}

const data = JSON.parse(content) as Record<string, StoreRecord>
const data = JSON.parse(content) as Record<
string,
ManifestEntry | StoreRecord
>
delete data[name]

const updatedContent = JSON.stringify(data, null, 2)
getFs().writeFileSync(this.manifestPath, updatedContent, 'utf8')
await this.writeManifest(data)
} catch (error) {
logger.warn(
`Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`,
Expand All @@ -263,8 +257,8 @@ export class DlxManifest {
async clearAll(): Promise<void> {
await processLock.withLock(this.lockPath, async () => {
try {
if (getFs().existsSync(this.manifestPath)) {
getFs().unlinkSync(this.manifestPath)
if (fs.existsSync(this.manifestPath)) {
fs.unlinkSync(this.manifestPath)
}
} catch (error) {
logger.warn(
Expand Down Expand Up @@ -295,7 +289,7 @@ export class DlxManifest {
*/
getAllPackages(): string[] {
try {
if (!getFs().existsSync(this.manifestPath)) {
if (!fs.existsSync(this.manifestPath)) {
return []
}

Expand Down Expand Up @@ -356,8 +350,8 @@ export class DlxManifest {

// Read existing data.
try {
if (getFs().existsSync(this.manifestPath)) {
const content = getFs().readFileSync(this.manifestPath, 'utf8')
if (fs.existsSync(this.manifestPath)) {
const content = fs.readFileSync(this.manifestPath, 'utf8')
if (content.trim()) {
data = JSON.parse(content) as Record<string, StoreRecord>
}
Expand All @@ -372,7 +366,7 @@ export class DlxManifest {
data[name] = record

// Ensure directory exists.
const manifestDir = getPath().dirname(this.manifestPath)
const manifestDir = path.dirname(this.manifestPath)
try {
safeMkdirSync(manifestDir, { recursive: true })
} catch (error) {
Expand All @@ -386,22 +380,13 @@ export class DlxManifest {
const tempPath = `${this.manifestPath}.tmp`

try {
getFs().writeFileSync(tempPath, content, 'utf8')
getFs().writeFileSync(this.manifestPath, content, 'utf8')

// Clean up temp file.
try {
if (getFs().existsSync(tempPath)) {
getFs().unlinkSync(tempPath)
}
} catch {
// Cleanup failed, not critical.
}
fs.writeFileSync(tempPath, content, 'utf8')
fs.renameSync(tempPath, this.manifestPath)
} catch (error) {
// Clean up temp file on error.
try {
if (getFs().existsSync(tempPath)) {
getFs().unlinkSync(tempPath)
if (fs.existsSync(tempPath)) {
fs.unlinkSync(tempPath)
}
} catch {
// Best effort cleanup.
Expand Down
8 changes: 3 additions & 5 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -762,9 +762,7 @@ export async function cacheFetchGhsa(
}

// Use getOrFetch to prevent race conditions (thundering herd).
const cached = await cache.getOrFetch(key, async () => {
const data = await fetchGhsaDetails(ghsaId, options)
return JSON.stringify(data)
})
return JSON.parse(cached as string) as GhsaDetails
return (await cache.getOrFetch(key, async () => {
return await fetchGhsaDetails(ghsaId, options)
})) as GhsaDetails
}
Loading