@agoric/internal 0.2.2-pismo-dev-0d5327f.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/package.json +15 -7
- package/src/action-types.d.ts +16 -0
- package/src/action-types.d.ts.map +1 -0
- package/src/action-types.js +17 -0
- package/src/batched-deliver.d.ts +15 -0
- package/src/batched-deliver.d.ts.map +1 -0
- package/src/batched-deliver.js +50 -0
- package/src/callback.d.ts +23 -0
- package/src/callback.d.ts.map +1 -0
- package/src/callback.js +322 -0
- package/src/chain-storage-paths.d.ts +16 -0
- package/src/chain-storage-paths.d.ts.map +1 -0
- package/src/chain-storage-paths.js +17 -0
- package/src/config.d.ts +25 -0
- package/src/config.d.ts.map +1 -0
- package/src/config.js +20 -3
- package/src/debug.d.ts +2 -0
- package/src/debug.d.ts.map +1 -0
- package/src/debug.js +41 -0
- package/src/index.d.ts +6 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +7 -2
- package/src/lib-chainStorage.d.ts +179 -0
- package/src/lib-chainStorage.d.ts.map +1 -0
- package/src/lib-chainStorage.js +304 -0
- package/src/magic-cookie-test-only.d.ts +2 -0
- package/src/magic-cookie-test-only.d.ts.map +1 -0
- package/src/magic-cookie-test-only.js +11 -0
- package/src/method-tools.d.ts +3 -0
- package/src/method-tools.d.ts.map +1 -0
- package/src/method-tools.js +110 -0
- package/src/node/buffer-line-transform.d.ts +41 -0
- package/src/node/buffer-line-transform.d.ts.map +1 -0
- package/src/node/buffer-line-transform.js +119 -0
- package/src/node/createBundles.d.ts +4 -0
- package/src/node/createBundles.d.ts.map +1 -0
- package/src/node/createBundles.js +80 -0
- package/src/node/fs-stream.d.ts +8 -0
- package/src/node/fs-stream.d.ts.map +1 -0
- package/src/node/fs-stream.js +105 -0
- package/src/node/shutdown.d.ts +6 -0
- package/src/node/shutdown.d.ts.map +1 -0
- package/src/node/shutdown.js +81 -0
- package/src/priority-senders.d.ts +31 -0
- package/src/priority-senders.d.ts.map +1 -0
- package/src/priority-senders.js +104 -0
- package/src/queue.d.ts +2 -0
- package/src/queue.d.ts.map +1 -0
- package/src/queue.js +58 -0
- package/src/scratch.d.ts +19 -0
- package/src/scratch.d.ts.map +1 -0
- package/src/scratch.js +52 -0
- package/src/storage-test-utils.d.ts +99 -0
- package/src/storage-test-utils.d.ts.map +1 -0
- package/src/storage-test-utils.js +228 -0
- package/src/testing-utils.d.ts +2 -0
- package/src/testing-utils.d.ts.map +1 -0
- package/src/testing-utils.js +14 -0
- package/src/typeGuards.d.ts +2 -0
- package/src/typeGuards.d.ts.map +1 -0
- package/src/typeGuards.js +5 -0
- package/src/types.d.ts +20 -0
- package/src/upgrade-api.d.ts +8 -0
- package/src/upgrade-api.d.ts.map +1 -0
- package/src/upgrade-api.js +41 -0
- package/src/utils.d.ts +67 -0
- package/src/utils.d.ts.map +1 -0
- package/src/utils.js +232 -124
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
// @jessie-check
|
|
3
|
+
import { isObject } from '@endo/marshal';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {{ name: string, upgradeMessage: string, incarnationNumber: number }} DisconnectionObject
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Makes an Error-like object for use as the rejection value of promises
|
|
11
|
+
* abandoned by upgrade.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} upgradeMessage
|
|
14
|
+
* @param {number} toIncarnationNumber
|
|
15
|
+
* @returns {DisconnectionObject}
|
|
16
|
+
*/
|
|
17
|
+
export const makeUpgradeDisconnection = (upgradeMessage, toIncarnationNumber) =>
|
|
18
|
+
harden({
|
|
19
|
+
name: 'vatUpgraded',
|
|
20
|
+
upgradeMessage,
|
|
21
|
+
incarnationNumber: toIncarnationNumber,
|
|
22
|
+
});
|
|
23
|
+
harden(makeUpgradeDisconnection);
|
|
24
|
+
|
|
25
|
+
// TODO: Simplify once we have @endo/patterns (or just export the shape).
|
|
26
|
+
// const upgradeDisconnectionShape = harden({
|
|
27
|
+
// name: 'vatUpgraded',
|
|
28
|
+
// upgradeMessage: M.string(),
|
|
29
|
+
// incarnationNumber: M.number(),
|
|
30
|
+
// });
|
|
31
|
+
// const isUpgradeDisconnection = err => matches(err, upgradeDisconnectionShape);
|
|
32
|
+
/**
|
|
33
|
+
* @param {any} err
|
|
34
|
+
* @returns {err is DisconnectionObject}
|
|
35
|
+
*/
|
|
36
|
+
export const isUpgradeDisconnection = err =>
|
|
37
|
+
isObject(err) &&
|
|
38
|
+
err.name === 'vatUpgraded' &&
|
|
39
|
+
typeof err.upgradeMessage === 'string' &&
|
|
40
|
+
typeof err.incarnationNumber === 'number';
|
|
41
|
+
harden(isUpgradeDisconnection);
|
package/src/utils.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export const BASIS_POINTS: 10000n;
|
|
2
|
+
export function fromUniqueEntries<K, V>(allEntries: Iterable<[K, V]>): {};
|
|
3
|
+
export function objectMap<O extends Record<string, any>, R>(original: O, mapFn: (value: O[keyof O], key: keyof O) => R): { [P in keyof O]: R; };
|
|
4
|
+
export function listDifference(leftNames: Array<string | symbol>, rightNames: Array<string | symbol>): (string | symbol)[];
|
|
5
|
+
export function throwLabeled(innerErr: Error, label: string | number, ErrorConstructor?: ErrorConstructor | undefined): never;
|
|
6
|
+
export function applyLabelingError<A, R>(func: (...args: A[]) => R, args: A[], label?: string | number | undefined): R;
|
|
7
|
+
/**
|
|
8
|
+
* @template T
|
|
9
|
+
* @typedef {{[KeyType in keyof T]: T[KeyType]} & {}} Simplify
|
|
10
|
+
* flatten the type output to improve type hints shown in editors
|
|
11
|
+
* https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {(...args: any[]) => any} Callable
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @template {{}} T
|
|
18
|
+
* @typedef {{ [K in keyof T]: T[K] extends Callable ? T[K] : DeeplyAwaited<T[K]> }} DeeplyAwaitedObject
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* @template T
|
|
22
|
+
* @typedef {T extends PromiseLike<any> ? Awaited<T> : T extends {} ? Simplify<DeeplyAwaitedObject<T>> : Awaited<T>} DeeplyAwaited
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* A more constrained version of {deeplyFulfilled} for type safety until
|
|
26
|
+
* https://github.com/endojs/endo/issues/1257
|
|
27
|
+
* Useful in starting contracts that need all terms to be fulfilled
|
|
28
|
+
* in order to be durable.
|
|
29
|
+
*
|
|
30
|
+
* @type {<T extends {}>(unfulfilledTerms: T) => Promise<DeeplyAwaited<T>>}
|
|
31
|
+
*/
|
|
32
|
+
export const deeplyFulfilledObject: <T extends {}>(unfulfilledTerms: T) => Promise<DeeplyAwaited<T>>;
|
|
33
|
+
export function makeMeasureSeconds(currentTimeMillisec: typeof import('perf_hooks').performance.now): <T>(fn: () => Promise<T>) => Promise<{
|
|
34
|
+
result: T;
|
|
35
|
+
duration: number;
|
|
36
|
+
}>;
|
|
37
|
+
export function makeAggregateError(errors: Error[], message?: string | undefined): Error;
|
|
38
|
+
export function PromiseAllOrErrors<T>(items: readonly (T | PromiseLike<T>)[]): Promise<T[]>;
|
|
39
|
+
/**
|
|
40
|
+
* @type {<T>(
|
|
41
|
+
* trier: () => Promise<T>,
|
|
42
|
+
* finalizer: (error?: unknown) => Promise<void>,
|
|
43
|
+
* ) => Promise<T>}
|
|
44
|
+
*/ export const aggregateTryFinally: <T>(trier: () => Promise<T>, finalizer: (error?: unknown) => Promise<void>) => Promise<T>;
|
|
45
|
+
export function assertAllDefined<T extends Record<string, unknown>>(obj: T): asserts obj is AllDefined<T>;
|
|
46
|
+
export const forever: AsyncIterable<undefined>;
|
|
47
|
+
export function whileTrue<T>(produce: () => T): AsyncIterable<Awaited<T>>;
|
|
48
|
+
export function untilTrue<T>(produce: () => T): AsyncIterable<Awaited<T>>;
|
|
49
|
+
/** @type { <X, Y>(xs: X[], ys: Y[]) => [X, Y][]} */
|
|
50
|
+
export const zip: <X, Y>(xs: X[], ys: Y[]) => [X, Y][];
|
|
51
|
+
/** @type { <T extends Record<string, ERef<any>>>(obj: T) => Promise<{ [K in keyof T]: Awaited<T[K]>}> } */
|
|
52
|
+
export const allValues: <T extends Record<string, any>>(obj: T) => Promise<{ [K in keyof T]: Awaited<T[K]>; }>;
|
|
53
|
+
export function synchronizedTee<T = unknown>(sourceStream: AsyncIterator<T, void, void>, readerCount: number): AsyncGenerator<T, void, void>[];
|
|
54
|
+
/**
|
|
55
|
+
* <T>
|
|
56
|
+
*/
|
|
57
|
+
export type ERef<T> = import('@endo/eventual-send').ERef<T>;
|
|
58
|
+
/**
|
|
59
|
+
* flatten the type output to improve type hints shown in editors
|
|
60
|
+
* https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts
|
|
61
|
+
*/
|
|
62
|
+
export type Simplify<T> = { [KeyType_1 in keyof T]: T[KeyType_1]; };
|
|
63
|
+
export type Callable = (...args: any[]) => any;
|
|
64
|
+
export type DeeplyAwaitedObject<T extends {}> = { [K in keyof T]: T[K] extends Callable ? T[K] : DeeplyAwaited<T[K]>; };
|
|
65
|
+
export type DeeplyAwaited<T> = T extends PromiseLike<any> ? Awaited<T> : T extends {} ? Simplify<DeeplyAwaitedObject<T>> : Awaited<T>;
|
|
66
|
+
export type AllDefined<T extends Record<string, unknown>> = { [P in keyof T]: Exclude<T[P], undefined>; };
|
|
67
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["utils.js"],"names":[],"mappings":"AAcA,kCAAoC;AAa7B,0EAcN;AA0CM,gJAIN;AAOM,0CAHI,MAAM,MAAM,GAAG,MAAM,CAAC,cACtB,MAAM,MAAM,GAAG,MAAM,CAAC,uBAKhC;AASM,uCALI,KAAK,SACL,MAAM,GAAC,MAAM,oDAEX,KAAK,CAYjB;AAUM,uHAyBN;AAGD;;;;;GAKG;AAEH;;GAEG;AAEH;;;GAGG;AAEH;;;GAGG;AAEH;;;;;;;GAOG;AACH,qGAGE;AAUK,wDAHI,cAAc,YAAY,EAAE,WAAW,CAAC,GAAG;;cACmB,MAAM;GAW9E;AAMM,2CAHI,KAAK,EAAE,uCAcjB;AAOM,4FAeN;AAED;;;;;GAKG,CAAC,mFAFoB,OAAO,KAAK,QAAQ,IAAI,CAAC,gBAY7C;AAiBG,0GAUN;AAQD,+CAAoD;AAU7C,0EAUH;AAUG,0EAaH;AAEJ,oDAAoD;AACpD,uDAAqE;AAErE,2GAA2G;AAC3G,+GAIE;AAWK,sGAFI,MAAM,mCA4FhB;;;;sBAlbyB,OAAO,qBAAqB,EAAE,IAAI,CAAC,CAAC,CAAC;;;;;;iCAkJxC,GAAG,EAAE,KAAK,GAAG;;+BAUvB,CAAC,SAAS,YAAY,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,SAAS,oBAAoB,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC"}
|
package/src/utils.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
2
|
+
// @jessie-check
|
|
3
|
+
|
|
4
|
+
import { E } from '@endo/far';
|
|
3
5
|
import { deeplyFulfilled, isObject } from '@endo/marshal';
|
|
4
|
-
import { isPromise } from '@endo/promise-kit';
|
|
6
|
+
import { isPromise, makePromiseKit } from '@endo/promise-kit';
|
|
7
|
+
import { makeQueue } from '@endo/stream';
|
|
8
|
+
import { asyncGenerate, makeSet } from 'jessie.js';
|
|
9
|
+
|
|
10
|
+
const { entries, fromEntries, keys, values } = Object;
|
|
11
|
+
const { ownKeys } = Reflect;
|
|
5
12
|
|
|
6
|
-
|
|
13
|
+
const { details: X, quote: q, Fail } = assert;
|
|
7
14
|
|
|
8
|
-
const
|
|
9
|
-
const { ownKeys, apply } = Reflect;
|
|
15
|
+
export const BASIS_POINTS = 10_000n;
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
/** @template T @typedef {import('@endo/eventual-send').ERef<T>} ERef<T> */
|
|
12
18
|
|
|
13
19
|
/**
|
|
14
20
|
* Throws if multiple entries use the same property name. Otherwise acts
|
|
15
|
-
* like `Object.fromEntries
|
|
16
|
-
* computed from user-provided data.
|
|
21
|
+
* like `Object.fromEntries` but hardens the result.
|
|
22
|
+
* Use it to protect from property names computed from user-provided data.
|
|
17
23
|
*
|
|
18
24
|
* @template K,V
|
|
19
25
|
* @param {Iterable<[K,V]>} allEntries
|
|
@@ -21,18 +27,18 @@ const { details: X, quote: q } = assert;
|
|
|
21
27
|
*/
|
|
22
28
|
export const fromUniqueEntries = allEntries => {
|
|
23
29
|
const entriesArray = [...allEntries];
|
|
24
|
-
const result = fromEntries(entriesArray);
|
|
30
|
+
const result = harden(fromEntries(entriesArray));
|
|
25
31
|
if (ownKeys(result).length === entriesArray.length) {
|
|
26
32
|
return result;
|
|
27
33
|
}
|
|
28
|
-
const names =
|
|
34
|
+
const names = makeSet();
|
|
29
35
|
for (const [name, _] of entriesArray) {
|
|
30
36
|
if (names.has(name)) {
|
|
31
|
-
|
|
37
|
+
Fail`collision on property name ${q(name)}: ${entriesArray}`;
|
|
32
38
|
}
|
|
33
39
|
names.add(name);
|
|
34
40
|
}
|
|
35
|
-
|
|
41
|
+
throw Fail`internal: failed to create object from unique entries`;
|
|
36
42
|
};
|
|
37
43
|
harden(fromUniqueEntries);
|
|
38
44
|
|
|
@@ -82,8 +88,12 @@ export const objectMap = (original, mapFn) => {
|
|
|
82
88
|
};
|
|
83
89
|
harden(objectMap);
|
|
84
90
|
|
|
91
|
+
/**
|
|
92
|
+
* @param {Array<string | symbol>} leftNames
|
|
93
|
+
* @param {Array<string | symbol>} rightNames
|
|
94
|
+
*/
|
|
85
95
|
export const listDifference = (leftNames, rightNames) => {
|
|
86
|
-
const rightSet =
|
|
96
|
+
const rightSet = makeSet(rightNames);
|
|
87
97
|
return leftNames.filter(name => !rightSet.has(name));
|
|
88
98
|
};
|
|
89
99
|
harden(listDifference);
|
|
@@ -91,7 +101,7 @@ harden(listDifference);
|
|
|
91
101
|
/**
|
|
92
102
|
* @param {Error} innerErr
|
|
93
103
|
* @param {string|number} label
|
|
94
|
-
* @param {ErrorConstructor
|
|
104
|
+
* @param {ErrorConstructor} [ErrorConstructor]
|
|
95
105
|
* @returns {never}
|
|
96
106
|
*/
|
|
97
107
|
export const throwLabeled = (innerErr, label, ErrorConstructor = undefined) => {
|
|
@@ -125,110 +135,54 @@ export const applyLabelingError = (func, args, label = undefined) => {
|
|
|
125
135
|
throwLabeled(err, label);
|
|
126
136
|
}
|
|
127
137
|
if (isPromise(result)) {
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
// If result is a rejected promise, this will return a promise with a
|
|
139
|
+
// different rejection reason. But this confuses TypeScript because it types
|
|
140
|
+
// that case as `Promise<never>` which is cool for a promise that will never
|
|
141
|
+
// fulfill. But TypeScript doesn't understand that this will only happen
|
|
142
|
+
// when `result` was a rejected promise. In only this case `R` should
|
|
143
|
+
// already allow `Promise<never>` as a subtype.
|
|
144
|
+
/** @type {unknown} */
|
|
145
|
+
const relabeled = E.when(result, undefined, reason =>
|
|
146
|
+
throwLabeled(reason, label),
|
|
147
|
+
);
|
|
148
|
+
return /** @type {R} */ (relabeled);
|
|
136
149
|
} else {
|
|
137
150
|
return result;
|
|
138
151
|
}
|
|
139
152
|
};
|
|
140
153
|
harden(applyLabelingError);
|
|
141
154
|
|
|
142
|
-
const compareStringified = (left, right) => {
|
|
143
|
-
left = String(left);
|
|
144
|
-
right = String(right);
|
|
145
|
-
// eslint-disable-next-line no-nested-ternary
|
|
146
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
147
|
-
};
|
|
148
|
-
|
|
149
155
|
/**
|
|
150
|
-
* @
|
|
151
|
-
* @
|
|
156
|
+
* @template T
|
|
157
|
+
* @typedef {{[KeyType in keyof T]: T[KeyType]} & {}} Simplify
|
|
158
|
+
* flatten the type output to improve type hints shown in editors
|
|
159
|
+
* https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts
|
|
152
160
|
*/
|
|
153
|
-
export const getMethodNames = obj => {
|
|
154
|
-
const result = [];
|
|
155
|
-
while (obj !== null && obj !== Object.prototype) {
|
|
156
|
-
const mNames = ownKeys(obj).filter(name => typeof obj[name] === 'function');
|
|
157
|
-
result.push(...mNames);
|
|
158
|
-
obj = getPrototypeOf(obj);
|
|
159
|
-
}
|
|
160
|
-
result.sort(compareStringified);
|
|
161
|
-
return harden(result);
|
|
162
|
-
};
|
|
163
|
-
harden(getMethodNames);
|
|
164
161
|
|
|
165
162
|
/**
|
|
166
|
-
*
|
|
167
|
-
* https://github.com/Agoric/agoric-sdk/pull/5970 transition, from all methods
|
|
168
|
-
* being own properties to methods being inherited from a common prototype.
|
|
169
|
-
* This transition breaks two patterns used in prior code: autobinding,
|
|
170
|
-
* and enumerating methods by enumerating own properties. For both, the
|
|
171
|
-
* preferred repairs are
|
|
172
|
-
* * autobinding: Replace, for example,
|
|
173
|
-
* `foo(obj.method)` with `foo(arg => `obj.method(arg))`. IOW, stop relying
|
|
174
|
-
* on expressions like `obj.method` to extract a method still bound to the
|
|
175
|
-
* state of `obj` because, for virtual and durable objects,
|
|
176
|
-
* they no longer will after #5970.
|
|
177
|
-
* * method enumeration: Replace, for example
|
|
178
|
-
* `Reflect.ownKeys(obj)` with `getMethodNames(obj)`.
|
|
179
|
-
*
|
|
180
|
-
* Once all problematic cases have been converted in this manner, this
|
|
181
|
-
* `bindAllMethods` hack can and TODO should be deleted. However, we currently
|
|
182
|
-
* have no reliable static way to track down and fix all autobinding sites.
|
|
183
|
-
* For those objects that have not yet been fully repaired by the above two
|
|
184
|
-
* techniques, `bindAllMethods` creates an object that acts much like the
|
|
185
|
-
* pre-#5970 objects, with all their methods as instance-bound own properties.
|
|
186
|
-
* It does this by making a new object inheriting from `obj` where the new
|
|
187
|
-
* object has bound own methods overridding all the methods it would have
|
|
188
|
-
* inherited from `obj`.
|
|
189
|
-
*
|
|
190
|
-
* @param {Remotable} obj
|
|
191
|
-
* @returns {Remotable}
|
|
163
|
+
* @typedef {(...args: any[]) => any} Callable
|
|
192
164
|
*/
|
|
193
|
-
export const bindAllMethods = obj =>
|
|
194
|
-
harden(
|
|
195
|
-
create(
|
|
196
|
-
obj,
|
|
197
|
-
fromEntries(
|
|
198
|
-
getMethodNames(obj).map(name => [
|
|
199
|
-
name,
|
|
200
|
-
{
|
|
201
|
-
value: (...args) => apply(obj[name], obj, args),
|
|
202
|
-
enumerable: true,
|
|
203
|
-
},
|
|
204
|
-
]),
|
|
205
|
-
),
|
|
206
|
-
),
|
|
207
|
-
);
|
|
208
|
-
harden(bindAllMethods);
|
|
209
165
|
|
|
210
166
|
/**
|
|
211
167
|
* @template {{}} T
|
|
212
|
-
* @typedef {{ [K in keyof T]: DeeplyAwaited<T[K]> }} DeeplyAwaitedObject
|
|
168
|
+
* @typedef {{ [K in keyof T]: T[K] extends Callable ? T[K] : DeeplyAwaited<T[K]> }} DeeplyAwaitedObject
|
|
213
169
|
*/
|
|
214
170
|
|
|
215
171
|
/**
|
|
216
|
-
* Caveats:
|
|
217
|
-
* - doesn't recur within Promise results
|
|
218
|
-
* - resulting type has wrapper in its name
|
|
219
|
-
*
|
|
220
172
|
* @template T
|
|
221
|
-
* @typedef {T extends PromiseLike ? Awaited<T> : T extends {} ? DeeplyAwaitedObject<T
|
|
173
|
+
* @typedef {T extends PromiseLike<any> ? Awaited<T> : T extends {} ? Simplify<DeeplyAwaitedObject<T>> : Awaited<T>} DeeplyAwaited
|
|
222
174
|
*/
|
|
223
175
|
|
|
224
176
|
/**
|
|
225
|
-
* A more constrained version of {deeplyFulfilled} for type safety until
|
|
226
|
-
*
|
|
177
|
+
* A more constrained version of {deeplyFulfilled} for type safety until
|
|
178
|
+
* https://github.com/endojs/endo/issues/1257
|
|
179
|
+
* Useful in starting contracts that need all terms to be fulfilled
|
|
180
|
+
* in order to be durable.
|
|
227
181
|
*
|
|
228
|
-
* @type {<T extends {}>(unfulfilledTerms: T) =>
|
|
182
|
+
* @type {<T extends {}>(unfulfilledTerms: T) => Promise<DeeplyAwaited<T>>}
|
|
229
183
|
*/
|
|
230
|
-
export const deeplyFulfilledObject = obj => {
|
|
231
|
-
|
|
184
|
+
export const deeplyFulfilledObject = async obj => {
|
|
185
|
+
isObject(obj) || Fail`param must be an object`;
|
|
232
186
|
return deeplyFulfilled(obj);
|
|
233
187
|
};
|
|
234
188
|
|
|
@@ -241,6 +195,7 @@ export const deeplyFulfilledObject = obj => {
|
|
|
241
195
|
* @returns {<T>(fn: () => Promise<T>) => Promise<{ result: T, duration: number }>}
|
|
242
196
|
*/
|
|
243
197
|
export const makeMeasureSeconds = currentTimeMillisec => {
|
|
198
|
+
/** @param {() => any} fn */
|
|
244
199
|
const measureSeconds = async fn => {
|
|
245
200
|
const t0 = currentTimeMillisec();
|
|
246
201
|
const result = await fn();
|
|
@@ -255,7 +210,7 @@ export const makeMeasureSeconds = currentTimeMillisec => {
|
|
|
255
210
|
* @param {string} [message]
|
|
256
211
|
*/
|
|
257
212
|
export const makeAggregateError = (errors, message) => {
|
|
258
|
-
const err =
|
|
213
|
+
const err = Error(message);
|
|
259
214
|
Object.defineProperties(err, {
|
|
260
215
|
name: {
|
|
261
216
|
value: 'AggregateError',
|
|
@@ -269,11 +224,11 @@ export const makeAggregateError = (errors, message) => {
|
|
|
269
224
|
|
|
270
225
|
/**
|
|
271
226
|
* @template T
|
|
272
|
-
* @param {readonly (T | PromiseLike<T>)[]}
|
|
227
|
+
* @param {readonly (T | PromiseLike<T>)[]} items
|
|
273
228
|
* @returns {Promise<T[]>}
|
|
274
229
|
*/
|
|
275
|
-
export const PromiseAllOrErrors = async
|
|
276
|
-
return Promise.allSettled(
|
|
230
|
+
export const PromiseAllOrErrors = async items => {
|
|
231
|
+
return Promise.allSettled(items).then(results => {
|
|
277
232
|
const errors = /** @type {PromiseRejectedResult[]} */ (
|
|
278
233
|
results.filter(({ status }) => status === 'rejected')
|
|
279
234
|
).map(result => result.reason);
|
|
@@ -307,37 +262,190 @@ export const PromiseAllOrErrors = async values => {
|
|
|
307
262
|
);
|
|
308
263
|
|
|
309
264
|
/**
|
|
310
|
-
* @
|
|
311
|
-
* @
|
|
265
|
+
* @template {Record<string, unknown>} T
|
|
266
|
+
* @typedef {{[P in keyof T]: Exclude<T[P], undefined>;}} AllDefined
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Concise way to check values are available from object literal shorthand.
|
|
271
|
+
* Throws error message to specify the missing values.
|
|
272
|
+
*
|
|
273
|
+
* @template {Record<string, unknown>} T
|
|
274
|
+
* @param {T} obj
|
|
275
|
+
* @throws if any value in the object entries is not defined
|
|
276
|
+
* @returns {asserts obj is AllDefined<T>}
|
|
312
277
|
*/
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
278
|
+
|
|
279
|
+
export const assertAllDefined = obj => {
|
|
280
|
+
const missing = [];
|
|
281
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
282
|
+
if (val === undefined) {
|
|
283
|
+
missing.push(key);
|
|
318
284
|
}
|
|
285
|
+
}
|
|
286
|
+
if (missing.length > 0) {
|
|
287
|
+
Fail`missing ${q(missing)}`;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
/** @type {IteratorResult<undefined, never>} */
|
|
292
|
+
const notDone = harden({ done: false, value: undefined });
|
|
293
|
+
|
|
294
|
+
/** @type {IteratorResult<never, void>} */
|
|
295
|
+
const alwaysDone = harden({ done: true, value: undefined });
|
|
296
|
+
|
|
297
|
+
export const forever = asyncGenerate(() => notDone);
|
|
319
298
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
299
|
+
/**
|
|
300
|
+
* @template T
|
|
301
|
+
* @param {() => T} produce
|
|
302
|
+
* The value of `await produce()` is used for its truthiness vs falsiness.
|
|
303
|
+
* IOW, it is coerced to a boolean so the caller need not bother doing this
|
|
304
|
+
* themselves.
|
|
305
|
+
* @returns {AsyncIterable<Awaited<T>>}
|
|
306
|
+
*/
|
|
307
|
+
export const whileTrue = produce =>
|
|
308
|
+
asyncGenerate(async () => {
|
|
309
|
+
const value = await produce();
|
|
310
|
+
if (!value) {
|
|
311
|
+
return alwaysDone;
|
|
323
312
|
}
|
|
313
|
+
return harden({
|
|
314
|
+
done: false,
|
|
315
|
+
value,
|
|
316
|
+
});
|
|
317
|
+
});
|
|
324
318
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
319
|
+
/**
|
|
320
|
+
* @template T
|
|
321
|
+
* @param {() => T} produce
|
|
322
|
+
* The value of `await produce()` is used for its truthiness vs falsiness.
|
|
323
|
+
* IOW, it is coerced to a boolean so the caller need not bother doing this
|
|
324
|
+
* themselves.
|
|
325
|
+
* @returns {AsyncIterable<Awaited<T>>}
|
|
326
|
+
*/
|
|
327
|
+
export const untilTrue = produce =>
|
|
328
|
+
asyncGenerate(async () => {
|
|
329
|
+
const value = await produce();
|
|
330
|
+
if (value) {
|
|
331
|
+
return harden({
|
|
332
|
+
done: true,
|
|
333
|
+
value,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return harden({
|
|
337
|
+
done: false,
|
|
338
|
+
value,
|
|
339
|
+
});
|
|
340
|
+
});
|
|
329
341
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
cleanup(); // eslint-disable-line no-use-before-define
|
|
333
|
-
reject(err);
|
|
334
|
-
};
|
|
342
|
+
/** @type { <X, Y>(xs: X[], ys: Y[]) => [X, Y][]} */
|
|
343
|
+
export const zip = (xs, ys) => harden(xs.map((x, i) => [x, ys[+i]]));
|
|
335
344
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
345
|
+
/** @type { <T extends Record<string, ERef<any>>>(obj: T) => Promise<{ [K in keyof T]: Awaited<T[K]>}> } */
|
|
346
|
+
export const allValues = async obj => {
|
|
347
|
+
const resolved = await Promise.all(values(obj));
|
|
348
|
+
// @ts-expect-error cast
|
|
349
|
+
return harden(fromEntries(zip(keys(obj), resolved)));
|
|
350
|
+
};
|
|
340
351
|
|
|
341
|
-
|
|
342
|
-
|
|
352
|
+
/**
|
|
353
|
+
* A tee implementation where all readers are synchronized with each other.
|
|
354
|
+
* They all consume the source stream in lockstep, and any one returning or
|
|
355
|
+
* throwing early will affect the others.
|
|
356
|
+
*
|
|
357
|
+
* @template [T=unknown]
|
|
358
|
+
* @param {AsyncIterator<T, void, void>} sourceStream
|
|
359
|
+
* @param {number} readerCount
|
|
360
|
+
*/
|
|
361
|
+
export const synchronizedTee = (sourceStream, readerCount) => {
|
|
362
|
+
/** @type {IteratorReturnResult<void> | undefined} */
|
|
363
|
+
let doneResult;
|
|
364
|
+
|
|
365
|
+
/** @typedef {IteratorResult<(value: PromiseLike<IteratorResult<T>>) => void>} QueuePayload */
|
|
366
|
+
/** @type {import('@endo/stream').AsyncQueue<QueuePayload>[]} */
|
|
367
|
+
const queues = [];
|
|
368
|
+
|
|
369
|
+
/** @returns {Promise<void>} */
|
|
370
|
+
const pullNext = async () => {
|
|
371
|
+
const requests = await Promise.allSettled(queues.map(queue => queue.get()));
|
|
372
|
+
const rejections = [];
|
|
373
|
+
/** @type {Array<(value: PromiseLike<IteratorResult<T>>) => void>} */
|
|
374
|
+
const resolvers = [];
|
|
375
|
+
let done = false;
|
|
376
|
+
for (const settledResult of requests) {
|
|
377
|
+
if (settledResult.status === 'rejected') {
|
|
378
|
+
rejections.push(settledResult.reason);
|
|
379
|
+
} else {
|
|
380
|
+
done ||= !!settledResult.value.done;
|
|
381
|
+
resolvers.push(settledResult.value.value);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/** @type {Promise<IteratorResult<T>>} */
|
|
385
|
+
let result;
|
|
386
|
+
if (doneResult) {
|
|
387
|
+
result = Promise.resolve(doneResult);
|
|
388
|
+
} else if (rejections.length) {
|
|
389
|
+
const error = assert.error(assert.details`Teed stream threw`);
|
|
390
|
+
assert.note(error, assert.details`Teed rejections: ${rejections}`);
|
|
391
|
+
result =
|
|
392
|
+
sourceStream.throw?.(error) ||
|
|
393
|
+
Promise.resolve(sourceStream.return?.()).then(() =>
|
|
394
|
+
Promise.reject(error),
|
|
395
|
+
);
|
|
396
|
+
} else if (done) {
|
|
397
|
+
result =
|
|
398
|
+
sourceStream.return?.() ||
|
|
399
|
+
Promise.resolve({ done: true, value: undefined });
|
|
400
|
+
} else {
|
|
401
|
+
result = sourceStream.next();
|
|
402
|
+
}
|
|
403
|
+
result.then(
|
|
404
|
+
r => {
|
|
405
|
+
if (r.done) {
|
|
406
|
+
doneResult = r;
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
() => {
|
|
410
|
+
doneResult = { done: true, value: undefined };
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
resolvers.forEach(resolve => resolve(result));
|
|
414
|
+
return pullNext();
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const readers = Array.from({ length: readerCount }).map(() => {
|
|
418
|
+
/** @type {import('@endo/stream').AsyncQueue<QueuePayload>} */
|
|
419
|
+
const queue = makeQueue();
|
|
420
|
+
queues.push(queue);
|
|
421
|
+
|
|
422
|
+
/** @type {AsyncGenerator<T, void, void>} */
|
|
423
|
+
const reader = harden({
|
|
424
|
+
async next() {
|
|
425
|
+
/** @type {import('@endo/promise-kit').PromiseKit<IteratorResult<T>>} */
|
|
426
|
+
const { promise, resolve } = makePromiseKit();
|
|
427
|
+
queue.put({ value: resolve, done: false });
|
|
428
|
+
return promise;
|
|
429
|
+
},
|
|
430
|
+
async return() {
|
|
431
|
+
/** @type {import('@endo/promise-kit').PromiseKit<IteratorResult<T>>} */
|
|
432
|
+
const { promise, resolve } = makePromiseKit();
|
|
433
|
+
queue.put({ value: resolve, done: true });
|
|
434
|
+
return promise;
|
|
435
|
+
},
|
|
436
|
+
async throw(reason) {
|
|
437
|
+
const rejection = Promise.reject(reason);
|
|
438
|
+
queue.put(rejection);
|
|
439
|
+
return rejection;
|
|
440
|
+
},
|
|
441
|
+
// eslint-disable-next-line no-restricted-globals
|
|
442
|
+
[Symbol.asyncIterator]() {
|
|
443
|
+
return reader;
|
|
444
|
+
},
|
|
445
|
+
});
|
|
446
|
+
return reader;
|
|
343
447
|
});
|
|
448
|
+
|
|
449
|
+
void pullNext();
|
|
450
|
+
return readers;
|
|
451
|
+
};
|