@alchemy.run/node-utils 0.0.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/lib/adapter.d.ts +14 -0
- package/lib/adapter.d.ts.map +1 -0
- package/lib/adapter.js +65 -0
- package/lib/adapter.js.map +1 -0
- package/lib/exit-hook.d.ts +22 -0
- package/lib/exit-hook.d.ts.map +1 -0
- package/lib/exit-hook.js +86 -0
- package/lib/exit-hook.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +24 -0
- package/lib/index.js.map +1 -0
- package/lib/lockfile.d.ts +53 -0
- package/lib/lockfile.d.ts.map +1 -0
- package/lib/lockfile.js +287 -0
- package/lib/lockfile.js.map +1 -0
- package/lib/mtime-precision.d.ts +11 -0
- package/lib/mtime-precision.d.ts.map +1 -0
- package/lib/mtime-precision.js +40 -0
- package/lib/mtime-precision.js.map +1 -0
- package/lib/retry.d.ts +56 -0
- package/lib/retry.d.ts.map +1 -0
- package/lib/retry.js +199 -0
- package/lib/retry.js.map +1 -0
- package/package.json +27 -0
- package/src/adapter.ts +94 -0
- package/src/exit-hook.ts +96 -0
- package/src/index.ts +46 -0
- package/src/lockfile.ts +502 -0
- package/src/mtime-precision.ts +83 -0
- package/src/retry.ts +309 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const cacheSymbol = Symbol();
|
|
2
|
+
export function probe(file, fs, callback) {
|
|
3
|
+
const cachedFs = fs;
|
|
4
|
+
const cachedPrecision = cachedFs[cacheSymbol];
|
|
5
|
+
if (cachedPrecision) {
|
|
6
|
+
return fs.stat(file, (err, stat) => {
|
|
7
|
+
/* istanbul ignore if */
|
|
8
|
+
if (err) {
|
|
9
|
+
return callback(err);
|
|
10
|
+
}
|
|
11
|
+
callback(null, stat.mtime, cachedPrecision);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
// Set mtime by ceiling Date.now() to seconds + 5ms so that it's "not on the second"
|
|
15
|
+
const mtime = new Date(Math.ceil(Date.now() / 1000) * 1000 + 5);
|
|
16
|
+
fs.utimes(file, mtime, mtime, (err) => {
|
|
17
|
+
/* istanbul ignore if */
|
|
18
|
+
if (err) {
|
|
19
|
+
return callback(err);
|
|
20
|
+
}
|
|
21
|
+
fs.stat(file, (err, stat) => {
|
|
22
|
+
/* istanbul ignore if */
|
|
23
|
+
if (err) {
|
|
24
|
+
return callback(err);
|
|
25
|
+
}
|
|
26
|
+
const precision = stat.mtime.getTime() % 1000 === 0 ? "s" : "ms";
|
|
27
|
+
// Cache the precision in a non-enumerable way
|
|
28
|
+
Object.defineProperty(fs, cacheSymbol, { value: precision });
|
|
29
|
+
callback(null, stat.mtime, precision);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export function getMtime(precision) {
|
|
34
|
+
let now = Date.now();
|
|
35
|
+
if (precision === "s") {
|
|
36
|
+
now = Math.ceil(now / 1000) * 1000;
|
|
37
|
+
}
|
|
38
|
+
return new Date(now);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=mtime-precision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mtime-precision.js","sourceRoot":"","sources":["../src/mtime-precision.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC;AAM7B,MAAM,UAAU,KAAK,CACnB,IAAY,EACZ,EAAoB,EACpB,QAAuB;IAEvB,MAAM,QAAQ,GAAG,EAAc,CAAC;IAChC,MAAM,eAAe,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IAE9C,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACjC,wBAAwB;YACxB,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;YAED,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oFAAoF;IACpF,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IAEhE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE;QACpC,wBAAwB;QACxB,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QAED,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YAC1B,wBAAwB;YACxB,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;YAED,MAAM,SAAS,GACb,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAEjD,8CAA8C;YAC9C,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAE7D,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,SAAyB;IAChD,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAErB,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QACtB,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACrC,CAAC;IAED,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
package/lib/retry.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface OperationOptions {
|
|
2
|
+
retries?: number;
|
|
3
|
+
factor?: number;
|
|
4
|
+
minTimeout?: number;
|
|
5
|
+
maxTimeout?: number;
|
|
6
|
+
randomize?: boolean;
|
|
7
|
+
forever?: boolean;
|
|
8
|
+
unref?: boolean;
|
|
9
|
+
maxRetryTime?: number;
|
|
10
|
+
}
|
|
11
|
+
interface RetryOperationOptions {
|
|
12
|
+
forever?: boolean;
|
|
13
|
+
unref?: boolean;
|
|
14
|
+
maxRetryTime?: number;
|
|
15
|
+
}
|
|
16
|
+
interface AttemptTimeoutOptions {
|
|
17
|
+
timeout?: number;
|
|
18
|
+
cb?: (attempt?: number) => void;
|
|
19
|
+
}
|
|
20
|
+
type AttemptFn = (attempt: number) => void;
|
|
21
|
+
export declare function createTimeout(attempt: number, opts: Required<Pick<OperationOptions, 'minTimeout' | 'maxTimeout' | 'factor' | 'randomize'>>): number;
|
|
22
|
+
export declare function timeouts(options?: OperationOptions | number[]): number[];
|
|
23
|
+
export declare class RetryOperation {
|
|
24
|
+
private readonly originalTimeouts;
|
|
25
|
+
private remainingTimeouts;
|
|
26
|
+
private readonly options;
|
|
27
|
+
private readonly maxRetryTime;
|
|
28
|
+
private readonly cachedTimeouts;
|
|
29
|
+
private fn;
|
|
30
|
+
private readonly errorList;
|
|
31
|
+
private attemptCount;
|
|
32
|
+
private operationTimeout;
|
|
33
|
+
private operationTimeoutCb;
|
|
34
|
+
private operationTimer;
|
|
35
|
+
private retryTimer;
|
|
36
|
+
private operationStart;
|
|
37
|
+
constructor(initialTimeouts: number[], options?: RetryOperationOptions | boolean);
|
|
38
|
+
reset(): void;
|
|
39
|
+
stop(): void;
|
|
40
|
+
retry(err?: Error | null): boolean;
|
|
41
|
+
attempt(fn: AttemptFn, timeoutOps?: AttemptTimeoutOptions): void;
|
|
42
|
+
errors(): Error[];
|
|
43
|
+
attempts(): number;
|
|
44
|
+
mainError(): Error | null;
|
|
45
|
+
}
|
|
46
|
+
export declare function operation(options?: OperationOptions | number[]): RetryOperation;
|
|
47
|
+
export declare function wrap<T extends Record<string, any>>(obj: T, optionsOrMethods?: OperationOptions | string[], methodList?: string[]): void;
|
|
48
|
+
declare const _default: {
|
|
49
|
+
operation: typeof operation;
|
|
50
|
+
timeouts: typeof timeouts;
|
|
51
|
+
createTimeout: typeof createTimeout;
|
|
52
|
+
wrap: typeof wrap;
|
|
53
|
+
RetryOperation: typeof RetryOperation;
|
|
54
|
+
};
|
|
55
|
+
export default _default;
|
|
56
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,qBAAqB;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,qBAAqB;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,KAAK,SAAS,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAU3C,wBAAgB,aAAa,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,CAAC,CAAC,GAC7F,MAAM,CAKR;AAED,wBAAgB,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,CAwBxE;AAED,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAW;IAC5C,OAAO,CAAC,iBAAiB,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkB;IAEjD,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,kBAAkB,CAA6C;IACvE,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,cAAc,CAAK;gBAEf,eAAe,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,qBAAqB,GAAG,OAAY;IAWpF,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IAWZ,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,OAAO;IAuDlC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,qBAAqB,GAAG,IAAI;IAsBhE,MAAM,IAAI,KAAK,EAAE;IAIjB,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,KAAK,GAAG,IAAI;CAuB5B;AAED,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,GAAG,cAAc,CAS/E;AAED,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9C,GAAG,EAAE,CAAC,EACN,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,MAAM,EAAE,EAC9C,UAAU,CAAC,EAAE,MAAM,EAAE,GACtB,IAAI,CA2CN;;;;;;;;AAED,wBAA4E"}
|
package/lib/retry.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
const DEFAULTS = {
|
|
2
|
+
retries: 10,
|
|
3
|
+
factor: 2,
|
|
4
|
+
minTimeout: 1000,
|
|
5
|
+
maxTimeout: Infinity,
|
|
6
|
+
randomize: false,
|
|
7
|
+
};
|
|
8
|
+
export function createTimeout(attempt, opts) {
|
|
9
|
+
const random = opts.randomize ? Math.random() + 1 : 1;
|
|
10
|
+
const timeout = Math.round(random * Math.max(opts.minTimeout, 1) * opts.factor ** attempt);
|
|
11
|
+
return Math.min(timeout, opts.maxTimeout);
|
|
12
|
+
}
|
|
13
|
+
export function timeouts(options) {
|
|
14
|
+
if (Array.isArray(options)) {
|
|
15
|
+
return [...options];
|
|
16
|
+
}
|
|
17
|
+
const opts = { ...DEFAULTS, ...options };
|
|
18
|
+
if (opts.minTimeout > opts.maxTimeout) {
|
|
19
|
+
throw new Error('minTimeout is greater than maxTimeout');
|
|
20
|
+
}
|
|
21
|
+
const result = [];
|
|
22
|
+
for (let i = 0; i < opts.retries; i++) {
|
|
23
|
+
result.push(createTimeout(i, opts));
|
|
24
|
+
}
|
|
25
|
+
if (options && !Array.isArray(options) && options.forever && result.length === 0) {
|
|
26
|
+
result.push(createTimeout(opts.retries, opts));
|
|
27
|
+
}
|
|
28
|
+
result.sort((a, b) => a - b);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
export class RetryOperation {
|
|
32
|
+
originalTimeouts;
|
|
33
|
+
remainingTimeouts;
|
|
34
|
+
options;
|
|
35
|
+
maxRetryTime;
|
|
36
|
+
cachedTimeouts;
|
|
37
|
+
fn = null;
|
|
38
|
+
errorList = [];
|
|
39
|
+
attemptCount = 1;
|
|
40
|
+
operationTimeout = null;
|
|
41
|
+
operationTimeoutCb = null;
|
|
42
|
+
operationTimer = null;
|
|
43
|
+
retryTimer = null;
|
|
44
|
+
operationStart = 0;
|
|
45
|
+
constructor(initialTimeouts, options = {}) {
|
|
46
|
+
// Compatibility for the old (timeouts, retryForever) signature
|
|
47
|
+
const opts = typeof options === 'boolean' ? { forever: options } : options;
|
|
48
|
+
this.originalTimeouts = [...initialTimeouts];
|
|
49
|
+
this.remainingTimeouts = [...initialTimeouts];
|
|
50
|
+
this.options = opts;
|
|
51
|
+
this.maxRetryTime = opts.maxRetryTime ?? Infinity;
|
|
52
|
+
this.cachedTimeouts = opts.forever ? [...initialTimeouts] : null;
|
|
53
|
+
}
|
|
54
|
+
reset() {
|
|
55
|
+
this.attemptCount = 1;
|
|
56
|
+
this.remainingTimeouts = [...this.originalTimeouts];
|
|
57
|
+
}
|
|
58
|
+
stop() {
|
|
59
|
+
if (this.operationTimer) {
|
|
60
|
+
clearTimeout(this.operationTimer);
|
|
61
|
+
}
|
|
62
|
+
if (this.retryTimer) {
|
|
63
|
+
clearTimeout(this.retryTimer);
|
|
64
|
+
}
|
|
65
|
+
this.remainingTimeouts = [];
|
|
66
|
+
}
|
|
67
|
+
retry(err) {
|
|
68
|
+
if (this.operationTimer) {
|
|
69
|
+
clearTimeout(this.operationTimer);
|
|
70
|
+
}
|
|
71
|
+
if (!err) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const elapsed = Date.now() - this.operationStart;
|
|
75
|
+
if (elapsed >= this.maxRetryTime) {
|
|
76
|
+
this.errorList.push(err);
|
|
77
|
+
this.errorList.unshift(new Error('RetryOperation timeout occurred'));
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
this.errorList.push(err);
|
|
81
|
+
let timeout = this.remainingTimeouts.shift();
|
|
82
|
+
if (timeout === undefined) {
|
|
83
|
+
if (this.cachedTimeouts) {
|
|
84
|
+
// retry forever, only keep last error
|
|
85
|
+
this.errorList.splice(0, this.errorList.length - 1);
|
|
86
|
+
timeout = this.cachedTimeouts[this.cachedTimeouts.length - 1];
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
this.retryTimer = setTimeout(() => {
|
|
93
|
+
this.attemptCount += 1;
|
|
94
|
+
if (this.operationTimeoutCb) {
|
|
95
|
+
this.operationTimer = setTimeout(() => {
|
|
96
|
+
this.operationTimeoutCb?.(this.attemptCount);
|
|
97
|
+
}, this.operationTimeout ?? 0);
|
|
98
|
+
if (this.options.unref && typeof this.operationTimer.unref === 'function') {
|
|
99
|
+
this.operationTimer.unref();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
this.fn?.(this.attemptCount);
|
|
103
|
+
}, timeout);
|
|
104
|
+
if (this.options.unref && typeof this.retryTimer.unref === 'function') {
|
|
105
|
+
this.retryTimer.unref();
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
attempt(fn, timeoutOps) {
|
|
110
|
+
this.fn = fn;
|
|
111
|
+
if (timeoutOps) {
|
|
112
|
+
if (timeoutOps.timeout != null) {
|
|
113
|
+
this.operationTimeout = timeoutOps.timeout;
|
|
114
|
+
}
|
|
115
|
+
if (timeoutOps.cb) {
|
|
116
|
+
this.operationTimeoutCb = timeoutOps.cb;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (this.operationTimeoutCb) {
|
|
120
|
+
this.operationTimer = setTimeout(() => {
|
|
121
|
+
this.operationTimeoutCb?.();
|
|
122
|
+
}, this.operationTimeout ?? 0);
|
|
123
|
+
}
|
|
124
|
+
this.operationStart = Date.now();
|
|
125
|
+
this.fn(this.attemptCount);
|
|
126
|
+
}
|
|
127
|
+
errors() {
|
|
128
|
+
return this.errorList;
|
|
129
|
+
}
|
|
130
|
+
attempts() {
|
|
131
|
+
return this.attemptCount;
|
|
132
|
+
}
|
|
133
|
+
mainError() {
|
|
134
|
+
if (this.errorList.length === 0) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const counts = new Map();
|
|
138
|
+
let mainError = null;
|
|
139
|
+
let mainErrorCount = 0;
|
|
140
|
+
for (const error of this.errorList) {
|
|
141
|
+
const message = error.message;
|
|
142
|
+
const count = (counts.get(message) ?? 0) + 1;
|
|
143
|
+
counts.set(message, count);
|
|
144
|
+
if (count >= mainErrorCount) {
|
|
145
|
+
mainError = error;
|
|
146
|
+
mainErrorCount = count;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return mainError;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function operation(options) {
|
|
153
|
+
const computedTimeouts = timeouts(options);
|
|
154
|
+
const opts = !Array.isArray(options) ? options : undefined;
|
|
155
|
+
return new RetryOperation(computedTimeouts, {
|
|
156
|
+
forever: opts?.forever || opts?.retries === Infinity,
|
|
157
|
+
unref: opts?.unref,
|
|
158
|
+
maxRetryTime: opts?.maxRetryTime,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export function wrap(obj, optionsOrMethods, methodList) {
|
|
162
|
+
let options;
|
|
163
|
+
let methods;
|
|
164
|
+
if (Array.isArray(optionsOrMethods)) {
|
|
165
|
+
methods = optionsOrMethods;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
options = optionsOrMethods;
|
|
169
|
+
methods = methodList;
|
|
170
|
+
}
|
|
171
|
+
if (!methods) {
|
|
172
|
+
methods = [];
|
|
173
|
+
for (const key in obj) {
|
|
174
|
+
if (typeof obj[key] === 'function') {
|
|
175
|
+
methods.push(key);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const method of methods) {
|
|
180
|
+
const original = obj[method];
|
|
181
|
+
obj[method] = function retryWrapper(...args) {
|
|
182
|
+
const op = operation(options);
|
|
183
|
+
const callback = args.pop();
|
|
184
|
+
args.push(function (err, ...rest) {
|
|
185
|
+
if (op.retry(err)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const finalErr = err ? op.mainError() : err;
|
|
189
|
+
callback.call(this, finalErr, ...rest);
|
|
190
|
+
});
|
|
191
|
+
op.attempt(() => {
|
|
192
|
+
original.apply(obj, args);
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
obj[method].options = options;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export default { operation, timeouts, createTimeout, wrap, RetryOperation };
|
|
199
|
+
//# sourceMappingURL=retry.js.map
|
package/lib/retry.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alchemy.run/node-utils",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"author": "Sam Goodwin (sam@alchemy.run)",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git@github.com:alchemy-run/node-utils.git"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"lib"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"bun": "./src/index.ts",
|
|
17
|
+
"types": "./lib/index.d.ts",
|
|
18
|
+
"default": "./lib/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "bun test"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
type AnyFs = Record<string, any>;
|
|
4
|
+
type AnyCallback = (err: NodeJS.ErrnoException | null, result?: any) => void;
|
|
5
|
+
type AsyncMethod = (...args: any[]) => void;
|
|
6
|
+
|
|
7
|
+
function createSyncFs(fs: AnyFs): AnyFs {
|
|
8
|
+
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"] as const;
|
|
9
|
+
const newFs: AnyFs = { ...fs };
|
|
10
|
+
|
|
11
|
+
methods.forEach((method) => {
|
|
12
|
+
newFs[method] = (...args: any[]) => {
|
|
13
|
+
const callback = args.pop() as AnyCallback;
|
|
14
|
+
let ret;
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
ret = fs[`${method}Sync`](...args);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
return callback(err as NodeJS.ErrnoException);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
callback(null, ret);
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return newFs;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ----------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export function toPromise<T = any>(
|
|
32
|
+
method: AsyncMethod,
|
|
33
|
+
): (...args: any[]) => Promise<T> {
|
|
34
|
+
return (...args: any[]) =>
|
|
35
|
+
new Promise<T>((resolve, reject) => {
|
|
36
|
+
args.push((err: NodeJS.ErrnoException | null, result: T) => {
|
|
37
|
+
if (err) {
|
|
38
|
+
reject(err);
|
|
39
|
+
} else {
|
|
40
|
+
resolve(result);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
method(...args);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function toSync<T = any>(method: AsyncMethod): (...args: any[]) => T {
|
|
49
|
+
return (...args: any[]) => {
|
|
50
|
+
let err: NodeJS.ErrnoException | null | undefined;
|
|
51
|
+
let result: T | undefined;
|
|
52
|
+
|
|
53
|
+
args.push((_err: NodeJS.ErrnoException | null, _result: T) => {
|
|
54
|
+
err = _err;
|
|
55
|
+
result = _result;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
method(...args);
|
|
59
|
+
|
|
60
|
+
if (err) {
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return result as T;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface SyncOptions {
|
|
69
|
+
fs?: AnyFs;
|
|
70
|
+
retries?: number | { retries?: number };
|
|
71
|
+
[key: string]: any;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function toSyncOptions(options?: SyncOptions): SyncOptions {
|
|
75
|
+
// Shallow clone options because we are going to mutate them
|
|
76
|
+
const next: SyncOptions = { ...options };
|
|
77
|
+
|
|
78
|
+
// Transform fs to use the sync methods instead
|
|
79
|
+
next.fs = createSyncFs(next.fs || fs);
|
|
80
|
+
|
|
81
|
+
// Retries are not allowed because it requires the flow to be sync
|
|
82
|
+
if (
|
|
83
|
+
(typeof next.retries === "number" && next.retries > 0) ||
|
|
84
|
+
(next.retries &&
|
|
85
|
+
typeof (next.retries as { retries?: number }).retries === "number" &&
|
|
86
|
+
((next.retries as { retries?: number }).retries as number) > 0)
|
|
87
|
+
) {
|
|
88
|
+
throw Object.assign(new Error("Cannot use retries with the sync api"), {
|
|
89
|
+
code: "ESYNC",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return next;
|
|
94
|
+
}
|
package/src/exit-hook.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight replacement for the `exit-hook` npm package.
|
|
3
|
+
*
|
|
4
|
+
* The third-party `exit-hook` registers process listeners (`exit`, `SIGINT`,
|
|
5
|
+
* `SIGTERM`, and `message`) that are never removed — even after every
|
|
6
|
+
* callback has been unregistered. Those dangling listeners are harmless in
|
|
7
|
+
* long-running processes, but in short-lived child processes (e.g. those
|
|
8
|
+
* spawned by `node --test`) they can prevent clean exit by holding refs on
|
|
9
|
+
* handles such as the IPC channel.
|
|
10
|
+
*
|
|
11
|
+
* This module tracks the number of active registrations and removes **all**
|
|
12
|
+
* process listeners once the last registration is unregistered, so they
|
|
13
|
+
* cannot keep the event loop alive after dispose.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const callbacks = new Set<() => void>();
|
|
17
|
+
let registered = false;
|
|
18
|
+
let called = false;
|
|
19
|
+
|
|
20
|
+
function runCallbacks(): void {
|
|
21
|
+
if (called) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
called = true;
|
|
25
|
+
for (const callback of callbacks) {
|
|
26
|
+
callback();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function onExit(): void {
|
|
31
|
+
runCallbacks();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function onSignalInt(): void {
|
|
35
|
+
runCallbacks();
|
|
36
|
+
// eslint-disable-next-line unicorn/no-process-exit -- intentional: replicate default SIGINT behavior
|
|
37
|
+
process.exit(128 + 2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function onSignalTerm(): void {
|
|
41
|
+
runCallbacks();
|
|
42
|
+
// eslint-disable-next-line unicorn/no-process-exit -- intentional: replicate default SIGTERM behavior
|
|
43
|
+
process.exit(128 + 15);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function onMessage(message: unknown): void {
|
|
47
|
+
if (message === "shutdown") {
|
|
48
|
+
runCallbacks();
|
|
49
|
+
// eslint-disable-next-line unicorn/no-process-exit -- intentional: PM2 graceful shutdown
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function addListeners(): void {
|
|
55
|
+
registered = true;
|
|
56
|
+
called = false;
|
|
57
|
+
process.on("exit", onExit);
|
|
58
|
+
process.on("SIGINT", onSignalInt);
|
|
59
|
+
process.on("SIGTERM", onSignalTerm);
|
|
60
|
+
// Only listen for IPC "shutdown" messages (PM2 support) when the process
|
|
61
|
+
// actually has an IPC channel. Even without this guard the listener is
|
|
62
|
+
// harmless when there is no channel, but being explicit avoids any
|
|
63
|
+
// accidental ref of a future channel.
|
|
64
|
+
if (process.send !== undefined) {
|
|
65
|
+
process.on("message", onMessage);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function removeListeners(): void {
|
|
70
|
+
registered = false;
|
|
71
|
+
process.removeListener("exit", onExit);
|
|
72
|
+
process.removeListener("SIGINT", onSignalInt);
|
|
73
|
+
process.removeListener("SIGTERM", onSignalTerm);
|
|
74
|
+
process.removeListener("message", onMessage);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Register a callback to run when the process exits. Returns a function
|
|
79
|
+
* that unregisters the callback. When the last callback is unregistered,
|
|
80
|
+
* all underlying process listeners are removed so they cannot keep the
|
|
81
|
+
* event loop alive.
|
|
82
|
+
*/
|
|
83
|
+
export function exitHook(callback: () => void): () => void {
|
|
84
|
+
callbacks.add(callback);
|
|
85
|
+
|
|
86
|
+
if (!registered) {
|
|
87
|
+
addListeners();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return () => {
|
|
91
|
+
callbacks.delete(callback);
|
|
92
|
+
if (callbacks.size === 0 && registered) {
|
|
93
|
+
removeListeners();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { toPromise, toSync, toSyncOptions } from "./adapter.ts";
|
|
2
|
+
import type {
|
|
3
|
+
CheckOptions,
|
|
4
|
+
LockOptions,
|
|
5
|
+
ReleaseFn,
|
|
6
|
+
UnlockOptions,
|
|
7
|
+
} from "./lockfile.ts";
|
|
8
|
+
import * as lockfile from "./lockfile.ts";
|
|
9
|
+
|
|
10
|
+
export type { CheckOptions, LockOptions, ReleaseFn, UnlockOptions };
|
|
11
|
+
|
|
12
|
+
export async function lock(
|
|
13
|
+
file: string,
|
|
14
|
+
options?: LockOptions,
|
|
15
|
+
): Promise<() => Promise<void>> {
|
|
16
|
+
const release = await toPromise<ReleaseFn>(lockfile.lock)(file, options);
|
|
17
|
+
|
|
18
|
+
return toPromise<void>(release);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function lockSync(file: string, options?: LockOptions): () => void {
|
|
22
|
+
const release = toSync<ReleaseFn>(lockfile.lock)(
|
|
23
|
+
file,
|
|
24
|
+
toSyncOptions(options),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return toSync<void>(release);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function unlock(file: string, options?: UnlockOptions): Promise<void> {
|
|
31
|
+
return toPromise<void>(lockfile.unlock)(file, options);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function unlockSync(file: string, options?: UnlockOptions): void {
|
|
35
|
+
return toSync<void>(lockfile.unlock)(file, toSyncOptions(options));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function check(file: string, options?: CheckOptions): Promise<boolean> {
|
|
39
|
+
return toPromise<boolean>(lockfile.check)(file, options);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function checkSync(file: string, options?: CheckOptions): boolean {
|
|
43
|
+
return toSync<boolean>(lockfile.check)(file, toSyncOptions(options));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default lock;
|