@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.
- package/CHANGELOG.md +116 -95
- package/README.md +24 -181
- package/dist/archives.js +13 -0
- package/dist/cacache.js +6 -8
- package/dist/cache-with-ttl.js +1 -1
- package/dist/constants/socket.js +1 -1
- package/dist/dlx/detect.js +25 -8
- package/dist/dlx/manifest.js +8 -19
- package/dist/dlx/package.js +16 -2
- package/dist/env/socket-cli.d.ts +4 -3
- package/dist/env/socket-cli.js +1 -1
- package/dist/errors.d.ts +96 -2
- package/dist/errors.js +55 -0
- package/dist/external/pony-cause.js +12 -11
- package/dist/fs.js +8 -2
- package/dist/github.js +3 -2
- package/dist/globs.js +5 -1
- package/dist/ipc.js +2 -2
- package/dist/json/edit.js +3 -2
- 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 +14 -54
- package/dist/packages/isolation.js +4 -4
- package/dist/packages/specs.js +9 -2
- package/dist/performance.js +3 -2
- package/dist/process-lock.js +4 -12
- package/dist/promise-queue.d.ts +9 -4
- package/dist/promise-queue.js +9 -7
- 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/releases/github.js +3 -2
- package/dist/releases/socket-btm.d.ts +61 -5
- package/dist/releases/socket-btm.js +2 -2
- package/dist/schema/parse.d.ts +26 -0
- package/dist/schema/parse.js +38 -0
- package/dist/schema/types.d.ts +121 -0
- package/dist/schema/validate.d.ts +35 -0
- package/dist/{validation/validate-schema.js → schema/validate.js} +4 -14
- package/dist/suppress-warnings.js +0 -2
- package/dist/url.js +5 -1
- package/dist/versions.js +2 -2
- package/dist/words.js +4 -7
- package/package.json +15 -15
- 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/validation/validate-schema.d.ts +0 -124
- /package/dist/{validation → schema}/types.js +0 -0
package/dist/json/parse.js
CHANGED
|
@@ -21,9 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var parse_exports = {};
|
|
22
22
|
__export(parse_exports, {
|
|
23
23
|
isJsonPrimitive: () => isJsonPrimitive,
|
|
24
|
-
jsonParse: () => jsonParse
|
|
24
|
+
jsonParse: () => jsonParse,
|
|
25
|
+
safeJsonParse: () => safeJsonParse
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(parse_exports);
|
|
28
|
+
var import_validate = require("../schema/validate");
|
|
27
29
|
var import_strings = require("../strings");
|
|
28
30
|
const JSONParse = JSON.parse;
|
|
29
31
|
// @__NO_SIDE_EFFECTS__
|
|
@@ -69,8 +71,44 @@ function jsonParse(content, options) {
|
|
|
69
71
|
}
|
|
70
72
|
return void 0;
|
|
71
73
|
}
|
|
74
|
+
const DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
75
|
+
function prototypePollutionReviver(key, value) {
|
|
76
|
+
if (DANGEROUS_KEYS.has(key)) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
"JSON contains potentially malicious prototype pollution keys"
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
const DEFAULT_MAX_SIZE = 10 * 1024 * 1024;
|
|
84
|
+
// @__NO_SIDE_EFFECTS__
|
|
85
|
+
function safeJsonParse(jsonString, schema, options = {}) {
|
|
86
|
+
const { allowPrototype = false, maxSize = DEFAULT_MAX_SIZE } = options;
|
|
87
|
+
const byteLength = Buffer.byteLength(jsonString, "utf8");
|
|
88
|
+
if (byteLength > maxSize) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`JSON string exceeds maximum size limit${maxSize !== DEFAULT_MAX_SIZE ? ` of ${maxSize} bytes` : ""}`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = allowPrototype ? JSONParse(jsonString) : JSONParse(jsonString, prototypePollutionReviver);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new Error(`Failed to parse JSON: ${error}`);
|
|
98
|
+
}
|
|
99
|
+
if (schema) {
|
|
100
|
+
const result = (0, import_validate.validateSchema)(schema, parsed);
|
|
101
|
+
if (!result.ok) {
|
|
102
|
+
const summary = result.errors.map((e) => `${e.path.join(".") || "(root)"}: ${e.message}`).join(", ");
|
|
103
|
+
throw new Error(`Validation failed: ${summary}`);
|
|
104
|
+
}
|
|
105
|
+
return result.value;
|
|
106
|
+
}
|
|
107
|
+
return parsed;
|
|
108
|
+
}
|
|
72
109
|
// Annotate the CommonJS export names for ESM import in node:
|
|
73
110
|
0 && (module.exports = {
|
|
74
111
|
isJsonPrimitive,
|
|
75
|
-
jsonParse
|
|
112
|
+
jsonParse,
|
|
113
|
+
safeJsonParse
|
|
76
114
|
});
|
package/dist/json/types.d.ts
CHANGED
|
@@ -72,6 +72,55 @@ export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
|
|
|
72
72
|
* ```
|
|
73
73
|
*/
|
|
74
74
|
export type JsonReviver = (key: string, value: unknown) => unknown;
|
|
75
|
+
/**
|
|
76
|
+
* Options for `safeJsonParse`: security controls for untrusted JSON.
|
|
77
|
+
*
|
|
78
|
+
* Distinct from `JsonParseOptions` (which is scoped to reviver /
|
|
79
|
+
* error-handling for trusted-source fs reads). Use this type when
|
|
80
|
+
* parsing user input, network payloads, or anything beyond a trust
|
|
81
|
+
* boundary.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* const options: SafeJsonParseOptions = {
|
|
86
|
+
* maxSize: 1024 * 1024, // 1MB limit
|
|
87
|
+
* allowPrototype: false // Block prototype pollution
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export interface SafeJsonParseOptions {
|
|
92
|
+
/**
|
|
93
|
+
* Allow dangerous prototype pollution keys (`__proto__`, `constructor`, `prototype`).
|
|
94
|
+
* Set to `true` only if you trust the JSON source completely.
|
|
95
|
+
*
|
|
96
|
+
* @default false
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* // Will throw error by default
|
|
101
|
+
* safeJsonParse('{"__proto__": {"polluted": true}}')
|
|
102
|
+
*
|
|
103
|
+
* // Allows the parse (dangerous!)
|
|
104
|
+
* safeJsonParse('{"__proto__": {"polluted": true}}', undefined, {
|
|
105
|
+
* allowPrototype: true
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
allowPrototype?: boolean | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Maximum allowed size of JSON string in bytes.
|
|
112
|
+
* Prevents memory exhaustion from extremely large payloads.
|
|
113
|
+
*
|
|
114
|
+
* @default 10_485_760 (10 MB)
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* // Limit to 1KB
|
|
119
|
+
* safeJsonParse(jsonString, undefined, { maxSize: 1024 })
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
maxSize?: number | undefined;
|
|
123
|
+
}
|
|
75
124
|
/**
|
|
76
125
|
* Options for JSON parsing operations.
|
|
77
126
|
*/
|
package/dist/memoization.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Options for memoization behavior.
|
|
7
7
|
*/
|
|
8
|
-
export type MemoizeOptions<Args extends unknown[]
|
|
8
|
+
export type MemoizeOptions<Args extends unknown[]> = {
|
|
9
9
|
/** Custom cache key generator (defaults to JSON.stringify) */
|
|
10
10
|
keyGen?: (...args: Args) => string;
|
|
11
11
|
/** Maximum cache size (LRU eviction when exceeded) */
|
|
@@ -49,7 +49,7 @@ export declare function clearAllMemoizationCaches(): void;
|
|
|
49
49
|
* }
|
|
50
50
|
* }
|
|
51
51
|
*/
|
|
52
|
-
export declare function Memoize(options?: MemoizeOptions<unknown[]
|
|
52
|
+
export declare function Memoize(options?: MemoizeOptions<unknown[]>): (_target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
53
53
|
/**
|
|
54
54
|
* Memoize a function with configurable caching behavior.
|
|
55
55
|
* Caches function results to avoid repeated computation.
|
|
@@ -69,7 +69,7 @@ export declare function Memoize(options?: MemoizeOptions<unknown[], unknown>): (
|
|
|
69
69
|
* expensiveOperation(1000) // Computed
|
|
70
70
|
* expensiveOperation(1000) // Cached
|
|
71
71
|
*/
|
|
72
|
-
export declare function memoize<Args extends unknown[], Result>(fn: (...args: Args) => Result, options?: MemoizeOptions<Args
|
|
72
|
+
export declare function memoize<Args extends unknown[], Result>(fn: (...args: Args) => Result, options?: MemoizeOptions<Args>): (...args: Args) => Result;
|
|
73
73
|
/**
|
|
74
74
|
* Memoize an async function.
|
|
75
75
|
* Similar to memoize() but handles promises properly.
|
|
@@ -89,26 +89,7 @@ export declare function memoize<Args extends unknown[], Result>(fn: (...args: Ar
|
|
|
89
89
|
* await fetchUser('123') // Fetches from API
|
|
90
90
|
* await fetchUser('123') // Returns cached result
|
|
91
91
|
*/
|
|
92
|
-
export declare function memoizeAsync<Args extends unknown[], Result>(fn: (...args: Args) => Promise<Result>, options?: MemoizeOptions<Args
|
|
93
|
-
/**
|
|
94
|
-
* Create a debounced memoized function.
|
|
95
|
-
* Combines memoization with debouncing for expensive operations.
|
|
96
|
-
*
|
|
97
|
-
* @param fn - Function to memoize and debounce
|
|
98
|
-
* @param wait - Debounce wait time in milliseconds
|
|
99
|
-
* @param options - Memoization options
|
|
100
|
-
* @returns Debounced memoized function
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* import { memoizeDebounced } from '@socketsecurity/lib/memoization'
|
|
104
|
-
*
|
|
105
|
-
* const search = memoizeDebounced(
|
|
106
|
-
* (query: string) => performSearch(query),
|
|
107
|
-
* 300,
|
|
108
|
-
* { name: 'search' }
|
|
109
|
-
* )
|
|
110
|
-
*/
|
|
111
|
-
export declare function memoizeDebounced<Args extends unknown[], Result>(fn: (...args: Args) => Result, wait: number, options?: MemoizeOptions<Args, Result>): (...args: Args) => Result;
|
|
92
|
+
export declare function memoizeAsync<Args extends unknown[], Result>(fn: (...args: Args) => Promise<Result>, options?: MemoizeOptions<Args>): (...args: Args) => Promise<Result>;
|
|
112
93
|
/**
|
|
113
94
|
* Memoize with WeakMap for object keys.
|
|
114
95
|
* Allows garbage collection when objects are no longer referenced.
|
package/dist/memoization.js
CHANGED
|
@@ -24,7 +24,6 @@ __export(memoization_exports, {
|
|
|
24
24
|
clearAllMemoizationCaches: () => clearAllMemoizationCaches,
|
|
25
25
|
memoize: () => memoize,
|
|
26
26
|
memoizeAsync: () => memoizeAsync,
|
|
27
|
-
memoizeDebounced: () => memoizeDebounced,
|
|
28
27
|
memoizeWeak: () => memoizeWeak,
|
|
29
28
|
once: () => once
|
|
30
29
|
});
|
|
@@ -78,15 +77,13 @@ function memoize(fn, options = {}) {
|
|
|
78
77
|
throw new TypeError("TTL must be non-negative");
|
|
79
78
|
}
|
|
80
79
|
const cache = /* @__PURE__ */ new Map();
|
|
81
|
-
const accessOrder = [];
|
|
82
80
|
cacheRegistry.push(() => {
|
|
83
81
|
cache.clear();
|
|
84
|
-
accessOrder.length = 0;
|
|
85
82
|
});
|
|
86
83
|
function evictLRU() {
|
|
87
|
-
if (cache.size >= maxSize
|
|
88
|
-
const oldest =
|
|
89
|
-
if (oldest) {
|
|
84
|
+
if (cache.size >= maxSize) {
|
|
85
|
+
const oldest = cache.keys().next().value;
|
|
86
|
+
if (oldest !== void 0) {
|
|
90
87
|
cache.delete(oldest);
|
|
91
88
|
(0, import_debug.debugLog)(`[memoize:${name}] clear`, {
|
|
92
89
|
key: oldest,
|
|
@@ -107,19 +104,12 @@ function memoize(fn, options = {}) {
|
|
|
107
104
|
if (cached) {
|
|
108
105
|
if (!isExpired(cached)) {
|
|
109
106
|
cached.hits++;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
accessOrder.splice(index2, 1);
|
|
113
|
-
}
|
|
114
|
-
accessOrder.push(key);
|
|
107
|
+
cache.delete(key);
|
|
108
|
+
cache.set(key, cached);
|
|
115
109
|
(0, import_debug.debugLog)(`[memoize:${name}] hit`, { key, hits: cached.hits });
|
|
116
110
|
return cached.value;
|
|
117
111
|
}
|
|
118
112
|
cache.delete(key);
|
|
119
|
-
const index = accessOrder.indexOf(key);
|
|
120
|
-
if (index !== -1) {
|
|
121
|
-
accessOrder.splice(index, 1);
|
|
122
|
-
}
|
|
123
113
|
}
|
|
124
114
|
(0, import_debug.debugLog)(`[memoize:${name}] miss`, { key });
|
|
125
115
|
const value = fn(...args);
|
|
@@ -129,7 +119,6 @@ function memoize(fn, options = {}) {
|
|
|
129
119
|
timestamp: Date.now(),
|
|
130
120
|
hits: 0
|
|
131
121
|
});
|
|
132
|
-
accessOrder.push(key);
|
|
133
122
|
(0, import_debug.debugLog)(`[memoize:${name}] set`, { key, cacheSize: cache.size });
|
|
134
123
|
return value;
|
|
135
124
|
};
|
|
@@ -142,15 +131,13 @@ function memoizeAsync(fn, options = {}) {
|
|
|
142
131
|
ttl = Number.POSITIVE_INFINITY
|
|
143
132
|
} = options;
|
|
144
133
|
const cache = /* @__PURE__ */ new Map();
|
|
145
|
-
const accessOrder = [];
|
|
146
134
|
cacheRegistry.push(() => {
|
|
147
135
|
cache.clear();
|
|
148
|
-
accessOrder.length = 0;
|
|
149
136
|
});
|
|
150
137
|
function evictLRU() {
|
|
151
|
-
if (cache.size >= maxSize
|
|
152
|
-
const oldest =
|
|
153
|
-
if (oldest) {
|
|
138
|
+
if (cache.size >= maxSize) {
|
|
139
|
+
const oldest = cache.keys().next().value;
|
|
140
|
+
if (oldest !== void 0) {
|
|
154
141
|
cache.delete(oldest);
|
|
155
142
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] clear`, {
|
|
156
143
|
key: oldest,
|
|
@@ -165,6 +152,10 @@ function memoizeAsync(fn, options = {}) {
|
|
|
165
152
|
}
|
|
166
153
|
return Date.now() - entry.timestamp > ttl;
|
|
167
154
|
}
|
|
155
|
+
function bumpRecency(key, entry) {
|
|
156
|
+
cache.delete(key);
|
|
157
|
+
cache.set(key, entry);
|
|
158
|
+
}
|
|
168
159
|
const refreshing = /* @__PURE__ */ new Map();
|
|
169
160
|
return async function memoized(...args) {
|
|
170
161
|
const key = keyGen(...args);
|
|
@@ -172,29 +163,17 @@ function memoizeAsync(fn, options = {}) {
|
|
|
172
163
|
if (cached) {
|
|
173
164
|
if (!isExpired(cached)) {
|
|
174
165
|
cached.hits++;
|
|
175
|
-
|
|
176
|
-
if (index2 !== -1) {
|
|
177
|
-
accessOrder.splice(index2, 1);
|
|
178
|
-
}
|
|
179
|
-
accessOrder.push(key);
|
|
166
|
+
bumpRecency(key, cached);
|
|
180
167
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] hit`, { key, hits: cached.hits });
|
|
181
168
|
return await cached.value;
|
|
182
169
|
}
|
|
183
170
|
const inflight = refreshing.get(key);
|
|
184
171
|
if (inflight) {
|
|
185
172
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] stale-dedup`, { key });
|
|
186
|
-
|
|
187
|
-
if (inflightIndex !== -1) {
|
|
188
|
-
accessOrder.splice(inflightIndex, 1);
|
|
189
|
-
}
|
|
190
|
-
accessOrder.push(key);
|
|
173
|
+
bumpRecency(key, cached);
|
|
191
174
|
return await inflight;
|
|
192
175
|
}
|
|
193
176
|
cache.delete(key);
|
|
194
|
-
const index = accessOrder.indexOf(key);
|
|
195
|
-
if (index !== -1) {
|
|
196
|
-
accessOrder.splice(index, 1);
|
|
197
|
-
}
|
|
198
177
|
}
|
|
199
178
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] miss`, { key });
|
|
200
179
|
const promise = fn(...args).then(
|
|
@@ -210,10 +189,6 @@ function memoizeAsync(fn, options = {}) {
|
|
|
210
189
|
(error) => {
|
|
211
190
|
refreshing.delete(key);
|
|
212
191
|
cache.delete(key);
|
|
213
|
-
const index = accessOrder.indexOf(key);
|
|
214
|
-
if (index !== -1) {
|
|
215
|
-
accessOrder.splice(index, 1);
|
|
216
|
-
}
|
|
217
192
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] error`, { key, error });
|
|
218
193
|
throw error;
|
|
219
194
|
}
|
|
@@ -225,24 +200,10 @@ function memoizeAsync(fn, options = {}) {
|
|
|
225
200
|
timestamp: Date.now(),
|
|
226
201
|
hits: 0
|
|
227
202
|
});
|
|
228
|
-
accessOrder.push(key);
|
|
229
203
|
(0, import_debug.debugLog)(`[memoizeAsync:${name}] set`, { key, cacheSize: cache.size });
|
|
230
204
|
return await promise;
|
|
231
205
|
};
|
|
232
206
|
}
|
|
233
|
-
function memoizeDebounced(fn, wait, options = {}) {
|
|
234
|
-
const memoized = memoize(fn, options);
|
|
235
|
-
let timeoutId;
|
|
236
|
-
return function debounced(...args) {
|
|
237
|
-
if (timeoutId) {
|
|
238
|
-
clearTimeout(timeoutId);
|
|
239
|
-
}
|
|
240
|
-
timeoutId = setTimeout(() => {
|
|
241
|
-
memoized(...args);
|
|
242
|
-
}, wait);
|
|
243
|
-
return memoized(...args);
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
207
|
function memoizeWeak(fn) {
|
|
247
208
|
const cache = /* @__PURE__ */ new WeakMap();
|
|
248
209
|
return function memoized(key) {
|
|
@@ -276,7 +237,6 @@ function once(fn) {
|
|
|
276
237
|
clearAllMemoizationCaches,
|
|
277
238
|
memoize,
|
|
278
239
|
memoizeAsync,
|
|
279
|
-
memoizeDebounced,
|
|
280
240
|
memoizeWeak,
|
|
281
241
|
once
|
|
282
242
|
});
|
|
@@ -35,6 +35,7 @@ __export(isolation_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(isolation_exports);
|
|
36
36
|
var import_npm_package_arg = __toESM(require("../external/npm-package-arg"));
|
|
37
37
|
var import_platform = require("../constants/platform");
|
|
38
|
+
var import_errors = require("../errors");
|
|
38
39
|
var import_normalize = require("../paths/normalize");
|
|
39
40
|
var import_socket = require("../paths/socket");
|
|
40
41
|
var import_spawn = require("../spawn");
|
|
@@ -69,10 +70,9 @@ async function mergePackageJson(pkgJsonPath, originalPkgJson) {
|
|
|
69
70
|
try {
|
|
70
71
|
pkgJson = JSON.parse(await fs.promises.readFile(pkgJsonPath, "utf8"));
|
|
71
72
|
} catch (error) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
73
|
+
throw new Error(`Failed to parse ${pkgJsonPath}: ${(0, import_errors.errorMessage)(error)}`, {
|
|
74
|
+
cause: error
|
|
75
|
+
});
|
|
76
76
|
}
|
|
77
77
|
const mergedPkgJson = originalPkgJson ? { ...originalPkgJson, ...pkgJson } : pkgJson;
|
|
78
78
|
return mergedPkgJson;
|
package/dist/packages/specs.js
CHANGED
|
@@ -42,9 +42,16 @@ var import_objects = require("../objects");
|
|
|
42
42
|
var import_strings = require("../strings");
|
|
43
43
|
// @__NO_SIDE_EFFECTS__
|
|
44
44
|
function getRepoUrlDetails(repoUrl = "") {
|
|
45
|
-
const
|
|
45
|
+
const match = /^(?:[a-z][a-z+]*:\/\/)(?:[^/@]+@)?github\.com\/([^?#]+)(?:[?#]|$)/i.exec(
|
|
46
|
+
repoUrl
|
|
47
|
+
);
|
|
48
|
+
if (!match || !match[1]) {
|
|
49
|
+
return { user: "", project: "" };
|
|
50
|
+
}
|
|
51
|
+
const userAndRepo = match[1].split("/");
|
|
46
52
|
const user = userAndRepo[0] || "";
|
|
47
|
-
const
|
|
53
|
+
const rawProject = userAndRepo[1] ?? "";
|
|
54
|
+
const project = rawProject.endsWith(".git") ? rawProject.slice(0, -4) : rawProject;
|
|
48
55
|
return { user, project };
|
|
49
56
|
}
|
|
50
57
|
// @__NO_SIDE_EFFECTS__
|
package/dist/performance.js
CHANGED
|
@@ -44,6 +44,7 @@ __export(performance_exports, {
|
|
|
44
44
|
module.exports = __toCommonJS(performance_exports);
|
|
45
45
|
var import_node_process = __toESM(require("node:process"));
|
|
46
46
|
var import_debug = require("./debug");
|
|
47
|
+
var import_errors = require("./errors");
|
|
47
48
|
const performanceMetrics = [];
|
|
48
49
|
function isPerfEnabled() {
|
|
49
50
|
return import_node_process.default.env["DEBUG"]?.includes("perf") || false;
|
|
@@ -128,7 +129,7 @@ async function measure(operation, fn, metadata) {
|
|
|
128
129
|
} catch (e) {
|
|
129
130
|
stop({
|
|
130
131
|
success: false,
|
|
131
|
-
error:
|
|
132
|
+
error: (0, import_errors.errorMessage)(e)
|
|
132
133
|
});
|
|
133
134
|
throw e;
|
|
134
135
|
}
|
|
@@ -143,7 +144,7 @@ function measureSync(operation, fn, metadata) {
|
|
|
143
144
|
} catch (e) {
|
|
144
145
|
stop({
|
|
145
146
|
success: false,
|
|
146
|
-
error:
|
|
147
|
+
error: (0, import_errors.errorMessage)(e)
|
|
147
148
|
});
|
|
148
149
|
throw e;
|
|
149
150
|
}
|
package/dist/process-lock.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(process_lock_exports, {
|
|
|
23
23
|
processLock: () => processLock
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(process_lock_exports);
|
|
26
|
+
var import_errors = require("./errors");
|
|
26
27
|
var import_fs = require("./fs");
|
|
27
28
|
var import_logger = require("./logger");
|
|
28
29
|
var import_promises = require("./promises");
|
|
@@ -87,9 +88,7 @@ class ProcessLockManager {
|
|
|
87
88
|
fs.utimesSync(lockPath, now, now);
|
|
88
89
|
}
|
|
89
90
|
} catch (error) {
|
|
90
|
-
logger.warn(
|
|
91
|
-
`Failed to touch lock ${lockPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
92
|
-
);
|
|
91
|
+
logger.warn(`Failed to touch lock ${lockPath}: ${(0, import_errors.errorMessage)(error)}`);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
/**
|
|
@@ -136,9 +135,7 @@ class ProcessLockManager {
|
|
|
136
135
|
if (!stats) {
|
|
137
136
|
return false;
|
|
138
137
|
}
|
|
139
|
-
|
|
140
|
-
const staleSeconds = Math.floor(staleMs / 1e3);
|
|
141
|
-
return ageSeconds > staleSeconds;
|
|
138
|
+
return Date.now() - stats.mtime.getTime() > staleMs;
|
|
142
139
|
} catch {
|
|
143
140
|
return false;
|
|
144
141
|
}
|
|
@@ -186,9 +183,6 @@ class ProcessLockManager {
|
|
|
186
183
|
}
|
|
187
184
|
}
|
|
188
185
|
const fs = /* @__PURE__ */ getFs();
|
|
189
|
-
if (fs.existsSync(lockPath)) {
|
|
190
|
-
throw new Error(`Lock already exists: ${lockPath}`);
|
|
191
|
-
}
|
|
192
186
|
const parent = (/* @__PURE__ */ getPath()).dirname(lockPath);
|
|
193
187
|
if (parent && parent !== "." && parent !== lockPath) {
|
|
194
188
|
fs.mkdirSync(parent, { recursive: true });
|
|
@@ -282,9 +276,7 @@ To resolve:
|
|
|
282
276
|
}
|
|
283
277
|
this.activeLocks.delete(lockPath);
|
|
284
278
|
} catch (error) {
|
|
285
|
-
logger.warn(
|
|
286
|
-
`Failed to release lock ${lockPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
287
|
-
);
|
|
279
|
+
logger.warn(`Failed to release lock ${lockPath}: ${(0, import_errors.errorMessage)(error)}`);
|
|
288
280
|
}
|
|
289
281
|
}
|
|
290
282
|
/**
|
package/dist/promise-queue.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Bounded concurrency promise queue.
|
|
3
3
|
* Exports the `PromiseQueue` class, which limits how many async tasks run
|
|
4
|
-
* simultaneously, supports an optional max queue length (
|
|
5
|
-
*
|
|
4
|
+
* simultaneously, supports an optional max queue length (new tasks beyond
|
|
5
|
+
* the cap are rejected with "Task dropped: queue length exceeded"), and
|
|
6
|
+
* exposes an idle-wait helper.
|
|
6
7
|
*/
|
|
7
8
|
export declare class PromiseQueue {
|
|
8
9
|
private queue;
|
|
@@ -13,13 +14,17 @@ export declare class PromiseQueue {
|
|
|
13
14
|
/**
|
|
14
15
|
* Creates a new PromiseQueue
|
|
15
16
|
* @param maxConcurrency - Maximum number of promises that can run concurrently
|
|
16
|
-
* @param maxQueueLength - Maximum queue size
|
|
17
|
+
* @param maxQueueLength - Maximum queue size; submissions past the cap
|
|
18
|
+
* reject with "Task dropped: queue length exceeded" instead of evicting
|
|
19
|
+
* a caller that has been waiting patiently. Callers must handle this
|
|
20
|
+
* rejection or they'll see an unhandled rejection.
|
|
17
21
|
*/
|
|
18
22
|
constructor(maxConcurrency: number, maxQueueLength?: number | undefined);
|
|
19
23
|
/**
|
|
20
24
|
* Add a task to the queue
|
|
21
25
|
* @param fn - Async function to execute
|
|
22
|
-
* @returns Promise that resolves with the function's result
|
|
26
|
+
* @returns Promise that resolves with the function's result, or rejects
|
|
27
|
+
* with "Task dropped: queue length exceeded" if the queue is full.
|
|
23
28
|
*/
|
|
24
29
|
add<T>(fn: () => Promise<T>): Promise<T>;
|
|
25
30
|
private runNext;
|
package/dist/promise-queue.js
CHANGED
|
@@ -32,7 +32,10 @@ class PromiseQueue {
|
|
|
32
32
|
/**
|
|
33
33
|
* Creates a new PromiseQueue
|
|
34
34
|
* @param maxConcurrency - Maximum number of promises that can run concurrently
|
|
35
|
-
* @param maxQueueLength - Maximum queue size
|
|
35
|
+
* @param maxQueueLength - Maximum queue size; submissions past the cap
|
|
36
|
+
* reject with "Task dropped: queue length exceeded" instead of evicting
|
|
37
|
+
* a caller that has been waiting patiently. Callers must handle this
|
|
38
|
+
* rejection or they'll see an unhandled rejection.
|
|
36
39
|
*/
|
|
37
40
|
constructor(maxConcurrency, maxQueueLength) {
|
|
38
41
|
this.maxConcurrency = maxConcurrency;
|
|
@@ -44,17 +47,16 @@ class PromiseQueue {
|
|
|
44
47
|
/**
|
|
45
48
|
* Add a task to the queue
|
|
46
49
|
* @param fn - Async function to execute
|
|
47
|
-
* @returns Promise that resolves with the function's result
|
|
50
|
+
* @returns Promise that resolves with the function's result, or rejects
|
|
51
|
+
* with "Task dropped: queue length exceeded" if the queue is full.
|
|
48
52
|
*/
|
|
49
53
|
async add(fn) {
|
|
50
54
|
return await new Promise((resolve, reject) => {
|
|
51
|
-
const task = { fn, resolve, reject };
|
|
52
55
|
if (this.maxQueueLength !== void 0 && this.queue.length >= this.maxQueueLength) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
droppedTask.reject(new Error("Task dropped: queue length exceeded"));
|
|
56
|
-
}
|
|
56
|
+
reject(new Error("Task dropped: queue length exceeded"));
|
|
57
|
+
return;
|
|
57
58
|
}
|
|
59
|
+
const task = { fn, resolve, reject };
|
|
58
60
|
this.queue.push(task);
|
|
59
61
|
this.runNext();
|
|
60
62
|
});
|
package/dist/promises.d.ts
CHANGED
|
@@ -440,3 +440,44 @@ export declare function pRetry<T>(callbackFn: (...args: unknown[]) => Promise<T>
|
|
|
440
440
|
* // => { retries: 5, minTimeout: 200, maxTimeout: 5000, factor: 2 }
|
|
441
441
|
*/
|
|
442
442
|
export declare function resolveRetryOptions(options?: number | RetryOptions | undefined): RetryOptions;
|
|
443
|
+
/**
|
|
444
|
+
* Shape returned by {@link withResolvers}: a fresh pending promise plus
|
|
445
|
+
* the `resolve` / `reject` handles that settle it.
|
|
446
|
+
*
|
|
447
|
+
* Matches the spec return-shape exactly
|
|
448
|
+
* ([ECMA-262 §27.2.4.9](https://tc39.es/ecma262/#sec-promise.withResolvers)).
|
|
449
|
+
*/
|
|
450
|
+
export interface PromiseWithResolvers<T> {
|
|
451
|
+
/** The pending promise. */
|
|
452
|
+
promise: Promise<T>;
|
|
453
|
+
/** Resolves {@link promise} with the given value (or thenable). */
|
|
454
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
455
|
+
/** Rejects {@link promise} with the given reason. */
|
|
456
|
+
reject: (reason?: unknown) => void;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Create a pending promise together with its `resolve` and `reject`
|
|
460
|
+
* handles as first-class values, per
|
|
461
|
+
* [ECMA-262 §27.2.4.9](https://tc39.es/ecma262/#sec-promise.withResolvers).
|
|
462
|
+
*
|
|
463
|
+
* Bound to native `Promise.withResolvers` when available (Node 20.12+ /
|
|
464
|
+
* 21+ / 22+; V8 ≥ 12.0); otherwise falls back to a spec-equivalent
|
|
465
|
+
* `new Promise(executor)` implementation that captures the handles via
|
|
466
|
+
* closure. The returned object always has own data properties `promise`,
|
|
467
|
+
* `resolve`, `reject` on `Object.prototype` — writable, enumerable, and
|
|
468
|
+
* configurable — matching the spec's `CreateDataPropertyOrThrow` steps.
|
|
469
|
+
*
|
|
470
|
+
* Use this instead of the manual
|
|
471
|
+
* `let resolve; const p = new Promise(r => { resolve = r })` dance for
|
|
472
|
+
* deferred-resolution patterns (event-driven bridges, adapter layers,
|
|
473
|
+
* handshake signaling) where the settle path lives outside the executor.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* ```typescript
|
|
477
|
+
* const { promise, resolve, reject } = withResolvers<string>()
|
|
478
|
+
* emitter.once('ready', () => resolve('ok'))
|
|
479
|
+
* emitter.once('error', err => reject(err))
|
|
480
|
+
* const result = await promise
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
export declare const withResolvers: <T>() => PromiseWithResolvers<T>;
|
package/dist/promises.js
CHANGED
|
@@ -27,7 +27,8 @@ __export(promises_exports, {
|
|
|
27
27
|
pFilter: () => pFilter,
|
|
28
28
|
pFilterChunk: () => pFilterChunk,
|
|
29
29
|
pRetry: () => pRetry,
|
|
30
|
-
resolveRetryOptions: () => resolveRetryOptions
|
|
30
|
+
resolveRetryOptions: () => resolveRetryOptions,
|
|
31
|
+
withResolvers: () => withResolvers
|
|
31
32
|
});
|
|
32
33
|
module.exports = __toCommonJS(promises_exports);
|
|
33
34
|
var import_arrays = require("./arrays");
|
|
@@ -258,6 +259,21 @@ function resolveRetryOptions(options) {
|
|
|
258
259
|
}
|
|
259
260
|
return options ? { ...defaults, ...options } : defaults;
|
|
260
261
|
}
|
|
262
|
+
const maybeNativeWithResolvers = Promise.withResolvers;
|
|
263
|
+
const withResolvers = typeof maybeNativeWithResolvers === "function" ? (
|
|
264
|
+
// Bind so callers who destructure the export don't lose `this`.
|
|
265
|
+
maybeNativeWithResolvers.bind(
|
|
266
|
+
Promise
|
|
267
|
+
)
|
|
268
|
+
) : () => {
|
|
269
|
+
let resolve;
|
|
270
|
+
let reject;
|
|
271
|
+
const promise = new Promise((res, rej) => {
|
|
272
|
+
resolve = res;
|
|
273
|
+
reject = rej;
|
|
274
|
+
});
|
|
275
|
+
return { promise, resolve, reject };
|
|
276
|
+
};
|
|
261
277
|
// Annotate the CommonJS export names for ESM import in node:
|
|
262
278
|
0 && (module.exports = {
|
|
263
279
|
normalizeIterationOptions,
|
|
@@ -267,5 +283,6 @@ function resolveRetryOptions(options) {
|
|
|
267
283
|
pFilter,
|
|
268
284
|
pFilterChunk,
|
|
269
285
|
pRetry,
|
|
270
|
-
resolveRetryOptions
|
|
286
|
+
resolveRetryOptions,
|
|
287
|
+
withResolvers
|
|
271
288
|
});
|
package/dist/regexps.d.ts
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Regular expression utilities including
|
|
3
|
-
* Provides regex escaping and pattern matching
|
|
2
|
+
* @fileoverview Regular expression utilities including a spec-compliant
|
|
3
|
+
* `RegExp.escape` fallback. Provides regex escaping and pattern matching
|
|
4
|
+
* helpers.
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
* Escape special characters in a string for use in a regular expression.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* escapeRegExp('foo.bar') // 'foo\\.bar'
|
|
11
|
-
* escapeRegExp('a+b*c?') // 'a\\+b\\*c\\?'
|
|
12
|
-
* new RegExp(escapeRegExp('[test]')) // /\[test\]/
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
export declare function escapeRegExp(str: string): string;
|
|
6
|
+
export declare const escapeRegExp: (str: string) => string;
|