@agoric/vow 0.2.0-upgrade-17-dev-ec448b0.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/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> = (T extends Vow<infer U> ? EUnwrap<U> : T extends PromiseLike<infer U> ? EUnwrap<U> : 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
- export type Vow<T = any> = CopyTagged<"Vow", VowPayload<T>>;
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
- import type { RemotableObject } from '@endo/pass-style';
56
- import type { Remote } from '@agoric/internal';
57
- import type { CopyTagged } from '@endo/pass-style';
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
@@ -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;;;;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"}
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 retriable shortening of the vow chain.
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,GACpC,IAAQ,CAAC,WAAW,GAAG,CAAC,EAAE,SAAS,CAAC;yBAiMvB,UAAU,CAAC,OAAO,aAAa,CAAC;0BA3MvB,mBAAmB;4BAEJ,YAAY;gCAHrB,mBAAmB"}
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"}
@@ -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
- * @param {EVow<unknown>[]} vows
9
- */
10
- all(vows: EVow<unknown>[]): import("./types.js").Vow<any[]>;
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: import("./types.js").Watcher<any, any, never, any[]> | undefined, watcherArgs: any[] | undefined): Promise<any | never>;
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 { EVow } from './types.js';
25
+ import type { Vow } from './types.js';
20
26
  //# sourceMappingURL=watch-utils.d.ts.map
@@ -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;IAsCO;;OAEG;cADQ,KAAK,OAAO,CAAC,EAAE;IAuC1B,gCAAgC;;GAgGvC;0BAhNsB,mBAAmB;2BAClB,YAAY;0BACb,WAAW;4BACmC,YAAY;uCAAZ,YAAY;0BAAZ,YAAY"}
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"}
@@ -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, EVow} from './types.js';
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.any()).rest(M.any()).returns(M.any()),
61
- onRejected: M.call(M.any()).rest(M.any()).returns(M.any()),
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 {EVow<unknown>[]} vows
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
- all(vows) {
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 vow results.
91
- for (let index = 0; index < vows.length; index += 1) {
92
- watch(vows[index], this.facets.watcher, {
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: vows.length,
150
+ numResults: specimens.length,
151
+ isAllSettled,
96
152
  });
97
153
  }
98
154
 
99
- if (vows.length > 0) {
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: vows.length,
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
- /** @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
- },
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(value)) {
156
- resultsMap.init(index, value);
221
+ if (zone.isStorable(possiblyWrappedResult)) {
222
+ resultsMap.init(index, possiblyWrappedResult);
157
223
  } else {
158
- nonStorableResults.set(index, value);
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 { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
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