@socketsecurity/lib 5.19.1 → 5.21.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.
- package/CHANGELOG.md +105 -74
- package/dist/archives.js +13 -0
- package/dist/cacache.js +6 -8
- package/dist/cache-with-ttl.d.ts +7 -0
- package/dist/cache-with-ttl.js +27 -8
- package/dist/constants/socket.js +1 -1
- package/dist/dlx/detect.js +25 -8
- package/dist/dlx/lockfile.js +4 -1
- package/dist/dlx/manifest.d.ts +10 -4
- package/dist/dlx/package.d.ts +1 -1
- package/dist/dlx/package.js +19 -3
- package/dist/external/@npmcli/package-json/lib/read-package.js +40 -32
- package/dist/external/@npmcli/package-json/lib/sort.js +104 -92
- package/dist/external/@npmcli/package-json.js +9 -3968
- package/dist/external/@sinclair/typebox/value.js +9007 -0
- package/dist/external/@sinclair/typebox.js +7891 -0
- package/dist/external/debug.js +162 -328
- package/dist/external/npm-pack.js +13935 -33342
- package/dist/fs.js +8 -2
- package/dist/globs.js +5 -1
- package/dist/http-request.d.ts +0 -25
- package/dist/http-request.js +6 -5
- package/dist/ipc.js +43 -10
- package/dist/json/edit.d.ts +1 -1
- package/dist/json/parse.d.ts +47 -2
- package/dist/json/parse.js +40 -2
- package/dist/json/types.d.ts +49 -0
- package/dist/memoization.d.ts +4 -23
- package/dist/memoization.js +15 -49
- package/dist/packages/specs.js +9 -2
- package/dist/paths/packages.js +6 -2
- package/dist/process-lock.js +1 -6
- package/dist/promise-queue.d.ts +9 -4
- package/dist/promise-queue.js +10 -8
- package/dist/promises.d.ts +41 -0
- package/dist/promises.js +19 -2
- package/dist/regexps.d.ts +4 -13
- package/dist/regexps.js +60 -3
- package/dist/schema/parse.d.ts +26 -0
- package/dist/{zod.js → schema/parse.js} +14 -6
- package/dist/schema/types.d.ts +121 -0
- package/dist/schema/validate.d.ts +35 -0
- package/dist/schema/validate.js +98 -0
- package/dist/stdio/progress.js +1 -1
- package/dist/suppress-warnings.js +0 -2
- package/dist/tables.js +2 -3
- package/dist/url.js +5 -1
- package/dist/versions.js +2 -2
- package/dist/words.js +4 -7
- package/package.json +15 -14
- package/dist/external/zod.js +0 -15223
- package/dist/validation/json-parser.d.ts +0 -58
- package/dist/validation/json-parser.js +0 -63
- package/dist/validation/types.d.ts +0 -118
- package/dist/zod.d.ts +0 -5
- /package/dist/{validation → schema}/types.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,62 +5,100 @@ 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.
|
|
8
|
+
## [5.21.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.21.0) - 2026-04-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
- `@socketsecurity/lib/schema/validate` — non-throwing Zod/TypeBox validator returning `{ ok, value } | { ok, errors }` with normalized paths
|
|
13
|
+
- `@socketsecurity/lib/schema/parse` — throwing variant for fail-fast trust boundaries
|
|
14
|
+
- `@socketsecurity/lib/schema/types` — `Schema<T>`, `ValidateResult<T>`, `ValidationIssue`, `AnySchema`, `Infer<S>`
|
|
15
|
+
- `@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
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
### Changed
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
- `@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
|
|
20
|
+
- `@socketsecurity/lib/memoization` `MemoizeOptions<Args>` — dropped the unused second type parameter. Consumers who wrote `MemoizeOptions<Args, Result>` must drop the second argument
|
|
21
|
+
- `@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
|
|
22
|
+
- `@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`
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
- `@socketsecurity/lib/stdio/progress` — progress-bar utility (`ProgressBar` class)
|
|
18
|
-
- `@socketsecurity/lib/stdio/clear` — terminal line/screen/cursor helpers
|
|
19
|
-
- `src/external/@inquirer/{checkbox,confirm,input,password,search,select}.js` vendor shims
|
|
20
|
-
- Corresponding test suites
|
|
24
|
+
### Removed
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
- `@socketsecurity/lib/validation/*` subpath retired — exports re-homed:
|
|
27
|
+
- `validateSchema` / `parseSchema` → `@socketsecurity/lib/schema/validate` / `@socketsecurity/lib/schema/parse`
|
|
28
|
+
- `safeJsonParse` → `@socketsecurity/lib/json/parse`
|
|
29
|
+
- Types → `@socketsecurity/lib/schema/types` and `@socketsecurity/lib/json/types`
|
|
30
|
+
- `memoizeDebounced` from `@socketsecurity/lib/memoization` — was misnamed and had no consumers. Use `memoize` / `memoizeAsync` with a `ttl` instead
|
|
23
31
|
|
|
24
|
-
###
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- `@socketsecurity/lib/versions` `maxVersion()` / `minVersion()` — return the latest/earliest prerelease for all-prerelease inputs (previously returned `undefined`)
|
|
35
|
+
- `@socketsecurity/lib/fs` `findUp()` / `findUpSync()` — traverse up to and **including** the filesystem root (previously missed matches at `/.foo`)
|
|
36
|
+
- `@socketsecurity/lib/words` `capitalize()` — safe for non-BMP characters (emoji, astral-plane scripts); previously produced broken surrogate pairs
|
|
37
|
+
- `@socketsecurity/lib/words` `determineArticle()` — case-insensitive vowel match (`Apple` → `an Apple`)
|
|
38
|
+
- `@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"`)
|
|
39
|
+
- `@socketsecurity/lib/promise-queue` — bounded queue now rejects the newest submission when full, preserving in-flight work
|
|
40
|
+
- `@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`)
|
|
41
|
+
- `@socketsecurity/lib/process-lock` — sub-second `staleMs` values now honored at full precision; TOCTOU window on lock acquisition closed
|
|
42
|
+
- `@socketsecurity/lib/suppress-warnings` `withSuppressedWarnings()` — no longer wipes concurrent suppressions on exit
|
|
43
|
+
- Unbounded LRU caches in `@socketsecurity/lib/dlx` capped (binary path, package.json path); negative package.json lookups now expire after 10s
|
|
44
|
+
- Glob cache keys for array-valued options (e.g. `ignore`) are order-insensitive
|
|
25
45
|
|
|
26
|
-
|
|
27
|
-
- `normalizeHash()`, `computeHashes()`, `verifyHash()` — `verifyHash` uses `crypto.timingSafeEqual` for constant-time comparison
|
|
28
|
-
- `DlxHashMismatchError` — carries `expected` + `actual` for diagnostics
|
|
46
|
+
### Performance
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
- `@socketsecurity/lib/memoization` — `memoize()` / `memoizeAsync()` cache-hit bookkeeping dropped from O(n) to O(1). Noticeable on caches with many entries
|
|
49
|
+
- `@socketsecurity/lib/cacache` — wildcard `clear()` no longer recompiles the match regex per streamed entry
|
|
31
50
|
|
|
32
|
-
|
|
33
|
-
- `writeSafeNpmrc()` — defense-in-depth `.npmrc` writer matching the Arborist overrides
|
|
34
|
-
- Optional `before?: Date` on `safeIdealTree` for release-age enforcement during resolution
|
|
51
|
+
## [5.20.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.1) - 2026-04-19
|
|
35
52
|
|
|
36
|
-
###
|
|
53
|
+
### Fixed
|
|
37
54
|
|
|
38
|
-
- `
|
|
39
|
-
-
|
|
40
|
-
- `
|
|
55
|
+
- `@socketsecurity/lib/ipc` — harden stub-file writes against symlink/TOCTOU attacks on shared-tmp filesystems (POSIX ownership + mode validation, `O_EXCL | O_NOFOLLOW` open)
|
|
56
|
+
- `@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
|
|
57
|
+
- `@socketsecurity/lib/cache-with-ttl` — cap the in-memory memo layer with LRU eviction (`memoMaxSize`, default 1000); long-running processes no longer grow unbounded
|
|
58
|
+
- `@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
|
|
59
|
+
- `@socketsecurity/lib/tables` — `displayWidth` now measures rendered terminal cells (via `stringWidth`) instead of UTF-16 code units; CJK / emoji / combining marks align correctly
|
|
60
|
+
- `@socketsecurity/lib/paths/packages` — `resolvePackageJsonDirname` / `resolvePackageJsonPath` no longer mis-identify files like `/foo/my-package.json` as package manifests
|
|
61
|
+
- `@socketsecurity/lib/json/edit` — `@example` import path corrected
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
## [5.20.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.20.0) - 2026-04-19
|
|
43
64
|
|
|
44
|
-
|
|
45
|
-
- `DlxBinaryOptions.hash?: HashSpec` — ergonomic alternative to the lower-level `integrity` and `sha256` fields (both still accepted)
|
|
65
|
+
### Added
|
|
46
66
|
|
|
47
|
-
|
|
67
|
+
- `@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
|
|
48
68
|
|
|
49
|
-
|
|
69
|
+
> **Deprecated in 5.21.0**: moved to `@socketsecurity/lib/schema/*`.
|
|
50
70
|
|
|
51
|
-
###
|
|
71
|
+
### Fixed
|
|
52
72
|
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
- `@socketsecurity/lib/promise-queue` — synchronous throws inside a queued task now convert to proper rejections instead of escaping as uncaught exceptions
|
|
74
|
+
- `@socketsecurity/lib/stdio/progress` `formatTime()` — clamp negative milliseconds so over-ticking / clock-skewed bars don't render negative ETAs
|
|
75
|
+
- `@socketsecurity/lib/dlx/lockfile` — scratch-directory cleanup can no longer clobber the real exception from the main block
|
|
76
|
+
- `@socketsecurity/lib/dlx/package` `parsePackageSpec` — normalize a bare trailing `@` (e.g. `"pkg@"`) to `version: undefined`
|
|
77
|
+
- `@socketsecurity/lib/stdio/prompts` — tighten an internal destructure type away from `as any`
|
|
78
|
+
- `@socketsecurity/lib/http-request` — hoist checksum regex literals out of a per-line loop
|
|
79
|
+
|
|
80
|
+
## [5.19.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.1) - 2026-04-19
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
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.
|
|
85
|
+
|
|
86
|
+
## [5.19.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.19.0) - 2026-04-19
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- `@socketsecurity/lib/dlx/integrity` — hash verification utilities: `HashSpec`, `NormalizedHash`, `ComputedHashes`, `normalizeHash()`, `computeHashes()`, `verifyHash()` (constant-time via `crypto.timingSafeEqual`), `DlxHashMismatchError`
|
|
91
|
+
- `@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
|
|
92
|
+
- `@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
|
|
93
|
+
- `DlxPackageOptions.hash`, `DlxPackageOptions.lockfile`, `DlxBinaryOptions.hash` — first-class integrity + lockfile options on the dlx entry points
|
|
94
|
+
|
|
95
|
+
### Fixed
|
|
96
|
+
|
|
97
|
+
- `pacote` shim — exposes `tarball`, `manifest`, `packument` alongside `extract`. Fixes a latent runtime crash in `fetchPackageManifest` / `fetchPackagePackument` callers
|
|
98
|
+
|
|
99
|
+
### Changed
|
|
100
|
+
|
|
101
|
+
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.)
|
|
64
102
|
|
|
65
103
|
## [5.18.2](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.2) - 2026-04-14
|
|
66
104
|
|
|
@@ -70,70 +108,63 @@ Restored:
|
|
|
70
108
|
|
|
71
109
|
## [5.18.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.1) - 2026-04-14
|
|
72
110
|
|
|
73
|
-
### Changed
|
|
111
|
+
### Changed
|
|
74
112
|
|
|
75
|
-
-
|
|
76
|
-
- npm-pack.js: 69,738 → 66,443 lines (2.59MB → 2.46MB), 22 duplicate packages removed
|
|
113
|
+
- 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
|
|
77
114
|
|
|
78
115
|
## [5.18.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.0) - 2026-04-14
|
|
79
116
|
|
|
80
|
-
### Added
|
|
117
|
+
### Added
|
|
81
118
|
|
|
82
|
-
- Socket Firewall API check before package downloads
|
|
119
|
+
- `@socketsecurity/lib/dlx` — Socket Firewall API check before package downloads. Resolves the dependency tree and blocks on critical/high severity alerts
|
|
83
120
|
|
|
84
|
-
### Changed
|
|
121
|
+
### Changed
|
|
85
122
|
|
|
86
|
-
-
|
|
123
|
+
- `@socketsecurity/lib/http-request` — default `User-Agent` updated from `socket-registry/1.0` to `socketsecurity-lib/{version}`
|
|
87
124
|
|
|
88
125
|
## [5.17.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.17.0) - 2026-04-14
|
|
89
126
|
|
|
90
|
-
### Added
|
|
127
|
+
### Added
|
|
91
128
|
|
|
92
|
-
- `isUnixPath()` — detect MSYS/Git Bash drive
|
|
129
|
+
- `@socketsecurity/lib/paths` `isUnixPath()` — detect MSYS/Git Bash drive-letter notation (`/c/...`)
|
|
93
130
|
|
|
94
|
-
### Changed
|
|
131
|
+
### Changed
|
|
95
132
|
|
|
96
|
-
- `normalizePath()`
|
|
97
|
-
- `fromUnixPath()`
|
|
133
|
+
- `@socketsecurity/lib/paths` `normalizePath()` — converts MSYS drive letters on Windows (`/c/path` → `C:/path`)
|
|
134
|
+
- `@socketsecurity/lib/paths` `fromUnixPath()` — produces native Windows paths with backslashes (`/c/path` → `C:\path`), making it the true inverse of `toUnixPath()`
|
|
98
135
|
|
|
99
136
|
## [5.16.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.16.0) - 2026-04-14
|
|
100
137
|
|
|
101
|
-
### Added
|
|
138
|
+
### Added
|
|
102
139
|
|
|
103
|
-
- `fromUnixPath()` — convert MSYS/Git Bash Unix-style paths (`/c/path`) back to native Windows format (`C:/path`), inverse of `toUnixPath` (#168)
|
|
140
|
+
- `@socketsecurity/lib/paths` `fromUnixPath()` — convert MSYS/Git Bash Unix-style paths (`/c/path`) back to native Windows format (`C:/path`), inverse of `toUnixPath` (#168)
|
|
104
141
|
|
|
105
|
-
### Fixed
|
|
142
|
+
### Fixed
|
|
106
143
|
|
|
107
|
-
-
|
|
144
|
+
- `@socketsecurity/lib/dlx` `isInSocketDlx` — normalize the dlx directory path for Windows compatibility
|
|
108
145
|
|
|
109
146
|
## [5.15.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.15.0) - 2026-04-06
|
|
110
147
|
|
|
111
|
-
### Added
|
|
112
|
-
|
|
113
|
-
- `stream` option on `HttpRequestOptions` — resolves with `HttpResponse` immediately after headers arrive, leaving `rawResponse` unconsumed for piping to files
|
|
114
|
-
- `headers`, `ok`, `status`, `statusText` fields on `HttpDownloadResult`
|
|
115
|
-
|
|
116
|
-
### Changed — http-request
|
|
148
|
+
### Added
|
|
117
149
|
|
|
118
|
-
- `
|
|
150
|
+
- `@socketsecurity/lib/http-request` — `stream` option on `HttpRequestOptions` resolves with `HttpResponse` immediately after headers arrive, leaving `rawResponse` unconsumed for piping to files
|
|
151
|
+
- `@socketsecurity/lib/http-request` — `headers`, `ok`, `status`, `statusText` fields on `HttpDownloadResult`
|
|
119
152
|
|
|
120
153
|
## [5.14.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.14.0) - 2026-04-06
|
|
121
154
|
|
|
122
|
-
### Added
|
|
155
|
+
### Added
|
|
123
156
|
|
|
124
|
-
-
|
|
125
|
-
- `
|
|
126
|
-
- `
|
|
127
|
-
-
|
|
128
|
-
- `
|
|
129
|
-
- `
|
|
157
|
+
- `@socketsecurity/lib/http-request`:
|
|
158
|
+
- `HttpResponseError` class — thrown on non-2xx when `throwOnError` is enabled; carries the full `HttpResponse`
|
|
159
|
+
- `throwOnError` option — non-2xx responses throw instead of resolving with `ok: false`
|
|
160
|
+
- `onRetry` callback — customize retry behavior per-attempt (`false` to stop, a `number` to override delay, `undefined` for default backoff)
|
|
161
|
+
- Streaming body support — `body` accepts `Readable` streams (incl. `form-data`), auto-merges `getHeaders()` when present
|
|
162
|
+
- `parseRetryAfterHeader()` — standalone RFC 7231 §7.1.3 parser
|
|
163
|
+
- `sanitizeHeaders()` — redact sensitive headers for safe logging
|
|
130
164
|
|
|
131
|
-
### Changed
|
|
165
|
+
### Changed
|
|
132
166
|
|
|
133
|
-
- `HttpRequestOptions.body`
|
|
134
|
-
- Redirect responses now drained via `res.resume()` to free sockets
|
|
135
|
-
- `maxResponseSize` exceeded now cleans up both response and request
|
|
136
|
-
- `onResponse` hooks wrapped in try/catch — user hook errors can no longer leave promises pending
|
|
167
|
+
- `@socketsecurity/lib/http-request` — `HttpRequestOptions.body` widened to `Buffer | Readable | string`; `onResponse` hook errors no longer leave promises pending
|
|
137
168
|
|
|
138
169
|
## [5.13.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.13.0) - 2026-04-05
|
|
139
170
|
|
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
|
|
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
|
-
|
|
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 (
|
|
87
|
+
if (matches(entry.key)) {
|
|
90
88
|
try {
|
|
91
89
|
await cacache2.rm.entry(cacheDir, entry.key);
|
|
92
90
|
removed++;
|
package/dist/cache-with-ttl.d.ts
CHANGED
|
@@ -126,6 +126,13 @@ export interface TtlCacheOptions {
|
|
|
126
126
|
* @default true
|
|
127
127
|
*/
|
|
128
128
|
memoize?: boolean | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Maximum number of entries to keep in the in-memory memo cache. When
|
|
131
|
+
* exceeded, the least-recently-used entry is evicted. The persistent
|
|
132
|
+
* (cacache) layer is unaffected.
|
|
133
|
+
* @default 1000
|
|
134
|
+
*/
|
|
135
|
+
memoMaxSize?: number | undefined;
|
|
129
136
|
/**
|
|
130
137
|
* Custom cache key prefix.
|
|
131
138
|
* Must not contain wildcards (*).
|
package/dist/cache-with-ttl.js
CHANGED
|
@@ -36,10 +36,12 @@ module.exports = __toCommonJS(cache_with_ttl_exports);
|
|
|
36
36
|
var cacache = __toESM(require("./cacache"));
|
|
37
37
|
const DEFAULT_TTL_MS = 5 * 60 * 1e3;
|
|
38
38
|
const DEFAULT_PREFIX = "ttl-cache";
|
|
39
|
+
const DEFAULT_MEMO_MAX_SIZE = 1e3;
|
|
39
40
|
function createTtlCache(options) {
|
|
40
41
|
const opts = {
|
|
41
42
|
__proto__: null,
|
|
42
43
|
memoize: true,
|
|
44
|
+
memoMaxSize: DEFAULT_MEMO_MAX_SIZE,
|
|
43
45
|
prefix: DEFAULT_PREFIX,
|
|
44
46
|
ttl: DEFAULT_TTL_MS,
|
|
45
47
|
...options
|
|
@@ -50,6 +52,18 @@ function createTtlCache(options) {
|
|
|
50
52
|
);
|
|
51
53
|
}
|
|
52
54
|
const memoCache = /* @__PURE__ */ new Map();
|
|
55
|
+
const memoMaxSize = Math.max(1, opts.memoMaxSize ?? DEFAULT_MEMO_MAX_SIZE);
|
|
56
|
+
function memoSet(fullKey, entry) {
|
|
57
|
+
if (memoCache.has(fullKey)) {
|
|
58
|
+
memoCache.delete(fullKey);
|
|
59
|
+
} else if (memoCache.size >= memoMaxSize) {
|
|
60
|
+
const oldest = memoCache.keys().next().value;
|
|
61
|
+
if (oldest !== void 0) {
|
|
62
|
+
memoCache.delete(oldest);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
memoCache.set(fullKey, entry);
|
|
66
|
+
}
|
|
53
67
|
const ttl = opts.ttl ?? DEFAULT_TTL_MS;
|
|
54
68
|
function buildKey(key) {
|
|
55
69
|
return `${opts.prefix}:${key}`;
|
|
@@ -70,7 +84,7 @@ function createTtlCache(options) {
|
|
|
70
84
|
}
|
|
71
85
|
const escaped = fullPattern.replaceAll(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
72
86
|
const regexPattern = escaped.replaceAll("*", ".*");
|
|
73
|
-
const regex = new RegExp(`^${regexPattern}
|
|
87
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
74
88
|
return (key) => regex.test(key);
|
|
75
89
|
}
|
|
76
90
|
async function get(key) {
|
|
@@ -83,6 +97,7 @@ function createTtlCache(options) {
|
|
|
83
97
|
if (opts.memoize) {
|
|
84
98
|
const memoEntry = memoCache.get(fullKey);
|
|
85
99
|
if (memoEntry && !isExpired(memoEntry)) {
|
|
100
|
+
memoSet(fullKey, memoEntry);
|
|
86
101
|
return memoEntry.data;
|
|
87
102
|
}
|
|
88
103
|
if (memoEntry) {
|
|
@@ -103,7 +118,7 @@ function createTtlCache(options) {
|
|
|
103
118
|
}
|
|
104
119
|
if (!isExpired(entry)) {
|
|
105
120
|
if (opts.memoize) {
|
|
106
|
-
|
|
121
|
+
memoSet(fullKey, entry);
|
|
107
122
|
}
|
|
108
123
|
return entry.data;
|
|
109
124
|
}
|
|
@@ -158,7 +173,7 @@ function createTtlCache(options) {
|
|
|
158
173
|
}
|
|
159
174
|
results.set(originalKey, parsed.data);
|
|
160
175
|
if (opts.memoize) {
|
|
161
|
-
|
|
176
|
+
memoSet(cacheEntry.key, parsed);
|
|
162
177
|
}
|
|
163
178
|
} catch {
|
|
164
179
|
}
|
|
@@ -177,7 +192,7 @@ function createTtlCache(options) {
|
|
|
177
192
|
expiresAt: Date.now() + ttl
|
|
178
193
|
};
|
|
179
194
|
if (opts.memoize) {
|
|
180
|
-
|
|
195
|
+
memoSet(fullKey, entry);
|
|
181
196
|
}
|
|
182
197
|
try {
|
|
183
198
|
await cacache.put(fullKey, JSON.stringify(entry), {
|
|
@@ -188,14 +203,18 @@ function createTtlCache(options) {
|
|
|
188
203
|
}
|
|
189
204
|
const inflightRequests = /* @__PURE__ */ new Map();
|
|
190
205
|
async function getOrFetch(key, fetcher) {
|
|
206
|
+
const fullKey = buildKey(key);
|
|
207
|
+
const preexisting = inflightRequests.get(fullKey);
|
|
208
|
+
if (preexisting) {
|
|
209
|
+
return await preexisting;
|
|
210
|
+
}
|
|
191
211
|
const cached = await get(key);
|
|
192
212
|
if (cached !== void 0) {
|
|
193
213
|
return cached;
|
|
194
214
|
}
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return await existing;
|
|
215
|
+
const rechecked = inflightRequests.get(fullKey);
|
|
216
|
+
if (rechecked) {
|
|
217
|
+
return await rechecked;
|
|
199
218
|
}
|
|
200
219
|
const promise = (async () => {
|
|
201
220
|
try {
|
package/dist/constants/socket.js
CHANGED
|
@@ -77,7 +77,7 @@ const SOCKET_FIREWALL_APP_NAME = "sfw";
|
|
|
77
77
|
const SOCKET_REGISTRY_APP_NAME = "registry";
|
|
78
78
|
const SOCKET_APP_PREFIX = "_";
|
|
79
79
|
const SOCKET_LIB_NAME = "@socketsecurity/lib";
|
|
80
|
-
const SOCKET_LIB_VERSION = "5.
|
|
80
|
+
const SOCKET_LIB_VERSION = "5.21.0";
|
|
81
81
|
const SOCKET_LIB_URL = "https://github.com/SocketDev/socket-lib";
|
|
82
82
|
const SOCKET_LIB_USER_AGENT = `socketsecurity-lib/${SOCKET_LIB_VERSION} (${SOCKET_LIB_URL})`;
|
|
83
83
|
const SOCKET_IPC_HANDSHAKE = "SOCKET_IPC_HANDSHAKE";
|
package/dist/dlx/detect.js
CHANGED
|
@@ -33,7 +33,20 @@ var import_socket = require("../paths/socket");
|
|
|
33
33
|
let _fs;
|
|
34
34
|
let _path;
|
|
35
35
|
const NODE_JS_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs"]);
|
|
36
|
+
const PACKAGE_JSON_PATH_CACHE_MAX_SIZE = 200;
|
|
37
|
+
const PACKAGE_JSON_NEGATIVE_TTL_MS = 1e4;
|
|
36
38
|
const packageJsonPathCache = /* @__PURE__ */ new Map();
|
|
39
|
+
function packageJsonPathCacheSet(key, value) {
|
|
40
|
+
if (packageJsonPathCache.has(key)) {
|
|
41
|
+
packageJsonPathCache.delete(key);
|
|
42
|
+
} else if (packageJsonPathCache.size >= PACKAGE_JSON_PATH_CACHE_MAX_SIZE) {
|
|
43
|
+
const oldest = packageJsonPathCache.keys().next().value;
|
|
44
|
+
if (oldest !== void 0) {
|
|
45
|
+
packageJsonPathCache.delete(oldest);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
packageJsonPathCache.set(key, { path: value, at: Date.now() });
|
|
49
|
+
}
|
|
37
50
|
const packageJsonContentCache = /* @__PURE__ */ new Map();
|
|
38
51
|
function findPackageJson(filePath) {
|
|
39
52
|
const fs = /* @__PURE__ */ getFs();
|
|
@@ -41,25 +54,29 @@ function findPackageJson(filePath) {
|
|
|
41
54
|
const startDir = path.dirname(path.resolve(filePath));
|
|
42
55
|
const cached = packageJsonPathCache.get(startDir);
|
|
43
56
|
if (cached !== void 0) {
|
|
44
|
-
if (cached === null) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
if (cached.path === null) {
|
|
58
|
+
if (Date.now() - cached.at < PACKAGE_JSON_NEGATIVE_TTL_MS) {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
packageJsonPathCache.delete(startDir);
|
|
62
|
+
} else if (fs.existsSync(cached.path)) {
|
|
63
|
+
packageJsonPathCacheSet(startDir, cached.path);
|
|
64
|
+
return cached.path;
|
|
65
|
+
} else {
|
|
66
|
+
packageJsonPathCache.delete(startDir);
|
|
49
67
|
}
|
|
50
|
-
packageJsonPathCache.delete(startDir);
|
|
51
68
|
}
|
|
52
69
|
let currentDir = startDir;
|
|
53
70
|
const root = path.parse(currentDir).root;
|
|
54
71
|
while (currentDir !== root) {
|
|
55
72
|
const packageJsonPath = path.join(currentDir, "package.json");
|
|
56
73
|
if (fs.existsSync(packageJsonPath)) {
|
|
57
|
-
|
|
74
|
+
packageJsonPathCacheSet(startDir, packageJsonPath);
|
|
58
75
|
return packageJsonPath;
|
|
59
76
|
}
|
|
60
77
|
currentDir = path.dirname(currentDir);
|
|
61
78
|
}
|
|
62
|
-
|
|
79
|
+
packageJsonPathCacheSet(startDir, null);
|
|
63
80
|
return void 0;
|
|
64
81
|
}
|
|
65
82
|
// @__NO_SIDE_EFFECTS__
|
package/dist/dlx/lockfile.js
CHANGED
|
@@ -128,7 +128,10 @@ async function generatePackagePin(options) {
|
|
|
128
128
|
lockfile: ideal.lockfile
|
|
129
129
|
};
|
|
130
130
|
} finally {
|
|
131
|
-
|
|
131
|
+
try {
|
|
132
|
+
await (0, import_fs.safeDelete)(scratch, { force: true });
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/dlx/manifest.d.ts
CHANGED
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
* Manages persistent caching of DLX package and binary metadata with TTL support
|
|
4
4
|
* and atomic file operations.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* - getManifestEntry
|
|
8
|
-
* - setPackageEntry
|
|
9
|
-
* - setBinaryEntry
|
|
6
|
+
* Primary API (on {@link DlxManifest}):
|
|
7
|
+
* - `getManifestEntry(spec)` — retrieve a manifest entry by spec
|
|
8
|
+
* - `setPackageEntry(spec, key, details)` — store npm package metadata
|
|
9
|
+
* - `setBinaryEntry(spec, key, details)` — store binary download metadata
|
|
10
|
+
* - `getAllPackages()` — enumerate cached package names
|
|
11
|
+
* - `clear(name)` / `clearAll()` — eviction
|
|
12
|
+
* - `isFresh(record, ttlMs)` — TTL check
|
|
13
|
+
*
|
|
14
|
+
* The bare `get(name)` / `set(name, record)` methods are deprecated
|
|
15
|
+
* legacy shims kept for backward compatibility with pre-5.x callers.
|
|
10
16
|
*
|
|
11
17
|
* Features:
|
|
12
18
|
* - TTL-based cache expiration
|
package/dist/dlx/package.d.ts
CHANGED
|
@@ -136,7 +136,7 @@ export interface DlxPackageResult {
|
|
|
136
136
|
* await result.spawnPromise
|
|
137
137
|
* ```
|
|
138
138
|
*/
|
|
139
|
-
export declare function dlxPackage(args: readonly string[] | string[], options
|
|
139
|
+
export declare function dlxPackage(args: readonly string[] | string[], options: DlxPackageOptions, spawnExtra?: SpawnExtra | undefined): Promise<DlxPackageResult>;
|
|
140
140
|
/**
|
|
141
141
|
* Download and install a package without executing it.
|
|
142
142
|
* This is useful for self-update or when you need the package files
|
package/dist/dlx/package.js
CHANGED
|
@@ -62,7 +62,19 @@ const FIREWALL_BLOCK_SEVERITIES = /* @__PURE__ */ new Set([
|
|
|
62
62
|
"critical",
|
|
63
63
|
"high"
|
|
64
64
|
]);
|
|
65
|
+
const BINARY_PATH_CACHE_MAX_SIZE = 200;
|
|
65
66
|
const binaryPathCache = /* @__PURE__ */ new Map();
|
|
67
|
+
function binaryPathCacheSet(key, value) {
|
|
68
|
+
if (binaryPathCache.has(key)) {
|
|
69
|
+
binaryPathCache.delete(key);
|
|
70
|
+
} else if (binaryPathCache.size >= BINARY_PATH_CACHE_MAX_SIZE) {
|
|
71
|
+
const oldest = binaryPathCache.keys().next().value;
|
|
72
|
+
if (oldest !== void 0) {
|
|
73
|
+
binaryPathCache.delete(oldest);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
binaryPathCache.set(key, value);
|
|
77
|
+
}
|
|
66
78
|
async function checkFirewallPurls(arb, requestedPackage) {
|
|
67
79
|
const idealTree = arb.idealTree;
|
|
68
80
|
if (!idealTree) {
|
|
@@ -141,7 +153,7 @@ async function dlxPackage(args, options, spawnExtra) {
|
|
|
141
153
|
const spawnPromise = executePackage(
|
|
142
154
|
downloadResult.binaryPath,
|
|
143
155
|
args,
|
|
144
|
-
options
|
|
156
|
+
options.spawnOptions,
|
|
145
157
|
spawnExtra
|
|
146
158
|
);
|
|
147
159
|
return {
|
|
@@ -414,9 +426,12 @@ function parsePackageSpec(spec) {
|
|
|
414
426
|
if (atIndex === -1 || atIndex === 0) {
|
|
415
427
|
return { name: spec, version: void 0 };
|
|
416
428
|
}
|
|
429
|
+
const sliced = spec.slice(atIndex + 1);
|
|
417
430
|
return {
|
|
418
431
|
name: spec.slice(0, atIndex),
|
|
419
|
-
|
|
432
|
+
// A trailing `@` (e.g. `'pkg@'`) yields an empty slice — normalize
|
|
433
|
+
// to undefined so downstream "no version" checks behave.
|
|
434
|
+
version: sliced || void 0
|
|
420
435
|
};
|
|
421
436
|
}
|
|
422
437
|
}
|
|
@@ -428,6 +443,7 @@ function resolveBinaryPath(basePath) {
|
|
|
428
443
|
const cached = binaryPathCache.get(basePath);
|
|
429
444
|
if (cached) {
|
|
430
445
|
if (fs.existsSync(cached)) {
|
|
446
|
+
binaryPathCacheSet(basePath, cached);
|
|
431
447
|
return cached;
|
|
432
448
|
}
|
|
433
449
|
binaryPathCache.delete(basePath);
|
|
@@ -436,7 +452,7 @@ function resolveBinaryPath(basePath) {
|
|
|
436
452
|
for (const ext of extensions) {
|
|
437
453
|
const testPath = basePath + ext;
|
|
438
454
|
if (fs.existsSync(testPath)) {
|
|
439
|
-
|
|
455
|
+
binaryPathCacheSet(basePath, testPath);
|
|
440
456
|
return testPath;
|
|
441
457
|
}
|
|
442
458
|
}
|