@agoric/async-flow 0.1.1-upgrade-16-dev-d45b478.0 → 0.1.1-upgrade-17-dev-3b97a9f.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.
Files changed (46) hide show
  1. package/index.d.ts +2 -0
  2. package/index.js +2 -0
  3. package/package.json +20 -19
  4. package/src/async-flow.d.ts +19 -12
  5. package/src/async-flow.d.ts.map +1 -1
  6. package/src/async-flow.js +31 -16
  7. package/src/bijection.d.ts +7 -4
  8. package/src/bijection.d.ts.map +1 -1
  9. package/src/bijection.js +90 -15
  10. package/src/convert.d.ts +1 -0
  11. package/src/convert.d.ts.map +1 -1
  12. package/src/convert.js +7 -5
  13. package/src/endowments.d.ts +16 -0
  14. package/src/endowments.d.ts.map +1 -0
  15. package/src/endowments.js +294 -0
  16. package/src/ephemera.d.ts +1 -0
  17. package/src/ephemera.d.ts.map +1 -1
  18. package/src/ephemera.js +4 -0
  19. package/src/equate.js +4 -4
  20. package/src/log-store.d.ts +4 -2
  21. package/src/log-store.d.ts.map +1 -1
  22. package/src/log-store.js +5 -1
  23. package/src/replay-membrane.d.ts +19 -50
  24. package/src/replay-membrane.d.ts.map +1 -1
  25. package/src/replay-membrane.js +218 -18
  26. package/src/type-guards.d.ts.map +1 -1
  27. package/src/type-guards.js +21 -7
  28. package/src/types.d.ts +211 -60
  29. package/src/types.js +1 -164
  30. package/test/async-flow-crank.test.js +6 -0
  31. package/test/async-flow-early-completion.test.js +2 -0
  32. package/test/async-flow-no-this.js +6 -0
  33. package/test/async-flow.test.js +5 -2
  34. package/test/bad-host.test.js +5 -0
  35. package/test/bijection.test.js +12 -6
  36. package/test/convert.test.js +5 -0
  37. package/test/endowments.test.js +157 -0
  38. package/test/equate.test.js +6 -2
  39. package/test/log-store.test.js +9 -1
  40. package/test/replay-membrane-eventual.test.js +134 -8
  41. package/test/replay-membrane-settlement.test.js +24 -5
  42. package/test/replay-membrane-zombie.test.js +43 -14
  43. package/test/replay-membrane.test.js +39 -13
  44. package/test/types.test-d.ts +73 -0
  45. package/tsconfig.json +2 -0
  46. package/src/types.d.ts.map +0 -1
package/src/types.js CHANGED
@@ -1,164 +1 @@
1
- /**
2
- * @import {PromiseKit} from '@endo/promise-kit'
3
- * @import {Passable} from '@endo/pass-style'
4
- * @import {Zone} from '@agoric/base-zone'
5
- * @import {Vow, VowTools} from '@agoric/vow'
6
- * @import {LogStore} from './log-store.js'
7
- * @import {Bijection} from './bijection.js'
8
- * @import {ReplayMembrane} from './replay-membrane.js'
9
- */
10
-
11
- /**
12
- * @typedef {'Running' |
13
- * 'Sleeping' |
14
- * 'Replaying' |
15
- * 'Failed' |
16
- * 'Done'
17
- * } FlowState
18
- */
19
-
20
- /**
21
- * @template {Passable} [T=Passable]
22
- * @typedef {T} Guest
23
- */
24
-
25
- /**
26
- * @template {Passable} [T=Passable]
27
- * @typedef {T} Host
28
- */
29
-
30
- /**
31
- * A HostVow must be durably storable. It corresponds to an
32
- * ephemeral guest promise.
33
- *
34
- * @template {Passable} [T=Passable]
35
- * @typedef {Host<Vow<T>>} HostVow
36
- */
37
-
38
- /**
39
- * @typedef {(...activationArgs: Guest[]) => Guest<Promise>} GuestAsyncFunc
40
- */
41
-
42
- /**
43
- * @typedef {(...activationArgs: Host[]) => HostVow} HostAsyncFuncWrapper
44
- */
45
-
46
- /**
47
- * @typedef {object} PreparationOptions
48
- * @property {VowTools} [vowTools]
49
- * @property {() => LogStore} [makeLogStore]
50
- * @property {() => Bijection} [makeBijection]
51
- */
52
-
53
- /**
54
- * @typedef {'return'|'throw'} OutcomeKind
55
- */
56
-
57
- /**
58
- * @typedef {{kind: 'return', result: any}
59
- * | {kind: 'throw', problem: any}
60
- * } Outcome
61
- */
62
-
63
- /**
64
- * @template {WeakKey} [S=WeakKey]
65
- * @template {any} [V=any]
66
- * @typedef {object} Ephemera
67
- * @property {(self: S) => V} for
68
- * @property {(self: S) => void} resetFor
69
- */
70
-
71
- /**
72
- * This is the typedef for the membrane log entries we currently implement.
73
- * See comment below for the commented-out typedef for the full
74
- * membrane log entry, which we do not yet support.
75
- *
76
- * @typedef {[ // ///////////////// From Host to Guest /////////////////////////
77
- * op: 'doFulfill',
78
- * vow: HostVow,
79
- * fulfillment: Host,
80
- * ] | [
81
- * op: 'doReject',
82
- * vow: HostVow,
83
- * reason: Host,
84
- * ] | [
85
- * op: 'doReturn',
86
- * callIndex: number,
87
- * result: Host,
88
- * ] | [
89
- * op: 'doThrow',
90
- * callIndex: number,
91
- * problem: Host,
92
- * ] | [ // ///////////////////// From Guest to Host /////////////////////////
93
- * op: 'checkCall',
94
- * target: Host,
95
- * optVerb: PropertyKey|undefined,
96
- * args: Host[],
97
- * callIndex: number
98
- * ]} LogEntry
99
- */
100
-
101
- /**
102
- * This would be the typedef for the full membrane log, if we supported
103
- * - the guest sending guest-promises and guest-remotables to the host
104
- * - the guest using `E` to eventual-send to guest wrappers of host
105
- * vows and remotables.
106
- *
107
- * at-typedef {[ // ///////////////// From Host to Guest ///////////////////////
108
- * op: 'doFulfill',
109
- * vow: HostVow,
110
- * fulfillment: Host,
111
- * ] | [
112
- * op: 'doReject',
113
- * vow: HostVow,
114
- * reason: Host,
115
- * ] | [
116
- * op: 'doCall',
117
- * target: Host,
118
- * optVerb: PropertyKey|undefined,
119
- * args: Host[],
120
- * callIndex: number
121
- * ] | [
122
- * op: 'doSend',
123
- * target: Host,
124
- * optVerb: PropertyKey|undefined,
125
- * args: Host[],
126
- * callIndex: number
127
- * ] | [
128
- * op: 'doReturn',
129
- * callIndex: number,
130
- * result: Host,
131
- * ] | [
132
- * op: 'doThrow',
133
- * callIndex: number,
134
- * problem: Host,
135
- * ] | [ // ///////////////////// From Guest to Host /////////////////////////
136
- * op: 'checkFulfill',
137
- * vow: HostVow,
138
- * fulfillment: Host,
139
- * ] | [
140
- * op: 'checkReject',
141
- * vow: HostVow,
142
- * reason: Host,
143
- * ] | [
144
- * op: 'checkCall',
145
- * target: Host,
146
- * optVerb: PropertyKey|undefined,
147
- * args: Host[],
148
- * callIndex: number
149
- * ] | [
150
- * op: 'checkSend',
151
- * target: Host,
152
- * optVerb: PropertyKey|undefined,
153
- * args: Host[],
154
- * callIndex: number
155
- * ] | [
156
- * op: 'checkReturn',
157
- * callIndex: number,
158
- * result: Host,
159
- * ] | [
160
- * op: 'checkThrow',
161
- * callIndex: number,
162
- * problem: Host,
163
- * ]} LogEntry
164
- */
1
+ export const empty = 'Empty JS file to correspond with its .d.ts twin';
@@ -16,6 +16,12 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
16
16
 
17
17
  import { prepareAsyncFlowTools } from '../src/async-flow.js';
18
18
 
19
+ /**
20
+ * @import {PromiseKit} from '@endo/promise-kit'
21
+ * @import {Zone} from '@agoric/base-zone'
22
+ * @import {Ephemera} from './types.js';
23
+ */
24
+
19
25
  const neverSettlesP = new Promise(() => {});
20
26
 
21
27
  /**
@@ -18,6 +18,8 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
18
18
  import { prepareAsyncFlowTools } from '../src/async-flow.js';
19
19
 
20
20
  /**
21
+ * @import {Zone} from '@agoric/base-zone';
22
+ * @import {Vow, VowTools} from '@agoric/vow'
21
23
  * @import {AsyncFlow} from '../src/async-flow.js'
22
24
  */
23
25
 
@@ -9,6 +9,12 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
9
9
 
10
10
  import { prepareAsyncFlowTools } from '../src/async-flow.js';
11
11
 
12
+ /**
13
+ * @import {Zone} from '@agoric/base-zone';
14
+ * @import {Vow, VowTools} from '@agoric/vow'
15
+ * @import {AsyncFlow} from '../src/async-flow.js'
16
+ */
17
+
12
18
  const { apply } = Reflect;
13
19
 
14
20
  /**
@@ -21,6 +21,9 @@ import { prepareAsyncFlowTools } from '../src/async-flow.js';
21
21
 
22
22
  /**
23
23
  * @import {AsyncFlow} from '../src/async-flow.js'
24
+ * @import {Vow, VowTools} from '@agoric/vow'
25
+ * @import {PromiseKit} from '@endo/promise-kit'
26
+ * @import {Zone} from '@agoric/base-zone'
24
27
  */
25
28
 
26
29
  /**
@@ -239,7 +242,7 @@ const testGoodReplay = async (t, zone) => {
239
242
  // same question. different answer
240
243
  t.is(prod2, 42);
241
244
  t.log('about to await p3');
242
- await p3;
245
+ t.is(await p3.catch(r => r), 'done');
243
246
  t.log('p3 settled');
244
247
  },
245
248
  };
@@ -291,7 +294,7 @@ const testGoodReplay = async (t, zone) => {
291
294
  ]);
292
295
 
293
296
  // @ts-expect-error TS doesn't know it is a resolver
294
- r3.resolve('done');
297
+ r3.reject('done');
295
298
  await eventLoopIteration();
296
299
 
297
300
  t.is(await when(outcomeV), undefined);
@@ -17,6 +17,11 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
17
17
 
18
18
  import { prepareAsyncFlowTools } from '../src/async-flow.js';
19
19
 
20
+ /**
21
+ * @import {PromiseKit} from '@endo/promise-kit'
22
+ * @import {Zone} from '@agoric/base-zone'
23
+ */
24
+
20
25
  const nonPassableFunc = () => 'non-passable-function';
21
26
  harden(nonPassableFunc);
22
27
  const guestCreatedPromise = harden(Promise.resolve('guest-created'));
@@ -15,6 +15,12 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
15
15
 
16
16
  import { prepareBijection } from '../src/bijection.js';
17
17
 
18
+ /**
19
+ * @import {PromiseKit} from '@endo/promise-kit'
20
+ * @import {Zone} from '@agoric/base-zone'
21
+ * @import {Ephemera} from './types.js';
22
+ */
23
+
18
24
  /**
19
25
  * @param {any} t
20
26
  * @param {Zone} zone
@@ -45,7 +51,7 @@ const testBijection = (t, zone) => {
45
51
  t.false(bij.hasGuest(h1));
46
52
  t.false(bij.hasHost(g1));
47
53
 
48
- bij.init(g1, h1);
54
+ bij.unwrapInit(g1, h1);
49
55
 
50
56
  t.true(bij.has(g1, h1));
51
57
  t.is(toPassableCap(bij.guestToHost(g1)), toPassableCap(h1));
@@ -55,11 +61,11 @@ const testBijection = (t, zone) => {
55
61
  t.false(bij.hasGuest(h1));
56
62
  t.false(bij.hasHost(g1));
57
63
 
58
- t.throws(() => bij.init(g1, h2), {
64
+ t.throws(() => bij.unwrapInit(g1, h2), {
59
65
  message:
60
66
  'guestToHost key already bound: "[Alleged: g1]" -> "[Alleged: h1]" vs "[Alleged: h2]"',
61
67
  });
62
- t.throws(() => bij.init(g2, h1), {
68
+ t.throws(() => bij.unwrapInit(g2, h1), {
63
69
  message:
64
70
  'hostToGuest key already bound: "[Alleged: h1]" -> "[Alleged: g1]" vs "[Alleged: g2]"',
65
71
  });
@@ -68,11 +74,11 @@ const testBijection = (t, zone) => {
68
74
  'internal: g->h "[Alleged: g1]" -> "[Alleged: h2]" vs "[Alleged: h1]"',
69
75
  });
70
76
  t.false(bij.has(g2, h2));
71
- bij.init(g2, h2);
77
+ bij.unwrapInit(g2, h2);
72
78
  t.true(bij.has(g2, h2));
73
79
 
74
80
  t.false(bij.has(g3, h3));
75
- bij.init(g3, h3);
81
+ bij.unwrapInit(g3, h3);
76
82
  t.true(bij.has(g3, h3));
77
83
  t.false(bij.has(h3, g3));
78
84
  };
@@ -111,7 +117,7 @@ test('test heap bijection reset', t => {
111
117
  const g1 = Far('g1', {});
112
118
 
113
119
  t.false(bij.has(g1, h1));
114
- bij.init(g1, h1);
120
+ bij.unwrapInit(g1, h1);
115
121
  t.true(bij.has(g1, h1));
116
122
  bij.reset();
117
123
  t.false(bij.has(g1, h1));
@@ -18,6 +18,11 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
18
18
  import { makeConvertKit } from '../src/convert.js';
19
19
  import { prepareBijection } from '../src/bijection.js';
20
20
 
21
+ /**
22
+ * @import {PromiseKit} from '@endo/promise-kit'
23
+ * @import {Zone} from '@agoric/base-zone'
24
+ */
25
+
21
26
  /**
22
27
  * @param {any} t
23
28
  * @param {Zone} zone
@@ -0,0 +1,157 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ } from './prepare-test-env-ava.js';
8
+
9
+ import { Far, getInterfaceOf, isPassable, passStyleOf } from '@endo/pass-style';
10
+ import { prepareVowTools } from '@agoric/vow';
11
+ import { isVow } from '@agoric/vow/src/vow-utils.js';
12
+ import { makeHeapZone } from '@agoric/zone/heap.js';
13
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
14
+ import { makeDurableZone } from '@agoric/zone/durable.js';
15
+
16
+ import { forwardingMethods, prepareEndowmentTools } from '../src/endowments.js';
17
+ import { makeConvertKit } from '../src/convert.js';
18
+ import { prepareBijection } from '../src/bijection.js';
19
+
20
+ const { ownKeys } = Reflect;
21
+
22
+ const testEndowmentPlay = async (t, zone, gen, isDurable) => {
23
+ const vowTools = prepareVowTools(zone);
24
+ const { when } = vowTools;
25
+ const { prepareEndowment, unwrap } = prepareEndowmentTools(zone, {
26
+ vowTools,
27
+ });
28
+
29
+ const endowment = harden({
30
+ promise: Promise.resolve(`${gen} promise`),
31
+ storable: {
32
+ emptyRecord: {},
33
+ primitive: 'foo',
34
+ null: null,
35
+ undefined,
36
+ exo: zone.exo('AnExo', undefined, {
37
+ name() {
38
+ return `${gen} exo`;
39
+ },
40
+ }),
41
+ error: URIError(`${gen} error`),
42
+ },
43
+ far: Far('AFar', {
44
+ name: () => `${gen} far`,
45
+ }),
46
+ function() {
47
+ return `${gen} function`;
48
+ },
49
+ array: [() => `${gen} f1`, () => `${gen} f2`],
50
+ state: {
51
+ // So the concrete keys differ by gen
52
+ get [`${gen}_foo`]() {
53
+ return `${gen} foo`;
54
+ },
55
+ get [`${gen}_bar`]() {
56
+ return `${gen} bar`;
57
+ },
58
+ },
59
+ });
60
+
61
+ const wrapped = prepareEndowment(zone, 't1', endowment);
62
+
63
+ t.is(passStyleOf(wrapped), 'copyRecord');
64
+ t.is(passStyleOf(wrapped.promise), 'tagged');
65
+ t.true(isVow(wrapped.promise));
66
+ t.is(endowment.storable, wrapped.storable);
67
+ t.deepEqual(ownKeys(endowment), ownKeys(wrapped));
68
+ t.deepEqual(ownKeys(endowment.storable), ownKeys(wrapped.storable));
69
+ t.is(passStyleOf(wrapped.storable), 'copyRecord');
70
+ t.is(wrapped.storable.exo.name(), `${gen} exo`);
71
+ if (isDurable) {
72
+ t.not(endowment.far, wrapped.far); // since not durably storable
73
+ } else {
74
+ t.is(endowment.far, wrapped.far); // storable in heap, virtual
75
+ }
76
+ t.is(passStyleOf(wrapped.far), 'remotable');
77
+ t.is(wrapped.far.name(), `${gen} far`);
78
+ t.is(passStyleOf(wrapped.function), 'remotable');
79
+ t.is(wrapped.function.apply([]), `${gen} function`);
80
+ t.is(passStyleOf(wrapped.array), 'copyArray');
81
+ t.is(passStyleOf(wrapped.array[0]), 'remotable');
82
+ t.is(wrapped.array[0].apply([]), `${gen} f1`);
83
+ t.is(passStyleOf(wrapped.state), 'remotable');
84
+ t.is(endowment.state[`${gen}_foo`], `${gen} foo`);
85
+ t.is(wrapped.state.get(`${gen}_foo`), `${gen} foo`);
86
+
87
+ const makeBijection = prepareBijection(zone, unwrap);
88
+ const bij = zone.makeOnce('bij', makeBijection);
89
+
90
+ const makeGuestForHostRemotable = hRem => {
91
+ const iface = getInterfaceOf(hRem);
92
+ return Far(`${iface} guest wrapper`, forwardingMethods(hRem));
93
+ };
94
+
95
+ const makeGuestForHostVow = hVow => {
96
+ return when(hVow);
97
+ };
98
+
99
+ const {
100
+ // guestToHost,
101
+ hostToGuest,
102
+ } = makeConvertKit(bij, makeGuestForHostRemotable, makeGuestForHostVow);
103
+
104
+ const unwrapped = hostToGuest(wrapped);
105
+
106
+ t.false(isPassable(unwrapped));
107
+ t.is(passStyleOf(unwrapped.promise), 'promise');
108
+ t.is(await unwrapped.promise, `${gen} promise`);
109
+ t.not(wrapped.storable, unwrapped.storable);
110
+ t.is(passStyleOf(unwrapped.storable), 'copyRecord');
111
+ t.deepEqual(ownKeys(wrapped), ownKeys(unwrapped));
112
+ t.deepEqual(ownKeys(wrapped.storable), ownKeys(unwrapped.storable));
113
+ t.not(wrapped.storable.exo, unwrapped.storable.exo);
114
+ t.is(unwrapped.storable.exo.name(), `${gen} exo`);
115
+ t.is(passStyleOf(unwrapped.far), 'remotable');
116
+ t.is(unwrapped.far.name(), `${gen} far`);
117
+ t.false(isPassable(unwrapped.function));
118
+ t.is(typeof unwrapped.function, 'function');
119
+ t.is(unwrapped.function(), `${gen} function`);
120
+ t.is(unwrapped.array[0](), `${gen} f1`);
121
+ t.false(isPassable(unwrapped.state));
122
+ t.is(typeof unwrapped.state, 'object');
123
+ t.is(unwrapped.state[`${gen}_foo`], `${gen} foo`);
124
+ };
125
+
126
+ const testEndowmentBadReplay = async (_t, _zone, _gen, _isDurable) => {
127
+ // FIXME TODO This upgrade should fail since it doesn't re-prepare
128
+ // everything. Only after that's fixed does it make sense to
129
+ // expand this to test insufficient re-preparation.
130
+ };
131
+
132
+ await test.serial('test heap endowments', async t => {
133
+ const zone = makeHeapZone('heapRoot');
134
+ return testEndowmentPlay(t, zone, 'first', false);
135
+ });
136
+
137
+ test.serial('test virtual endowments', async t => {
138
+ annihilate();
139
+ const zone = makeVirtualZone('virtualRoot');
140
+ return testEndowmentPlay(t, zone, 'first', false);
141
+ });
142
+
143
+ test.serial('test durable endowments', async t => {
144
+ annihilate();
145
+
146
+ nextLife();
147
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
148
+ await testEndowmentPlay(t, zone1, 'first', true);
149
+
150
+ nextLife();
151
+ const zone2 = makeDurableZone(getBaggage(), 'durableRoot');
152
+ await testEndowmentBadReplay(t, zone2, '2nd', true);
153
+
154
+ nextLife();
155
+ const zone3 = makeDurableZone(getBaggage(), 'durableRoot');
156
+ return testEndowmentPlay(t, zone3, '3rd', true);
157
+ });
@@ -18,6 +18,10 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
18
18
  import { prepareBijection } from '../src/bijection.js';
19
19
  import { makeEquate } from '../src/equate.js';
20
20
 
21
+ /**
22
+ * @import {Zone} from '@agoric/base-zone'
23
+ */
24
+
21
25
  /**
22
26
  * @param {any} t
23
27
  * @param {Zone} zone
@@ -50,7 +54,7 @@ const testEquate = (t, zone, showOnConsole = false) => {
50
54
  message:
51
55
  'cannot yet send guest remotables to host "[Alleged: g1]" vs "[Alleged: h1]"',
52
56
  });
53
- bij.init(g1, h1);
57
+ bij.unwrapInit(g1, h1);
54
58
  t.notThrows(() => equate(g1, h1));
55
59
  t.throws(() => equate(g1, h2), {
56
60
  message: 'internal: g->h "[Alleged: g1]" -> "[Vow]" vs "[Alleged: h1]"',
@@ -58,7 +62,7 @@ const testEquate = (t, zone, showOnConsole = false) => {
58
62
  t.throws(() => equate(g2, h1), {
59
63
  message: 'internal: unexpected h->g "[Alleged: h1]" -> "[Alleged: g1]"',
60
64
  });
61
- bij.init(g2, h2);
65
+ bij.unwrapInit(g2, h2);
62
66
  equate(g2, h2);
63
67
 
64
68
  t.throws(() => equate(g1, h2), {
@@ -14,6 +14,14 @@ import { makeDurableZone } from '@agoric/zone/durable.js';
14
14
 
15
15
  import { prepareLogStore } from '../src/log-store.js';
16
16
 
17
+ /**
18
+ * @import {PromiseKit} from '@endo/promise-kit'
19
+ * @import {Zone} from '@agoric/base-zone'
20
+ * @import {Vow, VowTools} from '@agoric/vow'
21
+ * @import {LogStore} from '../src/log-store.js';
22
+ * @import {Bijection} from '../src/bijection.js';
23
+ */
24
+
17
25
  /**
18
26
  * @param {any} t
19
27
  * @param {Zone} zone
@@ -88,7 +96,7 @@ const testLogStoreReplay = async (t, zone) => {
88
96
  t.is(await log.promiseReplayDone(), undefined);
89
97
  };
90
98
 
91
- await test('test heap log-store', async t => {
99
+ await test.serial('test heap log-store', async t => {
92
100
  const zone = makeHeapZone('heapRoot');
93
101
  return testLogStorePlay(t, zone);
94
102
  });