@ls-stack/utils 3.7.0 → 3.9.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/arrayUtils.cjs +22 -2
- package/lib/arrayUtils.d.cts +2 -1
- package/lib/arrayUtils.d.ts +2 -1
- package/lib/arrayUtils.js +6 -3
- package/lib/asyncQueue.cjs +239 -0
- package/lib/asyncQueue.d.cts +56 -0
- package/lib/asyncQueue.d.ts +56 -0
- package/lib/asyncQueue.js +201 -0
- package/lib/cache.js +1 -1
- package/lib/chunk-DFXNVEH6.js +14 -0
- package/lib/{chunk-XMUFRC2U.js → chunk-UTFE4P3P.js} +17 -1
- package/lib/concurrentCalls.cjs +311 -0
- package/lib/concurrentCalls.d.cts +75 -0
- package/lib/concurrentCalls.d.ts +75 -0
- package/lib/concurrentCalls.js +257 -0
- package/lib/createThrottleController.js +1 -1
- package/lib/parallelAsyncCalls.d.cts +2 -0
- package/lib/parallelAsyncCalls.d.ts +2 -0
- package/lib/promiseUtils.js +3 -10
- package/lib/testUtils.cjs +5 -5
- package/lib/testUtils.js +4 -4
- package/lib/yamlStringify.js +3 -3
- package/package.json +11 -2
package/lib/arrayUtils.cjs
CHANGED
|
@@ -29,9 +29,17 @@ __export(arrayUtils_exports, {
|
|
|
29
29
|
isInArray: () => isInArray,
|
|
30
30
|
rejectArrayUndefinedValues: () => rejectArrayUndefinedValues,
|
|
31
31
|
rejectDuplicates: () => rejectDuplicates,
|
|
32
|
-
sortBy: () => sortBy
|
|
32
|
+
sortBy: () => sortBy,
|
|
33
|
+
truncateArray: () => truncateArray
|
|
33
34
|
});
|
|
34
35
|
module.exports = __toCommonJS(arrayUtils_exports);
|
|
36
|
+
|
|
37
|
+
// src/assertions.ts
|
|
38
|
+
function isFunction(value) {
|
|
39
|
+
return typeof value === "function";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/arrayUtils.ts
|
|
35
43
|
function filterAndMap(array, mapFilter) {
|
|
36
44
|
const result = [];
|
|
37
45
|
let i = -1;
|
|
@@ -133,6 +141,17 @@ function rejectDuplicates(array, getKey = (item) => item) {
|
|
|
133
141
|
}
|
|
134
142
|
return result;
|
|
135
143
|
}
|
|
144
|
+
function truncateArray(array, maxLength, appendIfTruncated) {
|
|
145
|
+
const truncate = array.length > maxLength;
|
|
146
|
+
const result = truncate ? [...array.slice(0, maxLength)] : array;
|
|
147
|
+
if (truncate && appendIfTruncated) {
|
|
148
|
+
if (isFunction(appendIfTruncated)) {
|
|
149
|
+
return [...result, appendIfTruncated(array.length - maxLength)];
|
|
150
|
+
}
|
|
151
|
+
return [...result, appendIfTruncated];
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
136
155
|
// Annotate the CommonJS export names for ESM import in node:
|
|
137
156
|
0 && (module.exports = {
|
|
138
157
|
arrayWithPrev,
|
|
@@ -144,5 +163,6 @@ function rejectDuplicates(array, getKey = (item) => item) {
|
|
|
144
163
|
isInArray,
|
|
145
164
|
rejectArrayUndefinedValues,
|
|
146
165
|
rejectDuplicates,
|
|
147
|
-
sortBy
|
|
166
|
+
sortBy,
|
|
167
|
+
truncateArray
|
|
148
168
|
});
|
package/lib/arrayUtils.d.cts
CHANGED
|
@@ -52,5 +52,6 @@ declare function findBeforeIndex<T>(array: T[], index: number, predicate: (item:
|
|
|
52
52
|
declare function rejectArrayUndefinedValues<T extends unknown[]>(array: T): T;
|
|
53
53
|
declare function hasDuplicates<T>(array: T[], getKey?: (item: T) => unknown): boolean;
|
|
54
54
|
declare function rejectDuplicates<T>(array: T[], getKey?: (item: T) => unknown): T[];
|
|
55
|
+
declare function truncateArray<T>(array: T[], maxLength: number, appendIfTruncated?: T | ((truncatedCount: number) => T)): T[];
|
|
55
56
|
|
|
56
|
-
export { type FilterAndMapReturn, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findBeforeIndex, hasDuplicates, isInArray, rejectArrayUndefinedValues, rejectDuplicates, sortBy };
|
|
57
|
+
export { type FilterAndMapReturn, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findBeforeIndex, hasDuplicates, isInArray, rejectArrayUndefinedValues, rejectDuplicates, sortBy, truncateArray };
|
package/lib/arrayUtils.d.ts
CHANGED
|
@@ -52,5 +52,6 @@ declare function findBeforeIndex<T>(array: T[], index: number, predicate: (item:
|
|
|
52
52
|
declare function rejectArrayUndefinedValues<T extends unknown[]>(array: T): T;
|
|
53
53
|
declare function hasDuplicates<T>(array: T[], getKey?: (item: T) => unknown): boolean;
|
|
54
54
|
declare function rejectDuplicates<T>(array: T[], getKey?: (item: T) => unknown): T[];
|
|
55
|
+
declare function truncateArray<T>(array: T[], maxLength: number, appendIfTruncated?: T | ((truncatedCount: number) => T)): T[];
|
|
55
56
|
|
|
56
|
-
export { type FilterAndMapReturn, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findBeforeIndex, hasDuplicates, isInArray, rejectArrayUndefinedValues, rejectDuplicates, sortBy };
|
|
57
|
+
export { type FilterAndMapReturn, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findBeforeIndex, hasDuplicates, isInArray, rejectArrayUndefinedValues, rejectDuplicates, sortBy, truncateArray };
|
package/lib/arrayUtils.js
CHANGED
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
isInArray,
|
|
9
9
|
rejectArrayUndefinedValues,
|
|
10
10
|
rejectDuplicates,
|
|
11
|
-
sortBy
|
|
12
|
-
|
|
11
|
+
sortBy,
|
|
12
|
+
truncateArray
|
|
13
|
+
} from "./chunk-UTFE4P3P.js";
|
|
14
|
+
import "./chunk-3XCS7FVO.js";
|
|
13
15
|
export {
|
|
14
16
|
arrayWithPrev,
|
|
15
17
|
arrayWithPrevAndIndex,
|
|
@@ -20,5 +22,6 @@ export {
|
|
|
20
22
|
isInArray,
|
|
21
23
|
rejectArrayUndefinedValues,
|
|
22
24
|
rejectDuplicates,
|
|
23
|
-
sortBy
|
|
25
|
+
sortBy,
|
|
26
|
+
truncateArray
|
|
24
27
|
};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/asyncQueue.ts
|
|
21
|
+
var asyncQueue_exports = {};
|
|
22
|
+
__export(asyncQueue_exports, {
|
|
23
|
+
createAsyncQueue: () => createAsyncQueue,
|
|
24
|
+
createAsyncQueueWithId: () => createAsyncQueueWithId
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(asyncQueue_exports);
|
|
27
|
+
var import_evtmitter = require("evtmitter");
|
|
28
|
+
var import_t_result = require("t-result");
|
|
29
|
+
|
|
30
|
+
// src/assertions.ts
|
|
31
|
+
function isObject(value) {
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function isFunction(value) {
|
|
35
|
+
return typeof value === "function";
|
|
36
|
+
}
|
|
37
|
+
function isPromise(value) {
|
|
38
|
+
return isObject(value) && "then" in value && isFunction(value.then);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/promiseUtils.ts
|
|
42
|
+
function defer() {
|
|
43
|
+
let resolve;
|
|
44
|
+
let reject;
|
|
45
|
+
const promise = new Promise((_resolve, _reject) => {
|
|
46
|
+
resolve = _resolve;
|
|
47
|
+
reject = _reject;
|
|
48
|
+
});
|
|
49
|
+
return { resolve, reject, promise };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/asyncQueue.ts
|
|
53
|
+
var AsyncQueue = class {
|
|
54
|
+
#queue = [];
|
|
55
|
+
#pending = 0;
|
|
56
|
+
#size = 0;
|
|
57
|
+
#concurrency;
|
|
58
|
+
#completed = 0;
|
|
59
|
+
#failed = 0;
|
|
60
|
+
#idleResolvers = [];
|
|
61
|
+
events = (0, import_evtmitter.evtmitter)();
|
|
62
|
+
#signal;
|
|
63
|
+
#taskTimeout;
|
|
64
|
+
constructor({
|
|
65
|
+
concurrency = 1,
|
|
66
|
+
signal,
|
|
67
|
+
timeout: taskTimeout
|
|
68
|
+
} = {}) {
|
|
69
|
+
this.#concurrency = concurrency;
|
|
70
|
+
this.#signal = signal;
|
|
71
|
+
this.#taskTimeout = taskTimeout;
|
|
72
|
+
}
|
|
73
|
+
#enqueue(task) {
|
|
74
|
+
this.#queue.push(task);
|
|
75
|
+
this.#size++;
|
|
76
|
+
}
|
|
77
|
+
add(fn, options) {
|
|
78
|
+
const deferred = defer();
|
|
79
|
+
const taskTimeout = this.#taskTimeout ?? options?.timeout;
|
|
80
|
+
const task = {
|
|
81
|
+
run: async (ctx) => {
|
|
82
|
+
if (isPromise(fn)) {
|
|
83
|
+
return fn;
|
|
84
|
+
}
|
|
85
|
+
return await fn(ctx);
|
|
86
|
+
},
|
|
87
|
+
resolve: deferred.resolve,
|
|
88
|
+
reject: deferred.reject,
|
|
89
|
+
signal: options?.signal,
|
|
90
|
+
id: options?.id,
|
|
91
|
+
timeout: taskTimeout
|
|
92
|
+
};
|
|
93
|
+
this.#enqueue(task);
|
|
94
|
+
this.#processQueue();
|
|
95
|
+
return deferred.promise;
|
|
96
|
+
}
|
|
97
|
+
resultifyAdd(fn, options) {
|
|
98
|
+
const cb = async (ctx) => {
|
|
99
|
+
if (isPromise(fn)) {
|
|
100
|
+
return await fn;
|
|
101
|
+
}
|
|
102
|
+
return fn(ctx);
|
|
103
|
+
};
|
|
104
|
+
return this.add((ctx) => (0, import_t_result.resultify)(cb(ctx)), options);
|
|
105
|
+
}
|
|
106
|
+
async #processQueue() {
|
|
107
|
+
if (this.#pending >= this.#concurrency || this.#queue.length === 0) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const task = this.#queue.shift();
|
|
111
|
+
if (!task) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.#pending++;
|
|
115
|
+
this.#size--;
|
|
116
|
+
const signals = [];
|
|
117
|
+
if (task.signal) {
|
|
118
|
+
signals.push(task.signal);
|
|
119
|
+
}
|
|
120
|
+
if (this.#signal) {
|
|
121
|
+
signals.push(this.#signal);
|
|
122
|
+
}
|
|
123
|
+
if (task.timeout) {
|
|
124
|
+
signals.push(AbortSignal.timeout(task.timeout));
|
|
125
|
+
}
|
|
126
|
+
const signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
|
|
127
|
+
let abortListener;
|
|
128
|
+
const signalAbortPromise = new Promise((_, reject) => {
|
|
129
|
+
if (signal) {
|
|
130
|
+
const error = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
131
|
+
if (signal.aborted) {
|
|
132
|
+
reject(error);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
abortListener = () => {
|
|
136
|
+
reject(error);
|
|
137
|
+
};
|
|
138
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
try {
|
|
142
|
+
const taskRunPromise = task.run({ signal, id: task.id });
|
|
143
|
+
this.events.emit("start", { id: task.id });
|
|
144
|
+
const result = await Promise.race([taskRunPromise, signalAbortPromise]);
|
|
145
|
+
if ((0, import_t_result.isResult)(result)) {
|
|
146
|
+
task.resolve(result);
|
|
147
|
+
if (result.error) {
|
|
148
|
+
this.#failed++;
|
|
149
|
+
this.events.emit("error", { id: task.id, error: result.error });
|
|
150
|
+
} else {
|
|
151
|
+
this.#completed++;
|
|
152
|
+
this.events.emit("complete", { id: task.id, value: result.value });
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
const error = new Error("Response not a Result");
|
|
156
|
+
task.resolve(import_t_result.Result.err(error));
|
|
157
|
+
this.#failed++;
|
|
158
|
+
this.events.emit("error", {
|
|
159
|
+
id: task.id,
|
|
160
|
+
error: (0, import_t_result.unknownToError)(error)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
task.resolve(import_t_result.Result.err(error));
|
|
165
|
+
this.#failed++;
|
|
166
|
+
this.events.emit("error", { id: task.id, error: (0, import_t_result.unknownToError)(error) });
|
|
167
|
+
} finally {
|
|
168
|
+
if (signal && abortListener) {
|
|
169
|
+
signal.removeEventListener("abort", abortListener);
|
|
170
|
+
}
|
|
171
|
+
this.#pending--;
|
|
172
|
+
this.#processQueue();
|
|
173
|
+
if (this.#pending === 0 && this.#size === 0) {
|
|
174
|
+
this.#resolveIdleWaiters();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
#resolveIdleWaiters() {
|
|
179
|
+
while (this.#idleResolvers.length > 0) {
|
|
180
|
+
const resolve = this.#idleResolvers.shift();
|
|
181
|
+
if (resolve) {
|
|
182
|
+
resolve();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async onIdle() {
|
|
187
|
+
if (this.#pending === 0 && this.#size === 0) {
|
|
188
|
+
return Promise.resolve();
|
|
189
|
+
}
|
|
190
|
+
return new Promise((resolve) => {
|
|
191
|
+
this.#idleResolvers.push(resolve);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
clear({ resetCounters = true } = {}) {
|
|
195
|
+
this.#queue = [];
|
|
196
|
+
this.#size = 0;
|
|
197
|
+
if (resetCounters) {
|
|
198
|
+
this.#completed = 0;
|
|
199
|
+
this.#failed = 0;
|
|
200
|
+
}
|
|
201
|
+
if (this.#pending === 0) {
|
|
202
|
+
this.#resolveIdleWaiters();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
get completed() {
|
|
206
|
+
return this.#completed;
|
|
207
|
+
}
|
|
208
|
+
get failed() {
|
|
209
|
+
return this.#failed;
|
|
210
|
+
}
|
|
211
|
+
get pending() {
|
|
212
|
+
return this.#pending;
|
|
213
|
+
}
|
|
214
|
+
get size() {
|
|
215
|
+
return this.#size;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var AsyncQueueWithId = class extends AsyncQueue {
|
|
219
|
+
constructor(options) {
|
|
220
|
+
super(options);
|
|
221
|
+
}
|
|
222
|
+
add(fn, options) {
|
|
223
|
+
return super.add(fn, options);
|
|
224
|
+
}
|
|
225
|
+
resultifyAdd(fn, options) {
|
|
226
|
+
return super.resultifyAdd(fn, options);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
function createAsyncQueue(options) {
|
|
230
|
+
return new AsyncQueue(options);
|
|
231
|
+
}
|
|
232
|
+
function createAsyncQueueWithId(options) {
|
|
233
|
+
return new AsyncQueueWithId(options);
|
|
234
|
+
}
|
|
235
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
236
|
+
0 && (module.exports = {
|
|
237
|
+
createAsyncQueue,
|
|
238
|
+
createAsyncQueueWithId
|
|
239
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as evtmitter from 'evtmitter';
|
|
2
|
+
import { ResultValidErrors, Result } from 't-result';
|
|
3
|
+
|
|
4
|
+
type AsyncQueueOptions = {
|
|
5
|
+
concurrency?: number;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
};
|
|
9
|
+
type AddOptions<I> = {
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
id?: I;
|
|
13
|
+
};
|
|
14
|
+
type RunCtx<I> = {
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
id?: I;
|
|
17
|
+
};
|
|
18
|
+
declare class AsyncQueue<T, E extends ResultValidErrors = Error, I = undefined> {
|
|
19
|
+
#private;
|
|
20
|
+
events: evtmitter.Emitter<{
|
|
21
|
+
error: {
|
|
22
|
+
id: I;
|
|
23
|
+
error: E | Error;
|
|
24
|
+
};
|
|
25
|
+
complete: {
|
|
26
|
+
id: I;
|
|
27
|
+
value: T;
|
|
28
|
+
};
|
|
29
|
+
start: {
|
|
30
|
+
id: I;
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
33
|
+
constructor({ concurrency, signal, timeout: taskTimeout, }?: AsyncQueueOptions);
|
|
34
|
+
add(fn: ((ctx: RunCtx<I>) => Promise<Result<T, E>> | Result<T, E>) | Promise<Result<T, E>>, options?: AddOptions<I>): Promise<Result<T, E | Error>>;
|
|
35
|
+
resultifyAdd(fn: ((ctx: RunCtx<I>) => Promise<T> | T) | Promise<T>, options?: AddOptions<I>): Promise<Result<T, E | Error>>;
|
|
36
|
+
onIdle(): Promise<void>;
|
|
37
|
+
clear({ resetCounters }?: {
|
|
38
|
+
resetCounters?: boolean;
|
|
39
|
+
}): void;
|
|
40
|
+
get completed(): number;
|
|
41
|
+
get failed(): number;
|
|
42
|
+
get pending(): number;
|
|
43
|
+
get size(): number;
|
|
44
|
+
}
|
|
45
|
+
type AddOptionsWithId<I> = Omit<AddOptions<I>, 'id'> & {
|
|
46
|
+
id: I;
|
|
47
|
+
};
|
|
48
|
+
declare class AsyncQueueWithId<T, I, E extends ResultValidErrors = Error> extends AsyncQueue<T, E, I> {
|
|
49
|
+
constructor(options?: AsyncQueueOptions);
|
|
50
|
+
add(fn: ((ctx: RunCtx<I>) => Promise<Result<T, E>> | Result<T, E>) | Promise<Result<T, E>>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
51
|
+
resultifyAdd(fn: ((ctx: RunCtx<I>) => Promise<T> | T) | Promise<T>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
52
|
+
}
|
|
53
|
+
declare function createAsyncQueue<T, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueue<T, E, undefined>;
|
|
54
|
+
declare function createAsyncQueueWithId<T, I, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueueWithId<T, I, E>;
|
|
55
|
+
|
|
56
|
+
export { createAsyncQueue, createAsyncQueueWithId };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as evtmitter from 'evtmitter';
|
|
2
|
+
import { ResultValidErrors, Result } from 't-result';
|
|
3
|
+
|
|
4
|
+
type AsyncQueueOptions = {
|
|
5
|
+
concurrency?: number;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
};
|
|
9
|
+
type AddOptions<I> = {
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
id?: I;
|
|
13
|
+
};
|
|
14
|
+
type RunCtx<I> = {
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
id?: I;
|
|
17
|
+
};
|
|
18
|
+
declare class AsyncQueue<T, E extends ResultValidErrors = Error, I = undefined> {
|
|
19
|
+
#private;
|
|
20
|
+
events: evtmitter.Emitter<{
|
|
21
|
+
error: {
|
|
22
|
+
id: I;
|
|
23
|
+
error: E | Error;
|
|
24
|
+
};
|
|
25
|
+
complete: {
|
|
26
|
+
id: I;
|
|
27
|
+
value: T;
|
|
28
|
+
};
|
|
29
|
+
start: {
|
|
30
|
+
id: I;
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
33
|
+
constructor({ concurrency, signal, timeout: taskTimeout, }?: AsyncQueueOptions);
|
|
34
|
+
add(fn: ((ctx: RunCtx<I>) => Promise<Result<T, E>> | Result<T, E>) | Promise<Result<T, E>>, options?: AddOptions<I>): Promise<Result<T, E | Error>>;
|
|
35
|
+
resultifyAdd(fn: ((ctx: RunCtx<I>) => Promise<T> | T) | Promise<T>, options?: AddOptions<I>): Promise<Result<T, E | Error>>;
|
|
36
|
+
onIdle(): Promise<void>;
|
|
37
|
+
clear({ resetCounters }?: {
|
|
38
|
+
resetCounters?: boolean;
|
|
39
|
+
}): void;
|
|
40
|
+
get completed(): number;
|
|
41
|
+
get failed(): number;
|
|
42
|
+
get pending(): number;
|
|
43
|
+
get size(): number;
|
|
44
|
+
}
|
|
45
|
+
type AddOptionsWithId<I> = Omit<AddOptions<I>, 'id'> & {
|
|
46
|
+
id: I;
|
|
47
|
+
};
|
|
48
|
+
declare class AsyncQueueWithId<T, I, E extends ResultValidErrors = Error> extends AsyncQueue<T, E, I> {
|
|
49
|
+
constructor(options?: AsyncQueueOptions);
|
|
50
|
+
add(fn: ((ctx: RunCtx<I>) => Promise<Result<T, E>> | Result<T, E>) | Promise<Result<T, E>>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
51
|
+
resultifyAdd(fn: ((ctx: RunCtx<I>) => Promise<T> | T) | Promise<T>, options?: AddOptionsWithId<I>): Promise<Result<T, E | Error>>;
|
|
52
|
+
}
|
|
53
|
+
declare function createAsyncQueue<T, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueue<T, E, undefined>;
|
|
54
|
+
declare function createAsyncQueueWithId<T, I, E extends ResultValidErrors = Error>(options?: AsyncQueueOptions): AsyncQueueWithId<T, I, E>;
|
|
55
|
+
|
|
56
|
+
export { createAsyncQueue, createAsyncQueueWithId };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defer
|
|
3
|
+
} from "./chunk-DFXNVEH6.js";
|
|
4
|
+
import {
|
|
5
|
+
isPromise
|
|
6
|
+
} from "./chunk-3XCS7FVO.js";
|
|
7
|
+
|
|
8
|
+
// src/asyncQueue.ts
|
|
9
|
+
import { evtmitter } from "evtmitter";
|
|
10
|
+
import {
|
|
11
|
+
isResult,
|
|
12
|
+
Result,
|
|
13
|
+
resultify,
|
|
14
|
+
unknownToError
|
|
15
|
+
} from "t-result";
|
|
16
|
+
var AsyncQueue = class {
|
|
17
|
+
#queue = [];
|
|
18
|
+
#pending = 0;
|
|
19
|
+
#size = 0;
|
|
20
|
+
#concurrency;
|
|
21
|
+
#completed = 0;
|
|
22
|
+
#failed = 0;
|
|
23
|
+
#idleResolvers = [];
|
|
24
|
+
events = evtmitter();
|
|
25
|
+
#signal;
|
|
26
|
+
#taskTimeout;
|
|
27
|
+
constructor({
|
|
28
|
+
concurrency = 1,
|
|
29
|
+
signal,
|
|
30
|
+
timeout: taskTimeout
|
|
31
|
+
} = {}) {
|
|
32
|
+
this.#concurrency = concurrency;
|
|
33
|
+
this.#signal = signal;
|
|
34
|
+
this.#taskTimeout = taskTimeout;
|
|
35
|
+
}
|
|
36
|
+
#enqueue(task) {
|
|
37
|
+
this.#queue.push(task);
|
|
38
|
+
this.#size++;
|
|
39
|
+
}
|
|
40
|
+
add(fn, options) {
|
|
41
|
+
const deferred = defer();
|
|
42
|
+
const taskTimeout = this.#taskTimeout ?? options?.timeout;
|
|
43
|
+
const task = {
|
|
44
|
+
run: async (ctx) => {
|
|
45
|
+
if (isPromise(fn)) {
|
|
46
|
+
return fn;
|
|
47
|
+
}
|
|
48
|
+
return await fn(ctx);
|
|
49
|
+
},
|
|
50
|
+
resolve: deferred.resolve,
|
|
51
|
+
reject: deferred.reject,
|
|
52
|
+
signal: options?.signal,
|
|
53
|
+
id: options?.id,
|
|
54
|
+
timeout: taskTimeout
|
|
55
|
+
};
|
|
56
|
+
this.#enqueue(task);
|
|
57
|
+
this.#processQueue();
|
|
58
|
+
return deferred.promise;
|
|
59
|
+
}
|
|
60
|
+
resultifyAdd(fn, options) {
|
|
61
|
+
const cb = async (ctx) => {
|
|
62
|
+
if (isPromise(fn)) {
|
|
63
|
+
return await fn;
|
|
64
|
+
}
|
|
65
|
+
return fn(ctx);
|
|
66
|
+
};
|
|
67
|
+
return this.add((ctx) => resultify(cb(ctx)), options);
|
|
68
|
+
}
|
|
69
|
+
async #processQueue() {
|
|
70
|
+
if (this.#pending >= this.#concurrency || this.#queue.length === 0) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const task = this.#queue.shift();
|
|
74
|
+
if (!task) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.#pending++;
|
|
78
|
+
this.#size--;
|
|
79
|
+
const signals = [];
|
|
80
|
+
if (task.signal) {
|
|
81
|
+
signals.push(task.signal);
|
|
82
|
+
}
|
|
83
|
+
if (this.#signal) {
|
|
84
|
+
signals.push(this.#signal);
|
|
85
|
+
}
|
|
86
|
+
if (task.timeout) {
|
|
87
|
+
signals.push(AbortSignal.timeout(task.timeout));
|
|
88
|
+
}
|
|
89
|
+
const signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
|
|
90
|
+
let abortListener;
|
|
91
|
+
const signalAbortPromise = new Promise((_, reject) => {
|
|
92
|
+
if (signal) {
|
|
93
|
+
const error = signal.reason instanceof Error ? signal.reason : new DOMException("Aborted", "AbortError");
|
|
94
|
+
if (signal.aborted) {
|
|
95
|
+
reject(error);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
abortListener = () => {
|
|
99
|
+
reject(error);
|
|
100
|
+
};
|
|
101
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
const taskRunPromise = task.run({ signal, id: task.id });
|
|
106
|
+
this.events.emit("start", { id: task.id });
|
|
107
|
+
const result = await Promise.race([taskRunPromise, signalAbortPromise]);
|
|
108
|
+
if (isResult(result)) {
|
|
109
|
+
task.resolve(result);
|
|
110
|
+
if (result.error) {
|
|
111
|
+
this.#failed++;
|
|
112
|
+
this.events.emit("error", { id: task.id, error: result.error });
|
|
113
|
+
} else {
|
|
114
|
+
this.#completed++;
|
|
115
|
+
this.events.emit("complete", { id: task.id, value: result.value });
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const error = new Error("Response not a Result");
|
|
119
|
+
task.resolve(Result.err(error));
|
|
120
|
+
this.#failed++;
|
|
121
|
+
this.events.emit("error", {
|
|
122
|
+
id: task.id,
|
|
123
|
+
error: unknownToError(error)
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
task.resolve(Result.err(error));
|
|
128
|
+
this.#failed++;
|
|
129
|
+
this.events.emit("error", { id: task.id, error: unknownToError(error) });
|
|
130
|
+
} finally {
|
|
131
|
+
if (signal && abortListener) {
|
|
132
|
+
signal.removeEventListener("abort", abortListener);
|
|
133
|
+
}
|
|
134
|
+
this.#pending--;
|
|
135
|
+
this.#processQueue();
|
|
136
|
+
if (this.#pending === 0 && this.#size === 0) {
|
|
137
|
+
this.#resolveIdleWaiters();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
#resolveIdleWaiters() {
|
|
142
|
+
while (this.#idleResolvers.length > 0) {
|
|
143
|
+
const resolve = this.#idleResolvers.shift();
|
|
144
|
+
if (resolve) {
|
|
145
|
+
resolve();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async onIdle() {
|
|
150
|
+
if (this.#pending === 0 && this.#size === 0) {
|
|
151
|
+
return Promise.resolve();
|
|
152
|
+
}
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
this.#idleResolvers.push(resolve);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
clear({ resetCounters = true } = {}) {
|
|
158
|
+
this.#queue = [];
|
|
159
|
+
this.#size = 0;
|
|
160
|
+
if (resetCounters) {
|
|
161
|
+
this.#completed = 0;
|
|
162
|
+
this.#failed = 0;
|
|
163
|
+
}
|
|
164
|
+
if (this.#pending === 0) {
|
|
165
|
+
this.#resolveIdleWaiters();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
get completed() {
|
|
169
|
+
return this.#completed;
|
|
170
|
+
}
|
|
171
|
+
get failed() {
|
|
172
|
+
return this.#failed;
|
|
173
|
+
}
|
|
174
|
+
get pending() {
|
|
175
|
+
return this.#pending;
|
|
176
|
+
}
|
|
177
|
+
get size() {
|
|
178
|
+
return this.#size;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
var AsyncQueueWithId = class extends AsyncQueue {
|
|
182
|
+
constructor(options) {
|
|
183
|
+
super(options);
|
|
184
|
+
}
|
|
185
|
+
add(fn, options) {
|
|
186
|
+
return super.add(fn, options);
|
|
187
|
+
}
|
|
188
|
+
resultifyAdd(fn, options) {
|
|
189
|
+
return super.resultifyAdd(fn, options);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
function createAsyncQueue(options) {
|
|
193
|
+
return new AsyncQueue(options);
|
|
194
|
+
}
|
|
195
|
+
function createAsyncQueueWithId(options) {
|
|
196
|
+
return new AsyncQueueWithId(options);
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
createAsyncQueue,
|
|
200
|
+
createAsyncQueueWithId
|
|
201
|
+
};
|
package/lib/cache.js
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
durationObjToMs
|
|
3
3
|
} from "./chunk-5MNYPLZI.js";
|
|
4
4
|
import "./chunk-HTCYUMDR.js";
|
|
5
|
+
import "./chunk-II4R3VVX.js";
|
|
5
6
|
import {
|
|
6
7
|
isPromise
|
|
7
8
|
} from "./chunk-3XCS7FVO.js";
|
|
8
|
-
import "./chunk-II4R3VVX.js";
|
|
9
9
|
|
|
10
10
|
// src/cache.ts
|
|
11
11
|
function cachedGetter(getter) {
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isFunction
|
|
3
|
+
} from "./chunk-3XCS7FVO.js";
|
|
4
|
+
|
|
1
5
|
// src/arrayUtils.ts
|
|
2
6
|
function filterAndMap(array, mapFilter) {
|
|
3
7
|
const result = [];
|
|
@@ -100,6 +104,17 @@ function rejectDuplicates(array, getKey = (item) => item) {
|
|
|
100
104
|
}
|
|
101
105
|
return result;
|
|
102
106
|
}
|
|
107
|
+
function truncateArray(array, maxLength, appendIfTruncated) {
|
|
108
|
+
const truncate = array.length > maxLength;
|
|
109
|
+
const result = truncate ? [...array.slice(0, maxLength)] : array;
|
|
110
|
+
if (truncate && appendIfTruncated) {
|
|
111
|
+
if (isFunction(appendIfTruncated)) {
|
|
112
|
+
return [...result, appendIfTruncated(array.length - maxLength)];
|
|
113
|
+
}
|
|
114
|
+
return [...result, appendIfTruncated];
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
103
118
|
|
|
104
119
|
export {
|
|
105
120
|
filterAndMap,
|
|
@@ -111,5 +126,6 @@ export {
|
|
|
111
126
|
findBeforeIndex,
|
|
112
127
|
rejectArrayUndefinedValues,
|
|
113
128
|
hasDuplicates,
|
|
114
|
-
rejectDuplicates
|
|
129
|
+
rejectDuplicates,
|
|
130
|
+
truncateArray
|
|
115
131
|
};
|