@agoric/vow 0.1.1-dev-4f70e66.0 → 0.1.1-dev-8edf902.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/package.json +4 -4
- package/src/tools.d.ts +5 -2
- package/src/tools.d.ts.map +1 -1
- package/src/tools.js +17 -6
- package/src/types.d.ts +8 -0
- package/src/types.d.ts.map +1 -1
- package/src/types.js +20 -0
- package/src/vow.d.ts.map +1 -1
- package/src/vow.js +66 -12
- package/src/watch-utils.d.ts +13 -3
- package/src/watch-utils.d.ts.map +1 -1
- package/src/watch-utils.js +105 -21
- package/src/watch.d.ts +3 -3
- package/src/watch.d.ts.map +1 -1
- package/src/watch.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/vow",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
3
|
+
"version": "0.1.1-dev-8edf902.0+8edf902",
|
|
4
4
|
"description": "Remote (shortening and disconnection-tolerant) Promise-likes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"lint:types": "tsc"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@agoric/base-zone": "0.1.1-dev-
|
|
24
|
-
"@agoric/internal": "0.3.3-dev-
|
|
23
|
+
"@agoric/base-zone": "0.1.1-dev-8edf902.0+8edf902",
|
|
24
|
+
"@agoric/internal": "0.3.3-dev-8edf902.0+8edf902",
|
|
25
25
|
"@endo/env-options": "^1.1.4",
|
|
26
26
|
"@endo/eventual-send": "^1.2.2",
|
|
27
27
|
"@endo/pass-style": "^1.4.0",
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"typeCoverage": {
|
|
55
55
|
"atLeast": 89.6
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "8edf90288c8a7b248ec4961d342063e2b8c52303"
|
|
58
58
|
}
|
package/src/tools.d.ts
CHANGED
|
@@ -2,12 +2,15 @@ export function prepareVowTools(zone: Zone, powers?: {
|
|
|
2
2
|
isRetryableReason?: IsRetryableReason | undefined;
|
|
3
3
|
} | undefined): {
|
|
4
4
|
when: <T, TResult1 = import("./types.js").EUnwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("./types.js").EUnwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
|
|
5
|
-
watch: <T = any, TResult1 = T, TResult2 = never, C extends any[] = any[]>(specimenP:
|
|
5
|
+
watch: <T = any, TResult1 = T, TResult2 = never, C extends any[] = any[]>(specimenP: EVow<T>, watcher?: import("./types.js").Watcher<T, TResult1, TResult2, C> | undefined, ...watcherArgs: C) => import("./types.js").Vow<Exclude<TResult1, void> | Exclude<TResult2, void> extends never ? TResult1 : Exclude<TResult1, void> | Exclude<TResult2, void>>;
|
|
6
6
|
makeVowKit: <T>() => import("./types.js").VowKit<T>;
|
|
7
|
-
allVows: (
|
|
7
|
+
allVows: (maybeVows: EVow<unknown>[]) => import("./types.js").Vow<any[]>;
|
|
8
8
|
asVow: <T extends unknown>(fn: (...args: any[]) => import("./types.js").Vow<Awaited<T>> | Awaited<T> | import("./types.js").PromiseVow<T>) => import("./types.js").Vow<Awaited<T>>;
|
|
9
|
+
asPromise: AsPromiseFunction;
|
|
9
10
|
};
|
|
10
11
|
export type VowTools = ReturnType<typeof prepareVowTools>;
|
|
11
12
|
import type { Zone } from '@agoric/base-zone';
|
|
12
13
|
import type { IsRetryableReason } from './types.js';
|
|
14
|
+
import type { EVow } from './types.js';
|
|
15
|
+
import type { AsPromiseFunction } from './types.js';
|
|
13
16
|
//# sourceMappingURL=tools.d.ts.map
|
package/src/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["tools.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["tools.js"],"names":[],"mappings":"AAiBO,sCAJI,IAAI;;;;;;yBAsBF,KAAK,OAAO,CAAC,EAAE;oCAaykC,GAAG;;EAJvmC;uBAGa,UAAU,CAAC,OAAO,eAAe,CAAC;0BAvCzB,mBAAmB;uCACmB,YAAY;0BAAZ,YAAY;uCAAZ,YAAY"}
|
package/src/tools.js
CHANGED
|
@@ -5,8 +5,10 @@ import { prepareWatch } from './watch.js';
|
|
|
5
5
|
import { prepareWatchUtils } from './watch-utils.js';
|
|
6
6
|
import { makeAsVow } from './vow-utils.js';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* @import {Zone} from '@agoric/base-zone';
|
|
10
|
+
* @import {IsRetryableReason, AsPromiseFunction, EVow} from './types.js';
|
|
11
|
+
*/
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* @param {Zone} zone
|
|
@@ -19,18 +21,27 @@ export const prepareVowTools = (zone, powers = {}) => {
|
|
|
19
21
|
const makeVowKit = prepareVowKit(zone);
|
|
20
22
|
const when = makeWhen(isRetryableReason);
|
|
21
23
|
const watch = prepareWatch(zone, makeVowKit, isRetryableReason);
|
|
22
|
-
const makeWatchUtils = prepareWatchUtils(zone,
|
|
24
|
+
const makeWatchUtils = prepareWatchUtils(zone, {
|
|
25
|
+
watch,
|
|
26
|
+
when,
|
|
27
|
+
makeVowKit,
|
|
28
|
+
isRetryableReason,
|
|
29
|
+
});
|
|
23
30
|
const watchUtils = makeWatchUtils();
|
|
24
31
|
const asVow = makeAsVow(makeVowKit);
|
|
25
32
|
|
|
26
33
|
/**
|
|
27
34
|
* Vow-tolerant implementation of Promise.all.
|
|
28
35
|
*
|
|
29
|
-
* @param {unknown[]}
|
|
36
|
+
* @param {EVow<unknown>[]} maybeVows
|
|
30
37
|
*/
|
|
31
|
-
const allVows =
|
|
38
|
+
const allVows = maybeVows => watchUtils.all(maybeVows);
|
|
39
|
+
|
|
40
|
+
/** @type {AsPromiseFunction} */
|
|
41
|
+
const asPromise = (specimenP, ...watcherArgs) =>
|
|
42
|
+
watchUtils.asPromise(specimenP, ...watcherArgs);
|
|
32
43
|
|
|
33
|
-
return harden({ when, watch, makeVowKit, allVows, asVow });
|
|
44
|
+
return harden({ when, watch, makeVowKit, allVows, asVow, asPromise });
|
|
34
45
|
};
|
|
35
46
|
harden(prepareVowTools);
|
|
36
47
|
|
package/src/types.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export type IsRetryableReason = (reason: any, priorRetryValue: any) => any;
|
|
|
8
8
|
*/
|
|
9
9
|
export type PromiseVow<T> = Promise<T | Vow<T>>;
|
|
10
10
|
export type ERef<T> = T | PromiseLike<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Eventually a value T or Vow for it.
|
|
13
|
+
*/
|
|
14
|
+
export type EVow<T> = ERef<T | Vow<T>>;
|
|
11
15
|
/**
|
|
12
16
|
* Follow the chain of vow shortening to the end, returning the final value.
|
|
13
17
|
* This is used within E, so we must narrow the type to its remote form.
|
|
@@ -44,6 +48,10 @@ export type Watcher<T = any, TResult1 = T, TResult2 = never, C extends any[] = a
|
|
|
44
48
|
onFulfilled?: ((value: T, ...args: C) => Vow<TResult1> | PromiseVow<TResult1> | TResult1) | undefined;
|
|
45
49
|
onRejected?: ((reason: any, ...args: C) => Vow<TResult2> | PromiseVow<TResult2> | TResult2) | undefined;
|
|
46
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Converts a vow or promise to a promise, ensuring proper handling of ephemeral promises.
|
|
53
|
+
*/
|
|
54
|
+
export type AsPromiseFunction<T = any, TResult1 = T, TResult2 = never, C extends any[] = any[]> = (specimenP: ERef<T | Vow<T>>, watcher?: Watcher<T, TResult1, TResult2, C> | undefined, watcherArgs?: C | undefined) => Promise<TResult1 | TResult2>;
|
|
47
55
|
import type { RemotableObject } from '@endo/pass-style';
|
|
48
56
|
import type { Remote } from '@agoric/internal';
|
|
49
57
|
import type { CopyTagged } from '@endo/pass-style';
|
package/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":";;;yCAaW,GAAG,mBACH,GAAG,KAED,GAAG;;;;;uBAKH,CAAC,IACD,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;iBAKnB,CAAC,IACD,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;;;;;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":";;;yCAaW,GAAG,mBACH,GAAG,KAED,GAAG;;;;;uBAKH,CAAC,IACD,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;iBAKnB,CAAC,IACD,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;;;;iBAKlB,CAAC,IACD,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;;;;;oBAMhB,CAAC,IACD,CACZ,CAAK,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvC,CAAK,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAC/C,CAAK,CACF;;;;;;;kBAIU,CAAC;;;;;;;aAMD,MAAM,OAAO,CAAC,CAAC,CAAC;;uBAOhB,CAAC;WAED,eAAe,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;;gBAIlC,CAAC,UACF,WAAW,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;mBAI/B,CAAC,UACF;IACZ,GAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAChB,QAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CAC1B;wBAIU,CAAC,UACF;IAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CAAE;oBAIvE,CAAC,QACD,QAAQ,MACR,QAAQ,UACA,CAAC,SAAT,GAAG,EAAG;2BAEE,CAAC,WAAW,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,QAAQ;2BAChE,GAAG,WAAW,CAAC,KAAK,GAAG,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,QAAQ;;;;;8BAM5E,CAAC,QACD,QAAQ,MACR,QAAQ,UACA,CAAC,SAAT,GAAG,EAAG,wBAET,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,2FAGd,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;qCArGP,kBAAkB;4BAC3B,kBAAkB;gCAFd,kBAAkB"}
|
package/src/types.js
CHANGED
|
@@ -29,6 +29,12 @@ export {};
|
|
|
29
29
|
* @typedef {T | PromiseLike<T>} ERef
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Eventually a value T or Vow for it.
|
|
34
|
+
* @template T
|
|
35
|
+
* @typedef {ERef<T | Vow<T>>} EVow
|
|
36
|
+
*/
|
|
37
|
+
|
|
32
38
|
/**
|
|
33
39
|
* Follow the chain of vow shortening to the end, returning the final value.
|
|
34
40
|
* This is used within E, so we must narrow the type to its remote form.
|
|
@@ -86,3 +92,17 @@ export {};
|
|
|
86
92
|
* @property {(value: T, ...args: C) => Vow<TResult1> | PromiseVow<TResult1> | TResult1} [onFulfilled]
|
|
87
93
|
* @property {(reason: any, ...args: C) => Vow<TResult2> | PromiseVow<TResult2> | TResult2} [onRejected]
|
|
88
94
|
*/
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Converts a vow or promise to a promise, ensuring proper handling of ephemeral promises.
|
|
98
|
+
*
|
|
99
|
+
* @template [T=any]
|
|
100
|
+
* @template [TResult1=T]
|
|
101
|
+
* @template [TResult2=never]
|
|
102
|
+
* @template {any[]} [C=any[]]
|
|
103
|
+
* @callback AsPromiseFunction
|
|
104
|
+
* @param {ERef<T | Vow<T>>} specimenP
|
|
105
|
+
* @param {Watcher<T, TResult1, TResult2, C>} [watcher]
|
|
106
|
+
* @param {C} [watcherArgs]
|
|
107
|
+
* @returns {Promise<TResult1 | TResult2>}
|
|
108
|
+
*/
|
package/src/vow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vow.d.ts","sourceRoot":"","sources":["vow.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vow.d.ts","sourceRoot":"","sources":["vow.js"],"names":[],"mappings":"AA0BO,oCAFI,IAAI,IAkLA,CAAC,OACD,OAAO,CAAC,CAAC,CASvB;0BAjMY,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC,GACpC,IAAQ,CAAC,WAAW,GAAG,CAAC,EAAE,SAAS,CAAC;yBAiMvB,UAAU,CAAC,OAAO,aAAa,CAAC;0BA3MvB,mBAAmB;4BAEJ,YAAY;gCAHrB,mBAAmB"}
|
package/src/vow.js
CHANGED
|
@@ -4,10 +4,13 @@ import { M } from '@endo/patterns';
|
|
|
4
4
|
import { makeTagged } from '@endo/pass-style';
|
|
5
5
|
import { PromiseWatcherI } from '@agoric/base-zone';
|
|
6
6
|
|
|
7
|
+
const { details: X } = assert;
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
|
-
* @import {PromiseKit} from '@endo/promise-kit'
|
|
9
|
-
* @import {Zone} from '@agoric/base-zone'
|
|
10
|
-
* @import {
|
|
10
|
+
* @import {PromiseKit} from '@endo/promise-kit';
|
|
11
|
+
* @import {Zone} from '@agoric/base-zone';
|
|
12
|
+
* @import {MapStore} from '@agoric/store';
|
|
13
|
+
* @import {VowResolver, VowKit} from './types.js';
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
const sink = () => {};
|
|
@@ -25,6 +28,9 @@ export const prepareVowKit = zone => {
|
|
|
25
28
|
/** @type {WeakMap<VowResolver, VowEphemera>} */
|
|
26
29
|
const resolverToEphemera = new WeakMap();
|
|
27
30
|
|
|
31
|
+
/** @type {WeakMap<VowResolver, any>} */
|
|
32
|
+
const resolverToNonStoredValue = new WeakMap();
|
|
33
|
+
|
|
28
34
|
/**
|
|
29
35
|
* Get the current incarnation's promise kit associated with a vowV0.
|
|
30
36
|
*
|
|
@@ -61,17 +67,24 @@ export const prepareVowKit = zone => {
|
|
|
61
67
|
shorten: M.call().returns(M.promise()),
|
|
62
68
|
}),
|
|
63
69
|
resolver: M.interface('VowResolver', {
|
|
64
|
-
resolve: M.call().optional(M.
|
|
65
|
-
reject: M.call().optional(M.
|
|
70
|
+
resolve: M.call().optional(M.raw()).returns(),
|
|
71
|
+
reject: M.call().optional(M.raw()).returns(),
|
|
66
72
|
}),
|
|
67
73
|
watchNextStep: PromiseWatcherI,
|
|
68
74
|
},
|
|
69
75
|
() => ({
|
|
70
|
-
value: undefined,
|
|
76
|
+
value: /** @type {any} */ (undefined),
|
|
71
77
|
// The stepStatus is null if the promise step hasn't settled yet.
|
|
72
78
|
stepStatus: /** @type {null | 'pending' | 'fulfilled' | 'rejected'} */ (
|
|
73
79
|
null
|
|
74
80
|
),
|
|
81
|
+
isStoredValue: /** @type {boolean} */ (false),
|
|
82
|
+
/**
|
|
83
|
+
* Map for future properties that aren't in the schema.
|
|
84
|
+
* UNTIL https://github.com/Agoric/agoric-sdk/issues/7407
|
|
85
|
+
* @type {MapStore<any, any> | undefined}
|
|
86
|
+
*/
|
|
87
|
+
extra: undefined,
|
|
75
88
|
}),
|
|
76
89
|
{
|
|
77
90
|
vowV0: {
|
|
@@ -79,12 +92,30 @@ export const prepareVowKit = zone => {
|
|
|
79
92
|
* @returns {Promise<any>}
|
|
80
93
|
*/
|
|
81
94
|
async shorten() {
|
|
82
|
-
const { stepStatus, value } = this.state;
|
|
95
|
+
const { stepStatus, isStoredValue, value } = this.state;
|
|
96
|
+
const { resolver } = this.facets;
|
|
97
|
+
|
|
83
98
|
switch (stepStatus) {
|
|
84
|
-
case 'fulfilled':
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
case 'fulfilled': {
|
|
100
|
+
if (isStoredValue) {
|
|
101
|
+
// Always return a stored fulfilled value.
|
|
102
|
+
return value;
|
|
103
|
+
} else if (resolverToNonStoredValue.has(resolver)) {
|
|
104
|
+
// Non-stored value is available.
|
|
105
|
+
return resolverToNonStoredValue.get(resolver);
|
|
106
|
+
}
|
|
107
|
+
// We can't recover the non-stored value, so throw the
|
|
108
|
+
// explanation.
|
|
87
109
|
throw value;
|
|
110
|
+
}
|
|
111
|
+
case 'rejected': {
|
|
112
|
+
if (!isStoredValue && resolverToNonStoredValue.has(resolver)) {
|
|
113
|
+
// Non-stored reason is available.
|
|
114
|
+
throw resolverToNonStoredValue.get(resolver);
|
|
115
|
+
}
|
|
116
|
+
// Always throw a stored rejection reason.
|
|
117
|
+
throw value;
|
|
118
|
+
}
|
|
88
119
|
case null:
|
|
89
120
|
case 'pending':
|
|
90
121
|
return provideCurrentKit(this.facets.resolver).promise;
|
|
@@ -131,15 +162,38 @@ export const prepareVowKit = zone => {
|
|
|
131
162
|
onFulfilled(value) {
|
|
132
163
|
const { resolver } = this.facets;
|
|
133
164
|
const { resolve } = getPromiseKitForResolution(resolver);
|
|
165
|
+
harden(value);
|
|
134
166
|
if (resolve) {
|
|
135
167
|
resolve(value);
|
|
136
168
|
}
|
|
137
169
|
this.state.stepStatus = 'fulfilled';
|
|
138
|
-
this.state.
|
|
170
|
+
this.state.isStoredValue = zone.isStorable(value);
|
|
171
|
+
if (this.state.isStoredValue) {
|
|
172
|
+
this.state.value = value;
|
|
173
|
+
} else {
|
|
174
|
+
resolverToNonStoredValue.set(resolver, value);
|
|
175
|
+
this.state.value = assert.error(
|
|
176
|
+
X`Vow fulfillment value was not stored: ${value}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
139
179
|
},
|
|
140
180
|
onRejected(reason) {
|
|
181
|
+
const { resolver } = this.facets;
|
|
182
|
+
const { reject } = getPromiseKitForResolution(resolver);
|
|
183
|
+
harden(reason);
|
|
184
|
+
if (reject) {
|
|
185
|
+
reject(reason);
|
|
186
|
+
}
|
|
141
187
|
this.state.stepStatus = 'rejected';
|
|
142
|
-
this.state.
|
|
188
|
+
this.state.isStoredValue = zone.isStorable(reason);
|
|
189
|
+
if (this.state.isStoredValue) {
|
|
190
|
+
this.state.value = reason;
|
|
191
|
+
} else {
|
|
192
|
+
resolverToNonStoredValue.set(resolver, reason);
|
|
193
|
+
this.state.value = assert.error(
|
|
194
|
+
X`Vow rejection reason was not stored: ${reason}`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
143
197
|
},
|
|
144
198
|
},
|
|
145
199
|
},
|
package/src/watch-utils.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
export function prepareWatchUtils(zone: Zone, watch
|
|
1
|
+
export function prepareWatchUtils(zone: Zone, { watch, when, makeVowKit, isRetryableReason }: {
|
|
2
|
+
watch: Watch;
|
|
3
|
+
when: When;
|
|
4
|
+
makeVowKit: () => VowKit<any>;
|
|
5
|
+
isRetryableReason: IsRetryableReason;
|
|
6
|
+
}): () => import("@endo/exo").Guarded<{
|
|
2
7
|
/**
|
|
3
|
-
* @param {unknown[]} vows
|
|
8
|
+
* @param {EVow<unknown>[]} vows
|
|
4
9
|
*/
|
|
5
|
-
all(vows: unknown[]): import("./types.js").Vow<any[]>;
|
|
10
|
+
all(vows: EVow<unknown>[]): import("./types.js").Vow<any[]>;
|
|
11
|
+
/** @type {AsPromiseFunction} */
|
|
12
|
+
asPromise(specimenP: any, watcher: import("./types.js").Watcher<any, any, never, any[]> | undefined, watcherArgs: any[] | undefined): Promise<any | never>;
|
|
6
13
|
}>;
|
|
7
14
|
import type { Zone } from '@agoric/base-zone';
|
|
8
15
|
import type { Watch } from './watch.js';
|
|
16
|
+
import type { When } from './when.js';
|
|
9
17
|
import type { VowKit } from './types.js';
|
|
18
|
+
import type { IsRetryableReason } from './types.js';
|
|
19
|
+
import type { EVow } from './types.js';
|
|
10
20
|
//# sourceMappingURL=watch-utils.d.ts.map
|
package/src/watch-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-utils.d.ts","sourceRoot":"","sources":["watch-utils.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"watch-utils.d.ts","sourceRoot":"","sources":["watch-utils.js"],"names":[],"mappings":"AA4CO,wCAPI,IAAI,kDAEZ;IAAsB,KAAK,EAAnB,KAAK;IACQ,IAAI,EAAjB,IAAI;IACsB,UAAU,EAApC,MAAM,OAAO,GAAG,CAAC;IACS,iBAAiB,EAA3C,iBAAiB;CAC3B;IAsCO;;OAEG;cADQ,KAAK,OAAO,CAAC,EAAE;IAuC1B,gCAAgC;;GAgGvC;0BAhNsB,mBAAmB;2BAClB,YAAY;0BACb,WAAW;4BACmC,YAAY;uCAAZ,YAAY;0BAAZ,YAAY"}
|
package/src/watch-utils.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { M } from '@endo/patterns';
|
|
4
|
+
import { PromiseWatcherI } from '@agoric/base-zone';
|
|
5
|
+
|
|
6
|
+
const { Fail, bare, details: X } = assert;
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
|
-
* @import {MapStore} from '@agoric/store/src/types.js'
|
|
7
|
-
* @import {
|
|
8
|
-
* @import {
|
|
9
|
-
* @import {
|
|
9
|
+
* @import {MapStore} from '@agoric/store/src/types.js';
|
|
10
|
+
* @import {Zone} from '@agoric/base-zone';
|
|
11
|
+
* @import {Watch} from './watch.js';
|
|
12
|
+
* @import {When} from './when.js';
|
|
13
|
+
* @import {VowKit, AsPromiseFunction, IsRetryableReason, EVow} from './types.js';
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
const VowShape = M.tagged(
|
|
@@ -16,23 +20,47 @@ const VowShape = M.tagged(
|
|
|
16
20
|
}),
|
|
17
21
|
);
|
|
18
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Like `provideLazy`, but accepts non-Passable values.
|
|
25
|
+
*
|
|
26
|
+
* @param {WeakMap} map
|
|
27
|
+
* @param {any} key
|
|
28
|
+
* @param {(key: any) => any} makeValue
|
|
29
|
+
*/
|
|
30
|
+
const provideLazyMap = (map, key, makeValue) => {
|
|
31
|
+
if (!map.has(key)) {
|
|
32
|
+
map.set(key, makeValue(key));
|
|
33
|
+
}
|
|
34
|
+
return map.get(key);
|
|
35
|
+
};
|
|
36
|
+
|
|
19
37
|
/**
|
|
20
38
|
* @param {Zone} zone
|
|
21
|
-
* @param {
|
|
22
|
-
* @param {
|
|
39
|
+
* @param {object} powers
|
|
40
|
+
* @param {Watch} powers.watch
|
|
41
|
+
* @param {When} powers.when
|
|
42
|
+
* @param {() => VowKit<any>} powers.makeVowKit
|
|
43
|
+
* @param {IsRetryableReason} powers.isRetryableReason
|
|
23
44
|
*/
|
|
24
|
-
export const prepareWatchUtils = (
|
|
45
|
+
export const prepareWatchUtils = (
|
|
46
|
+
zone,
|
|
47
|
+
{ watch, when, makeVowKit, isRetryableReason },
|
|
48
|
+
) => {
|
|
25
49
|
const detached = zone.detached();
|
|
50
|
+
const utilsToNonStorableResults = new WeakMap();
|
|
51
|
+
|
|
26
52
|
const makeWatchUtilsKit = zone.exoClassKit(
|
|
27
53
|
'WatchUtils',
|
|
28
54
|
{
|
|
29
55
|
utils: M.interface('Utils', {
|
|
30
56
|
all: M.call(M.arrayOf(M.any())).returns(VowShape),
|
|
57
|
+
asPromise: M.call(M.raw()).rest(M.raw()).returns(M.promise()),
|
|
31
58
|
}),
|
|
32
59
|
watcher: M.interface('Watcher', {
|
|
33
60
|
onFulfilled: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
34
61
|
onRejected: M.call(M.any()).rest(M.any()).returns(M.any()),
|
|
35
62
|
}),
|
|
63
|
+
retryRejectionPromiseWatcher: PromiseWatcherI,
|
|
36
64
|
},
|
|
37
65
|
() => {
|
|
38
66
|
/**
|
|
@@ -52,7 +80,7 @@ export const prepareWatchUtils = (zone, watch, makeVowKit) => {
|
|
|
52
80
|
{
|
|
53
81
|
utils: {
|
|
54
82
|
/**
|
|
55
|
-
* @param {unknown[]} vows
|
|
83
|
+
* @param {EVow<unknown>[]} vows
|
|
56
84
|
*/
|
|
57
85
|
all(vows) {
|
|
58
86
|
const { nextId: id, idToVowState } = this.state;
|
|
@@ -60,40 +88,75 @@ export const prepareWatchUtils = (zone, watch, makeVowKit) => {
|
|
|
60
88
|
const kit = makeVowKit();
|
|
61
89
|
|
|
62
90
|
// Preserve the order of the vow results.
|
|
63
|
-
let index = 0;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
91
|
+
for (let index = 0; index < vows.length; index += 1) {
|
|
92
|
+
watch(vows[index], this.facets.watcher, {
|
|
93
|
+
id,
|
|
94
|
+
index,
|
|
95
|
+
numResults: vows.length,
|
|
96
|
+
});
|
|
67
97
|
}
|
|
68
98
|
|
|
69
|
-
if (
|
|
99
|
+
if (vows.length > 0) {
|
|
70
100
|
// Save the state until rejection or all fulfilled.
|
|
71
101
|
this.state.nextId += 1n;
|
|
72
102
|
idToVowState.init(
|
|
73
103
|
id,
|
|
74
104
|
harden({
|
|
75
105
|
resolver: kit.resolver,
|
|
76
|
-
remaining:
|
|
106
|
+
remaining: vows.length,
|
|
77
107
|
resultsMap: detached.mapStore('resultsMap'),
|
|
78
108
|
}),
|
|
79
109
|
);
|
|
110
|
+
const idToNonStorableResults = provideLazyMap(
|
|
111
|
+
utilsToNonStorableResults,
|
|
112
|
+
this.facets.utils,
|
|
113
|
+
() => new Map(),
|
|
114
|
+
);
|
|
115
|
+
idToNonStorableResults.set(id, new Map());
|
|
80
116
|
} else {
|
|
81
117
|
// Base case: nothing to wait for.
|
|
82
118
|
kit.resolver.resolve(harden([]));
|
|
83
119
|
}
|
|
84
120
|
return kit.vow;
|
|
85
121
|
},
|
|
122
|
+
/** @type {AsPromiseFunction} */
|
|
123
|
+
asPromise(specimenP, ...watcherArgs) {
|
|
124
|
+
// Watch the specimen in case it is an ephemeral promise.
|
|
125
|
+
const vow = watch(specimenP, ...watcherArgs);
|
|
126
|
+
const promise = when(vow);
|
|
127
|
+
// Watch the ephemeral result promise to ensure that if its settlement is
|
|
128
|
+
// lost due to upgrade of this incarnation, we will at least cause an
|
|
129
|
+
// unhandled rejection in the new incarnation.
|
|
130
|
+
zone.watchPromise(promise, this.facets.retryRejectionPromiseWatcher);
|
|
131
|
+
|
|
132
|
+
return promise;
|
|
133
|
+
},
|
|
86
134
|
},
|
|
87
135
|
watcher: {
|
|
88
|
-
onFulfilled(value, { id, index }) {
|
|
136
|
+
onFulfilled(value, { id, index, numResults }) {
|
|
89
137
|
const { idToVowState } = this.state;
|
|
90
138
|
if (!idToVowState.has(id)) {
|
|
91
139
|
// Resolution of the returned vow happened already.
|
|
92
140
|
return;
|
|
93
141
|
}
|
|
94
142
|
const { remaining, resultsMap, resolver } = idToVowState.get(id);
|
|
143
|
+
const idToNonStorableResults = provideLazyMap(
|
|
144
|
+
utilsToNonStorableResults,
|
|
145
|
+
this.facets.utils,
|
|
146
|
+
() => new Map(),
|
|
147
|
+
);
|
|
148
|
+
const nonStorableResults = provideLazyMap(
|
|
149
|
+
idToNonStorableResults,
|
|
150
|
+
id,
|
|
151
|
+
() => new Map(),
|
|
152
|
+
);
|
|
153
|
+
|
|
95
154
|
// Capture the fulfilled value.
|
|
96
|
-
|
|
155
|
+
if (zone.isStorable(value)) {
|
|
156
|
+
resultsMap.init(index, value);
|
|
157
|
+
} else {
|
|
158
|
+
nonStorableResults.set(index, value);
|
|
159
|
+
}
|
|
97
160
|
const vowState = harden({
|
|
98
161
|
remaining: remaining - 1,
|
|
99
162
|
resultsMap,
|
|
@@ -105,13 +168,26 @@ export const prepareWatchUtils = (zone, watch, makeVowKit) => {
|
|
|
105
168
|
}
|
|
106
169
|
// We're done! Extract the array.
|
|
107
170
|
idToVowState.delete(id);
|
|
108
|
-
const results = new Array(
|
|
109
|
-
|
|
110
|
-
|
|
171
|
+
const results = new Array(numResults);
|
|
172
|
+
let numLost = 0;
|
|
173
|
+
for (let i = 0; i < numResults; i += 1) {
|
|
174
|
+
if (nonStorableResults.has(i)) {
|
|
175
|
+
results[i] = nonStorableResults.get(i);
|
|
176
|
+
} else if (resultsMap.has(i)) {
|
|
177
|
+
results[i] = resultsMap.get(i);
|
|
178
|
+
} else {
|
|
179
|
+
numLost += 1;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (numLost > 0) {
|
|
183
|
+
resolver.reject(
|
|
184
|
+
assert.error(X`${numLost} unstorable results were lost`),
|
|
185
|
+
);
|
|
186
|
+
} else {
|
|
187
|
+
resolver.resolve(harden(results));
|
|
111
188
|
}
|
|
112
|
-
resolver.resolve(harden(results));
|
|
113
189
|
},
|
|
114
|
-
onRejected(value, { id, index: _index }) {
|
|
190
|
+
onRejected(value, { id, index: _index, numResults: _numResults }) {
|
|
115
191
|
const { idToVowState } = this.state;
|
|
116
192
|
if (!idToVowState.has(id)) {
|
|
117
193
|
// First rejection wins.
|
|
@@ -122,6 +198,14 @@ export const prepareWatchUtils = (zone, watch, makeVowKit) => {
|
|
|
122
198
|
resolver.reject(value);
|
|
123
199
|
},
|
|
124
200
|
},
|
|
201
|
+
retryRejectionPromiseWatcher: {
|
|
202
|
+
onFulfilled(_result) {},
|
|
203
|
+
onRejected(reason, failedOp) {
|
|
204
|
+
if (isRetryableReason(reason, undefined)) {
|
|
205
|
+
Fail`Pending ${bare(failedOp)} could not retry; ${reason}`;
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
},
|
|
125
209
|
},
|
|
126
210
|
);
|
|
127
211
|
|
package/src/watch.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export function prepareWatch(zone: Zone, makeVowKit: () => VowKit<any>, isRetryableReason?: ((reason: any, lastValue: any) => any) | undefined): <T = any, TResult1 = T, TResult2 = never, C extends any[] = any[]>(specimenP:
|
|
1
|
+
export function prepareWatch(zone: Zone, makeVowKit: () => VowKit<any>, isRetryableReason?: ((reason: any, lastValue: any) => any) | undefined): <T = any, TResult1 = T, TResult2 = never, C extends any[] = any[]>(specimenP: EVow<T>, watcher?: Watcher<T, TResult1, TResult2, C> | undefined, ...watcherArgs: C) => Vow<Exclude<TResult1, void> | Exclude<TResult2, void> extends never ? TResult1 : Exclude<TResult1, void> | Exclude<TResult2, void>>;
|
|
2
2
|
export type Watch = ReturnType<typeof prepareWatch>;
|
|
3
3
|
import type { Zone } from '@agoric/base-zone';
|
|
4
4
|
import type { VowKit } from './types.js';
|
|
5
|
-
import type {
|
|
6
|
-
import type { ERef } from './types.js';
|
|
5
|
+
import type { EVow } from './types.js';
|
|
7
6
|
import type { Watcher } from './types.js';
|
|
7
|
+
import type { Vow } from './types.js';
|
|
8
8
|
//# sourceMappingURL=watch.d.ts.map
|
package/src/watch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["watch.js"],"names":[],"mappings":"AA2JO,mCAJI,IAAI,cACJ,MAAM,OAAO,GAAG,CAAC,gCACR,GAAG,aAAa,GAAG,KAAK,GAAG,iBAe/B,CAAC,QACD,QAAQ,MACR,QAAQ,UACA,CAAC,SAAT,GAAG,EAAG,qBACT,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["watch.js"],"names":[],"mappings":"AA2JO,mCAJI,IAAI,cACJ,MAAM,OAAO,GAAG,CAAC,gCACR,GAAG,aAAa,GAAG,KAAK,GAAG,iBAe/B,CAAC,QACD,QAAQ,MACR,QAAQ,UACA,CAAC,SAAT,GAAG,EAAG,qBACT,KAAK,CAAC,CAAC,2EAEP,CAAC,yIAoBb;oBAIa,UAAU,CAAC,OAAO,YAAY,CAAC;0BA/LJ,mBAAmB;4BACyB,YAAY;0BAAZ,YAAY;6BAAZ,YAAY;yBAAZ,YAAY"}
|
package/src/watch.js
CHANGED
|
@@ -6,7 +6,7 @@ const { apply } = Reflect;
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @import { PromiseWatcher, Zone } from '@agoric/base-zone';
|
|
9
|
-
* @import { ERef, IsRetryableReason, Vow, VowKit, VowResolver, Watcher } from './types.js';
|
|
9
|
+
* @import { ERef, EVow, IsRetryableReason, Vow, VowKit, VowResolver, Watcher } from './types.js';
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -170,7 +170,7 @@ export const prepareWatch = (
|
|
|
170
170
|
* @template [TResult1=T]
|
|
171
171
|
* @template [TResult2=never]
|
|
172
172
|
* @template {any[]} [C=any[]] watcher args
|
|
173
|
-
* @param {
|
|
173
|
+
* @param {EVow<T>} specimenP
|
|
174
174
|
* @param {Watcher<T, TResult1, TResult2, C>} [watcher]
|
|
175
175
|
* @param {C} watcherArgs
|
|
176
176
|
*/
|