@filen/utils 0.0.5 → 0.0.7
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/dist/checklistParser.js +1 -1
- package/dist/misc.js +50 -42
- package/dist/notes.js +4 -5
- package/dist/run.js +279 -196
- package/dist/semaphore.js +1 -1
- package/dist/types/run.d.ts +19 -9
- package/package.json +1 -1
package/dist/checklistParser.js
CHANGED
package/dist/misc.js
CHANGED
|
@@ -57,48 +57,53 @@ export function chunkArray(array, chunkSize) {
|
|
|
57
57
|
}
|
|
58
58
|
return chunks;
|
|
59
59
|
}
|
|
60
|
+
const ZERO_WIDTH_AND_CONTROL_RE = /[\u200B-\u200D\uFEFF\u00AD\u0000-\u001F\u007F-\u009F]/g;
|
|
61
|
+
const NON_ASCII_RE = /[^\x00-\x7F]/g;
|
|
62
|
+
const ILLEGAL_CHARS_WINDOWS_RE = /[<>:"/\\|?*]/g;
|
|
63
|
+
const ILLEGAL_CHARS_UNIX_RE = /\//g;
|
|
64
|
+
const TRAILING_DOTS_SPACES_RE = /[. ]+$/;
|
|
65
|
+
const WHITESPACE_RE = /\s+/g;
|
|
66
|
+
const RESERVED_NAMES_WINDOWS = new Set([
|
|
67
|
+
"CON",
|
|
68
|
+
"PRN",
|
|
69
|
+
"AUX",
|
|
70
|
+
"NUL",
|
|
71
|
+
"COM1",
|
|
72
|
+
"COM2",
|
|
73
|
+
"COM3",
|
|
74
|
+
"COM4",
|
|
75
|
+
"COM5",
|
|
76
|
+
"COM6",
|
|
77
|
+
"COM7",
|
|
78
|
+
"COM8",
|
|
79
|
+
"COM9",
|
|
80
|
+
"LPT1",
|
|
81
|
+
"LPT2",
|
|
82
|
+
"LPT3",
|
|
83
|
+
"LPT4",
|
|
84
|
+
"LPT5",
|
|
85
|
+
"LPT6",
|
|
86
|
+
"LPT7",
|
|
87
|
+
"LPT8",
|
|
88
|
+
"LPT9"
|
|
89
|
+
]);
|
|
90
|
+
const textEncoder = new TextEncoder();
|
|
60
91
|
export function sanitizeFileName(filename, replacement = "_") {
|
|
61
92
|
let sanitizedFilename = filename.normalize("NFC");
|
|
62
|
-
sanitizedFilename = sanitizedFilename.replace(
|
|
63
|
-
sanitizedFilename = sanitizedFilename.replace(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"AUX",
|
|
70
|
-
"NUL",
|
|
71
|
-
"COM1",
|
|
72
|
-
"COM2",
|
|
73
|
-
"COM3",
|
|
74
|
-
"COM4",
|
|
75
|
-
"COM5",
|
|
76
|
-
"COM6",
|
|
77
|
-
"COM7",
|
|
78
|
-
"COM8",
|
|
79
|
-
"COM9",
|
|
80
|
-
"LPT1",
|
|
81
|
-
"LPT2",
|
|
82
|
-
"LPT3",
|
|
83
|
-
"LPT4",
|
|
84
|
-
"LPT5",
|
|
85
|
-
"LPT6",
|
|
86
|
-
"LPT7",
|
|
87
|
-
"LPT8",
|
|
88
|
-
"LPT9"
|
|
89
|
-
]);
|
|
90
|
-
sanitizedFilename = sanitizedFilename.replace(illegalCharsWindows, replacement);
|
|
91
|
-
sanitizedFilename = sanitizedFilename.replace(illegalCharsUnix, replacement);
|
|
92
|
-
sanitizedFilename = sanitizedFilename.replace(/[. ]+$/, "");
|
|
93
|
-
sanitizedFilename = sanitizedFilename.replace(/\s+/g, replacement);
|
|
94
|
-
if (reservedNamesWindows.has(sanitizedFilename.toUpperCase())) {
|
|
93
|
+
sanitizedFilename = sanitizedFilename.replace(ZERO_WIDTH_AND_CONTROL_RE, "");
|
|
94
|
+
sanitizedFilename = sanitizedFilename.replace(NON_ASCII_RE, replacement);
|
|
95
|
+
sanitizedFilename = sanitizedFilename.replace(ILLEGAL_CHARS_WINDOWS_RE, replacement);
|
|
96
|
+
sanitizedFilename = sanitizedFilename.replace(ILLEGAL_CHARS_UNIX_RE, replacement);
|
|
97
|
+
sanitizedFilename = sanitizedFilename.replace(TRAILING_DOTS_SPACES_RE, "");
|
|
98
|
+
sanitizedFilename = sanitizedFilename.replace(WHITESPACE_RE, replacement);
|
|
99
|
+
if (RESERVED_NAMES_WINDOWS.has(sanitizedFilename.toUpperCase())) {
|
|
95
100
|
sanitizedFilename += replacement;
|
|
96
101
|
}
|
|
97
102
|
const maxByteLength = 255;
|
|
98
|
-
let byteLength =
|
|
103
|
+
let byteLength = textEncoder.encode(sanitizedFilename).length;
|
|
99
104
|
while (byteLength > maxByteLength && sanitizedFilename.length > 0) {
|
|
100
105
|
sanitizedFilename = sanitizedFilename.slice(0, -1);
|
|
101
|
-
byteLength =
|
|
106
|
+
byteLength = textEncoder.encode(sanitizedFilename).length;
|
|
102
107
|
}
|
|
103
108
|
if (!sanitizedFilename) {
|
|
104
109
|
return "file";
|
|
@@ -158,7 +163,7 @@ export function parseFilenPublicLink(url) {
|
|
|
158
163
|
try {
|
|
159
164
|
key = Buffer.from(key, "hex").toString("utf8");
|
|
160
165
|
}
|
|
161
|
-
catch
|
|
166
|
+
catch {
|
|
162
167
|
return null;
|
|
163
168
|
}
|
|
164
169
|
}
|
|
@@ -222,7 +227,7 @@ export function jsonBigIntReplacer(_, value) {
|
|
|
222
227
|
}
|
|
223
228
|
export function jsonBigIntReviver(_, value) {
|
|
224
229
|
if (typeof value === "string" && value.startsWith("$bigint:") && value.endsWith("n")) {
|
|
225
|
-
return BigInt(value.
|
|
230
|
+
return BigInt(value.slice(8, -1));
|
|
226
231
|
}
|
|
227
232
|
return value;
|
|
228
233
|
}
|
|
@@ -314,20 +319,20 @@ export function bpsToReadable(bps) {
|
|
|
314
319
|
if (!(bps > 0 && bps < 1099511627776)) {
|
|
315
320
|
return "0.1 B/s";
|
|
316
321
|
}
|
|
317
|
-
let i =
|
|
322
|
+
let i = -1;
|
|
318
323
|
let value = bps;
|
|
319
324
|
if (value >= 1024) {
|
|
320
325
|
value /= 1024;
|
|
321
|
-
i =
|
|
326
|
+
i = 0;
|
|
322
327
|
if (value >= 1024) {
|
|
323
328
|
value /= 1024;
|
|
324
|
-
i =
|
|
329
|
+
i = 1;
|
|
325
330
|
if (value >= 1024) {
|
|
326
331
|
value /= 1024;
|
|
327
|
-
i =
|
|
332
|
+
i = 2;
|
|
328
333
|
if (value >= 1024) {
|
|
329
334
|
value /= 1024;
|
|
330
|
-
i =
|
|
335
|
+
i = 3;
|
|
331
336
|
}
|
|
332
337
|
}
|
|
333
338
|
}
|
|
@@ -335,6 +340,9 @@ export function bpsToReadable(bps) {
|
|
|
335
340
|
if (value < 0.1) {
|
|
336
341
|
value = 0.1;
|
|
337
342
|
}
|
|
343
|
+
if (i < 0) {
|
|
344
|
+
return value.toFixed(1) + " B";
|
|
345
|
+
}
|
|
338
346
|
return value.toFixed(1) + " " + BPS_TO_READABLE_UNITS[i];
|
|
339
347
|
}
|
|
340
348
|
export const FORMAT_BYTES_SIZES = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
|
package/dist/notes.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import striptags from "striptags";
|
|
2
2
|
export function createNotePreviewFromContentText(type, content) {
|
|
3
|
-
var _a, _b, _c;
|
|
4
3
|
try {
|
|
5
4
|
if (!content || content.length === 0) {
|
|
6
5
|
return "";
|
|
7
6
|
}
|
|
8
7
|
if (type === "rich") {
|
|
9
8
|
if (content.indexOf("<p><br></p>") === -1) {
|
|
10
|
-
return striptags(
|
|
9
|
+
return striptags(content.split("\n")[0] ?? "").slice(0, 128);
|
|
11
10
|
}
|
|
12
|
-
return striptags(
|
|
11
|
+
return striptags(content.split("<p><br></p>")[0] ?? "").slice(0, 128);
|
|
13
12
|
}
|
|
14
13
|
if (type === "checklist") {
|
|
15
14
|
const ex = content
|
|
@@ -31,9 +30,9 @@ export function createNotePreviewFromContentText(type, content) {
|
|
|
31
30
|
}
|
|
32
31
|
return "";
|
|
33
32
|
}
|
|
34
|
-
return striptags(
|
|
33
|
+
return striptags(content.split("\n")[0] ?? "").slice(0, 128);
|
|
35
34
|
}
|
|
36
|
-
catch
|
|
35
|
+
catch {
|
|
37
36
|
return "";
|
|
38
37
|
}
|
|
39
38
|
}
|
package/dist/run.js
CHANGED
|
@@ -1,50 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var _a, _b, _c;
|
|
13
|
-
const deferredFunctions = [];
|
|
14
|
-
const defer = deferFn => {
|
|
15
|
-
deferredFunctions.push(deferFn);
|
|
1
|
+
export async function run(fn, options) {
|
|
2
|
+
const deferredFunctions = [];
|
|
3
|
+
const defer = deferFn => {
|
|
4
|
+
deferredFunctions.push(deferFn);
|
|
5
|
+
};
|
|
6
|
+
try {
|
|
7
|
+
const result = await fn(defer);
|
|
8
|
+
return {
|
|
9
|
+
success: true,
|
|
10
|
+
data: result,
|
|
11
|
+
error: null
|
|
16
12
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
error: null
|
|
23
|
-
};
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
options?.onError?.(e);
|
|
16
|
+
if (options?.throw) {
|
|
17
|
+
throw e;
|
|
24
18
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
data: null,
|
|
22
|
+
error: e
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
for (let i = deferredFunctions.length - 1; i >= 0; i--) {
|
|
27
|
+
try {
|
|
28
|
+
await deferredFunctions[i]?.();
|
|
30
29
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
data: null,
|
|
34
|
-
error: error
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
finally {
|
|
38
|
-
for (let i = deferredFunctions.length - 1; i >= 0; i--) {
|
|
39
|
-
try {
|
|
40
|
-
yield ((_b = deferredFunctions[i]) === null || _b === void 0 ? void 0 : _b.call(deferredFunctions));
|
|
41
|
-
}
|
|
42
|
-
catch (e) {
|
|
43
|
-
(_c = options === null || options === void 0 ? void 0 : options.onError) === null || _c === void 0 ? void 0 : _c.call(options, e instanceof Error ? e : new Error("Unknown error"));
|
|
44
|
-
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
options?.onError?.(e);
|
|
45
32
|
}
|
|
46
33
|
}
|
|
47
|
-
}
|
|
34
|
+
}
|
|
48
35
|
}
|
|
49
36
|
export class AbortError extends Error {
|
|
50
37
|
constructor(message = "Operation aborted") {
|
|
@@ -65,110 +52,103 @@ export function abortSignalReason(signal) {
|
|
|
65
52
|
}
|
|
66
53
|
return undefined;
|
|
67
54
|
}
|
|
68
|
-
catch
|
|
55
|
+
catch {
|
|
69
56
|
return undefined;
|
|
70
57
|
}
|
|
71
58
|
}
|
|
72
|
-
export function runAbortable(fn, options) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
59
|
+
export async function runAbortable(fn, options) {
|
|
60
|
+
const deferredFunctions = [];
|
|
61
|
+
const controller = options?.controller ?? new AbortController();
|
|
62
|
+
const signal = options?.signal ?? options?.controller?.signal ?? controller.signal;
|
|
63
|
+
const defer = deferFn => {
|
|
64
|
+
deferredFunctions.push(deferFn);
|
|
65
|
+
};
|
|
66
|
+
const abortable = async (abortableFn, opts) => {
|
|
67
|
+
if (signal.aborted) {
|
|
68
|
+
throw new AbortError(abortSignalReason(signal));
|
|
69
|
+
}
|
|
70
|
+
return await new Promise((resolve, reject) => {
|
|
71
|
+
;
|
|
72
|
+
(async () => {
|
|
73
|
+
const signal = opts?.signal ?? controller.signal;
|
|
74
|
+
const abortHandler = () => {
|
|
75
|
+
reject(new AbortError(abortSignalReason(signal)));
|
|
76
|
+
};
|
|
77
|
+
signal.addEventListener("abort", abortHandler);
|
|
78
|
+
try {
|
|
79
|
+
if (signal.aborted) {
|
|
91
80
|
reject(new AbortError(abortSignalReason(signal)));
|
|
92
|
-
|
|
93
|
-
signal.addEventListener("abort", abortHandler);
|
|
94
|
-
try {
|
|
95
|
-
if (signal.aborted) {
|
|
96
|
-
reject(new AbortError(abortSignalReason(signal)));
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const result = yield abortableFn();
|
|
100
|
-
if (signal.aborted) {
|
|
101
|
-
reject(new AbortError(abortSignalReason(signal)));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
resolve(result);
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
reject(error);
|
|
81
|
+
return;
|
|
108
82
|
}
|
|
109
|
-
|
|
110
|
-
|
|
83
|
+
const result = await abortableFn();
|
|
84
|
+
if (signal.aborted) {
|
|
85
|
+
reject(new AbortError(abortSignalReason(signal)));
|
|
86
|
+
return;
|
|
111
87
|
}
|
|
112
|
-
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
try {
|
|
116
|
-
if (signal.aborted) {
|
|
117
|
-
throw new AbortError(abortSignalReason(signal));
|
|
118
|
-
}
|
|
119
|
-
const result = yield fn({
|
|
120
|
-
abortable,
|
|
121
|
-
defer,
|
|
122
|
-
signal,
|
|
123
|
-
controller
|
|
124
|
-
});
|
|
125
|
-
if (signal.aborted) {
|
|
126
|
-
throw new AbortError(abortSignalReason(signal));
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
success: true,
|
|
130
|
-
data: result,
|
|
131
|
-
error: null
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
catch (e) {
|
|
135
|
-
const error = e instanceof Error ? e : new Error("Unknown error");
|
|
136
|
-
(_e = options === null || options === void 0 ? void 0 : options.onError) === null || _e === void 0 ? void 0 : _e.call(options, error);
|
|
137
|
-
if (options === null || options === void 0 ? void 0 : options.throw) {
|
|
138
|
-
throw error;
|
|
139
|
-
}
|
|
140
|
-
return {
|
|
141
|
-
success: false,
|
|
142
|
-
data: null,
|
|
143
|
-
error: error
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
finally {
|
|
147
|
-
for (let i = deferredFunctions.length - 1; i >= 0; i--) {
|
|
148
|
-
try {
|
|
149
|
-
yield ((_f = deferredFunctions[i]) === null || _f === void 0 ? void 0 : _f.call(deferredFunctions));
|
|
88
|
+
resolve(result);
|
|
150
89
|
}
|
|
151
90
|
catch (e) {
|
|
152
|
-
(
|
|
91
|
+
reject(e);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
signal.removeEventListener("abort", abortHandler);
|
|
153
95
|
}
|
|
96
|
+
})();
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
try {
|
|
100
|
+
if (signal.aborted) {
|
|
101
|
+
throw new AbortError(abortSignalReason(signal));
|
|
102
|
+
}
|
|
103
|
+
const result = await fn({
|
|
104
|
+
abortable,
|
|
105
|
+
defer,
|
|
106
|
+
signal,
|
|
107
|
+
controller
|
|
108
|
+
});
|
|
109
|
+
if (signal.aborted) {
|
|
110
|
+
throw new AbortError(abortSignalReason(signal));
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
success: true,
|
|
114
|
+
data: result,
|
|
115
|
+
error: null
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
options?.onError?.(e);
|
|
120
|
+
if (options?.throw) {
|
|
121
|
+
throw e;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
data: null,
|
|
126
|
+
error: e
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
for (let i = deferredFunctions.length - 1; i >= 0; i--) {
|
|
131
|
+
try {
|
|
132
|
+
await deferredFunctions[i]?.();
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
options?.onError?.(e);
|
|
154
136
|
}
|
|
155
137
|
}
|
|
156
|
-
}
|
|
138
|
+
}
|
|
157
139
|
}
|
|
158
140
|
export function runEffect(fn, options) {
|
|
159
|
-
var _a;
|
|
160
141
|
const deferredFunctions = [];
|
|
161
142
|
const defer = deferFn => {
|
|
162
143
|
deferredFunctions.push(deferFn);
|
|
163
144
|
};
|
|
164
145
|
const cleanup = () => {
|
|
165
|
-
var _a, _b;
|
|
166
146
|
for (let i = deferredFunctions.length - 1; i >= 0; i--) {
|
|
167
147
|
try {
|
|
168
|
-
|
|
148
|
+
deferredFunctions[i]?.();
|
|
169
149
|
}
|
|
170
150
|
catch (e) {
|
|
171
|
-
|
|
151
|
+
options?.onError?.(e);
|
|
172
152
|
}
|
|
173
153
|
}
|
|
174
154
|
};
|
|
@@ -182,57 +162,56 @@ export function runEffect(fn, options) {
|
|
|
182
162
|
};
|
|
183
163
|
}
|
|
184
164
|
catch (e) {
|
|
185
|
-
|
|
186
|
-
(
|
|
187
|
-
|
|
188
|
-
throw error;
|
|
165
|
+
options?.onError?.(e);
|
|
166
|
+
if (options?.throw) {
|
|
167
|
+
throw e;
|
|
189
168
|
}
|
|
190
169
|
return {
|
|
191
170
|
success: false,
|
|
192
171
|
data: null,
|
|
193
|
-
error:
|
|
172
|
+
error: e,
|
|
194
173
|
cleanup
|
|
195
174
|
};
|
|
196
175
|
}
|
|
197
176
|
finally {
|
|
198
|
-
if (options
|
|
177
|
+
if (options?.automaticCleanup) {
|
|
199
178
|
cleanup();
|
|
200
179
|
}
|
|
201
180
|
}
|
|
202
181
|
}
|
|
203
|
-
export function runRetry(fn, options) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
(_d = options === null || options === void 0 ? void 0 : options.onRetry) === null || _d === void 0 ? void 0 : _d.call(options, result.error, attempt);
|
|
226
|
-
const delay = backoff === "exponential" ? delayMs * Math.pow(2, attempt - 1) : delayMs * attempt;
|
|
227
|
-
yield new Promise(resolve => setTimeout(resolve, delay));
|
|
182
|
+
export async function runRetry(fn, options) {
|
|
183
|
+
const maxAttempts = options?.maxAttempts ?? 3;
|
|
184
|
+
const delayMs = options?.delayMs ?? 1000;
|
|
185
|
+
const backoff = options?.backoff ?? "exponential";
|
|
186
|
+
let lastError = null;
|
|
187
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
188
|
+
const result = await run(defer => fn(defer, attempt), {
|
|
189
|
+
...options,
|
|
190
|
+
throw: false
|
|
191
|
+
});
|
|
192
|
+
if (result.success) {
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
lastError = result.error;
|
|
196
|
+
if (attempt < maxAttempts) {
|
|
197
|
+
const shouldRetry = typeof options?.shouldRetry === "boolean"
|
|
198
|
+
? options.shouldRetry
|
|
199
|
+
: options && typeof options.shouldRetry === "function"
|
|
200
|
+
? options.shouldRetry(result.error, attempt)
|
|
201
|
+
: true;
|
|
202
|
+
if (!shouldRetry) {
|
|
203
|
+
break;
|
|
228
204
|
}
|
|
205
|
+
options?.onRetry?.(result.error, attempt);
|
|
206
|
+
const delay = backoff === "exponential" ? delayMs * Math.pow(2, attempt - 1) : delayMs * attempt;
|
|
207
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
229
208
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
success: false,
|
|
212
|
+
data: null,
|
|
213
|
+
error: lastError
|
|
214
|
+
};
|
|
236
215
|
}
|
|
237
216
|
export class TimeoutError extends Error {
|
|
238
217
|
constructor(message = "Operation timed out") {
|
|
@@ -240,39 +219,36 @@ export class TimeoutError extends Error {
|
|
|
240
219
|
this.name = "TimeoutError";
|
|
241
220
|
}
|
|
242
221
|
}
|
|
243
|
-
export function runTimeout(fn, timeoutMs, options) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
(_a = options === null || options === void 0 ? void 0 : options.onError) === null || _a === void 0 ? void 0 : _a.call(options, error);
|
|
263
|
-
if (options === null || options === void 0 ? void 0 : options.throw) {
|
|
264
|
-
throw error;
|
|
265
|
-
}
|
|
266
|
-
return {
|
|
267
|
-
success: false,
|
|
268
|
-
data: null,
|
|
269
|
-
error: error
|
|
270
|
-
};
|
|
222
|
+
export async function runTimeout(fn, timeoutMs, options) {
|
|
223
|
+
const controller = new AbortController();
|
|
224
|
+
try {
|
|
225
|
+
const result = await Promise.race([
|
|
226
|
+
run(fn, options),
|
|
227
|
+
new Promise((_, reject) => {
|
|
228
|
+
const timeoutId = setTimeout(() => {
|
|
229
|
+
controller.abort();
|
|
230
|
+
reject(new TimeoutError(`Operation timed out after ${timeoutMs}ms`));
|
|
231
|
+
}, timeoutMs);
|
|
232
|
+
controller.signal.addEventListener("abort", () => clearTimeout(timeoutId));
|
|
233
|
+
})
|
|
234
|
+
]);
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
options?.onError?.(e);
|
|
239
|
+
if (options?.throw) {
|
|
240
|
+
throw e;
|
|
271
241
|
}
|
|
272
|
-
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
data: null,
|
|
245
|
+
error: e
|
|
246
|
+
};
|
|
247
|
+
}
|
|
273
248
|
}
|
|
274
249
|
export function runDebounced(fn, delayMs, options) {
|
|
275
250
|
let timeoutId = null;
|
|
251
|
+
let pendingResolve = null;
|
|
276
252
|
let pendingPromise = null;
|
|
277
253
|
return (...args) => {
|
|
278
254
|
if (timeoutId) {
|
|
@@ -280,15 +256,122 @@ export function runDebounced(fn, delayMs, options) {
|
|
|
280
256
|
}
|
|
281
257
|
if (!pendingPromise) {
|
|
282
258
|
pendingPromise = new Promise(resolve => {
|
|
283
|
-
|
|
284
|
-
const result = yield run(defer => fn(defer, ...args), options);
|
|
285
|
-
resolve(result);
|
|
286
|
-
pendingPromise = null;
|
|
287
|
-
timeoutId = null;
|
|
288
|
-
}), delayMs);
|
|
259
|
+
pendingResolve = resolve;
|
|
289
260
|
});
|
|
290
261
|
}
|
|
262
|
+
timeoutId = setTimeout(async () => {
|
|
263
|
+
const result = await run(defer => fn(defer, ...args), options);
|
|
264
|
+
pendingResolve(result);
|
|
265
|
+
pendingPromise = null;
|
|
266
|
+
pendingResolve = null;
|
|
267
|
+
timeoutId = null;
|
|
268
|
+
}, delayMs);
|
|
291
269
|
return pendingPromise;
|
|
292
270
|
};
|
|
293
271
|
}
|
|
272
|
+
export function createAbortablePipeline(signal) {
|
|
273
|
+
const controller = new AbortController();
|
|
274
|
+
const controllerSignal = controller.signal;
|
|
275
|
+
if (signal) {
|
|
276
|
+
if (signal.aborted) {
|
|
277
|
+
controller.abort(signal.reason);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), {
|
|
281
|
+
once: true
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
let chain = Promise.resolve();
|
|
286
|
+
let halted = false;
|
|
287
|
+
const step = (fn) => {
|
|
288
|
+
let resolve;
|
|
289
|
+
let reject;
|
|
290
|
+
const promise = new Promise((res, rej) => {
|
|
291
|
+
resolve = res;
|
|
292
|
+
reject = rej;
|
|
293
|
+
});
|
|
294
|
+
chain = chain.then(async () => {
|
|
295
|
+
if (halted || controllerSignal.aborted) {
|
|
296
|
+
reject(new AbortError(controllerSignal.aborted ? abortSignalReason(controllerSignal) : "Pipeline halted"));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const stepDeferred = [];
|
|
300
|
+
const defer = deferFn => {
|
|
301
|
+
stepDeferred.push(deferFn);
|
|
302
|
+
};
|
|
303
|
+
const runCleanups = async () => {
|
|
304
|
+
for (let i = stepDeferred.length - 1; i >= 0; i--) {
|
|
305
|
+
try {
|
|
306
|
+
await stepDeferred[i]?.();
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
let fnSucceeded = false;
|
|
313
|
+
let fnValue;
|
|
314
|
+
let fnError;
|
|
315
|
+
const fnPromise = (async () => {
|
|
316
|
+
try {
|
|
317
|
+
fnValue = await fn(defer, controllerSignal);
|
|
318
|
+
fnSucceeded = true;
|
|
319
|
+
}
|
|
320
|
+
catch (e) {
|
|
321
|
+
fnError = e;
|
|
322
|
+
fnSucceeded = false;
|
|
323
|
+
}
|
|
324
|
+
})();
|
|
325
|
+
if (controllerSignal.aborted) {
|
|
326
|
+
await fnPromise;
|
|
327
|
+
await runCleanups();
|
|
328
|
+
if (fnSucceeded) {
|
|
329
|
+
resolve(fnValue);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
halted = true;
|
|
333
|
+
reject(fnError);
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
await new Promise((res, rej) => {
|
|
339
|
+
const onAbort = () => {
|
|
340
|
+
rej(new AbortError(abortSignalReason(controllerSignal)));
|
|
341
|
+
};
|
|
342
|
+
controllerSignal.addEventListener("abort", onAbort, {
|
|
343
|
+
once: true
|
|
344
|
+
});
|
|
345
|
+
fnPromise.then(() => {
|
|
346
|
+
controllerSignal.removeEventListener("abort", onAbort);
|
|
347
|
+
res();
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
catch (e) {
|
|
352
|
+
await runCleanups();
|
|
353
|
+
halted = true;
|
|
354
|
+
reject(e);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
await runCleanups();
|
|
358
|
+
if (fnSucceeded) {
|
|
359
|
+
resolve(fnValue);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
halted = true;
|
|
363
|
+
reject(fnError);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
return {
|
|
367
|
+
then: promise.then.bind(promise),
|
|
368
|
+
catch: promise.catch.bind(promise),
|
|
369
|
+
finally: promise.finally.bind(promise)
|
|
370
|
+
};
|
|
371
|
+
};
|
|
372
|
+
return {
|
|
373
|
+
step,
|
|
374
|
+
signal: controllerSignal
|
|
375
|
+
};
|
|
376
|
+
}
|
|
294
377
|
export default run;
|
package/dist/semaphore.js
CHANGED
|
@@ -40,7 +40,7 @@ export class Semaphore {
|
|
|
40
40
|
return unresolved;
|
|
41
41
|
}
|
|
42
42
|
processQueue() {
|
|
43
|
-
|
|
43
|
+
while (this.waiting.length > 0 && this.counter < this.maxCount) {
|
|
44
44
|
this.counter++;
|
|
45
45
|
const waiter = this.waiting.shift();
|
|
46
46
|
if (waiter) {
|
package/dist/types/run.d.ts
CHANGED
|
@@ -3,21 +3,21 @@ export type Success<T> = {
|
|
|
3
3
|
data: T;
|
|
4
4
|
error: null;
|
|
5
5
|
};
|
|
6
|
-
export type Failure<E =
|
|
6
|
+
export type Failure<E = unknown> = {
|
|
7
7
|
success: false;
|
|
8
8
|
data: null;
|
|
9
9
|
error: E;
|
|
10
10
|
};
|
|
11
|
-
export type Result<T, E =
|
|
11
|
+
export type Result<T, E = unknown> = Success<T> | Failure<E>;
|
|
12
12
|
export type GenericFnResult = number | boolean | string | object | null | undefined | symbol | bigint | void | Promise<number | boolean | string | object | null | undefined | symbol | bigint | void> | Array<number | boolean | string | object | null | undefined | symbol | bigint | void>;
|
|
13
13
|
export type DeferFn = (fn: () => GenericFnResult) => void;
|
|
14
14
|
export type DeferredFunction = () => GenericFnResult;
|
|
15
15
|
export type DeferredFunctions = Array<DeferredFunction>;
|
|
16
16
|
export type Options = {
|
|
17
17
|
throw?: boolean;
|
|
18
|
-
onError?: (err:
|
|
18
|
+
onError?: (err: unknown) => void;
|
|
19
19
|
};
|
|
20
|
-
export declare function run<TResult, E =
|
|
20
|
+
export declare function run<TResult, E = unknown>(fn: (deferFn: DeferFn) => Promise<TResult> | TResult, options?: Options): Promise<Result<TResult, E>>;
|
|
21
21
|
export type AbortableFn = (abortableFn: () => GenericFnResult, opts?: {
|
|
22
22
|
signal?: AbortSignal;
|
|
23
23
|
}) => GenericFnResult;
|
|
@@ -25,7 +25,7 @@ export declare class AbortError extends Error {
|
|
|
25
25
|
constructor(message?: string);
|
|
26
26
|
}
|
|
27
27
|
export declare function abortSignalReason(signal: AbortSignal): string | undefined;
|
|
28
|
-
export declare function runAbortable<TResult, E =
|
|
28
|
+
export declare function runAbortable<TResult, E = unknown>(fn: ({ abortable, defer, signal, controller }: {
|
|
29
29
|
abortable: AbortableFn;
|
|
30
30
|
defer: DeferFn;
|
|
31
31
|
signal: AbortSignal;
|
|
@@ -34,12 +34,12 @@ export declare function runAbortable<TResult, E = Error>(fn: ({ abortable, defer
|
|
|
34
34
|
controller?: AbortController;
|
|
35
35
|
signal?: AbortSignal;
|
|
36
36
|
}): Promise<Result<TResult, E>>;
|
|
37
|
-
export declare function runEffect<TResult, E =
|
|
37
|
+
export declare function runEffect<TResult, E = unknown>(fn: (deferFn: DeferFn) => TResult, options?: Options & {
|
|
38
38
|
automaticCleanup?: boolean;
|
|
39
39
|
}): Result<TResult, E> & {
|
|
40
40
|
cleanup: () => void;
|
|
41
41
|
};
|
|
42
|
-
export declare function runRetry<TResult, E =
|
|
42
|
+
export declare function runRetry<TResult, E = unknown>(fn: (deferFn: DeferFn, attempt: number) => Promise<TResult> | TResult, options?: Options & {
|
|
43
43
|
maxAttempts?: number;
|
|
44
44
|
delayMs?: number;
|
|
45
45
|
backoff?: "linear" | "exponential";
|
|
@@ -49,6 +49,16 @@ export declare function runRetry<TResult, E = Error>(fn: (deferFn: DeferFn, atte
|
|
|
49
49
|
export declare class TimeoutError extends Error {
|
|
50
50
|
constructor(message?: string);
|
|
51
51
|
}
|
|
52
|
-
export declare function runTimeout<TResult, E =
|
|
53
|
-
export declare function runDebounced<TResult, TArgs extends unknown[]>(fn: (defer: DeferFn, ...args: TArgs) => Promise<TResult> | TResult, delayMs: number, options?: Options): (...args: TArgs) => Promise<Result<TResult,
|
|
52
|
+
export declare function runTimeout<TResult, E = unknown>(fn: (deferFn: DeferFn) => Promise<TResult> | TResult, timeoutMs: number, options?: Options): Promise<Result<TResult, E>>;
|
|
53
|
+
export declare function runDebounced<TResult, TArgs extends unknown[]>(fn: (defer: DeferFn, ...args: TArgs) => Promise<TResult> | TResult, delayMs: number, options?: Options): (...args: TArgs) => Promise<Result<TResult, unknown>>;
|
|
54
|
+
export type StepFn<T> = (defer: DeferFn, signal: AbortSignal) => Promise<T> | T;
|
|
55
|
+
export type StepHandle<T> = {
|
|
56
|
+
then: Promise<T>["then"];
|
|
57
|
+
catch: Promise<T>["catch"];
|
|
58
|
+
finally: Promise<T>["finally"];
|
|
59
|
+
};
|
|
60
|
+
export declare function createAbortablePipeline(signal?: AbortSignal): {
|
|
61
|
+
step: <T>(fn: StepFn<T>) => StepHandle<T>;
|
|
62
|
+
signal: AbortSignal;
|
|
63
|
+
};
|
|
54
64
|
export default run;
|