@agoric/vow 0.2.0-upgrade-17-dev-a1453b2.0 → 0.2.0-upgrade-18-dev-bf39b10.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/README.md +64 -3
- package/package.json +16 -15
- package/src/E.d.ts.map +1 -1
- package/src/index.d.ts +1 -3
- package/src/index.d.ts.map +1 -1
- package/src/index.js +1 -8
- package/src/message-breakpoints.d.ts.map +1 -1
- package/src/retryable.d.ts +75 -0
- package/src/retryable.d.ts.map +1 -0
- package/src/retryable.js +224 -0
- package/src/tools.d.ts +2 -13
- package/src/tools.d.ts.map +1 -1
- package/src/tools.js +32 -21
- package/src/types-index.d.ts +5 -0
- package/src/types-index.js +2 -0
- package/src/types.d.ts +72 -5
- package/src/types.d.ts.map +1 -1
- package/src/types.ts +196 -0
- package/src/vow-utils.js +1 -1
- package/src/vow.d.ts.map +1 -1
- package/src/watch-utils.d.ts +12 -6
- package/src/watch-utils.d.ts.map +1 -1
- package/src/watch-utils.js +100 -40
- package/vat.js +10 -2
- package/src/types.js +0 -108
package/src/types.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { Remote } from '@agoric/internal';
|
|
2
|
+
import type { Zone } from '@agoric/zone';
|
|
3
|
+
import type { CopyTagged, RemotableObject } from '@endo/pass-style';
|
|
1
4
|
/**
|
|
2
5
|
* Return truthy if a rejection reason should result in a retry.
|
|
3
6
|
*/
|
|
@@ -16,7 +19,7 @@ export type EVow<T> = ERef<T | Vow<T>>;
|
|
|
16
19
|
* Follow the chain of vow shortening to the end, returning the final value.
|
|
17
20
|
* This is used within E, so we must narrow the type to its remote form.
|
|
18
21
|
*/
|
|
19
|
-
export type EUnwrap<T> =
|
|
22
|
+
export type EUnwrap<T> = T extends Vow<infer U> ? EUnwrap<U> : T extends PromiseLike<infer U> ? EUnwrap<U> : T;
|
|
20
23
|
/**
|
|
21
24
|
* The first version of the vow implementation
|
|
22
25
|
* object. CAVEAT: These methods must never be changed or added to, to provide
|
|
@@ -35,7 +38,10 @@ export type VowV0<T = any> = {
|
|
|
35
38
|
export type VowPayload<T = any> = {
|
|
36
39
|
vowV0: RemotableObject & Remote<VowV0<T>>;
|
|
37
40
|
};
|
|
38
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Vows are objects that represent promises that can be stored durably.
|
|
43
|
+
*/
|
|
44
|
+
export type Vow<T = any> = CopyTagged<'Vow', VowPayload<T>>;
|
|
39
45
|
export type VowKit<T = any> = {
|
|
40
46
|
vow: Vow<T>;
|
|
41
47
|
resolver: VowResolver<T>;
|
|
@@ -52,7 +58,68 @@ export type Watcher<T = any, TResult1 = T, TResult2 = never, C extends any[] = a
|
|
|
52
58
|
* Converts a vow or promise to a promise, ensuring proper handling of ephemeral promises.
|
|
53
59
|
*/
|
|
54
60
|
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>;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
export interface RetryableTool {
|
|
62
|
+
/**
|
|
63
|
+
* Create a function that retries the given function if the underlying
|
|
64
|
+
* async function rejects due to an upgrade disconnection. The return value
|
|
65
|
+
* of the created function is a vow that settles to the final retry result.
|
|
66
|
+
*
|
|
67
|
+
* The retried function should be idempotent.
|
|
68
|
+
*
|
|
69
|
+
* @param fnZone the zone for the named function
|
|
70
|
+
* @param name base name to use in the zone
|
|
71
|
+
* @param fn the retried function
|
|
72
|
+
*/
|
|
73
|
+
<F extends (...args: any[]) => Promise<any>>(fnZone: Zone, name: string, fn: F): F extends (...args: infer Args) => Promise<infer R> ? (...args: Args) => Vow<R> : never;
|
|
74
|
+
}
|
|
75
|
+
export type VowTools = {
|
|
76
|
+
/**
|
|
77
|
+
* Vow-tolerant implementation of Promise.all that takes an iterable of vows
|
|
78
|
+
* and other {@link Passable}s and returns a single {@link Vow}. It resolves
|
|
79
|
+
* with an array of values when all of the input's promises or vows are
|
|
80
|
+
* fulfilled and rejects when any of the input's promises or vows are rejected
|
|
81
|
+
* with the first rejection reason.
|
|
82
|
+
*/
|
|
83
|
+
all: (maybeVows: unknown[]) => Vow<any[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Vow-tolerant
|
|
86
|
+
* implementation of Promise.allSettled that takes an iterable of vows and other
|
|
87
|
+
* {@link Passable}s and returns a single {@link Vow}. It resolves when all of
|
|
88
|
+
* the input's promises or vows are settled with an array of settled outcome
|
|
89
|
+
* objects.
|
|
90
|
+
*/
|
|
91
|
+
allSettled: (maybeVows: unknown[]) => Vow<({
|
|
92
|
+
status: 'fulfilled';
|
|
93
|
+
value: any;
|
|
94
|
+
} | {
|
|
95
|
+
status: 'rejected';
|
|
96
|
+
reason: any;
|
|
97
|
+
})[]>;
|
|
98
|
+
allVows: (maybeVows: unknown[]) => Vow<any[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Convert a vow or promise to a promise, ensuring proper handling of ephemeral promises.
|
|
101
|
+
*/
|
|
102
|
+
asPromise: AsPromiseFunction;
|
|
103
|
+
/**
|
|
104
|
+
* Helper function that
|
|
105
|
+
* coerces the result of a function to a Vow. Helpful for scenarios like a
|
|
106
|
+
* synchronously thrown error.
|
|
107
|
+
*/
|
|
108
|
+
asVow: <T extends unknown>(fn: (...args: any[]) => Vow<Awaited<T>> | Awaited<T> | PromiseVow<T>) => Vow<Awaited<T>>;
|
|
109
|
+
makeVowKit: <T>() => VowKit<T>;
|
|
110
|
+
retryable: RetryableTool;
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated use `retryable`
|
|
113
|
+
*/
|
|
114
|
+
retriable: RetryableTool;
|
|
115
|
+
watch: <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>>;
|
|
116
|
+
/**
|
|
117
|
+
* Shorten `specimenP` until we achieve a final result.
|
|
118
|
+
*
|
|
119
|
+
* Does not survive upgrade (even if specimenP is a durable Vow).
|
|
120
|
+
*
|
|
121
|
+
* Use only if the Vow will resolve _promptly_ {@see {@link @agoric/swingset-vat/docs/async.md}}.
|
|
122
|
+
*/
|
|
123
|
+
when: <T, TResult1 = EUnwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: EUnwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
|
|
124
|
+
};
|
|
58
125
|
//# sourceMappingURL=types.d.ts.map
|
package/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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"}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/* eslint-disable no-use-before-define */
|
|
2
|
+
import type { Remote } from '@agoric/internal';
|
|
3
|
+
import type { Zone } from '@agoric/zone';
|
|
4
|
+
import type { CopyTagged, RemotableObject } from '@endo/pass-style';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return truthy if a rejection reason should result in a retry.
|
|
8
|
+
*/
|
|
9
|
+
export type IsRetryableReason = (reason: any, priorRetryValue: any) => any;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Return type of a function that may
|
|
13
|
+
* return a promise or a vow.
|
|
14
|
+
*/
|
|
15
|
+
export type PromiseVow<T> = Promise<T | Vow<T>>;
|
|
16
|
+
|
|
17
|
+
export type ERef<T> = T | PromiseLike<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Eventually a value T or Vow for it.
|
|
20
|
+
*/
|
|
21
|
+
export type EVow<T> = ERef<T | Vow<T>>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Follow the chain of vow shortening to the end, returning the final value.
|
|
25
|
+
* This is used within E, so we must narrow the type to its remote form.
|
|
26
|
+
*/
|
|
27
|
+
export type EUnwrap<T> =
|
|
28
|
+
T extends Vow<infer U>
|
|
29
|
+
? EUnwrap<U>
|
|
30
|
+
: T extends PromiseLike<infer U>
|
|
31
|
+
? EUnwrap<U>
|
|
32
|
+
: T;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The first version of the vow implementation
|
|
36
|
+
* object. CAVEAT: These methods must never be changed or added to, to provide
|
|
37
|
+
* forward/backward compatibility. Create a new object and bump its version
|
|
38
|
+
* number instead.
|
|
39
|
+
*/
|
|
40
|
+
export type VowV0<T = any> = {
|
|
41
|
+
/**
|
|
42
|
+
* Attempt to unwrap all vows in this
|
|
43
|
+
* promise chain, returning a promise for the final value. A rejection may
|
|
44
|
+
* indicate a temporary routing failure requiring a retry, otherwise that the
|
|
45
|
+
* decider of the terminal promise rejected it.
|
|
46
|
+
*/
|
|
47
|
+
shorten: () => Promise<T>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type VowPayload<T = any> = {
|
|
51
|
+
vowV0: RemotableObject & Remote<VowV0<T>>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Vows are objects that represent promises that can be stored durably.
|
|
56
|
+
*/
|
|
57
|
+
export type Vow<T = any> = CopyTagged<'Vow', VowPayload<T>>;
|
|
58
|
+
|
|
59
|
+
export type VowKit<T = any> = {
|
|
60
|
+
vow: Vow<T>;
|
|
61
|
+
resolver: VowResolver<T>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type VowResolver<T = any> = {
|
|
65
|
+
resolve(value?: T | PromiseVow<T>): void;
|
|
66
|
+
reject(reason?: any): void;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type Watcher<
|
|
70
|
+
T = any,
|
|
71
|
+
TResult1 = T,
|
|
72
|
+
TResult2 = never,
|
|
73
|
+
C extends any[] = any[],
|
|
74
|
+
> = {
|
|
75
|
+
onFulfilled?:
|
|
76
|
+
| ((
|
|
77
|
+
value: T,
|
|
78
|
+
...args: C
|
|
79
|
+
) => Vow<TResult1> | PromiseVow<TResult1> | TResult1)
|
|
80
|
+
| undefined;
|
|
81
|
+
onRejected?:
|
|
82
|
+
| ((
|
|
83
|
+
reason: any,
|
|
84
|
+
...args: C
|
|
85
|
+
) => Vow<TResult2> | PromiseVow<TResult2> | TResult2)
|
|
86
|
+
| undefined;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Converts a vow or promise to a promise, ensuring proper handling of ephemeral promises.
|
|
91
|
+
*/
|
|
92
|
+
export type AsPromiseFunction<
|
|
93
|
+
T = any,
|
|
94
|
+
TResult1 = T,
|
|
95
|
+
TResult2 = never,
|
|
96
|
+
C extends any[] = any[],
|
|
97
|
+
> = (
|
|
98
|
+
specimenP: ERef<T | Vow<T>>,
|
|
99
|
+
watcher?: Watcher<T, TResult1, TResult2, C> | undefined,
|
|
100
|
+
watcherArgs?: C | undefined,
|
|
101
|
+
) => Promise<TResult1 | TResult2>;
|
|
102
|
+
|
|
103
|
+
export interface RetryableTool {
|
|
104
|
+
/**
|
|
105
|
+
* Create a function that retries the given function if the underlying
|
|
106
|
+
* async function rejects due to an upgrade disconnection. The return value
|
|
107
|
+
* of the created function is a vow that settles to the final retry result.
|
|
108
|
+
*
|
|
109
|
+
* The retried function should be idempotent.
|
|
110
|
+
*
|
|
111
|
+
* @param fnZone the zone for the named function
|
|
112
|
+
* @param name base name to use in the zone
|
|
113
|
+
* @param fn the retried function
|
|
114
|
+
*/
|
|
115
|
+
<F extends (...args: any[]) => Promise<any>>(
|
|
116
|
+
fnZone: Zone,
|
|
117
|
+
name: string,
|
|
118
|
+
fn: F,
|
|
119
|
+
): F extends (...args: infer Args) => Promise<infer R>
|
|
120
|
+
? (...args: Args) => Vow<R>
|
|
121
|
+
: never;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type VowTools = {
|
|
125
|
+
/**
|
|
126
|
+
* Vow-tolerant implementation of Promise.all that takes an iterable of vows
|
|
127
|
+
* and other {@link Passable}s and returns a single {@link Vow}. It resolves
|
|
128
|
+
* with an array of values when all of the input's promises or vows are
|
|
129
|
+
* fulfilled and rejects when any of the input's promises or vows are rejected
|
|
130
|
+
* with the first rejection reason.
|
|
131
|
+
*/
|
|
132
|
+
all: (maybeVows: unknown[]) => Vow<any[]>;
|
|
133
|
+
/**
|
|
134
|
+
* Vow-tolerant
|
|
135
|
+
* implementation of Promise.allSettled that takes an iterable of vows and other
|
|
136
|
+
* {@link Passable}s and returns a single {@link Vow}. It resolves when all of
|
|
137
|
+
* the input's promises or vows are settled with an array of settled outcome
|
|
138
|
+
* objects.
|
|
139
|
+
*/
|
|
140
|
+
allSettled: (maybeVows: unknown[]) => Vow<
|
|
141
|
+
(
|
|
142
|
+
| {
|
|
143
|
+
status: 'fulfilled';
|
|
144
|
+
value: any;
|
|
145
|
+
}
|
|
146
|
+
| {
|
|
147
|
+
status: 'rejected';
|
|
148
|
+
reason: any;
|
|
149
|
+
}
|
|
150
|
+
)[]
|
|
151
|
+
>;
|
|
152
|
+
allVows: (maybeVows: unknown[]) => Vow<any[]>;
|
|
153
|
+
/**
|
|
154
|
+
* Convert a vow or promise to a promise, ensuring proper handling of ephemeral promises.
|
|
155
|
+
*/
|
|
156
|
+
asPromise: AsPromiseFunction;
|
|
157
|
+
/**
|
|
158
|
+
* Helper function that
|
|
159
|
+
* coerces the result of a function to a Vow. Helpful for scenarios like a
|
|
160
|
+
* synchronously thrown error.
|
|
161
|
+
*/
|
|
162
|
+
asVow: <T extends unknown>(
|
|
163
|
+
fn: (...args: any[]) => Vow<Awaited<T>> | Awaited<T> | PromiseVow<T>,
|
|
164
|
+
) => Vow<Awaited<T>>;
|
|
165
|
+
makeVowKit: <T>() => VowKit<T>;
|
|
166
|
+
retryable: RetryableTool;
|
|
167
|
+
/**
|
|
168
|
+
* @deprecated use `retryable`
|
|
169
|
+
*/
|
|
170
|
+
retriable: RetryableTool;
|
|
171
|
+
watch: <T = any, TResult1 = T, TResult2 = never, C extends any[] = any[]>(
|
|
172
|
+
specimenP: EVow<T>,
|
|
173
|
+
watcher?: Watcher<T, TResult1, TResult2, C> | undefined,
|
|
174
|
+
...watcherArgs: C
|
|
175
|
+
) => Vow<
|
|
176
|
+
Exclude<TResult1, void> | Exclude<TResult2, void> extends never
|
|
177
|
+
? TResult1
|
|
178
|
+
: Exclude<TResult1, void> | Exclude<TResult2, void>
|
|
179
|
+
>;
|
|
180
|
+
/**
|
|
181
|
+
* Shorten `specimenP` until we achieve a final result.
|
|
182
|
+
*
|
|
183
|
+
* Does not survive upgrade (even if specimenP is a durable Vow).
|
|
184
|
+
*
|
|
185
|
+
* Use only if the Vow will resolve _promptly_ {@see {@link @agoric/swingset-vat/docs/async.md}}.
|
|
186
|
+
*/
|
|
187
|
+
when: <T, TResult1 = EUnwrap<T>, TResult2 = never>(
|
|
188
|
+
specimenP: T,
|
|
189
|
+
onFulfilled?:
|
|
190
|
+
| ((value: EUnwrap<T>) => TResult1 | PromiseLike<TResult1>)
|
|
191
|
+
| undefined,
|
|
192
|
+
onRejected?:
|
|
193
|
+
| ((reason: any) => TResult2 | PromiseLike<TResult2>)
|
|
194
|
+
| undefined,
|
|
195
|
+
) => Promise<TResult1 | TResult2>;
|
|
196
|
+
};
|
package/src/vow-utils.js
CHANGED
|
@@ -29,7 +29,7 @@ harden(isVow);
|
|
|
29
29
|
/**
|
|
30
30
|
* A vow is a passable tagged as 'Vow'. Its payload is a record with
|
|
31
31
|
* API-versioned remotables. payload.vowV0 is the API for the `watch` and
|
|
32
|
-
* `when` operators to use for
|
|
32
|
+
* `when` operators to use for retryable shortening of the vow chain.
|
|
33
33
|
*
|
|
34
34
|
* If the specimen is a Vow, return its payload, otherwise undefined.
|
|
35
35
|
*
|
package/src/vow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,GAChC,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,SAAS,CAAC;yBAiMvB,UAAU,CAAC,OAAO,aAAa,CAAC;0BA3MvB,mBAAmB;4BAEJ,YAAY;gCAHrB,mBAAmB"}
|
package/src/watch-utils.d.ts
CHANGED
|
@@ -4,17 +4,23 @@ export function prepareWatchUtils(zone: Zone, { watch, when, makeVowKit, isRetry
|
|
|
4
4
|
makeVowKit: () => VowKit<any>;
|
|
5
5
|
isRetryableReason: IsRetryableReason;
|
|
6
6
|
}): () => import("@endo/exo").Guarded<{
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
/** @param {unknown[]} specimens */
|
|
8
|
+
all(specimens: unknown[]): Vow<any[]>;
|
|
9
|
+
/** @param {unknown[]} specimens */
|
|
10
|
+
allSettled(specimens: unknown[]): Vow<({
|
|
11
|
+
status: "fulfilled";
|
|
12
|
+
value: any;
|
|
13
|
+
} | {
|
|
14
|
+
status: "rejected";
|
|
15
|
+
reason: any;
|
|
16
|
+
})[]>;
|
|
11
17
|
/** @type {AsPromiseFunction} */
|
|
12
|
-
asPromise(specimenP: any, watcher
|
|
18
|
+
asPromise(specimenP: any, watcher?: import("./types.js").Watcher<any, any, never, any[]> | undefined, watcherArgs?: any[] | undefined): Promise<any>;
|
|
13
19
|
}>;
|
|
14
20
|
import type { Zone } from '@agoric/base-zone';
|
|
15
21
|
import type { Watch } from './watch.js';
|
|
16
22
|
import type { When } from './when.js';
|
|
17
23
|
import type { VowKit } from './types.js';
|
|
18
24
|
import type { IsRetryableReason } from './types.js';
|
|
19
|
-
import type {
|
|
25
|
+
import type { Vow } from './types.js';
|
|
20
26
|
//# 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":"AA4CO,wCAPI,IAAI,kDAEZ;IAAsB,KAAK,EAAnB,KAAK;IACQ,IAAI,EAAjB,IAAI;IACsB,UAAU,EAApC,MAAM,OAAO,GAAG,CAAC;IACS,iBAAiB,EAA3C,iBAAiB;CAC3B;
|
|
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;IA4CO,mCAAmC;mBAAvB,OAAO,EAAE;IAIrB,mCAAmC;0BAAvB,OAAO,EAAE,GAED,IAAI,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAC,GAAG;QAAC,MAAM,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,GAAG,CAAA;KAAC,CAAC,EAAE,CAAC;IAIlG,gCAAgC;;GAoLvC;0BA5QsB,mBAAmB;2BAClB,YAAY;0BACb,WAAW;4BACkC,YAAY;uCAAZ,YAAY;yBAAZ,YAAY"}
|
package/src/watch-utils.js
CHANGED
|
@@ -10,7 +10,7 @@ const { Fail, bare, details: X } = assert;
|
|
|
10
10
|
* @import {Zone} from '@agoric/base-zone';
|
|
11
11
|
* @import {Watch} from './watch.js';
|
|
12
12
|
* @import {When} from './when.js';
|
|
13
|
-
* @import {VowKit, AsPromiseFunction, IsRetryableReason,
|
|
13
|
+
* @import {VowKit, AsPromiseFunction, IsRetryableReason, Vow} from './types.js';
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const VowShape = M.tagged(
|
|
@@ -54,11 +54,16 @@ export const prepareWatchUtils = (
|
|
|
54
54
|
{
|
|
55
55
|
utils: M.interface('Utils', {
|
|
56
56
|
all: M.call(M.arrayOf(M.any())).returns(VowShape),
|
|
57
|
+
allSettled: M.call(M.arrayOf(M.any())).returns(VowShape),
|
|
57
58
|
asPromise: M.call(M.raw()).rest(M.raw()).returns(M.promise()),
|
|
58
59
|
}),
|
|
59
60
|
watcher: M.interface('Watcher', {
|
|
60
|
-
onFulfilled: M.call(M.
|
|
61
|
-
onRejected: M.call(M.
|
|
61
|
+
onFulfilled: M.call(M.raw()).rest(M.raw()).returns(M.raw()),
|
|
62
|
+
onRejected: M.call(M.raw()).rest(M.raw()).returns(M.raw()),
|
|
63
|
+
}),
|
|
64
|
+
helper: M.interface('Helper', {
|
|
65
|
+
createVow: M.call(M.arrayOf(M.any()), M.boolean()).returns(VowShape),
|
|
66
|
+
processResult: M.call(M.raw()).rest(M.raw()).returns(M.undefined()),
|
|
62
67
|
}),
|
|
63
68
|
retryRejectionPromiseWatcher: PromiseWatcherI,
|
|
64
69
|
},
|
|
@@ -68,6 +73,7 @@ export const prepareWatchUtils = (
|
|
|
68
73
|
* @property {number} remaining
|
|
69
74
|
* @property {MapStore<number, any>} resultsMap
|
|
70
75
|
* @property {VowKit['resolver']} resolver
|
|
76
|
+
* @property {boolean} [isAllSettled]
|
|
71
77
|
*/
|
|
72
78
|
/** @type {MapStore<bigint, VowState>} */
|
|
73
79
|
const idToVowState = detached.mapStore('idToVowState');
|
|
@@ -79,32 +85,83 @@ export const prepareWatchUtils = (
|
|
|
79
85
|
},
|
|
80
86
|
{
|
|
81
87
|
utils: {
|
|
88
|
+
/** @param {unknown[]} specimens */
|
|
89
|
+
all(specimens) {
|
|
90
|
+
return this.facets.helper.createVow(specimens, false);
|
|
91
|
+
},
|
|
92
|
+
/** @param {unknown[]} specimens */
|
|
93
|
+
allSettled(specimens) {
|
|
94
|
+
return /** @type {Vow<({status: 'fulfilled', value: any} | {status: 'rejected', reason: any})[]>} */ (
|
|
95
|
+
this.facets.helper.createVow(specimens, true)
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
/** @type {AsPromiseFunction} */
|
|
99
|
+
asPromise(specimenP, ...watcherArgs) {
|
|
100
|
+
// Watch the specimen in case it is an ephemeral promise.
|
|
101
|
+
const vow = watch(specimenP, ...watcherArgs);
|
|
102
|
+
const promise = when(vow);
|
|
103
|
+
// Watch the ephemeral result promise to ensure that if its settlement is
|
|
104
|
+
// lost due to upgrade of this incarnation, we will at least cause an
|
|
105
|
+
// unhandled rejection in the new incarnation.
|
|
106
|
+
zone.watchPromise(promise, this.facets.retryRejectionPromiseWatcher);
|
|
107
|
+
|
|
108
|
+
return promise;
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
watcher: {
|
|
82
112
|
/**
|
|
83
|
-
* @param {
|
|
113
|
+
* @param {unknown} value
|
|
114
|
+
* @param {object} ctx
|
|
115
|
+
* @param {bigint} ctx.id
|
|
116
|
+
* @param {number} ctx.index
|
|
117
|
+
* @param {number} ctx.numResults
|
|
118
|
+
* @param {boolean} ctx.isAllSettled
|
|
84
119
|
*/
|
|
85
|
-
|
|
120
|
+
onFulfilled(value, ctx) {
|
|
121
|
+
this.facets.helper.processResult(value, ctx, 'fulfilled');
|
|
122
|
+
},
|
|
123
|
+
/**
|
|
124
|
+
* @param {unknown} reason
|
|
125
|
+
* @param {object} ctx
|
|
126
|
+
* @param {bigint} ctx.id
|
|
127
|
+
* @param {number} ctx.index
|
|
128
|
+
* @param {number} ctx.numResults
|
|
129
|
+
* @param {boolean} ctx.isAllSettled
|
|
130
|
+
*/
|
|
131
|
+
onRejected(reason, ctx) {
|
|
132
|
+
this.facets.helper.processResult(reason, ctx, 'rejected');
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
helper: {
|
|
136
|
+
/**
|
|
137
|
+
* @param {unknown[]} specimens
|
|
138
|
+
* @param {boolean} isAllSettled
|
|
139
|
+
*/
|
|
140
|
+
createVow(specimens, isAllSettled) {
|
|
86
141
|
const { nextId: id, idToVowState } = this.state;
|
|
87
142
|
/** @type {VowKit<any[]>} */
|
|
88
143
|
const kit = makeVowKit();
|
|
89
144
|
|
|
90
|
-
// Preserve the order of the
|
|
91
|
-
for (let index = 0; index <
|
|
92
|
-
watch(
|
|
145
|
+
// Preserve the order of the results.
|
|
146
|
+
for (let index = 0; index < specimens.length; index += 1) {
|
|
147
|
+
watch(specimens[index], this.facets.watcher, {
|
|
93
148
|
id,
|
|
94
149
|
index,
|
|
95
|
-
numResults:
|
|
150
|
+
numResults: specimens.length,
|
|
151
|
+
isAllSettled,
|
|
96
152
|
});
|
|
97
153
|
}
|
|
98
154
|
|
|
99
|
-
if (
|
|
155
|
+
if (specimens.length > 0) {
|
|
100
156
|
// Save the state until rejection or all fulfilled.
|
|
101
157
|
this.state.nextId += 1n;
|
|
102
158
|
idToVowState.init(
|
|
103
159
|
id,
|
|
104
160
|
harden({
|
|
105
161
|
resolver: kit.resolver,
|
|
106
|
-
remaining:
|
|
162
|
+
remaining: specimens.length,
|
|
107
163
|
resultsMap: detached.mapStore('resultsMap'),
|
|
164
|
+
isAllSettled,
|
|
108
165
|
}),
|
|
109
166
|
);
|
|
110
167
|
const idToNonStorableResults = provideLazyMap(
|
|
@@ -119,27 +176,36 @@ export const prepareWatchUtils = (
|
|
|
119
176
|
}
|
|
120
177
|
return kit.vow;
|
|
121
178
|
},
|
|
122
|
-
/**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return promise;
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
watcher: {
|
|
136
|
-
onFulfilled(value, { id, index, numResults }) {
|
|
179
|
+
/**
|
|
180
|
+
* @param {unknown} result
|
|
181
|
+
* @param {object} ctx
|
|
182
|
+
* @param {bigint} ctx.id
|
|
183
|
+
* @param {number} ctx.index
|
|
184
|
+
* @param {number} ctx.numResults
|
|
185
|
+
* @param {boolean} ctx.isAllSettled
|
|
186
|
+
* @param {'fulfilled' | 'rejected'} status
|
|
187
|
+
*/
|
|
188
|
+
processResult(result, { id, index, numResults, isAllSettled }, status) {
|
|
137
189
|
const { idToVowState } = this.state;
|
|
138
190
|
if (!idToVowState.has(id)) {
|
|
139
191
|
// Resolution of the returned vow happened already.
|
|
140
192
|
return;
|
|
141
193
|
}
|
|
142
194
|
const { remaining, resultsMap, resolver } = idToVowState.get(id);
|
|
195
|
+
if (!isAllSettled && status === 'rejected') {
|
|
196
|
+
// For 'all', we reject immediately on the first rejection
|
|
197
|
+
idToVowState.delete(id);
|
|
198
|
+
resolver.reject(result);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const possiblyWrappedResult = isAllSettled
|
|
203
|
+
? harden({
|
|
204
|
+
status,
|
|
205
|
+
[status === 'fulfilled' ? 'value' : 'reason']: result,
|
|
206
|
+
})
|
|
207
|
+
: result;
|
|
208
|
+
|
|
143
209
|
const idToNonStorableResults = provideLazyMap(
|
|
144
210
|
utilsToNonStorableResults,
|
|
145
211
|
this.facets.utils,
|
|
@@ -152,15 +218,16 @@ export const prepareWatchUtils = (
|
|
|
152
218
|
);
|
|
153
219
|
|
|
154
220
|
// Capture the fulfilled value.
|
|
155
|
-
if (zone.isStorable(
|
|
156
|
-
resultsMap.init(index,
|
|
221
|
+
if (zone.isStorable(possiblyWrappedResult)) {
|
|
222
|
+
resultsMap.init(index, possiblyWrappedResult);
|
|
157
223
|
} else {
|
|
158
|
-
nonStorableResults.set(index,
|
|
224
|
+
nonStorableResults.set(index, possiblyWrappedResult);
|
|
159
225
|
}
|
|
160
226
|
const vowState = harden({
|
|
161
227
|
remaining: remaining - 1,
|
|
162
228
|
resultsMap,
|
|
163
229
|
resolver,
|
|
230
|
+
isAllSettled,
|
|
164
231
|
});
|
|
165
232
|
if (vowState.remaining > 0) {
|
|
166
233
|
idToVowState.set(id, vowState);
|
|
@@ -177,9 +244,12 @@ export const prepareWatchUtils = (
|
|
|
177
244
|
results[i] = resultsMap.get(i);
|
|
178
245
|
} else {
|
|
179
246
|
numLost += 1;
|
|
247
|
+
results[i] = isAllSettled
|
|
248
|
+
? { status: 'rejected', reason: 'Unstorable result was lost' }
|
|
249
|
+
: undefined;
|
|
180
250
|
}
|
|
181
251
|
}
|
|
182
|
-
if (numLost > 0) {
|
|
252
|
+
if (numLost > 0 && !isAllSettled) {
|
|
183
253
|
resolver.reject(
|
|
184
254
|
assert.error(X`${numLost} unstorable results were lost`),
|
|
185
255
|
);
|
|
@@ -187,16 +257,6 @@ export const prepareWatchUtils = (
|
|
|
187
257
|
resolver.resolve(harden(results));
|
|
188
258
|
}
|
|
189
259
|
},
|
|
190
|
-
onRejected(value, { id, index: _index, numResults: _numResults }) {
|
|
191
|
-
const { idToVowState } = this.state;
|
|
192
|
-
if (!idToVowState.has(id)) {
|
|
193
|
-
// First rejection wins.
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const { resolver } = idToVowState.get(id);
|
|
197
|
-
idToVowState.delete(id);
|
|
198
|
-
resolver.reject(value);
|
|
199
|
-
},
|
|
200
260
|
},
|
|
201
261
|
retryRejectionPromiseWatcher: {
|
|
202
262
|
onFulfilled(_result) {},
|
package/vat.js
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
/* global globalThis */
|
|
7
7
|
// @ts-check
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
isUpgradeDisconnection,
|
|
10
|
+
isAbandonedError,
|
|
11
|
+
} from '@agoric/internal/src/upgrade-api.js';
|
|
9
12
|
import { makeHeapZone } from '@agoric/base-zone/heap.js';
|
|
10
13
|
|
|
11
14
|
import { prepareBasicVowTools } from './src/tools.js';
|
|
@@ -15,11 +18,16 @@ import makeE from './src/E.js';
|
|
|
15
18
|
const isRetryableReason = (reason, priorRetryValue) => {
|
|
16
19
|
if (
|
|
17
20
|
isUpgradeDisconnection(reason) &&
|
|
18
|
-
(!priorRetryValue ||
|
|
21
|
+
(!isUpgradeDisconnection(priorRetryValue) ||
|
|
19
22
|
reason.incarnationNumber > priorRetryValue.incarnationNumber)
|
|
20
23
|
) {
|
|
21
24
|
return reason;
|
|
22
25
|
}
|
|
26
|
+
// For abandoned errors there is no way to differentiate errors from
|
|
27
|
+
// consecutive upgrades
|
|
28
|
+
if (isAbandonedError(reason) && !isAbandonedError(priorRetryValue)) {
|
|
29
|
+
return reason;
|
|
30
|
+
}
|
|
23
31
|
return undefined;
|
|
24
32
|
};
|
|
25
33
|
|