@socketsecurity/lib 5.20.1 → 5.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +116 -95
  2. package/README.md +24 -181
  3. package/dist/archives.js +13 -0
  4. package/dist/cacache.js +6 -8
  5. package/dist/cache-with-ttl.js +1 -1
  6. package/dist/constants/socket.js +1 -1
  7. package/dist/dlx/detect.js +25 -8
  8. package/dist/dlx/manifest.js +8 -19
  9. package/dist/dlx/package.js +16 -2
  10. package/dist/env/socket-cli.d.ts +4 -3
  11. package/dist/env/socket-cli.js +1 -1
  12. package/dist/errors.d.ts +96 -2
  13. package/dist/errors.js +55 -0
  14. package/dist/external/pony-cause.js +12 -11
  15. package/dist/fs.js +8 -2
  16. package/dist/github.js +3 -2
  17. package/dist/globs.js +5 -1
  18. package/dist/ipc.js +2 -2
  19. package/dist/json/edit.js +3 -2
  20. package/dist/json/parse.d.ts +47 -2
  21. package/dist/json/parse.js +40 -2
  22. package/dist/json/types.d.ts +49 -0
  23. package/dist/memoization.d.ts +4 -23
  24. package/dist/memoization.js +14 -54
  25. package/dist/packages/isolation.js +4 -4
  26. package/dist/packages/specs.js +9 -2
  27. package/dist/performance.js +3 -2
  28. package/dist/process-lock.js +4 -12
  29. package/dist/promise-queue.d.ts +9 -4
  30. package/dist/promise-queue.js +9 -7
  31. package/dist/promises.d.ts +41 -0
  32. package/dist/promises.js +19 -2
  33. package/dist/regexps.d.ts +4 -13
  34. package/dist/regexps.js +60 -3
  35. package/dist/releases/github.js +3 -2
  36. package/dist/releases/socket-btm.d.ts +61 -5
  37. package/dist/releases/socket-btm.js +2 -2
  38. package/dist/schema/parse.d.ts +26 -0
  39. package/dist/schema/parse.js +38 -0
  40. package/dist/schema/types.d.ts +121 -0
  41. package/dist/schema/validate.d.ts +35 -0
  42. package/dist/{validation/validate-schema.js → schema/validate.js} +4 -14
  43. package/dist/suppress-warnings.js +0 -2
  44. package/dist/url.js +5 -1
  45. package/dist/versions.js +2 -2
  46. package/dist/words.js +4 -7
  47. package/package.json +15 -15
  48. package/dist/validation/json-parser.d.ts +0 -58
  49. package/dist/validation/json-parser.js +0 -63
  50. package/dist/validation/types.d.ts +0 -118
  51. package/dist/validation/validate-schema.d.ts +0 -124
  52. /package/dist/{validation → schema}/types.js +0 -0
package/CHANGELOG.md CHANGED
@@ -5,92 +5,120 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [5.20.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.1) - 2026-04-19
8
+ ## [5.23.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.23.0) - 2026-04-22
9
9
 
10
- ### Fixed
10
+ ### Added
11
11
 
12
- - `src/ipc.ts`: harden stub-file writes against local symlink/TOCTOU. Previously `writeIpcStub` used `mkdir {recursive, mode: 0o700}` + `writeFile`, which on multi-user Linux (`/tmp` sticky-bit but world-writable) let a pre-positioned attacker-owned `.socket-ipc/<app>/` survive the mode argument and redirect the subsequent `writeFile` through symlinks to victim files. Now validates directory ownership + mode on POSIX after `mkdir`, then opens the stub with `O_CREAT | O_WRONLY | O_EXCL | O_NOFOLLOW` so pre-existing inodes trigger EEXIST and final-component symlinks trigger ELOOP rather than silent file overwrite
13
- - `src/cache-with-ttl.ts` `getOrFetch()` — the inflight-map check ran _after_ `await get(key)`, so two concurrent cold-cache callers both suspended on the same disk read, both saw no cached value, both skipped the inflight check, and both fired `fetcher()`. Moves the inflight check before the persistent-cache lookup (with a re-check afterward) so the advertised dedupe guarantee actually holds
14
- - `src/cache-with-ttl.ts` — cap the in-memory `memoCache` with LRU eviction (`memoMaxSize`, default 1000). Previously a long-running process (devserver, editor extension) querying many distinct keys grew memory without bound — expired entries were only reclaimed when the same key was read again
15
- - `src/memoization.ts` `memoizeAsync()` — `entry.timestamp` was set when a cache miss STARTED its `fn(...)` call, so a fn taking longer than `ttl` produced a value classified as expired the moment it resolved; every subsequent caller past the first ttl window re-fetched instead of hitting the cache. Now refreshes the timestamp in the resolve handler. Also bumps `accessOrder` on the stale-dedup branch so an entry mid-refresh isn't evicted while a peer is computing on its behalf
16
- - `src/tables.ts` `displayWidth` measured columns by `.length` of the ANSI-stripped string, i.e. UTF-16 code units rather than rendered terminal cells. CJK, emoji, and combined code points misaligned tables. Routes measurement through `stringWidth` (Intl.Segmenter + East Asian Width)
17
- - `src/paths/packages.ts` — `resolvePackageJsonDirname` / `resolvePackageJsonPath` gated on `filepath.endsWith('package.json')`, which misidentified any file whose name ended in that suffix (e.g. `/foo/my-package.json`) as a manifest. Now checks for the literal final segment
18
- - `src/json/edit.ts` — `@example` for `getEditableJsonClass` imported from `@socketsecurity/lib/json`, which is not a package export; fixed to `@socketsecurity/lib/json/edit`
12
+ - `@socketsecurity/lib/errors` `isError(value)` spec-compliant ES2025 [`Error.isError`](https://tc39.es/ecma262/#sec-error.iserror) with an `@@toStringTag`-based shim for older engines. Recognizes cross-realm Errors (worker threads, vm contexts, iframes) that same-realm `instanceof Error` misses
13
+ - `@socketsecurity/lib/errors` `errorMessage(value)` — extracts a readable message from any caught value (Error with cause chain via `messageWithCauses`, primitive, plain object, or nullish) with the shared `UNKNOWN_ERROR` (`'Unknown error'`) fallback. Replaces the `e instanceof Error ? e.message : String(e)` pattern
14
+ - `@socketsecurity/lib/errors` `errorStack(value)` companion helper returning the cause-aware stack for Error instances (via `stackWithCauses`) and `undefined` otherwise
15
+ - `@socketsecurity/lib/errors` `isErrnoException(value)` — narrows to `NodeJS.ErrnoException` (an Error with a non-empty uppercase-prefixed `.code`, matching the libuv `UV_E*` / Node `ERR_*` conventions), cross-realm safe
16
+ - `@socketsecurity/lib/errors` re-exports `UNKNOWN_ERROR` from `constants/core` so callers don't need a separate import
19
17
 
20
- ## [5.20.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.0) - 2026-04-19
18
+ ### Changed
19
+
20
+ - `@socketsecurity/lib/errors` pony-cause `messageWithCauses` / `stackWithCauses` / `findCauseByReference` / `getErrorCause` — patched to use `isError` internally so cross-realm Errors are recognized (previously returned `''` for any Error thrown in a different realm)
21
+
22
+ ## [5.22.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.22.0) - 2026-04-21
23
+
24
+ ### Changed
25
+
26
+ - `@socketsecurity/lib/releases/socket-btm` `getPlatformArch()` / `getBinaryAssetName()` — aligned with pnpm pack-app's `<os>-<arch>[-<libc>]` target format. The Windows OS segment is now `win32` (was `win`); `getPlatformArch('win32', 'x64')` returns `'win32-x64'` and `getBinaryAssetName('node', 'win32', 'x64')` returns `'node-win32-x64.exe'`. Callers that string-match on the output need updates
27
+
28
+ ## [5.21.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.21.0) - 2026-04-20
29
+
30
+ ### Added
21
31
 
22
- ### Addedvalidation
32
+ - `@socketsecurity/lib/schema/validate`non-throwing Zod/TypeBox validator returning `{ ok, value } | { ok, errors }` with normalized paths
33
+ - `@socketsecurity/lib/schema/parse` — throwing variant for fail-fast trust boundaries
34
+ - `@socketsecurity/lib/schema/types` — `Schema<T>`, `ValidateResult<T>`, `ValidationIssue`, `AnySchema`, `Infer<S>`
35
+ - `@socketsecurity/lib/promises` `withResolvers()` — spec-compliant [`Promise.withResolvers`](https://tc39.es/ecma262/#sec-promise.withResolvers) helper with `PromiseWithResolvers<T>` type. Uses the native implementation when available
23
36
 
24
- - `@socketsecurity/lib/validation/validate-schema` — universal validator that accepts any Zod-style schema (Zod v3/v4, or any `safeParse`-shaped duck type) and returns a tagged `{ ok: true, value } | { ok: false, errors }` result with normalized `{ path, message }` issues. Type inference flows through: callers get `z.infer<…>`, no casts. Zod is detected purely structurally via `.safeParse` — no runtime import of the `zod` package required
25
- - `parseSchema(schema, data)` — throwing twin of `validateSchema` for fail-fast trust-boundary validation
26
- - `Infer<S>`, `ValidateResult<T>`, `ValidationIssue`, `AnySchema` supporting types exported alongside the helpers
37
+ ### Changed
38
+
39
+ - `@socketsecurity/lib/regexps` `escapeRegExp()` — now spec-compliant with TC39 [`RegExp.escape`](https://tc39.es/ecma262/#sec-regexp.escape); uses the native implementation when available. **Caller-visible shape change**: escaped output now uses `\xHH` for many characters that previously passed through literally (e.g. `escapeRegExp('a')` is now `'\x61'`). Functional equivalence (the compiled regex matches the original input) is preserved; only callers that string-match on escape output need updates
40
+ - `@socketsecurity/lib/memoization` `MemoizeOptions<Args>` — dropped the unused second type parameter. Consumers who wrote `MemoizeOptions<Args, Result>` must drop the second argument
41
+ - `@socketsecurity/lib/packages/specs` `getRepoUrlDetails()` — now accepts `git+https://` / `git+ssh://` GitHub URLs and rejects lookalike hosts (`githubXcom`, `fake-github.com.attacker.tld`). scp-style `git@github.com:…` URLs (no `://`) now return `{ user: '', project: '' }` — callers must normalize to https/ssh upstream
42
+ - `@socketsecurity/lib/url` `urlSearchParamAsBoolean()` — accepts the same truthy vocabulary as `envAsBoolean` (`1` / `true` / `yes` / `on`, case-insensitive). Empty-string input now falls through to `defaultValue` instead of returning `false`
43
+
44
+ ### Removed
45
+
46
+ - `@socketsecurity/lib/validation/*` subpath retired — exports re-homed:
47
+ - `validateSchema` / `parseSchema` → `@socketsecurity/lib/schema/validate` / `@socketsecurity/lib/schema/parse`
48
+ - `safeJsonParse` → `@socketsecurity/lib/json/parse`
49
+ - Types → `@socketsecurity/lib/schema/types` and `@socketsecurity/lib/json/types`
50
+ - `memoizeDebounced` from `@socketsecurity/lib/memoization` — was misnamed and had no consumers. Use `memoize` / `memoizeAsync` with a `ttl` instead
27
51
 
28
52
  ### Fixed
29
53
 
30
- - `src/promise-queue.ts`: wrap `task.fn()` invocation via `Promise.resolve().then()` so a **synchronous** throw inside a queued task converts to a proper rejection on `task.reject` instead of escaping as an uncaught exception
31
- - `src/stdio/progress.ts` `formatTime()`: clamp negative milliseconds so an over-ticking or clock-skewed progress bar no longer renders a negative ETA like `-1m59s`
32
- - `src/dlx/lockfile.ts`: wrap the scratch-directory cleanup in `finally` with its own `try/catch` so a cleanup failure cannot clobber the real exception from the main try-block
33
- - `src/dlx/package.ts` `parsePackageSpec`: normalize a bare trailing `@` (e.g. `"pkg@"`) to `version: undefined` so downstream "no version provided" checks behave consistently
34
- - `src/stdio/prompts.ts`: tighten the `selectModule` destructure type to the two properties actually used (`default`, `Separator`) instead of an `as any` cast
35
- - `src/http-request.ts`: hoist `CHECKSUM_BSD_RE` and `CHECKSUM_GNU_RE` regex literals to module scope so `parseChecksums()` no longer re-declares them once per line inside its loop
36
- - `src/dlx/manifest.ts`: correct the `@fileoverview` "Primary API" list to match the actual `DlxManifest` methods (`get/set/clear/clearAll/isFresh/getManifestEntry`) and flag `setPackageEntry` / `setBinaryEntry` as deprecated
54
+ - `@socketsecurity/lib/versions` `maxVersion()` / `minVersion()` return the latest/earliest prerelease for all-prerelease inputs (previously returned `undefined`)
55
+ - `@socketsecurity/lib/fs` `findUp()` / `findUpSync()` traverse up to and **including** the filesystem root (previously missed matches at `/.foo`)
56
+ - `@socketsecurity/lib/words` `capitalize()` safe for non-BMP characters (emoji, astral-plane scripts); previously produced broken surrogate pairs
57
+ - `@socketsecurity/lib/words` `determineArticle()` case-insensitive vowel match (`Apple` `an Apple`)
58
+ - `@socketsecurity/lib/archives` `extractZip()` / `extractTar()` / `extractTarGz()` missing-archive errors now uniformly surface as `ENOENT` with `code` / `path` / message (previously `extractZip` surfaced adm-zip's generic `"Invalid filename"`)
59
+ - `@socketsecurity/lib/promise-queue` bounded queue now rejects the newest submission when full, preserving in-flight work
60
+ - `@socketsecurity/lib/cacache` / `@socketsecurity/lib/cache-with-ttl` wildcard key deletion anchors both ends of the pattern (`deleteAll('foo*bar')` no longer sweeps `foo123bar-extra`)
61
+ - `@socketsecurity/lib/process-lock` — sub-second `staleMs` values now honored at full precision; TOCTOU window on lock acquisition closed
62
+ - `@socketsecurity/lib/suppress-warnings` `withSuppressedWarnings()` — no longer wipes concurrent suppressions on exit
63
+ - Unbounded LRU caches in `@socketsecurity/lib/dlx` capped (binary path, package.json path); negative package.json lookups now expire after 10s
64
+ - Glob cache keys for array-valued options (e.g. `ignore`) are order-insensitive
37
65
 
38
- ## [5.19.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.1) - 2026-04-19
66
+ ### Performance
39
67
 
40
- ### Fixedstdio (restore accidentally-dropped modules)
68
+ - `@socketsecurity/lib/memoization``memoize()` / `memoizeAsync()` cache-hit bookkeeping dropped from O(n) to O(1). Noticeable on caches with many entries
69
+ - `@socketsecurity/lib/cacache` — wildcard `clear()` no longer recompiles the match regex per streamed entry
41
70
 
42
- 5.19.0 shipped a breaking change that was not called out in its changelog or version bump: a refactor commit removed `stdio/prompts`, `stdio/progress`, `stdio/clear`, and the vendored `external/@inquirer/*` shims. socket-cli and other consumers import `stdio/prompts` directly and broke on upgrade.
71
+ ## [5.20.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.1) - 2026-04-19
43
72
 
44
- Restored:
73
+ ### Fixed
45
74
 
46
- - `@socketsecurity/lib/stdio/prompts` — inquirer wrappers (`password`, `confirm`, `input`, `select`, `checkbox`, `search`)
47
- - `@socketsecurity/lib/stdio/progress` — progress-bar utility (`ProgressBar` class)
48
- - `@socketsecurity/lib/stdio/clear` — terminal line/screen/cursor helpers
49
- - `src/external/@inquirer/{checkbox,confirm,input,password,search,select}.js` vendor shims
50
- - Corresponding test suites
75
+ - `@socketsecurity/lib/ipc` — harden stub-file writes against symlink/TOCTOU attacks on shared-tmp filesystems (POSIX ownership + mode validation, `O_EXCL | O_NOFOLLOW` open)
76
+ - `@socketsecurity/lib/cache-with-ttl` `getOrFetch()` close concurrent-caller race that let two cold-cache awaits both skip the inflight-dedupe check and fire the fetcher twice
77
+ - `@socketsecurity/lib/cache-with-ttl` — cap the in-memory memo layer with LRU eviction (`memoMaxSize`, default 1000); long-running processes no longer grow unbounded
78
+ - `@socketsecurity/lib/memoization` `memoizeAsync()` — refresh cache entry timestamp on resolve so slow fetches (longer than `ttl`) aren't classified as expired the moment they land
79
+ - `@socketsecurity/lib/tables` `displayWidth` now measures rendered terminal cells (via `stringWidth`) instead of UTF-16 code units; CJK / emoji / combining marks align correctly
80
+ - `@socketsecurity/lib/paths/packages` — `resolvePackageJsonDirname` / `resolvePackageJsonPath` no longer mis-identify files like `/foo/my-package.json` as package manifests
81
+ - `@socketsecurity/lib/json/edit` — `@example` import path corrected
51
82
 
52
- ## [5.19.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.0) - 2026-04-19
83
+ ## [5.20.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.0) - 2026-04-19
84
+
85
+ ### Added
53
86
 
54
- ### Addeddlx/integrity (new module)
87
+ - `@socketsecurity/lib/validation/validate-schema`universal Zod-style schema validator with `validateSchema` (tagged result) and `parseSchema` (throwing); `Infer<S>`, `ValidateResult<T>`, `ValidationIssue`, `AnySchema` types. No runtime `zod` dependency
55
88
 
56
- - `HashSpec`, `NormalizedHash`, `ComputedHashes` types. `HashSpec` accepts a bare string (sha512 SRI or sha256 hex, sniffed) or an explicit `{ type, value }` object
57
- - `normalizeHash()`, `computeHashes()`, `verifyHash()` — `verifyHash` uses `crypto.timingSafeEqual` for constant-time comparison
58
- - `DlxHashMismatchError` — carries `expected` + `actual` for diagnostics
89
+ > **Deprecated in 5.21.0**: moved to `@socketsecurity/lib/schema/*`.
59
90
 
60
- ### Added — dlx/arborist (new module)
91
+ ### Fixed
61
92
 
62
- - `safeIdealTree()`, `safeReify()` — hardened `@npmcli/arborist` wrappers mirroring socket-cli v1.1.79 `SafeArborist` overrides (`audit: false`, `fund: false`, `ignoreScripts: true`, `progress: false`, `saveBundle: false`, `silent: true`)
63
- - `writeSafeNpmrc()` — defense-in-depth `.npmrc` writer matching the Arborist overrides
64
- - Optional `before?: Date` on `safeIdealTree` for release-age enforcement during resolution
93
+ - `@socketsecurity/lib/promise-queue` synchronous throws inside a queued task now convert to proper rejections instead of escaping as uncaught exceptions
94
+ - `@socketsecurity/lib/stdio/progress` `formatTime()` — clamp negative milliseconds so over-ticking / clock-skewed bars don't render negative ETAs
95
+ - `@socketsecurity/lib/dlx/lockfile` scratch-directory cleanup can no longer clobber the real exception from the main block
96
+ - `@socketsecurity/lib/dlx/package` `parsePackageSpec` — normalize a bare trailing `@` (e.g. `"pkg@"`) to `version: undefined`
97
+ - `@socketsecurity/lib/stdio/prompts` — tighten an internal destructure type away from `as any`
98
+ - `@socketsecurity/lib/http-request` — hoist checksum regex literals out of a per-line loop
65
99
 
66
- ### Added — dlx/lockfile (new module)
100
+ ## [5.19.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.1) - 2026-04-19
67
101
 
68
- - `generatePackagePin({ package, minReleaseDays?, minReleaseMins? })` — returns `PinDetails { name, version, hash: ComputedHashes, packageJson, lockfile }`. Runs Arborist in `packageLockOnly: true` mode against a tmp directory and auto-cleans
69
- - **Default `minReleaseDays: 7`** — resolution refuses to select versions published in the last week. Pass `0` to disable. `minReleaseMins` is a pnpm-style alias (mutually exclusive with `minReleaseDays`)
70
- - `LockfileSpec` type — export for use as the new `lockfile` option on `downloadPackage`
102
+ ### Fixed
71
103
 
72
- ### Addeddlx existing modules
104
+ Restore `@socketsecurity/lib/stdio/prompts`, `@socketsecurity/lib/stdio/progress`, and `@socketsecurity/lib/stdio/clear` accidentally removed in 5.19.0 without a major-bump callout. Downstream consumers that import `stdio/prompts` directly are unbroken.
73
105
 
74
- - `DlxPackageOptions.hash?: HashSpec` and `DlxPackageOptions.lockfile?: LockfileSpec` — passing a lockfile materializes it into the install dir (path → `fs.copyFileSync`, content → `fs.writeFileSync`) and drops a hardened `.npmrc` alongside before Arborist runs
75
- - `DlxBinaryOptions.hash?: HashSpec` — ergonomic alternative to the lower-level `integrity` and `sha256` fields (both still accepted)
106
+ ## [5.19.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.0) - 2026-04-19
76
107
 
77
- ### Fixed — external
108
+ ### Added
78
109
 
79
- - `pacote` shim now exposes `tarball`, `manifest`, `packument` alongside `extract`. **Fixes a latent runtime crash** in `src/packages/manifest.ts` callers (`fetchPackageManifest` / `fetchPackagePackument` called `.manifest(...)` / `.packument(...)` on a shim that previously only had `extract`, raising `TypeError: not a function`)
110
+ - `@socketsecurity/lib/dlx/integrity` hash verification utilities: `HashSpec`, `NormalizedHash`, `ComputedHashes`, `normalizeHash()`, `computeHashes()`, `verifyHash()` (constant-time via `crypto.timingSafeEqual`), `DlxHashMismatchError`
111
+ - `@socketsecurity/lib/dlx/arborist` — hardened `@npmcli/arborist` wrappers: `safeIdealTree()`, `safeReify()`, `writeSafeNpmrc()`. Locks down `audit`, `fund`, `ignoreScripts`, `saveBundle`, etc. Supports `before?: Date` for release-age enforcement
112
+ - `@socketsecurity/lib/dlx/lockfile` — `generatePackagePin()` returns `{ name, version, hash, packageJson, lockfile }` for a resolved package. Default `minReleaseDays: 7` refuses versions published in the last week (`0` to disable); `minReleaseMins` accepted as pnpm-style alias
113
+ - `DlxPackageOptions.hash`, `DlxPackageOptions.lockfile`, `DlxBinaryOptions.hash` — first-class integrity + lockfile options on the dlx entry points
80
114
 
81
- ### Changed — build (bundle size)
115
+ ### Fixed
82
116
 
83
- - `dist/external/npm-pack.js`: 2,526,598 1,755,460 bytes (−771 KB, −30.5%). New `STUB_MAP` entries for code paths our callers never reach:
84
- - `@sigstore/{bundle,core,protobuf-specs,sign,tuf,verify}`, `sigstore`, `tuf-js`, `@tufjs/{canonical-json,models}` — Sigstore attestation, only reached via `arb.audit()`
85
- - `@npmcli/metavuln-calculator` — audit-only
86
- - `@npmcli/query`, `postcss-selector-parser` — `arb.query()` unused
87
- - `@npmcli/run-script`, `@npmcli/node-gyp` guarded out by `ignoreScripts: true`
88
- - `@npmcli/git`, `pacote/lib/{git,file,dir,remote}.js` — registry specs only
89
- - arborist `audit-report.js`, `yarn-lock.js`, `isolated-reifier.js`, `query-selector-all.js`, `printable.js` — each gated or unused
90
- - `cacache/lib/verify.js` — `cacache.verify` (npm cache verify) unused
91
- - `proggy` — progress tracker, gated by `progress: false`
92
- - `debug/src/browser.js` — Node-only bundle
93
- - `dist/external/zod.js`: 597,238 → 291,430 bytes (−306 KB, −51.2%). Stubbed `zod/v4/{core,classic,mini}`'s eager `locales/index.cjs` barrel (40+ translation modules). Opt-in via `z.config(z.locales.xx())` is never called by us
117
+ - `pacote` shim exposes `tarball`, `manifest`, `packument` alongside `extract`. Fixes a latent runtime crash in `fetchPackageManifest` / `fetchPackagePackument` callers
118
+
119
+ ### Changed
120
+
121
+ Reduced bundle size of `dist/external/npm-pack.js` (−771 KB, −30.5%) and `dist/external/zod.js` (−306 KB, −51.2%) by stubbing code paths our callers never reach (Sigstore attestation, arborist audit/query, zod locale translations, etc.)
94
122
 
95
123
  ## [5.18.2](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.2) - 2026-04-14
96
124
 
@@ -100,70 +128,63 @@ Restored:
100
128
 
101
129
  ## [5.18.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.1) - 2026-04-14
102
130
 
103
- ### Changed — build
131
+ ### Changed
104
132
 
105
- - Dedup npm-pack.js bundle via pnpm overrides: pacote 21.5.0, make-fetch-happen 15.0.5, and 7 transitive npm packages (npm-bundled, npm-normalize-package-bin, json-parse-even-better-errors, @npmcli/installed-package-contents, @npmcli/name-from-folder, @npmcli/promise-spawn, @npmcli/redact)
106
- - npm-pack.js: 69,738 → 66,443 lines (2.59MB → 2.46MB), 22 duplicate packages removed
133
+ - Deduplicated the `dist/external/npm-pack` bundle via `pnpm overrides` (pacote 21.5.0, make-fetch-happen 15.0.5, and 7 transitive `@npmcli/*` packages) 22 duplicate packages removed, ~130 KB smaller
107
134
 
108
135
  ## [5.18.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.0) - 2026-04-14
109
136
 
110
- ### Added — dlx
137
+ ### Added
111
138
 
112
- - Socket Firewall API check before package downloads resolves dependency tree via `buildIdealTree`, checks all packages against `firewall-api.socket.dev/purl` in parallel, blocks on critical/high severity alerts
139
+ - `@socketsecurity/lib/dlx` — Socket Firewall API check before package downloads. Resolves the dependency tree and blocks on critical/high severity alerts
113
140
 
114
- ### Changed — http-request
141
+ ### Changed
115
142
 
116
- - Default `User-Agent` header updated from `socket-registry/1.0` to `socketsecurity-lib/{version}`
143
+ - `@socketsecurity/lib/http-request` — default `User-Agent` updated from `socket-registry/1.0` to `socketsecurity-lib/{version}`
117
144
 
118
145
  ## [5.17.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.17.0) - 2026-04-14
119
146
 
120
- ### Added — paths
147
+ ### Added
121
148
 
122
- - `isUnixPath()` — detect MSYS/Git Bash drive letter notation (`/c/...`)
149
+ - `@socketsecurity/lib/paths` `isUnixPath()` — detect MSYS/Git Bash drive-letter notation (`/c/...`)
123
150
 
124
- ### Changed — paths
151
+ ### Changed
125
152
 
126
- - `normalizePath()` now converts MSYS drive letters on Windows (`/c/path` → `C:/path`)
127
- - `fromUnixPath()` now produces native Windows paths with backslashes (`/c/path` → `C:\path`), making it the true inverse of `toUnixPath()`
153
+ - `@socketsecurity/lib/paths` `normalizePath()` converts MSYS drive letters on Windows (`/c/path` → `C:/path`)
154
+ - `@socketsecurity/lib/paths` `fromUnixPath()` produces native Windows paths with backslashes (`/c/path` → `C:\path`), making it the true inverse of `toUnixPath()`
128
155
 
129
156
  ## [5.16.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.16.0) - 2026-04-14
130
157
 
131
- ### Added — paths
158
+ ### Added
132
159
 
133
- - `fromUnixPath()` — convert MSYS/Git Bash Unix-style paths (`/c/path`) back to native Windows format (`C:/path`), inverse of `toUnixPath` (#168)
160
+ - `@socketsecurity/lib/paths` `fromUnixPath()` — convert MSYS/Git Bash Unix-style paths (`/c/path`) back to native Windows format (`C:/path`), inverse of `toUnixPath` (#168)
134
161
 
135
- ### Fixed — dlx
162
+ ### Fixed
136
163
 
137
- - Normalize dlx directory path in `isInSocketDlx` for Windows compatibility
164
+ - `@socketsecurity/lib/dlx` `isInSocketDlx` — normalize the dlx directory path for Windows compatibility
138
165
 
139
166
  ## [5.15.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.15.0) - 2026-04-06
140
167
 
141
- ### Added — http-request
142
-
143
- - `stream` option on `HttpRequestOptions` — resolves with `HttpResponse` immediately after headers arrive, leaving `rawResponse` unconsumed for piping to files
144
- - `headers`, `ok`, `status`, `statusText` fields on `HttpDownloadResult`
145
-
146
- ### Changed — http-request
168
+ ### Added
147
169
 
148
- - `httpDownload` now uses `httpRequest` with `stream: true` internally, eliminating ~120 lines of duplicated HTTP plumbing
170
+ - `@socketsecurity/lib/http-request``stream` option on `HttpRequestOptions` resolves with `HttpResponse` immediately after headers arrive, leaving `rawResponse` unconsumed for piping to files
171
+ - `@socketsecurity/lib/http-request` — `headers`, `ok`, `status`, `statusText` fields on `HttpDownloadResult`
149
172
 
150
173
  ## [5.14.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.14.0) - 2026-04-06
151
174
 
152
- ### Added — http-request
175
+ ### Added
153
176
 
154
- - `HttpResponseError` class — thrown on non-2xx when `throwOnError` is enabled, carries the full `HttpResponse`
155
- - `throwOnError` option on `HttpRequestOptions` non-2xx responses throw instead of resolving with `ok: false`, enabling retry of HTTP errors
156
- - `onRetry` callback on `HttpRequestOptions` customize retry behavior per-attempt (return `false` to stop, a `number` to override delay, `undefined` for default backoff)
157
- - Streaming body support `body` accepts `Readable` streams (incl. `form-data` npm package), auto-merges `getHeaders()` when present
158
- - `parseRetryAfterHeader()` standalone RFC 7231 §7.1.3 `Retry-After` header parser (strict integer seconds + HTTP-date formats)
159
- - `sanitizeHeaders()` — redact sensitive headers (`authorization`, `cookie`, `set-cookie`, `proxy-authorization`, `proxy-authenticate`, `www-authenticate`) for safe logging
177
+ - `@socketsecurity/lib/http-request`:
178
+ - `HttpResponseError` class thrown on non-2xx when `throwOnError` is enabled; carries the full `HttpResponse`
179
+ - `throwOnError` optionnon-2xx responses throw instead of resolving with `ok: false`
180
+ - `onRetry` callbackcustomize retry behavior per-attempt (`false` to stop, a `number` to override delay, `undefined` for default backoff)
181
+ - Streaming body support — `body` accepts `Readable` streams (incl. `form-data`), auto-merges `getHeaders()` when present
182
+ - `parseRetryAfterHeader()` — standalone RFC 7231 §7.1.3 parser
183
+ - `sanitizeHeaders()` — redact sensitive headers for safe logging
160
184
 
161
- ### Changed — http-request
185
+ ### Changed
162
186
 
163
- - `HttpRequestOptions.body` type widened from `Buffer | string` to `Buffer | Readable | string`
164
- - Redirect responses now drained via `res.resume()` to free sockets
165
- - `maxResponseSize` exceeded now cleans up both response and request
166
- - `onResponse` hooks wrapped in try/catch — user hook errors can no longer leave promises pending
187
+ - `@socketsecurity/lib/http-request` — `HttpRequestOptions.body` widened to `Buffer | Readable | string`; `onResponse` hook errors no longer leave promises pending
167
188
 
168
189
  ## [5.13.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.13.0) - 2026-04-05
169
190
 
package/README.md CHANGED
@@ -7,219 +7,62 @@
7
7
  [![Follow @SocketSecurity](https://img.shields.io/twitter/follow/SocketSecurity?style=social)](https://twitter.com/SocketSecurity)
8
8
  [![Follow @socket.dev on Bluesky](https://img.shields.io/badge/Follow-@socket.dev-1DA1F2?style=social&logo=bluesky)](https://bsky.app/profile/socket.dev)
9
9
 
10
- Core infrastructure library for [Socket.dev](https://socket.dev/) security tools. Provides utilities for file system operations, process spawning, HTTP requests, environment detection, logging, spinners, and more.
11
-
12
- ## Prerequisites
13
-
14
- **Node.js 22 or higher** is required.
10
+ Core utilities for [Socket.dev](https://socket.dev/) tools: file system, processes, HTTP, env detection, logging, spinners, and more. Tree-shakeable, TypeScript-first, cross-platform.
15
11
 
16
12
  ## Install
17
13
 
18
14
  ```bash
19
- # Using pnpm (recommended)
20
15
  pnpm add @socketsecurity/lib
21
-
22
- # Using npm
23
- npm install @socketsecurity/lib
24
-
25
- # Using yarn
26
- yarn add @socketsecurity/lib
27
16
  ```
28
17
 
29
18
  ## Quick Start
30
19
 
31
20
  ```typescript
32
21
  import { Spinner } from '@socketsecurity/lib/spinner'
33
- import { getDefaultLogger } from '@socketsecurity/lib/logger'
34
22
  import { readJson } from '@socketsecurity/lib/fs'
35
23
 
36
- const logger = getDefaultLogger()
37
- const spinner = Spinner({ text: 'Loading package.json...' })
38
-
24
+ const spinner = Spinner({ text: 'Loading…' })
39
25
  spinner.start()
40
26
  const pkg = await readJson('./package.json')
41
- spinner.successAndStop('Loaded successfully')
42
-
43
- logger.success(`Package: ${pkg.name}@${pkg.version}`)
27
+ spinner.successAndStop(`Loaded ${pkg.name}@${pkg.version}`)
44
28
  ```
45
29
 
46
- ## Documentation
47
-
48
- - [API Index](./docs/api-index.md) - Every subpath export with a one-line description (start here)
49
- - [Getting Started](./docs/getting-started.md) - Prerequisites, installation, and first examples
50
- - [Visual Effects](./docs/visual-effects.md) - Spinners, loggers, themes, and progress indicators
51
- - [File System](./docs/file-system.md) - File operations, globs, paths, and safe deletion
52
- - [HTTP Utilities](./docs/http-utilities.md) - Making requests, downloading files, and retry logic
53
- - [Process Utilities](./docs/process-utilities.md) - Spawning processes, IPC, and locks
54
- - [Package Management](./docs/package-management.md) - npm/pnpm/yarn detection and operations
55
- - [Environment](./docs/environment.md) - CI detection, env getters, and platform checks
56
- - [Constants](./docs/constants.md) - Node versions, npm URLs, and platform values
57
- - [Examples](./docs/examples.md) - Real-world usage patterns
58
- - [Troubleshooting](./docs/troubleshooting.md) - Common issues and solutions
59
-
60
- ## What's Inside
61
-
62
- ### Visual Effects
63
-
64
- Spinners, colored loggers, themes, progress bars, and terminal output formatting.
65
-
66
- - `Spinner` - Animated CLI spinners with progress tracking
67
- - `getDefaultLogger()` - Colored console logger with symbols
68
- - `LOG_SYMBOLS` - Colored terminal symbols (✓, ✗, ⚠, ℹ, →)
69
- - `setTheme()` - Customize colors across the library
70
-
71
- ### File System
72
-
73
- Cross-platform file operations with safe deletion and convenient wrappers.
74
-
75
- - `readFileUtf8()`, `readFileBinary()` - Read files as text or binary
76
- - `readJson()`, `writeJson()` - Parse and format JSON files
77
- - `safeDelete()` - Protected deletion with safety checks
78
- - `findUp()`, `findUpSync()` - Traverse up to find files
79
- - `safeMkdir()` - Create directories without EEXIST errors
80
- - `validateFiles()` - Check file readability (useful for Yarn PnP, pnpm)
81
-
82
- ### HTTP Utilities
83
-
84
- Native Node.js HTTP/HTTPS requests with retry logic and redirects.
85
-
86
- - `httpJson()` - Fetch and parse JSON from APIs
87
- - `httpText()` - Fetch text/HTML content
88
- - `httpDownload()` - Download files with progress callbacks
89
- - `httpRequest()` - Full control over requests and responses
90
- - Automatic redirects, exponential backoff retries, timeout support
91
-
92
- ### Process Management
93
-
94
- Spawn child processes safely with cross-platform support.
95
-
96
- - `spawn()` - Promise-based process spawning with output capture
97
- - `spawnSync()` - Synchronous version for blocking operations
98
- - Array-based arguments prevent command injection
99
- - Automatic Windows `.cmd`/`.bat` handling
100
- - `processLock.withLock()` / `processLock.acquire()` / `processLock.release()` - Ensure only one instance runs at a time
101
- - `writeIpcStub()` / `getIpcStubPath()` - Filesystem-based inter-process data handoff
102
-
103
- ### Environment Detection
104
-
105
- Type-safe environment variable access and platform detection.
106
-
107
- - `getCI()` - Detect CI environment
108
- - `getNodeEnv()` - Get NODE_ENV value
109
- - `isTest()` - Check if running tests
110
- - `getHome()` - Home directory (cross-platform, with Windows `USERPROFILE` fallback)
111
- - Test rewiring with `setEnv()`, `resetEnv()`
112
-
113
- ### Package Management
114
-
115
- Detect and work with npm, pnpm, and yarn.
116
-
117
- - `detectPackageManager()` - Identify running package manager from `npm_config_user_agent` / binary path
118
- - Package manifest operations
119
- - Lock file management
120
-
121
- ### Constants
122
-
123
- Pre-defined values for Node.js, npm, and platform detection.
124
-
125
- - `getNodeMajorVersion()` - Get current Node.js major version
126
- - `WIN32`, `DARWIN` - Platform booleans (use `!WIN32 && !DARWIN` for Linux)
127
- - `getAbortSignal()` - Global abort signal
128
-
129
- ### Utilities
130
-
131
- Helpers for arrays, objects, strings, promises, sorting, and more.
132
-
133
- - Arrays, objects, strings manipulation
134
- - Promise utilities and queues
135
- - Natural sorting
136
- - Version comparison
137
- - Error handling with causes
138
-
139
- ## Features
140
-
141
- - **Tree-shakeable exports** - Import only what you need
142
- - **Cross-platform** - Works on Windows, macOS, and Linux
143
- - **TypeScript-first** - Full type safety with .d.ts files
144
- - **Zero dependencies** (for core HTTP - uses Node.js native modules)
145
- - **Well-tested** - 6000+ tests across 139+ test files
146
- - **Security-focused** - Safe defaults, command injection protection
147
- - **CommonJS output** - Compatible with Node.js tooling
148
-
149
- ## Common Use Cases
150
-
151
- ### Running Shell Commands
30
+ Every export lives under a subpath — pick what you need:
152
31
 
153
32
  ```typescript
154
33
  import { spawn } from '@socketsecurity/lib/spawn'
155
-
156
- const result = await spawn('git', ['status'])
157
- console.log(result.stdout)
158
- ```
159
-
160
- ### Making API Requests
161
-
162
- ```typescript
163
34
  import { httpJson } from '@socketsecurity/lib/http-request'
164
-
165
- const data = await httpJson('https://api.example.com/data')
166
- ```
167
-
168
- ### Visual Feedback
169
-
170
- ```typescript
171
- import { Spinner } from '@socketsecurity/lib/spinner'
172
-
173
- const spinner = Spinner({ text: 'Processing...' })
174
- spinner.start()
175
- // ... do work ...
176
- spinner.successAndStop('Complete!')
177
- ```
178
-
179
- ### Safe File Deletion
180
-
181
- ```typescript
182
35
  import { safeDelete } from '@socketsecurity/lib/fs'
183
-
184
- // Protected against deleting parent directories
185
- await safeDelete('./build')
186
- ```
187
-
188
- ## Troubleshooting
189
-
190
- **Module not found**: Verify you're importing from the correct path:
191
-
192
- ```typescript
193
- // Correct
194
- import { Spinner } from '@socketsecurity/lib/spinner'
195
-
196
- // Wrong
197
- import { Spinner } from '@socketsecurity/lib'
198
36
  ```
199
37
 
200
- **Node version error**: This library requires Node.js 22+. Check your version:
38
+ ## Documentation
201
39
 
202
- ```bash
203
- node --version
204
- ```
40
+ Start with the [API Index](./docs/api-index.md) — every subpath export with a one-line description.
205
41
 
206
- For more issues, see the [Troubleshooting Guide](./docs/troubleshooting.md).
42
+ - [Getting Started](./docs/getting-started.md) – install + first examples
43
+ - [Visual Effects](./docs/visual-effects.md) – spinners, loggers, themes
44
+ - [File System](./docs/file-system.md) – files, globs, paths, safe deletion
45
+ - [HTTP Utilities](./docs/http-utilities.md) – requests, downloads, retries
46
+ - [Process Utilities](./docs/process-utilities.md) – spawn, IPC, locks
47
+ - [Package Management](./docs/package-management.md) – npm/pnpm/yarn detection
48
+ - [Environment](./docs/environment.md) – CI/platform detection, env getters
49
+ - [Constants](./docs/constants.md) – Node versions, npm URLs, platform values
50
+ - [Examples](./docs/examples.md) – real-world patterns
51
+ - [Troubleshooting](./docs/troubleshooting.md) – common issues
207
52
 
208
53
  ## Development
209
54
 
210
55
  ```bash
211
- pnpm install # Install dependencies
212
- pnpm build # Build the library
213
- pnpm test # Run tests
214
- pnpm run cover # Run tests with coverage
215
- pnpm dev # Watch mode
216
- pnpm run lint # Check code style
217
- pnpm run fix # Fix formatting issues
56
+ pnpm install # install
57
+ pnpm build # build
58
+ pnpm test # run tests
59
+ pnpm run cover # tests with coverage
60
+ pnpm dev # watch mode
61
+ pnpm run lint # check style
62
+ pnpm run fix # auto-fix formatting
218
63
  ```
219
64
 
220
- ## Contributing
221
-
222
- Contributions are welcome! Please read the [CLAUDE.md](./CLAUDE.md) file for development guidelines and coding standards.
65
+ See [CLAUDE.md](./CLAUDE.md) for contributor guidelines.
223
66
 
224
67
  ## License
225
68
 
package/dist/archives.js CHANGED
@@ -80,6 +80,16 @@ function validatePathWithinBase(targetPath, baseDir, entryName) {
80
80
  );
81
81
  }
82
82
  }
83
+ function assertArchiveExists(archivePath) {
84
+ if (!(0, import_node_fs.existsSync)(archivePath)) {
85
+ const err = new Error(
86
+ `ENOENT: no such file or directory, open '${archivePath}'`
87
+ );
88
+ err.code = "ENOENT";
89
+ err.path = archivePath;
90
+ throw err;
91
+ }
92
+ }
83
93
  function detectArchiveFormat(filePath) {
84
94
  const lower = filePath.toLowerCase();
85
95
  if (lower.endsWith(".tar.gz")) {
@@ -116,6 +126,7 @@ async function extractArchive(archivePath, outputDir, options = {}) {
116
126
  }
117
127
  }
118
128
  async function extractTar(archivePath, outputDir, options = {}) {
129
+ assertArchiveExists(archivePath);
119
130
  const {
120
131
  maxEntries = DEFAULT_MAX_ENTRIES,
121
132
  maxFileSize = DEFAULT_MAX_FILE_SIZE,
@@ -207,6 +218,7 @@ async function extractTar(archivePath, outputDir, options = {}) {
207
218
  }
208
219
  }
209
220
  async function extractTarGz(archivePath, outputDir, options = {}) {
221
+ assertArchiveExists(archivePath);
210
222
  const {
211
223
  maxEntries = DEFAULT_MAX_ENTRIES,
212
224
  maxFileSize = DEFAULT_MAX_FILE_SIZE,
@@ -298,6 +310,7 @@ async function extractTarGz(archivePath, outputDir, options = {}) {
298
310
  }
299
311
  }
300
312
  async function extractZip(archivePath, outputDir, options = {}) {
313
+ assertArchiveExists(archivePath);
301
314
  const {
302
315
  maxEntries = DEFAULT_MAX_ENTRIES,
303
316
  maxFileSize = DEFAULT_MAX_FILE_SIZE,
package/dist/cacache.js CHANGED
@@ -41,17 +41,14 @@ __export(cacache_exports, {
41
41
  module.exports = __toCommonJS(cacache_exports);
42
42
  var import_cacache = __toESM(require("./external/cacache"));
43
43
  var import_socket = require("./paths/socket");
44
- function matchesPattern(key, pattern) {
44
+ function createPatternMatcher(pattern) {
45
45
  if (!pattern.includes("*")) {
46
- return key.startsWith(pattern);
46
+ return (key) => key.startsWith(pattern);
47
47
  }
48
- const regex = patternToRegex(pattern);
49
- return regex.test(key);
50
- }
51
- function patternToRegex(pattern) {
52
48
  const escaped = pattern.replaceAll(/[.+?^${}()|[\]\\]/g, "\\$&");
53
49
  const regexPattern = escaped.replaceAll("*", ".*");
54
- return new RegExp(`^${regexPattern}`);
50
+ const regex = new RegExp(`^${regexPattern}$`);
51
+ return (key) => regex.test(key);
55
52
  }
56
53
  async function clear(options) {
57
54
  const opts = { __proto__: null, ...options };
@@ -84,9 +81,10 @@ async function clear(options) {
84
81
  return removed2;
85
82
  }
86
83
  let removed = 0;
84
+ const matches = createPatternMatcher(opts.prefix);
87
85
  const stream = cacache2.ls.stream(cacheDir);
88
86
  for await (const entry of stream) {
89
- if (matchesPattern(entry.key, opts.prefix)) {
87
+ if (matches(entry.key)) {
90
88
  try {
91
89
  await cacache2.rm.entry(cacheDir, entry.key);
92
90
  removed++;