@agoric/vow 0.1.1-dev-d492653.0 → 0.1.1-dev-4fca040.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/vow",
3
- "version": "0.1.1-dev-d492653.0+d492653",
3
+ "version": "0.1.1-dev-4fca040.0+4fca040",
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-d492653.0+d492653",
24
- "@agoric/internal": "0.3.3-dev-d492653.0+d492653",
23
+ "@agoric/base-zone": "0.1.1-dev-4fca040.0+4fca040",
24
+ "@agoric/internal": "0.3.3-dev-4fca040.0+4fca040",
25
25
  "@endo/env-options": "^1.1.4",
26
26
  "@endo/eventual-send": "^1.2.2",
27
27
  "@endo/pass-style": "^1.4.0",
@@ -53,5 +53,5 @@
53
53
  "typeCoverage": {
54
54
  "atLeast": 89.6
55
55
  },
56
- "gitHead": "d49265372b3cdd681558791b0c780e1c3062bdcc"
56
+ "gitHead": "4fca040204f3d45fc85c51b67e84d3ecb02728c8"
57
57
  }
package/src/tools.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export function prepareVowTools(zone: Zone, powers?: {
2
- isRetryableReason?: ((reason: any) => boolean) | undefined;
2
+ isRetryableReason?: IsRetryableReason | undefined;
3
3
  } | undefined): {
4
4
  when: <T, TResult1 = import("./types.js").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("./types.js").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
5
5
  watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = never, C = any>(specimenP: import("./types.js").ERef<T_1 | import("./types.js").Vow<T_1>>, watcher?: import("./types.js").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => import("./types.js").Vow<Exclude<TResult1_1, void> | Exclude<TResult2_1, void> extends never ? TResult1_1 : Exclude<TResult1_1, void> | Exclude<TResult2_1, void>>;
@@ -7,4 +7,5 @@ export function prepareVowTools(zone: Zone, powers?: {
7
7
  allVows: (vows: unknown[]) => import("./types.js").Vow<any[]>;
8
8
  };
9
9
  import type { Zone } from '@agoric/base-zone';
10
+ import type { IsRetryableReason } from './types.js';
10
11
  //# sourceMappingURL=tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["tools.js"],"names":[],"mappings":"AAaO;kCAFa,GAAG,KAAK,OAAO;;sFAEc,CAAC;;;oBAWrC,OAAO,EAAE;EAKrB;0BAvBuB,mBAAmB"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["tools.js"],"names":[],"mappings":"AAcO;;;sFACL,CAAF;;;oBAWa,OAAO,EAAE;EAKrB;0BAzBuB,mBAAmB;uCACN,YAAY"}
package/src/tools.js CHANGED
@@ -5,14 +5,16 @@ import { prepareWatch } from './watch.js';
5
5
  import { prepareWatchUtils } from './watch-utils.js';
6
6
 
7
7
  /** @import {Zone} from '@agoric/base-zone' */
8
+ /** @import {IsRetryableReason} from './types.js' */
8
9
 
9
10
  /**
10
11
  * @param {Zone} zone
11
12
  * @param {object} [powers]
12
- * @param {(reason: any) => boolean} [powers.isRetryableReason]
13
+ * @param {IsRetryableReason} [powers.isRetryableReason]
13
14
  */
14
15
  export const prepareVowTools = (zone, powers = {}) => {
15
- const { isRetryableReason = () => false } = powers;
16
+ const { isRetryableReason = /** @type {IsRetryableReason} */ (() => false) } =
17
+ powers;
16
18
  const makeVowKit = prepareVowKit(zone);
17
19
  const when = makeWhen(isRetryableReason);
18
20
  const watch = prepareWatch(zone, makeVowKit, isRetryableReason);
package/src/types.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Return truthy if a rejection reason should result in a retry.
3
+ */
4
+ export type IsRetryableReason = (reason: any, priorRetryValue: any) => any;
1
5
  /**
2
6
  * Return type of a function that may
3
7
  * return a promise or a vow.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":";;;;uBAc6B,CAAC,IAAjB,OAAO,CAAS,CAAC,AAAR,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;iBAMH,CAAC,IAAD,CAAC,AAAhB,GAAG,WAAW,CAAC,CAAC,CAAC;;;;;mBAY9B,CAAK;;;;;;;kBAWsB,CAAC;;;;;;;aAAf,MAAM,OAAO,CAAC,CAAC,CAAC;;uBASe,CAAC;;;gBAKJ,CAAC;;;mBAOhB,CAAC,UAFf;IACZ,GAAO,EAAE,GAAG,CACc,CAAC,AADb,CAAC,CAAC;IAChB,QAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CAC1B;wBAK0C,CAAC;oDAAI,IAAI;oBAAkB,GAAG,GAAG,IAAI;;oBAS7D,CAAC,QAAyD,QAAQ,MAClB,QAAQ,UAD3C,CAAC;2BAAd,CAAC,YAAY,CAAC;2BACb,GAAG;;;iEAlE0B,CAAA;;;oBAehB,SACjC;;iCAvBmC,kBAAkB;oCAHvB,qBAAqB;qCAEpB,kBAAkB;4BACd,kBAAkB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":";;;yCAeW,GAAG,mBACH,GAAG,KAED,GAAG;;;;;uBAMa,CAAC,IAAjB,OAAO,CAAS,CAAC,AAAR,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;iBAMH,CAAC,IAAD,CAAC,AAAhB,GAAG,WAAW,CAAC,CAAC,CAAC;;;;;mBAY9B,CAAK;;;;;;;kBAWsB,CAAC;;;;;;;aAAf,MAAM,OAAO,CAAC,CAAC,CAAC;;uBASe,CAAC;;;gBAKJ,CAAC;;;mBAOhB,CAAC,UAFf;IACZ,GAAO,EAAE,GAAG,CACc,CAAC,AADb,CAAC,CAAC;IAChB,QAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CAC1B;wBAK0C,CAAC;oDAAI,IAAI;oBAAkB,GAAG,GAAG,IAAI;;oBAS7D,CAAC,QAAyD,QAAQ,MAClB,QAAQ,UAD3C,CAAC;2BAAd,CAAC,YAAY,CAAC;2BACb,GAAG;;;iEA1EzB,CAAD;;;oBAcsB,SAAS;;iCAvBO,kBAAkB;oCAHvB,qBAAqB;qCAEpB,kBAAkB;4BACd,kBAAkB"}
package/src/types.js CHANGED
@@ -10,6 +10,16 @@ export {};
10
10
  * @import {prepareVowTools} from './tools.js'
11
11
  */
12
12
 
13
+ /**
14
+ * @callback IsRetryableReason
15
+ * Return truthy if a rejection reason should result in a retry.
16
+ * @param {any} reason
17
+ * @param {any} priorRetryValue the previous value returned by this function
18
+ * when deciding whether to retry the same logical operation
19
+ * @returns {any} If falsy, the reason is not retryable. If truthy, the
20
+ * priorRetryValue for the next call.
21
+ */
22
+
13
23
  /**
14
24
  * @template T
15
25
  * @typedef {Promise<T | Vow<T>>} PromiseVow Return type of a function that may
package/src/vow.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vow.d.ts","sourceRoot":"","sources":["vow.js"],"names":[],"mappings":"AAuBO,4CA4Ge,CAAC,iBAStB;;0BApIsB,mBAAmB;4BACJ,YAAY;gCAFrB,mBAAmB"}
1
+ {"version":3,"file":"vow.d.ts","sourceRoot":"","sources":["vow.js"],"names":[],"mappings":"AAuBO,4CA8He,CAAC,iBAStB;;0BAtJsB,mBAAmB;4BACJ,YAAY;gCAFrB,mBAAmB"}
package/src/vow.js CHANGED
@@ -69,7 +69,9 @@ export const prepareVowKit = zone => {
69
69
  () => ({
70
70
  value: undefined,
71
71
  // The stepStatus is null if the promise step hasn't settled yet.
72
- stepStatus: /** @type {null | 'fulfilled' | 'rejected'} */ (null),
72
+ stepStatus: /** @type {null | 'pending' | 'fulfilled' | 'rejected'} */ (
73
+ null
74
+ ),
73
75
  }),
74
76
  {
75
77
  vowV0: {
@@ -84,6 +86,7 @@ export const prepareVowKit = zone => {
84
86
  case 'rejected':
85
87
  throw value;
86
88
  case null:
89
+ case 'pending':
87
90
  return provideCurrentKit(this.facets.resolver).promise;
88
91
  default:
89
92
  throw new TypeError(`unexpected stepStatus ${stepStatus}`);
@@ -96,10 +99,17 @@ export const prepareVowKit = zone => {
96
99
  */
97
100
  resolve(value) {
98
101
  const { resolver } = this.facets;
99
- const { promise, resolve } = getPromiseKitForResolution(resolver);
102
+ const { stepStatus } = this.state;
103
+ const { resolve } = getPromiseKitForResolution(resolver);
100
104
  if (resolve) {
101
105
  resolve(value);
102
- zone.watchPromise(promise, this.facets.watchNextStep);
106
+ }
107
+ if (stepStatus === null) {
108
+ this.state.stepStatus = 'pending';
109
+ zone.watchPromise(
110
+ HandledPromise.resolve(value),
111
+ this.facets.watchNextStep,
112
+ );
103
113
  }
104
114
  },
105
115
  /**
@@ -107,15 +117,23 @@ export const prepareVowKit = zone => {
107
117
  */
108
118
  reject(reason) {
109
119
  const { resolver, watchNextStep } = this.facets;
120
+ const { stepStatus } = this.state;
110
121
  const { reject } = getPromiseKitForResolution(resolver);
111
122
  if (reject) {
112
123
  reject(reason);
124
+ }
125
+ if (stepStatus === null) {
113
126
  watchNextStep.onRejected(reason);
114
127
  }
115
128
  },
116
129
  },
117
130
  watchNextStep: {
118
131
  onFulfilled(value) {
132
+ const { resolver } = this.facets;
133
+ const { resolve } = getPromiseKitForResolution(resolver);
134
+ if (resolve) {
135
+ resolve(value);
136
+ }
119
137
  this.state.stepStatus = 'fulfilled';
120
138
  this.state.value = value;
121
139
  },
package/src/watch.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export function prepareWatch(zone: Zone, makeVowKit: () => VowKit<any>, isRetryableReason?: ((reason: any) => boolean) | undefined): <T = any, TResult1 = T, TResult2 = never, C = any>(specimenP: ERef<T | Vow<T>>, watcher?: Watcher<T, TResult1, TResult2> | undefined, watcherContext?: C | undefined) => Vow<Exclude<TResult1, void> | Exclude<TResult2, void> extends never ? TResult1 : Exclude<TResult1, void> | Exclude<TResult2, void>>;
1
+ export function prepareWatch(zone: Zone, makeVowKit: () => VowKit<any>, isRetryableReason?: ((reason: any, lastValue: any) => any) | undefined): <T = any, TResult1 = T, TResult2 = never, C = any>(specimenP: ERef<T | Vow<T>>, watcher?: Watcher<T, TResult1, TResult2> | undefined, watcherContext?: C | undefined) => 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';
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["watch.js"],"names":[],"mappings":"AAyHO,sGAFa,GAAG,KAAK,OAAO,iBAmBT,CAAC,2SA0B1B;oBAIa,UAAU,CAAC,OAAO,YAAY,CAAC;0BAjKJ,mBAAmB;4BACA,YAAY;yBAAZ,YAAY;0BAAZ,YAAY;6BAAZ,YAAY"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["watch.js"],"names":[],"mappings":"AAkIO,sGAFa,GAAG,aAAa,GAAG,KAAK,GAAG,iBAmBrB,CAAC,2SA0B1B;oBAIa,UAAU,CAAC,OAAO,YAAY,CAAC;0BA1KJ,mBAAmB;4BACmB,YAAY;yBAAZ,YAAY;0BAAZ,YAAY;6BAAZ,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, Vow, VowKit, VowResolver, Watcher } from './types.js';
9
+ * @import { ERef, IsRetryableReason, Vow, VowKit, VowResolver, Watcher } from './types.js';
10
10
  */
11
11
 
12
12
  /**
@@ -62,7 +62,7 @@ const settle = (resolver, watcher, wcb, value, watcherContext) => {
62
62
 
63
63
  /**
64
64
  * @param {Zone} zone
65
- * @param {(reason: any) => boolean} isRetryableReason
65
+ * @param {IsRetryableReason} isRetryableReason
66
66
  * @param {ReturnType<typeof makeWatchNextStep>} watchNextStep
67
67
  */
68
68
  const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) =>
@@ -80,6 +80,7 @@ const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) =>
80
80
  (resolver, watcher, watcherContext) => {
81
81
  const state = {
82
82
  vow: /** @type {unknown} */ (undefined),
83
+ priorRetryValue: /** @type {any} */ (undefined),
83
84
  resolver,
84
85
  watcher,
85
86
  watcherContext: harden(watcherContext),
@@ -96,17 +97,25 @@ const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) =>
96
97
  watchNextStep(value, this.self);
97
98
  return;
98
99
  }
100
+ this.state.priorRetryValue = undefined;
99
101
  this.state.watcher = undefined;
100
102
  this.state.resolver = undefined;
101
103
  settle(resolver, watcher, 'onFulfilled', value, watcherContext);
102
104
  },
103
105
  /** @type {Required<PromiseWatcher>['onRejected']} */
104
106
  onRejected(reason) {
105
- const { vow, watcher, watcherContext, resolver } = this.state;
106
- if (vow && isRetryableReason(reason)) {
107
- watchNextStep(vow, this.self);
108
- return;
107
+ const { vow, watcher, watcherContext, resolver, priorRetryValue } =
108
+ this.state;
109
+ if (vow) {
110
+ const retryValue = isRetryableReason(reason, priorRetryValue);
111
+ if (retryValue) {
112
+ // Retry the same specimen.
113
+ this.state.priorRetryValue = retryValue;
114
+ watchNextStep(vow, this.self);
115
+ return;
116
+ }
109
117
  }
118
+ this.state.priorRetryValue = undefined;
110
119
  this.state.resolver = undefined;
111
120
  this.state.watcher = undefined;
112
121
  settle(resolver, watcher, 'onRejected', reason, watcherContext);
@@ -117,12 +126,12 @@ const preparePromiseWatcher = (zone, isRetryableReason, watchNextStep) =>
117
126
  /**
118
127
  * @param {Zone} zone
119
128
  * @param {() => VowKit<any>} makeVowKit
120
- * @param {(reason: any) => boolean} [isRetryableReason]
129
+ * @param {(reason: any, lastValue: any) => any} [isRetryableReason]
121
130
  */
122
131
  export const prepareWatch = (
123
132
  zone,
124
133
  makeVowKit,
125
- isRetryableReason = _reason => false,
134
+ isRetryableReason = (_reason, _lastValue) => undefined,
126
135
  ) => {
127
136
  const watchNextStep = makeWatchNextStep(zone);
128
137
  const makePromiseWatcher = preparePromiseWatcher(
package/src/when.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export function makeWhen(isRetryableReason?: ((reason: any) => boolean) | undefined): <T, TResult1 = Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
1
+ export function makeWhen(isRetryableReason?: IsRetryableReason | undefined): <T, TResult1 = Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
2
2
  export type When = ReturnType<typeof makeWhen>;
3
+ import type { IsRetryableReason } from './types.js';
3
4
  import type { Unwrap } from './types.js';
4
5
  //# sourceMappingURL=when.d.ts.map
package/src/when.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["when.js"],"names":[],"mappings":"AAQO,uDAFa,GAAG,KAAK,OAAO,iBAUP,CAAC,EAEN,QAAQ,cAAG,QAAQ,qBAFd,CAAC,AADf,uCAGS,QAAQ,AAFY,GAAG,WAAW,CAElC,QAAQ,AAFmC,CAAC,sCAC7C,GAAG,KACS,QAAQ,AADJ,GAAG,WAAW,CAClB,QAAQ,AADmB,CAAC,kBAC/C,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAkC1C;mBAIa,UAAU,CAAC,OAAO,QAAQ,CAAC;4BArDb,YAAY"}
1
+ {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["when.js"],"names":[],"mappings":"AAQO,8EAUqB,CAAC,EAEN,QAAQ,cAAG,QAAQ,qBAFd,CAAC,AADf,uCAGS,QAAQ,AAFY,GAAG,WAAW,CAElC,QAAQ,AAFmC,CAAC,sCAC7C,GAAG,KACS,QAAQ,AADJ,GAAG,WAAW,CAClB,QAAQ,AADmB,CAAC,kBAC/C,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,CA2C1C;mBAIa,UAAU,CAAC,OAAO,QAAQ,CAAC;uCAhEM,YAAY;4BAAZ,YAAY"}
package/src/when.js CHANGED
@@ -1,12 +1,14 @@
1
1
  // @ts-check
2
2
  import { getVowPayload, basicE } from './vow-utils.js';
3
3
 
4
- /** @import { Unwrap } from './types.js' */
4
+ /** @import { IsRetryableReason, Unwrap } from './types.js' */
5
5
 
6
6
  /**
7
- * @param {(reason: any) => boolean} [isRetryableReason]
7
+ * @param {IsRetryableReason} [isRetryableReason]
8
8
  */
9
- export const makeWhen = (isRetryableReason = () => false) => {
9
+ export const makeWhen = (
10
+ isRetryableReason = /** @type {IsRetryableReason} */ (() => false),
11
+ ) => {
10
12
  /**
11
13
  * Shorten `specimenP` until we achieve a final result.
12
14
  *
@@ -25,16 +27,25 @@ export const makeWhen = (isRetryableReason = () => false) => {
25
27
  // Ensure we have a presence that won't be disconnected later.
26
28
  let result = await specimenP;
27
29
  let payload = getVowPayload(result);
30
+ let priorRetryValue;
28
31
  while (payload) {
29
32
  result = await basicE(payload.vowV0)
30
33
  .shorten()
31
- .catch(e => {
32
- if (isRetryableReason(e)) {
33
- // Shorten the same specimen to try again.
34
- return result;
35
- }
36
- throw e;
37
- });
34
+ .then(
35
+ res => {
36
+ priorRetryValue = undefined;
37
+ return res;
38
+ },
39
+ e => {
40
+ const nextValue = isRetryableReason(e, priorRetryValue);
41
+ if (nextValue) {
42
+ // Shorten the same specimen to try again.
43
+ priorRetryValue = nextValue;
44
+ return result;
45
+ }
46
+ throw e;
47
+ },
48
+ );
38
49
  // Advance to the next vow.
39
50
  payload = getVowPayload(result);
40
51
  }