@socketsecurity/lib 5.11.2 → 5.11.3
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 +10 -0
- package/dist/abort.js +1 -3
- package/dist/ansi.js +1 -1
- package/dist/argv/parse.js +1 -6
- package/dist/cache-with-ttl.js +10 -3
- package/dist/dlx/manifest.js +22 -33
- package/dist/external/@npmcli/package-json.js +5 -3
- package/dist/external/adm-zip.js +1 -0
- package/dist/external/debug.js +18 -10
- package/dist/external/external-pack.js +8 -2
- package/dist/external/libnpmexec.js +2 -2
- package/dist/external/npm-pack.js +380 -367
- package/dist/external/p-map.js +240 -0
- package/dist/external/pico-pack.js +245 -12
- package/dist/external/zod.js +1 -0
- package/dist/github.js +2 -4
- package/dist/http-request.js +3 -0
- package/dist/ipc.js +1 -0
- package/dist/memoization.js +46 -13
- package/dist/packages/isolation.js +9 -1
- package/dist/process-lock.js +16 -3
- package/dist/promise-queue.d.ts +2 -0
- package/dist/promise-queue.js +20 -9
- package/dist/promises.js +1 -3
- package/dist/releases/github.js +5 -1
- package/dist/stdio/progress.js +1 -1
- package/dist/validation/json-parser.js +10 -12
- package/package.json +8 -6
package/dist/memoization.js
CHANGED
|
@@ -29,6 +29,7 @@ __export(memoization_exports, {
|
|
|
29
29
|
});
|
|
30
30
|
module.exports = __toCommonJS(memoization_exports);
|
|
31
31
|
var import_debug = require("./debug");
|
|
32
|
+
const cacheRegistry = [];
|
|
32
33
|
function memoize(fn, options = {}) {
|
|
33
34
|
const {
|
|
34
35
|
keyGen = (...args) => JSON.stringify(args),
|
|
@@ -41,6 +42,10 @@ function memoize(fn, options = {}) {
|
|
|
41
42
|
}
|
|
42
43
|
const cache = /* @__PURE__ */ new Map();
|
|
43
44
|
const accessOrder = [];
|
|
45
|
+
cacheRegistry.push(() => {
|
|
46
|
+
cache.clear();
|
|
47
|
+
accessOrder.length = 0;
|
|
48
|
+
});
|
|
44
49
|
function evictLRU() {
|
|
45
50
|
if (cache.size >= maxSize && accessOrder.length > 0) {
|
|
46
51
|
const oldest = accessOrder.shift();
|
|
@@ -62,15 +67,22 @@ function memoize(fn, options = {}) {
|
|
|
62
67
|
return function memoized(...args) {
|
|
63
68
|
const key = keyGen(...args);
|
|
64
69
|
const cached = cache.get(key);
|
|
65
|
-
if (cached
|
|
66
|
-
cached
|
|
70
|
+
if (cached) {
|
|
71
|
+
if (!isExpired(cached)) {
|
|
72
|
+
cached.hits++;
|
|
73
|
+
const index2 = accessOrder.indexOf(key);
|
|
74
|
+
if (index2 !== -1) {
|
|
75
|
+
accessOrder.splice(index2, 1);
|
|
76
|
+
}
|
|
77
|
+
accessOrder.push(key);
|
|
78
|
+
(0, import_debug.debugLog)(`[memoize:${name}] hit`, { key, hits: cached.hits });
|
|
79
|
+
return cached.value;
|
|
80
|
+
}
|
|
81
|
+
cache.delete(key);
|
|
67
82
|
const index = accessOrder.indexOf(key);
|
|
68
83
|
if (index !== -1) {
|
|
69
84
|
accessOrder.splice(index, 1);
|
|
70
85
|
}
|
|
71
|
-
accessOrder.push(key);
|
|
72
|
-
(0, import_debug.debugLog)(`[memoize:${name}] hit`, { key, hits: cached.hits });
|
|
73
|
-
return cached.value;
|
|
74
86
|
}
|
|
75
87
|
(0, import_debug.debugLog)(`[memoize:${name}] miss`, { key });
|
|
76
88
|
const value = fn(...args);
|
|
@@ -94,6 +106,10 @@ function memoizeAsync(fn, options = {}) {
|
|
|
94
106
|
} = options;
|
|
95
107
|
const cache = /* @__PURE__ */ new Map();
|
|
96
108
|
const accessOrder = [];
|
|
109
|
+
cacheRegistry.push(() => {
|
|
110
|
+
cache.clear();
|
|
111
|
+
accessOrder.length = 0;
|
|
112
|
+
});
|
|
97
113
|
function evictLRU() {
|
|
98
114
|
if (cache.size >= maxSize && accessOrder.length > 0) {
|
|
99
115
|
const oldest = accessOrder.shift();
|
|
@@ -112,22 +128,36 @@ function memoizeAsync(fn, options = {}) {
|
|
|
112
128
|
}
|
|
113
129
|
return Date.now() - entry.timestamp > ttl;
|
|
114
130
|
}
|
|
131
|
+
const refreshing = /* @__PURE__ */ new Set();
|
|
115
132
|
return async function memoized(...args) {
|
|
116
133
|
const key = keyGen(...args);
|
|
117
134
|
const cached = cache.get(key);
|
|
118
|
-
if (cached
|
|
119
|
-
cached
|
|
135
|
+
if (cached) {
|
|
136
|
+
if (!isExpired(cached)) {
|
|
137
|
+
cached.hits++;
|
|
138
|
+
const index2 = accessOrder.indexOf(key);
|
|
139
|
+
if (index2 !== -1) {
|
|
140
|
+
accessOrder.splice(index2, 1);
|
|
141
|
+
}
|
|
142
|
+
accessOrder.push(key);
|
|
143
|
+
(0, import_debug.debugLog)(`[memoizeAsync:${name}] hit`, { key, hits: cached.hits });
|
|
144
|
+
return await cached.value;
|
|
145
|
+
}
|
|
146
|
+
if (refreshing.has(key)) {
|
|
147
|
+
(0, import_debug.debugLog)(`[memoizeAsync:${name}] stale-dedup`, { key });
|
|
148
|
+
return await cached.value;
|
|
149
|
+
}
|
|
150
|
+
cache.delete(key);
|
|
120
151
|
const index = accessOrder.indexOf(key);
|
|
121
152
|
if (index !== -1) {
|
|
122
153
|
accessOrder.splice(index, 1);
|
|
123
154
|
}
|
|
124
|
-
accessOrder.push(key);
|
|
125
|
-
(0, import_debug.debugLog)(`[memoizeAsync:${name}] hit`, { key, hits: cached.hits });
|
|
126
|
-
return await cached.value;
|
|
127
155
|
}
|
|
128
156
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] miss`, { key });
|
|
157
|
+
refreshing.add(key);
|
|
129
158
|
const promise = fn(...args).then(
|
|
130
159
|
(result) => {
|
|
160
|
+
refreshing.delete(key);
|
|
131
161
|
const entry = cache.get(key);
|
|
132
162
|
if (entry) {
|
|
133
163
|
entry.value = Promise.resolve(result);
|
|
@@ -135,6 +165,7 @@ function memoizeAsync(fn, options = {}) {
|
|
|
135
165
|
return result;
|
|
136
166
|
},
|
|
137
167
|
(error) => {
|
|
168
|
+
refreshing.delete(key);
|
|
138
169
|
cache.delete(key);
|
|
139
170
|
const index = accessOrder.indexOf(key);
|
|
140
171
|
if (index !== -1) {
|
|
@@ -167,14 +198,16 @@ function Memoize(options = {}) {
|
|
|
167
198
|
}
|
|
168
199
|
function clearAllMemoizationCaches() {
|
|
169
200
|
(0, import_debug.debugLog)("[memoize:all] clear", { action: "clear-all-caches" });
|
|
201
|
+
for (const clear of cacheRegistry) {
|
|
202
|
+
clear();
|
|
203
|
+
}
|
|
170
204
|
}
|
|
171
205
|
function memoizeWeak(fn) {
|
|
172
206
|
const cache = /* @__PURE__ */ new WeakMap();
|
|
173
207
|
return function memoized(key) {
|
|
174
|
-
|
|
175
|
-
if (cached !== void 0) {
|
|
208
|
+
if (cache.has(key)) {
|
|
176
209
|
(0, import_debug.debugLog)(`[memoizeWeak:${fn.name}] hit`);
|
|
177
|
-
return
|
|
210
|
+
return cache.get(key);
|
|
178
211
|
}
|
|
179
212
|
(0, import_debug.debugLog)(`[memoizeWeak:${fn.name}] miss`);
|
|
180
213
|
const result = fn(key);
|
|
@@ -69,7 +69,15 @@ async function resolveRealPath(pathStr) {
|
|
|
69
69
|
}
|
|
70
70
|
async function mergePackageJson(pkgJsonPath, originalPkgJson) {
|
|
71
71
|
const fs = /* @__PURE__ */ getFs();
|
|
72
|
-
|
|
72
|
+
let pkgJson;
|
|
73
|
+
try {
|
|
74
|
+
pkgJson = JSON.parse(await fs.promises.readFile(pkgJsonPath, "utf8"));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Failed to parse ${pkgJsonPath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
78
|
+
{ cause: error }
|
|
79
|
+
);
|
|
80
|
+
}
|
|
73
81
|
const mergedPkgJson = originalPkgJson ? { ...originalPkgJson, ...pkgJson } : pkgJson;
|
|
74
82
|
return mergedPkgJson;
|
|
75
83
|
}
|
package/dist/process-lock.js
CHANGED
|
@@ -179,7 +179,14 @@ class ProcessLockManager {
|
|
|
179
179
|
if (existsSync(lockPath)) {
|
|
180
180
|
throw new Error(`Lock already exists: ${lockPath}`);
|
|
181
181
|
}
|
|
182
|
-
|
|
182
|
+
const lastSlash = Math.max(
|
|
183
|
+
lockPath.lastIndexOf("/"),
|
|
184
|
+
lockPath.lastIndexOf("\\")
|
|
185
|
+
);
|
|
186
|
+
if (lastSlash > 0) {
|
|
187
|
+
mkdirSync(lockPath.slice(0, lastSlash), { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
mkdirSync(lockPath);
|
|
183
190
|
this.activeLocks.add(lockPath);
|
|
184
191
|
this.startTouchTimer(lockPath, touchIntervalMs);
|
|
185
192
|
return () => this.release(lockPath);
|
|
@@ -204,7 +211,10 @@ class ProcessLockManager {
|
|
|
204
211
|
);
|
|
205
212
|
}
|
|
206
213
|
if (code === "ENOTDIR") {
|
|
207
|
-
const lastSlashIndex =
|
|
214
|
+
const lastSlashIndex = Math.max(
|
|
215
|
+
lockPath.lastIndexOf("/"),
|
|
216
|
+
lockPath.lastIndexOf("\\")
|
|
217
|
+
);
|
|
208
218
|
const parentDir = lastSlashIndex === -1 ? "." : lockPath.slice(0, lastSlashIndex);
|
|
209
219
|
throw new Error(
|
|
210
220
|
`Cannot create lock directory: ${lockPath}
|
|
@@ -218,7 +228,10 @@ To resolve:
|
|
|
218
228
|
);
|
|
219
229
|
}
|
|
220
230
|
if (code === "ENOENT") {
|
|
221
|
-
const lastSlashIndex =
|
|
231
|
+
const lastSlashIndex = Math.max(
|
|
232
|
+
lockPath.lastIndexOf("/"),
|
|
233
|
+
lockPath.lastIndexOf("\\")
|
|
234
|
+
);
|
|
222
235
|
const parentDir = lastSlashIndex === -1 ? "." : lockPath.slice(0, lastSlashIndex);
|
|
223
236
|
throw new Error(
|
|
224
237
|
`Cannot create lock directory: ${lockPath}
|
package/dist/promise-queue.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare class PromiseQueue {
|
|
2
2
|
private queue;
|
|
3
3
|
private running;
|
|
4
|
+
private idleResolvers;
|
|
4
5
|
private readonly maxConcurrency;
|
|
5
6
|
private readonly maxQueueLength;
|
|
6
7
|
/**
|
|
@@ -16,6 +17,7 @@ export declare class PromiseQueue {
|
|
|
16
17
|
*/
|
|
17
18
|
add<T>(fn: () => Promise<T>): Promise<T>;
|
|
18
19
|
private runNext;
|
|
20
|
+
private notifyIdleIfNeeded;
|
|
19
21
|
/**
|
|
20
22
|
* Wait for all queued and running tasks to complete
|
|
21
23
|
*/
|
package/dist/promise-queue.js
CHANGED
|
@@ -25,6 +25,7 @@ module.exports = __toCommonJS(promise_queue_exports);
|
|
|
25
25
|
class PromiseQueue {
|
|
26
26
|
queue = [];
|
|
27
27
|
running = 0;
|
|
28
|
+
idleResolvers = [];
|
|
28
29
|
maxConcurrency;
|
|
29
30
|
maxQueueLength;
|
|
30
31
|
/**
|
|
@@ -47,7 +48,7 @@ class PromiseQueue {
|
|
|
47
48
|
async add(fn) {
|
|
48
49
|
return await new Promise((resolve, reject) => {
|
|
49
50
|
const task = { fn, resolve, reject };
|
|
50
|
-
if (this.maxQueueLength && this.queue.length >= this.maxQueueLength) {
|
|
51
|
+
if (this.maxQueueLength !== void 0 && this.queue.length >= this.maxQueueLength) {
|
|
51
52
|
const droppedTask = this.queue.shift();
|
|
52
53
|
if (droppedTask) {
|
|
53
54
|
droppedTask.reject(new Error("Task dropped: queue length exceeded"));
|
|
@@ -59,6 +60,7 @@ class PromiseQueue {
|
|
|
59
60
|
}
|
|
60
61
|
runNext() {
|
|
61
62
|
if (this.running >= this.maxConcurrency || this.queue.length === 0) {
|
|
63
|
+
this.notifyIdleIfNeeded();
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
const task = this.queue.shift();
|
|
@@ -71,19 +73,23 @@ class PromiseQueue {
|
|
|
71
73
|
this.runNext();
|
|
72
74
|
});
|
|
73
75
|
}
|
|
76
|
+
notifyIdleIfNeeded() {
|
|
77
|
+
if (this.running === 0 && this.queue.length === 0) {
|
|
78
|
+
for (const resolve of this.idleResolvers) {
|
|
79
|
+
resolve();
|
|
80
|
+
}
|
|
81
|
+
this.idleResolvers = [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
74
84
|
/**
|
|
75
85
|
* Wait for all queued and running tasks to complete
|
|
76
86
|
*/
|
|
77
87
|
async onIdle() {
|
|
88
|
+
if (this.running === 0 && this.queue.length === 0) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
78
91
|
return await new Promise((resolve) => {
|
|
79
|
-
|
|
80
|
-
if (this.running === 0 && this.queue.length === 0) {
|
|
81
|
-
resolve();
|
|
82
|
-
} else {
|
|
83
|
-
setImmediate(check);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
check();
|
|
92
|
+
this.idleResolvers.push(resolve);
|
|
87
93
|
});
|
|
88
94
|
}
|
|
89
95
|
/**
|
|
@@ -102,7 +108,12 @@ class PromiseQueue {
|
|
|
102
108
|
* Clear all pending tasks from the queue (does not affect running tasks)
|
|
103
109
|
*/
|
|
104
110
|
clear() {
|
|
111
|
+
const pending = this.queue;
|
|
105
112
|
this.queue = [];
|
|
113
|
+
for (const task of pending) {
|
|
114
|
+
task.reject(new Error("Task cancelled: queue cleared"));
|
|
115
|
+
}
|
|
116
|
+
this.notifyIdleIfNeeded();
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/promises.js
CHANGED
|
@@ -203,9 +203,7 @@ async function pRetry(callbackFn, options) {
|
|
|
203
203
|
try {
|
|
204
204
|
return await callbackFn(...args || [], { signal });
|
|
205
205
|
} catch (e) {
|
|
206
|
-
|
|
207
|
-
error = e;
|
|
208
|
-
}
|
|
206
|
+
error = e;
|
|
209
207
|
if (attempts < 0) {
|
|
210
208
|
break;
|
|
211
209
|
}
|
package/dist/releases/github.js
CHANGED
|
@@ -294,7 +294,11 @@ async function getReleaseAssetUrl(tag, assetPattern, repoConfig, options = {}) {
|
|
|
294
294
|
{ cause }
|
|
295
295
|
);
|
|
296
296
|
}
|
|
297
|
-
const
|
|
297
|
+
const assets = release.assets;
|
|
298
|
+
if (!Array.isArray(assets)) {
|
|
299
|
+
throw new Error(`Release ${tag} has no assets`);
|
|
300
|
+
}
|
|
301
|
+
const asset = assets.find((a) => isMatch(a.name));
|
|
298
302
|
if (!asset) {
|
|
299
303
|
const patternDesc = typeof assetPattern === "string" ? assetPattern : "matching pattern";
|
|
300
304
|
throw new Error(`Asset ${patternDesc} not found in release ${tag}`);
|
package/dist/stdio/progress.js
CHANGED
|
@@ -196,7 +196,7 @@ class ProgressBar {
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
function createProgressIndicator(current, total, label) {
|
|
199
|
-
const percent = Math.floor(current / total * 100);
|
|
199
|
+
const percent = total === 0 ? 0 : Math.floor(current / total * 100);
|
|
200
200
|
const progress = `${current}/${total}`;
|
|
201
201
|
let output = "";
|
|
202
202
|
if (label) {
|
|
@@ -27,7 +27,15 @@ __export(json_parser_exports, {
|
|
|
27
27
|
tryJsonParse: () => tryJsonParse
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(json_parser_exports);
|
|
30
|
-
const
|
|
30
|
+
const DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
31
|
+
function prototypePollutionReviver(key, value) {
|
|
32
|
+
if (DANGEROUS_KEYS.has(key)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"JSON contains potentially malicious prototype pollution keys"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
31
39
|
function safeJsonParse(jsonString, schema, options = {}) {
|
|
32
40
|
const { allowPrototype = false, maxSize = 10 * 1024 * 1024 } = options;
|
|
33
41
|
const byteLength = Buffer.byteLength(jsonString, "utf8");
|
|
@@ -38,20 +46,10 @@ function safeJsonParse(jsonString, schema, options = {}) {
|
|
|
38
46
|
}
|
|
39
47
|
let parsed;
|
|
40
48
|
try {
|
|
41
|
-
parsed = JSON.parse(jsonString);
|
|
49
|
+
parsed = allowPrototype ? JSON.parse(jsonString) : JSON.parse(jsonString, prototypePollutionReviver);
|
|
42
50
|
} catch (error) {
|
|
43
51
|
throw new Error(`Failed to parse JSON: ${error}`);
|
|
44
52
|
}
|
|
45
|
-
if (!allowPrototype && typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
46
|
-
const dangerous = ["__proto__", "constructor", "prototype"];
|
|
47
|
-
for (const key of dangerous) {
|
|
48
|
-
if (ObjectHasOwn(parsed, key)) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
"JSON contains potentially malicious prototype pollution keys"
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
53
|
if (schema) {
|
|
56
54
|
const result = schema.safeParse(parsed);
|
|
57
55
|
if (!result.success) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/lib",
|
|
3
|
-
"version": "5.11.
|
|
3
|
+
"version": "5.11.3",
|
|
4
4
|
"packageManager": "pnpm@10.33.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Core utilities and infrastructure for Socket.dev security tools",
|
|
@@ -734,7 +734,7 @@
|
|
|
734
734
|
"@socketregistry/is-unicode-supported": "1.0.5",
|
|
735
735
|
"@socketregistry/packageurl-js": "1.3.5",
|
|
736
736
|
"@socketregistry/yocto-spinner": "1.0.25",
|
|
737
|
-
"@socketsecurity/lib-stable": "npm:@socketsecurity/lib@5.11.
|
|
737
|
+
"@socketsecurity/lib-stable": "npm:@socketsecurity/lib@5.11.2",
|
|
738
738
|
"@types/node": "24.9.2",
|
|
739
739
|
"@typescript/native-preview": "7.0.0-dev.20250920.1",
|
|
740
740
|
"@vitest/coverage-v8": "4.0.3",
|
|
@@ -764,15 +764,16 @@
|
|
|
764
764
|
"npm-package-arg": "13.0.0",
|
|
765
765
|
"oxfmt": "^0.37.0",
|
|
766
766
|
"oxlint": "1.53.0",
|
|
767
|
+
"p-map": "7.0.4",
|
|
767
768
|
"pacote": "21.0.1",
|
|
768
|
-
"picomatch": "
|
|
769
|
+
"picomatch": "4.0.4",
|
|
769
770
|
"pony-cause": "2.1.11",
|
|
770
771
|
"semver": "7.7.2",
|
|
771
772
|
"signal-exit": "4.1.0",
|
|
772
773
|
"spdx-correct": "3.2.0",
|
|
773
774
|
"spdx-expression-parse": "4.0.0",
|
|
774
775
|
"streaming-iterables": "8.0.1",
|
|
775
|
-
"supports-color": "10.
|
|
776
|
+
"supports-color": "10.2.2",
|
|
776
777
|
"tar-fs": "3.1.2",
|
|
777
778
|
"tar-stream": "3.1.8",
|
|
778
779
|
"taze": "19.9.2",
|
|
@@ -821,7 +822,8 @@
|
|
|
821
822
|
"minizlib": "3.1.0",
|
|
822
823
|
"npm-package-arg": "12.0.2",
|
|
823
824
|
"npm-pick-manifest": "10.0.0",
|
|
824
|
-
"
|
|
825
|
+
"p-map": "7.0.4",
|
|
826
|
+
"picomatch": "4.0.4",
|
|
825
827
|
"proc-log": "6.1.0",
|
|
826
828
|
"semver": "7.7.2",
|
|
827
829
|
"signal-exit": "4.1.0",
|
|
@@ -829,7 +831,7 @@
|
|
|
829
831
|
"ssri": "12.0.0",
|
|
830
832
|
"string-width": "8.1.0",
|
|
831
833
|
"strip-ansi": "7.1.2",
|
|
832
|
-
"supports-color": "10.
|
|
834
|
+
"supports-color": "10.2.2",
|
|
833
835
|
"tar": "7.5.11",
|
|
834
836
|
"which": "5.0.0",
|
|
835
837
|
"wrap-ansi": "9.0.2",
|