@agoric/internal 0.3.3-dev-a0be2b3.0.a0be2b3 → 0.3.3-dev-6ebd99f.0.6ebd99f
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/README.md +1 -4
- package/package.json +4 -4
- package/src/index.js +8 -0
- package/src/js-utils.d.ts +1 -0
- package/src/js-utils.d.ts.map +1 -1
- package/src/js-utils.js +19 -0
- package/src/ses-utils.d.ts +6 -0
- package/src/ses-utils.d.ts.map +1 -1
- package/src/ses-utils.js +84 -1
- package/src/work-pool.d.ts +13 -0
- package/src/work-pool.d.ts.map +1 -0
- package/src/work-pool.js +233 -0
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ This package contains code that is required by agoric-sdk and not meant to be im
|
|
|
7
7
|
Like all `@agoric` packages it follows Semantic Versioning. Unlike the others, it will never have a stable API. In terms of [SemVer spec item 4](https://semver.org/#spec-item-4), it will never reach 1.0:
|
|
8
8
|
> Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
|
|
9
9
|
|
|
10
|
+
To keep down the size of [@endo/bundle-source](https://github.com/endojs/endo/tree/master/packages/bundle-source) bundles of source that imports from this package, modules that depend upon it should use deep imports (e.g., `import { defineName } from '@agoric/internal/src/js-utils.js';`) rather than importing the entire module.
|
|
10
11
|
|
|
11
12
|
# Design
|
|
12
13
|
|
|
@@ -19,7 +20,3 @@ It is meant to be a home for modules that have no dependencies on other packages
|
|
|
19
20
|
This package may not take dependencies on any others in this repository.
|
|
20
21
|
|
|
21
22
|
It must never export ambient types.
|
|
22
|
-
|
|
23
|
-
It should not be imported by deep imports. Eventually this will be enforced by [`exports`](https://nodejs.org/api/packages.html#exports) but the tooling isn't ready:
|
|
24
|
-
- https://github.com/import-js/eslint-plugin-import/issues/1810
|
|
25
|
-
- https://github.com/microsoft/TypeScript/issues/33079 (or some related problem with JSdoc types)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/internal",
|
|
3
|
-
"version": "0.3.3-dev-
|
|
3
|
+
"version": "0.3.3-dev-6ebd99f.0.6ebd99f",
|
|
4
4
|
"description": "Externally unsupported utilities internal to agoric-sdk",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"lint:types": "yarn run -T tsc"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@agoric/base-zone": "0.1.1-dev-
|
|
23
|
+
"@agoric/base-zone": "0.1.1-dev-6ebd99f.0.6ebd99f",
|
|
24
24
|
"@endo/common": "^1.2.13",
|
|
25
25
|
"@endo/compartment-mapper": "^1.6.3",
|
|
26
26
|
"@endo/errors": "^1.2.13",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"jessie.js": "^0.3.4"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@agoric/cosmic-proto": "0.4.1-dev-
|
|
40
|
+
"@agoric/cosmic-proto": "0.4.1-dev-6ebd99f.0.6ebd99f",
|
|
41
41
|
"@endo/exo": "^1.5.12",
|
|
42
42
|
"@endo/init": "^1.1.12",
|
|
43
43
|
"@endo/ses-ava": "^1.3.2",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"typeCoverage": {
|
|
66
66
|
"atLeast": 93.02
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "6ebd99f2c863b75f3f26316c408df1bce14a5daf"
|
|
69
69
|
}
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
/// <reference types="ses" />
|
|
4
4
|
|
|
5
|
+
// NOTE: Because @endo/bundle-source does not do tree-shaking (at least as of
|
|
6
|
+
// September 2025), bundles for sources that import from '@agoric/internal' will
|
|
7
|
+
// include each of these files even if none of their own exports are used.
|
|
8
|
+
// To keep the size of bundles down, deep imports from @agoric/internal are
|
|
9
|
+
// preferred.
|
|
10
|
+
// HOWEVER, there are still occasional imports of '@agoric/internal', so be
|
|
11
|
+
// judicious about what to include here!
|
|
12
|
+
|
|
5
13
|
export * from './cli-utils.js';
|
|
6
14
|
export * from './config.js';
|
|
7
15
|
export * from './debug.js';
|
package/src/js-utils.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export function deepCopyJsonable<T>(value: T): T;
|
|
|
26
26
|
export function deepMapObject<O extends Record<string, unknown>, M>(obj: O, mapper: <T extends Record<string, unknown>, K extends string & keyof T>(value: T[K], name: K, record: T) => T[K] | M): O | { [K_1 in keyof O]: K_1 extends string ? O[K_1] | M : never; };
|
|
27
27
|
export function defineName<F extends Function>(name: string, fn: F): F;
|
|
28
28
|
export function objectMapMutable<O extends Record<string, unknown>, M>(obj: O, mapper: <K extends keyof O>(value: O[K], key: K) => M): { [K in keyof O]: K extends string ? M : never; };
|
|
29
|
+
export function partialMap<T, U>(arr: T[], mapOrDrop: (value: T, index: number, arr: T[]) => U | undefined | false): U[];
|
|
29
30
|
export function provideLazyMap<K, V>(map: K extends WeakKey ? WeakMap<K, V> : Map<K, V>, key: K, makeValue: (key: K) => V): V;
|
|
30
31
|
export function makeMeasureSeconds(currentTimeMillisec: () => number): <T>(fn: () => Promise<T>) => Promise<{
|
|
31
32
|
result: T;
|
package/src/js-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"js-utils.d.ts","sourceRoot":"","sources":["js-utils.js"],"names":[],"mappings":"AASA,yEAAyE;AACzE,mBAA0C,IAAI,CAAE;AAEhD;;;;GAIG;AACH,2BAAuC,YAAY,CAAsB;AAEzE;;;;;;GAMG;AACH,+BAA2C,gBAAgB,CAEzD;AAEF;;;;;GAKG;AACH,uBAAmC,QAAQ,CAEzC;AAEF,2EAMG;AAgBI,iCAJM,CAAC,SACH,CAAC,GACC,CAAC,CAE4D;AAsEnE,8BAVgC,CAAC,SAA1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAE,EACzB,CAAC,OACH,CAAC,UACD,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,EACpE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,CAAC,KACN,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GACH,CAAC,GAAG,GAAG,GAAC,IAAI,MAAM,CAAC,GAAG,GAAC,SAAS,MAAM,GAAG,CAAC,CAAC,GAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAAE,CAGO;AAgBxE,2BALiB,CAAC,SAAZ,QAAU,QACZ,MAAM,MACN,CAAC,GACC,CAAC,CAG+B;AAetC,iCANgC,CAAC,SAA1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAE,EACzB,CAAC,OACH,CAAC,UACD,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GAC3C,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,GAAE,CAS5D;
|
|
1
|
+
{"version":3,"file":"js-utils.d.ts","sourceRoot":"","sources":["js-utils.js"],"names":[],"mappings":"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"}
|
package/src/js-utils.js
CHANGED
|
@@ -172,6 +172,25 @@ export const objectMapMutable = (obj, mapper) => {
|
|
|
172
172
|
return /** @type {any} */ (newObj);
|
|
173
173
|
};
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Map the elements of an array to new values, skipping elements for which the
|
|
177
|
+
* mapping results in either `undefined` or `false`.
|
|
178
|
+
*
|
|
179
|
+
* @template T
|
|
180
|
+
* @template U
|
|
181
|
+
* @param {T[]} arr
|
|
182
|
+
* @param {(value: T, index: number, arr: T[]) => U | undefined | false} mapOrDrop
|
|
183
|
+
* @returns {U[]}
|
|
184
|
+
*/
|
|
185
|
+
export const partialMap = (arr, mapOrDrop) =>
|
|
186
|
+
arr.reduce((results, el, i, arrArg) => {
|
|
187
|
+
const result = mapOrDrop(el, i, arrArg);
|
|
188
|
+
if (result !== undefined && result !== false) {
|
|
189
|
+
results.push(result);
|
|
190
|
+
}
|
|
191
|
+
return results;
|
|
192
|
+
}, /** @type {U[]} */ ([]));
|
|
193
|
+
|
|
175
194
|
/**
|
|
176
195
|
* Return the value from `map` associated with `key`. If there is not yet such a
|
|
177
196
|
* value, get one from `makeValue(key)` and update `map` before returning the
|
package/src/ses-utils.d.ts
CHANGED
|
@@ -30,6 +30,11 @@ export function makeLimitedConsole(makeLogger: (level: string) => (...args: unkn
|
|
|
30
30
|
* @type {<T extends {}>(unfulfilledTerms: T) => Promise<DeeplyAwaited<T>>}
|
|
31
31
|
*/
|
|
32
32
|
export const deeplyFulfilledObject: <T extends {}>(unfulfilledTerms: T) => Promise<DeeplyAwaited<T>>;
|
|
33
|
+
export function throwErrorCode<Code extends string>(details: Parameters<typeof makeError>[0], code: Code, opts?: Parameters<typeof makeError>[2] & {
|
|
34
|
+
constructor?: Parameters<typeof makeError>[1];
|
|
35
|
+
}): never;
|
|
36
|
+
export function tryNow<F extends (...args: any[]) => any, U = ReturnType<F>>(fn: F, transformError: (err: Error) => U, ...args: Parameters<F>): ReturnType<F> | U;
|
|
37
|
+
export function tryJsonParse(jsonText: string, onError: string | ((err: Error) => unknown)): any;
|
|
33
38
|
export function PromiseAllOrErrors<T>(items: readonly (T | PromiseLike<T>)[]): Promise<T[]>;
|
|
34
39
|
export function aggregateTryFinally<T>(trier: () => Promise<T>, finalizer: (error?: unknown) => Promise<unknown>): ReturnType<() => Promise<T>>;
|
|
35
40
|
export function withDeferredCleanup<T>(fn: (addCleanup: (fn: (err?: unknown) => Promise<void>) => void) => Promise<T>): ReturnType<(addCleanup: (fn: (err?: unknown) => Promise<void>) => void) => Promise<T>>;
|
|
@@ -61,6 +66,7 @@ import { objectMap } from '@endo/common/object-map.js';
|
|
|
61
66
|
import { objectMetaMap } from '@endo/common/object-meta-map.js';
|
|
62
67
|
import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
|
|
63
68
|
import type { LimitedConsole } from './js-utils.js';
|
|
69
|
+
import { makeError } from '@endo/errors';
|
|
64
70
|
import type { Permit } from './types.js';
|
|
65
71
|
import type { Attenuated } from './types.js';
|
|
66
72
|
import type { ERef } from '@endo/far';
|
package/src/ses-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ses-utils.d.ts","sourceRoot":"","sources":["ses-utils.js"],"names":[],"mappings":"AA8BO,+CADK,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAKvC,cAAc,CACjC;AAGD;;;;;GAKG;AAEH;;GAEG;AAEH;;;;;GAKG;AAEH;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,oCAFU,CAAC,CAAC,SAAS,EAAE,EAAE,gBAAgB,EAAE,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAKxE;
|
|
1
|
+
{"version":3,"file":"ses-utils.d.ts","sourceRoot":"","sources":["ses-utils.js"],"names":[],"mappings":"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"}
|
package/src/ses-utils.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { objectMap } from '@endo/common/object-map.js';
|
|
9
9
|
import { objectMetaMap } from '@endo/common/object-meta-map.js';
|
|
10
10
|
import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
|
|
11
|
-
import { q, Fail, makeError, annotateError, X } from '@endo/errors';
|
|
11
|
+
import { q, b, Fail, makeError, annotateError, X } from '@endo/errors';
|
|
12
12
|
import { deeplyFulfilled, isPrimitive } from '@endo/pass-style';
|
|
13
13
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
14
14
|
import { makeQueue } from '@endo/stream';
|
|
@@ -90,6 +90,89 @@ const makeAggregateError =
|
|
|
90
90
|
});
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Throw an error with an own "code" data property, supporting identification
|
|
95
|
+
* without parsing `message`. Note that such errors are not Passable and thus
|
|
96
|
+
* cannot appear inside a Passable structure, and even at top level the "code"
|
|
97
|
+
* property will be silently dropped by marshalling.
|
|
98
|
+
*
|
|
99
|
+
* @template {string} Code
|
|
100
|
+
* @param {Parameters<typeof makeError>[0]} details
|
|
101
|
+
* @param {Code} code
|
|
102
|
+
* @param {Parameters<typeof makeError>[2] & {
|
|
103
|
+
* constructor?: Parameters<typeof makeError>[1];
|
|
104
|
+
* }} [opts]
|
|
105
|
+
*/
|
|
106
|
+
export const throwErrorCode = (details, code, opts) => {
|
|
107
|
+
const err = makeError(details, opts?.constructor, {
|
|
108
|
+
...opts,
|
|
109
|
+
sanitize: false,
|
|
110
|
+
});
|
|
111
|
+
Object.defineProperty(err, 'code', { value: code, enumerable: true });
|
|
112
|
+
harden(err);
|
|
113
|
+
throw err;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Synchronusly invoke a function with the opportunity to handle any error
|
|
118
|
+
* similarly to a Promise `catch` callback (e.g., substituting a non-error
|
|
119
|
+
* returned value or throwing a possibly-new error). This is useful for (among
|
|
120
|
+
* other things) replacing generic error messages with specific ones (as in
|
|
121
|
+
* {@see tryJsonParse}).
|
|
122
|
+
*
|
|
123
|
+
* @template {(...args: any[]) => any} F
|
|
124
|
+
* @template [U=ReturnType<F>]
|
|
125
|
+
* @param {F} fn to invoke
|
|
126
|
+
* @param {(err: Error) => U} transformError callback to receive any error from
|
|
127
|
+
* invoking `fn` and either return a substitute value or throw a potentially
|
|
128
|
+
* new error
|
|
129
|
+
* @param {Parameters<F>} args for `fn`
|
|
130
|
+
* @returns {ReturnType<F> | U}
|
|
131
|
+
*/
|
|
132
|
+
export const tryNow = (fn, transformError, ...args) => {
|
|
133
|
+
try {
|
|
134
|
+
return fn(...args);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
try {
|
|
137
|
+
return transformError(err);
|
|
138
|
+
} catch (newErr) {
|
|
139
|
+
// Try to associate `err` with `newErr`.
|
|
140
|
+
if (!newErr.cause) {
|
|
141
|
+
const desc = {
|
|
142
|
+
value: err,
|
|
143
|
+
configurable: true,
|
|
144
|
+
enumerable: false,
|
|
145
|
+
writable: true,
|
|
146
|
+
};
|
|
147
|
+
if (!Reflect.defineProperty(newErr, 'cause', desc)) {
|
|
148
|
+
assert.note(newErr, err.message);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
throw newErr;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Parse JSON text, or handle an error by e.g. substituting a default value or
|
|
158
|
+
* replacing it with one bearing a non-generic message.
|
|
159
|
+
*
|
|
160
|
+
* @param {string} jsonText
|
|
161
|
+
* @param {string | ((err: Error) => unknown)} onError an error message or
|
|
162
|
+
* callback
|
|
163
|
+
*/
|
|
164
|
+
export const tryJsonParse = (jsonText, onError) => {
|
|
165
|
+
const transformError =
|
|
166
|
+
typeof onError === 'function'
|
|
167
|
+
? onError
|
|
168
|
+
: err => Fail([`${onError}: ${err.message} for input `, ''], jsonText);
|
|
169
|
+
return tryNow(() => {
|
|
170
|
+
const type = typeof jsonText;
|
|
171
|
+
type === 'string' || Fail`Input must be a string, not ${b(type)}`;
|
|
172
|
+
return JSON.parse(jsonText);
|
|
173
|
+
}, transformError);
|
|
174
|
+
};
|
|
175
|
+
|
|
93
176
|
/**
|
|
94
177
|
* @template T
|
|
95
178
|
* @param {readonly (T | PromiseLike<T>)[]} items
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function makeWorkPool<T, U = T, M extends "all" | "allSettled" = "all">(source: AsyncIterable<T> | Iterable<T>, config: undefined | [capacity: number][0] | {
|
|
2
|
+
capacity?: number;
|
|
3
|
+
mode?: M;
|
|
4
|
+
}, processInput?: (input: Awaited<T>, index?: number) => Promise<Awaited<U>> | Awaited<U>): AsyncGenerator<[M extends "allSettled" ? PromiseSettledResult<Awaited<U>> : Awaited<U>, number]> & {
|
|
5
|
+
done: Promise<boolean>;
|
|
6
|
+
then: () => never;
|
|
7
|
+
};
|
|
8
|
+
export type PromiseKit<T> = {
|
|
9
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
10
|
+
reject: (reason: any) => void;
|
|
11
|
+
promise: Promise<T>;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=work-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-pool.d.ts","sourceRoot":"","sources":["work-pool.js"],"names":[],"mappings":"AAgFO,6BAlBM,CAAC,EACA,CAAC,MACsB,CAAC,SAAxB,KAAK,GAAG,YAAa,kBACxB,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,UAC9B,SAAS,GACb,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GACrB;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAA;CAAE,iBAC3B,CACN,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EACjB,KAAK,CAAC,EAAE,MAAM,KACX,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAC3B,cAAc,CAC1B,CACM,CAAC,SAAS,YAAY,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC5E,MAAY,CACP,CACF,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,KAAK,CAAA;CAAE,CA0JnD;uBAtNY,CAAC;aAEA,CAAC,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI;YACnC,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI;aACrB,OAAO,CAAC,CAAC,CAAC"}
|
package/src/work-pool.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @file A pure JavaScript async work pool utility that is compatible with but
|
|
4
|
+
* not dependent upon a hardened environment.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { isInteger } = Number;
|
|
8
|
+
|
|
9
|
+
const sink = () => {};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {unknown} val
|
|
13
|
+
* @returns {val is bigint | boolean | null | number | string | symbol | undefined}
|
|
14
|
+
*/
|
|
15
|
+
const isPrimitive = val =>
|
|
16
|
+
!val || (typeof val !== 'object' && typeof val !== 'function');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @template T
|
|
20
|
+
* @typedef {object} PromiseKit
|
|
21
|
+
* @property {(value: T | PromiseLike<T>) => void} resolve
|
|
22
|
+
* @property {(reason: any) => void} reject
|
|
23
|
+
* @property {Promise<T>} promise
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @template T
|
|
28
|
+
* @returns {PromiseKit<T>}
|
|
29
|
+
*/
|
|
30
|
+
const makePromiseKit = () => {
|
|
31
|
+
/** @type {PromiseKit<T>['resolve']} */
|
|
32
|
+
let resolve;
|
|
33
|
+
/** @type {PromiseKit<T>['reject']} */
|
|
34
|
+
let reject;
|
|
35
|
+
const promise = new Promise((res, rej) => {
|
|
36
|
+
resolve = res;
|
|
37
|
+
reject = rej;
|
|
38
|
+
});
|
|
39
|
+
// @ts-expect-error TS2454 use before assign
|
|
40
|
+
return { promise, resolve, reject };
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Consume an async iterable with at most `capacity` unsettled results at any
|
|
45
|
+
* given time, passing each input through `processInput` and providing [result,
|
|
46
|
+
* index] pairs in settlement order. Source order can be recovered with consumer
|
|
47
|
+
* code like:
|
|
48
|
+
*
|
|
49
|
+
* const results = [];
|
|
50
|
+
* for (const [result, i] of makeWorkPool(...)) results[i] = result;
|
|
51
|
+
*
|
|
52
|
+
* or something more sophisticated to eagerly detect complete subsequences
|
|
53
|
+
* immediately following a previous high-water mark for contiguous results.
|
|
54
|
+
*
|
|
55
|
+
* To support cases in which `processInput` is used only for side effects rather
|
|
56
|
+
* than its return value, the returned AsyncGenerator has a promise-valued
|
|
57
|
+
* `done` property that fulfills when all input has been processed (to `true` if
|
|
58
|
+
* the source was exhausted or to `false` if iteration was aborted early),
|
|
59
|
+
* regardless of how many final iteration results have been consumed:
|
|
60
|
+
*
|
|
61
|
+
* await makeWorkPool(...).done;
|
|
62
|
+
*
|
|
63
|
+
* @template T
|
|
64
|
+
* @template [U=T]
|
|
65
|
+
* @template {'all' | 'allSettled'} [M='all']
|
|
66
|
+
* @param {AsyncIterable<T> | Iterable<T>} source
|
|
67
|
+
* @param {undefined
|
|
68
|
+
* | [capacity: number][0]
|
|
69
|
+
* | { capacity?: number; mode?: M }} config
|
|
70
|
+
* @param {(
|
|
71
|
+
* input: Awaited<T>,
|
|
72
|
+
* index?: number,
|
|
73
|
+
* ) => Promise<Awaited<U>> | Awaited<U>} [processInput]
|
|
74
|
+
* @returns {AsyncGenerator<
|
|
75
|
+
* [
|
|
76
|
+
* M extends 'allSettled' ? PromiseSettledResult<Awaited<U>> : Awaited<U>,
|
|
77
|
+
* number,
|
|
78
|
+
* ]
|
|
79
|
+
* > & { done: Promise<boolean>; then: () => never }}
|
|
80
|
+
*/
|
|
81
|
+
export const makeWorkPool = (
|
|
82
|
+
source,
|
|
83
|
+
config,
|
|
84
|
+
processInput = x => /** @type {any} */ (x),
|
|
85
|
+
) => {
|
|
86
|
+
// Validate arguments.
|
|
87
|
+
if (isPrimitive(config)) config = { capacity: config, mode: undefined };
|
|
88
|
+
const { capacity = 10, mode = 'all' } = config;
|
|
89
|
+
if (!(capacity === Infinity || (isInteger(capacity) && capacity > 0))) {
|
|
90
|
+
throw RangeError('capacity must be a positive integer');
|
|
91
|
+
}
|
|
92
|
+
if (mode !== 'all' && mode !== 'allSettled') {
|
|
93
|
+
throw RangeError('mode must be "all" or "allSettled"');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Normalize source into an `inputs` iterator.
|
|
97
|
+
const makeInputs = source[Symbol.asyncIterator] || source[Symbol.iterator];
|
|
98
|
+
const inputs =
|
|
99
|
+
/** @type {AsyncIterator<Awaited<T>> | Iterator<Awaited<T>>} */ (
|
|
100
|
+
Reflect.apply(makeInputs, source, [])
|
|
101
|
+
);
|
|
102
|
+
let inputsExhausted = false;
|
|
103
|
+
let terminated = false;
|
|
104
|
+
const doneKit = /** @type {PromiseKit<boolean>} */ (makePromiseKit());
|
|
105
|
+
|
|
106
|
+
// Concurrently consume up to `capacity` inputs, pushing the result of
|
|
107
|
+
// processing each into a linked chain of promises before consuming more.
|
|
108
|
+
let nextIndex = 0;
|
|
109
|
+
/**
|
|
110
|
+
* @typedef {object} ResultNode
|
|
111
|
+
* @property {Promise<ResultNode>} nextP
|
|
112
|
+
* @property {number} index
|
|
113
|
+
* @property {M extends 'allSettled'
|
|
114
|
+
* ? PromiseSettledResult<Awaited<U>>
|
|
115
|
+
* : Awaited<U>} result
|
|
116
|
+
*/
|
|
117
|
+
const { promise: headP, ...headResolvers } =
|
|
118
|
+
/** @type {PromiseKit<ResultNode>} */ (makePromiseKit());
|
|
119
|
+
let { resolve: resolveCurrent, reject } = headResolvers;
|
|
120
|
+
let inFlight = 0;
|
|
121
|
+
const takeMoreInput = async () => {
|
|
122
|
+
await null;
|
|
123
|
+
while (inFlight < capacity && !inputsExhausted && !terminated) {
|
|
124
|
+
inFlight += 1;
|
|
125
|
+
const index = nextIndex;
|
|
126
|
+
nextIndex += 1;
|
|
127
|
+
/** @type {Promise<IteratorResult<Awaited<T>>>} */
|
|
128
|
+
let iterResultP;
|
|
129
|
+
try {
|
|
130
|
+
iterResultP = Promise.resolve(inputs.next());
|
|
131
|
+
} catch (err) {
|
|
132
|
+
iterResultP = Promise.reject(err);
|
|
133
|
+
}
|
|
134
|
+
void iterResultP
|
|
135
|
+
.then(async iterResult => {
|
|
136
|
+
if (terminated) return;
|
|
137
|
+
|
|
138
|
+
if (iterResult.done) {
|
|
139
|
+
inFlight -= 1;
|
|
140
|
+
inputsExhausted = true;
|
|
141
|
+
void takeMoreInput();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Process the input, propagating errors if mode is not "allSettled".
|
|
146
|
+
await null;
|
|
147
|
+
/** @type {PromiseSettledResult<Awaited<U>>} */
|
|
148
|
+
let settlementDesc = { status: 'rejected', reason: undefined };
|
|
149
|
+
try {
|
|
150
|
+
const fulfillment = await processInput(iterResult.value, index);
|
|
151
|
+
if (terminated) return;
|
|
152
|
+
settlementDesc = { status: 'fulfilled', value: fulfillment };
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (terminated) return;
|
|
155
|
+
if (mode !== 'allSettled') throw err;
|
|
156
|
+
/** @type {PromiseRejectedResult} */ (settlementDesc).reason = err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Fulfill the current tail promise with a record that includes the
|
|
160
|
+
// source index to which it corresponds and a reference to a new
|
|
161
|
+
// [unsettled] successor (thereby extending the chain), then try to
|
|
162
|
+
// consume more input.
|
|
163
|
+
const { promise: nextP, ...nextResolvers } =
|
|
164
|
+
/** @type {PromiseKit<ResultNode>} */ (makePromiseKit());
|
|
165
|
+
// Analogous to `Promise.allSettled`, mode "allSettled" produces
|
|
166
|
+
// { status, value, reason } PromiseSettledResult records.
|
|
167
|
+
const result =
|
|
168
|
+
mode === 'allSettled'
|
|
169
|
+
? settlementDesc
|
|
170
|
+
: /** @type {PromiseFulfilledResult<Awaited<U>>} */ (
|
|
171
|
+
settlementDesc
|
|
172
|
+
).value;
|
|
173
|
+
inFlight -= 1;
|
|
174
|
+
void takeMoreInput();
|
|
175
|
+
const untypedResult = /** @type {any} */ (result);
|
|
176
|
+
resolveCurrent({ nextP, index, result: untypedResult });
|
|
177
|
+
({ resolve: resolveCurrent, reject } = nextResolvers);
|
|
178
|
+
})
|
|
179
|
+
.catch(err => {
|
|
180
|
+
// End the chain with this rejection.
|
|
181
|
+
terminated = true;
|
|
182
|
+
reject(err);
|
|
183
|
+
doneKit.reject(err);
|
|
184
|
+
void (async () => inputs.throw?.(err))().catch(sink);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (inFlight <= 0 && inputsExhausted) {
|
|
188
|
+
// @ts-expect-error This dummy signaling record conveys no result.
|
|
189
|
+
resolveCurrent({ nextP: undefined, index: -1, result: undefined });
|
|
190
|
+
doneKit.resolve(true);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const results = (async function* generateResults(nextP) {
|
|
195
|
+
await null;
|
|
196
|
+
let exhausted = false;
|
|
197
|
+
try {
|
|
198
|
+
for (;;) {
|
|
199
|
+
const { nextP: successor, index, result } = await nextP;
|
|
200
|
+
nextP = successor;
|
|
201
|
+
if (!successor) break;
|
|
202
|
+
yield /** @type {[typeof result, number]} */ (
|
|
203
|
+
Object.freeze([result, index])
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
exhausted = true;
|
|
207
|
+
} catch (err) {
|
|
208
|
+
terminated = true;
|
|
209
|
+
doneKit.reject(err);
|
|
210
|
+
void (async () => inputs.throw?.(err))().catch(sink);
|
|
211
|
+
throw err;
|
|
212
|
+
} finally {
|
|
213
|
+
const interrupted = !exhausted && !terminated;
|
|
214
|
+
terminated = true;
|
|
215
|
+
doneKit.resolve(false);
|
|
216
|
+
if (interrupted) void (async () => inputs.return?.())().catch(sink);
|
|
217
|
+
}
|
|
218
|
+
})(headP);
|
|
219
|
+
Object.defineProperty(results, 'done', {
|
|
220
|
+
value: doneKit.promise,
|
|
221
|
+
enumerable: true,
|
|
222
|
+
});
|
|
223
|
+
Object.defineProperty(results, 'then', {
|
|
224
|
+
value: () => {
|
|
225
|
+
throw Error('A work pool is not thenable; did you forget `.done`?');
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
void takeMoreInput();
|
|
230
|
+
|
|
231
|
+
// @ts-expect-error
|
|
232
|
+
return Object.freeze(results);
|
|
233
|
+
};
|