@agoric/swingset-vat 0.33.0-u18.1 → 0.33.0-u19.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.
@@ -4,7 +4,7 @@ import { makeLocalVatManagerFactory } from './manager-local.js';
4
4
  import { makeNodeSubprocessFactory } from './manager-subprocess-node.js';
5
5
  import { makeXsSubprocessFactory } from './manager-subprocess-xsnap.js';
6
6
 
7
- export function makeVatManagerFactory({
7
+ export function makeVatManagerMaker({
8
8
  allVatPowers,
9
9
  kernelKeeper,
10
10
  vatEndowments,
@@ -18,14 +18,12 @@ export function makeVatManagerFactory({
18
18
  vatEndowments,
19
19
  gcTools,
20
20
  });
21
-
22
21
  const nodeSubprocessFactory = makeNodeSubprocessFactory({
23
22
  startSubprocessWorker: startSubprocessWorkerNode,
24
23
  kernelKeeper,
25
24
  kernelSlog,
26
25
  testLog: allVatPowers.testLog,
27
26
  });
28
-
29
27
  const xsWorkerFactory = makeXsSubprocessFactory({
30
28
  startXSnap,
31
29
  kernelKeeper,
@@ -69,58 +67,41 @@ export function makeVatManagerFactory({
69
67
  * @param {import('@agoric/swingset-liveslots').LiveSlotsOptions} options.liveSlotsOptions
70
68
  * @returns { Promise<import('../../types-internal.js').VatManager> }
71
69
  */
72
- async function vatManagerFactory(
73
- vatID,
74
- { managerOptions, liveSlotsOptions },
75
- ) {
70
+ async function makeVatManager(vatID, options) {
71
+ const { managerOptions, liveSlotsOptions } = options;
76
72
  validateManagerOptions(managerOptions);
77
73
  const { workerOptions, enableSetup } = managerOptions;
78
74
  const { type } = workerOptions;
79
75
 
80
- if (type !== 'local' && 'setup' in managerOptions) {
81
- console.warn(`TODO: stop using setup() with ${type}`);
82
- }
83
- if (enableSetup) {
84
- if (managerOptions.setup) {
85
- return localFactory.createFromSetup(vatID, managerOptions);
86
- } else {
87
- return localFactory.createFromBundle(
88
- vatID,
89
- managerOptions.bundle,
90
- managerOptions,
91
- liveSlotsOptions,
92
- );
93
- }
94
- } else if (type === 'local') {
95
- return localFactory.createFromBundle(
96
- vatID,
97
- managerOptions.bundle,
98
- managerOptions,
99
- liveSlotsOptions,
100
- );
76
+ if (type !== 'local' && (enableSetup || 'setup' in managerOptions)) {
77
+ console.warn(`TODO: stop using enableSetup and setup() with ${type}`);
101
78
  }
102
79
 
103
- if (type === 'node-subprocess') {
104
- return nodeSubprocessFactory.createFromBundle(
105
- vatID,
106
- managerOptions.bundle,
107
- managerOptions,
108
- liveSlotsOptions,
109
- );
80
+ if (enableSetup && managerOptions.setup) {
81
+ return localFactory.createFromSetup(vatID, managerOptions);
110
82
  }
111
83
 
112
- if (type === 'xsnap') {
113
- assert(managerOptions.bundle, 'xsnap requires Bundle');
114
- return xsWorkerFactory.createFromBundle(
115
- vatID,
116
- managerOptions.bundle,
117
- managerOptions,
118
- liveSlotsOptions,
119
- );
84
+ /** @type {Pick<typeof xsWorkerFactory, 'createFromBundle'>} */
85
+ let factory;
86
+ if (enableSetup || type === 'local') {
87
+ factory = localFactory;
88
+ } else if (type === 'node-subprocess') {
89
+ factory = nodeSubprocessFactory;
90
+ } else if (type === 'xsnap') {
91
+ assert(managerOptions.bundle, 'worker type xsnap requires a bundle');
92
+ factory = xsWorkerFactory;
93
+ } else {
94
+ throw Error(`unknown vat worker type ${type}`);
120
95
  }
121
96
 
122
- throw Error(`unknown type ${type}, not 'local' or 'xsnap'`);
97
+ return factory.createFromBundle(
98
+ vatID,
99
+ // @ts-expect-error managerOptions.bundle might be undefined
100
+ managerOptions.bundle,
101
+ managerOptions,
102
+ liveSlotsOptions,
103
+ );
123
104
  }
124
105
 
125
- return harden(vatManagerFactory);
106
+ return harden(makeVatManager);
126
107
  }
@@ -128,8 +128,10 @@ export function makeXsSubprocessFactory({
128
128
 
129
129
  const vatKeeper = kernelKeeper.provideVatKeeper(vatID);
130
130
  const snapshotInfo = vatKeeper.getSnapshotInfo();
131
+ let uncompressedSizeLoaded = null;
131
132
  if (snapshotInfo) {
132
133
  kernelSlog.write({ type: 'heap-snapshot-load', vatID, ...snapshotInfo });
134
+ uncompressedSizeLoaded = snapshotInfo.uncompressedSize;
133
135
  }
134
136
 
135
137
  // `startXSnap` adds `nameDisplayArg` as a dummy argument so that 'ps'
@@ -240,9 +242,31 @@ export function makeXsSubprocessFactory({
240
242
  async function makeSnapshot(snapPos, snapStore, restartWorker) {
241
243
  const snapshotDescription = `${vatID}-${snapPos}`;
242
244
  const snapshotStream = worker.makeSnapshotStream(snapshotDescription);
245
+ const saveSnapshot = async saveStream => {
246
+ const results = await snapStore.saveSnapshot(
247
+ vatID,
248
+ snapPos,
249
+ saveStream,
250
+ );
251
+ const { hash: snapshotID, ...metrics } = results;
252
+ const uncompressedSizeDelta =
253
+ uncompressedSizeLoaded &&
254
+ metrics.uncompressedSize - uncompressedSizeLoaded;
255
+ uncompressedSizeLoaded = results.uncompressedSize;
256
+ kernelSlog.write({
257
+ type: 'heap-snapshot-save',
258
+ vatID,
259
+ snapshotID,
260
+ endPosition: snapPos,
261
+ ...metrics,
262
+ uncompressedSizeDelta,
263
+ restartWorker,
264
+ });
265
+ return results;
266
+ };
243
267
 
244
268
  if (!restartWorker) {
245
- return snapStore.saveSnapshot(vatID, snapPos, snapshotStream);
269
+ return saveSnapshot(snapshotStream);
246
270
  }
247
271
 
248
272
  /** @type {AsyncGenerator<Uint8Array, void, void>[]} */
@@ -268,7 +292,7 @@ export function makeXsSubprocessFactory({
268
292
  snapshotDescription,
269
293
  },
270
294
  }),
271
- snapStore.saveSnapshot(vatID, snapPos, snapStoreSaveStream),
295
+ saveSnapshot(snapStoreSaveStream),
272
296
  ]);
273
297
  await closeP;
274
298
 
@@ -9,7 +9,7 @@ export function makeVatRootObjectSlot() {
9
9
  export function makeVatLoader(stuff) {
10
10
  const {
11
11
  overrideVatManagerOptions = {},
12
- vatManagerFactory,
12
+ makeVatManager,
13
13
  kernelSlog,
14
14
  makeSourcedConsole,
15
15
  kernelKeeper,
@@ -127,7 +127,7 @@ export function makeVatLoader(stuff) {
127
127
  };
128
128
 
129
129
  const finish = starting && kernelSlog.startup(vatID);
130
- const manager = await vatManagerFactory(vatID, {
130
+ const manager = await makeVatManager(vatID, {
131
131
  managerOptions,
132
132
  liveSlotsOptions,
133
133
  });
@@ -150,7 +150,7 @@ export function makeVatLoader(stuff) {
150
150
  ...overrideVatManagerOptions,
151
151
  };
152
152
  const liveSlotsOptions = {};
153
- const manager = await vatManagerFactory(vatID, {
153
+ const manager = await makeVatManager(vatID, {
154
154
  managerOptions,
155
155
  liveSlotsOptions,
156
156
  });
@@ -32,16 +32,15 @@ function makeSupervisorDispatch(dispatch) {
32
32
  async function dispatchToVat(delivery) {
33
33
  // the (low-level) vat is responsible for giving up agency, but we still
34
34
  // protect against exceptions
35
- return Promise.resolve(delivery)
36
- .then(dispatch)
37
- .then(
38
- res => harden(['ok', res, null]),
39
- err => {
40
- // TODO react more thoughtfully, maybe terminate the vat
41
- console.warn(`error during vat dispatch() of ${delivery}`, err);
42
- return harden(['error', `${err}`, null]);
43
- },
44
- );
35
+ await null;
36
+ try {
37
+ const res = await dispatch(delivery);
38
+ return harden(['ok', res, null]);
39
+ } catch (err) {
40
+ // TODO react more thoughtfully, maybe terminate the vat
41
+ console.warn(`error during vat dispatch() of ${delivery}`, err);
42
+ return harden(['error', `${err}`, null]);
43
+ }
45
44
  }
46
45
 
47
46
  return harden(dispatchToVat);
package/src/typeGuards.js CHANGED
@@ -10,38 +10,40 @@ export const ManagerType = M.or(
10
10
 
11
11
  const Bundle = M.splitRecord({ moduleType: M.string() });
12
12
 
13
- const SwingsetConfigOptions = {
13
+ const VatConfigOptions = harden({
14
14
  creationOptions: M.splitRecord({}, { critical: M.boolean() }),
15
15
  parameters: M.recordOf(M.string(), M.any()),
16
- };
17
- harden(SwingsetConfigOptions);
16
+ });
18
17
 
19
- const SwingSetConfigProperties = M.or(
20
- M.splitRecord({ sourceSpec: M.string() }, SwingsetConfigOptions),
21
- M.splitRecord({ bundleSpec: M.string() }, SwingsetConfigOptions),
22
- M.splitRecord({ bundle: Bundle }, SwingsetConfigOptions),
23
- );
24
- const SwingSetConfigDescriptor = M.recordOf(
25
- M.string(),
26
- SwingSetConfigProperties,
27
- );
18
+ const makeSwingSetConfigProperties = (required = {}, optional = {}, rest) =>
19
+ M.or(
20
+ M.splitRecord({ sourceSpec: M.string(), ...required }, optional, rest),
21
+ M.splitRecord({ bundleSpec: M.string(), ...required }, optional, rest),
22
+ M.splitRecord({ bundle: Bundle, ...required }, optional, rest),
23
+ );
24
+ const makeSwingSetConfigDescriptor = (required, optional, rest) =>
25
+ M.recordOf(
26
+ M.string(),
27
+ makeSwingSetConfigProperties(required, optional, rest),
28
+ );
28
29
 
29
30
  /**
30
31
  * NOTE: this pattern suffices for PSM bootstrap,
31
32
  * but does not cover the whole SwingSet config syntax.
32
33
  *
33
34
  * {@link ./docs/configuration.md}
34
- * TODO: move this to swingset?
35
35
  *
36
36
  * @see SwingSetConfig
37
37
  * in ./types-external.js
38
38
  */
39
- export const SwingSetConfig = M.and(
40
- M.splitRecord({}, { defaultManagerType: ManagerType }),
41
- M.splitRecord({}, { includeDevDependencies: M.boolean() }),
42
- M.splitRecord({}, { defaultReapInterval: M.number() }), // not in type decl
43
- M.splitRecord({}, { snapshotInterval: M.number() }),
44
- M.splitRecord({}, { vats: SwingSetConfigDescriptor }),
45
- M.splitRecord({}, { bootstrap: M.string() }),
46
- M.splitRecord({}, { bundles: SwingSetConfigDescriptor }),
39
+ export const SwingSetConfig = M.splitRecord(
40
+ { vats: makeSwingSetConfigDescriptor(undefined, VatConfigOptions) },
41
+ {
42
+ defaultManagerType: ManagerType,
43
+ includeDevDependencies: M.boolean(),
44
+ defaultReapInterval: M.number(),
45
+ snapshotInterval: M.number(),
46
+ bootstrap: M.string(),
47
+ bundles: makeSwingSetConfigDescriptor(undefined, undefined, {}),
48
+ },
47
49
  );
@@ -1,10 +1,10 @@
1
- /** @import { ERef } from '@endo/far'; */
2
-
3
1
  export {};
4
2
 
5
3
  /**
6
4
  * @import {Guarded} from '@endo/exo';
5
+ * @import {ERef} from '@endo/far';
7
6
  * @import {Passable, RemotableObject} from '@endo/pass-style';
7
+ * @import {LimitedConsole} from '@agoric/internal/src/js-utils.js';
8
8
  */
9
9
 
10
10
  /* This file defines types that part of the external API of swingset. That
@@ -129,14 +129,6 @@ export {};
129
129
  * @typedef { (dr: VatDeliveryResult) => void } SlogFinishDelivery
130
130
  * @typedef { (ksr: KernelSyscallResult, vsr: VatSyscallResult) => void } SlogFinishSyscall
131
131
  * @typedef { { write: ({}) => void,
132
- * vatConsole: (vatID: string, origConsole: {}) => {},
133
- * delivery: (vatID: string,
134
- * newCrankNum: BigInt, newDeliveryNum: BigInt,
135
- * kd: KernelDeliveryObject, vd: VatDeliveryObject,
136
- * replay?: boolean) => SlogFinishDelivery,
137
- * syscall: (vatID: string,
138
- * ksc: KernelSyscallObject | undefined,
139
- * vsc: VatSyscallObject) => SlogFinishSyscall,
140
132
  * provideVatSlogger: (vatID: string,
141
133
  * dynamic?: boolean,
142
134
  * description?: string,
@@ -144,6 +136,20 @@ export {};
144
136
  * vatSourceBundle?: unknown,
145
137
  * managerType?: string,
146
138
  * vatParameters?: unknown) => { vatSlog: VatSlog },
139
+ * vatConsole: (vatID: string, origConsole: LimitedConsole) => LimitedConsole,
140
+ * startup: (vatID: string) => () => void,
141
+ * delivery: (vatID: string,
142
+ * newCrankNum: BigInt, newDeliveryNum: BigInt,
143
+ * kd: KernelDeliveryObject, vd: VatDeliveryObject,
144
+ * replay?: boolean) => SlogFinishDelivery,
145
+ * syscall: (vatID: string,
146
+ * ksc: KernelSyscallObject | undefined,
147
+ * vsc: VatSyscallObject) => SlogFinishSyscall,
148
+ * changeCList: (vatID: string,
149
+ * crankNum: BigInt,
150
+ * mode: 'import' | 'export' | 'drop',
151
+ * kernelSlot: string,
152
+ * vatSlot: string) => void,
147
153
  * terminateVat: (vatID: string, shouldReject: boolean, info: SwingSetCapData) => void,
148
154
  * } } KernelSlog
149
155
  * @typedef {{
@@ -154,27 +160,25 @@ export {};
154
160
  */
155
161
 
156
162
  /**
163
+ * @typedef {{ bundle: Bundle }} BundleRef a bundle object
164
+ * @typedef {{ bundleName: string }} BundleName a name identifying a property in the `bundles` of a SwingSetOptions object
165
+ * @typedef {{ bundleSpec: string }} BundleSpec a path to a bundle file
166
+ * @typedef {{ sourceSpec: string }} SourceSpec a package specifier such as "@agoric/swingset-vat/tools/vat-puppet.js"
167
+ *
157
168
  * @typedef {{
158
- * sourceSpec: string // path to pre-bundled root
159
- * }} SourceSpec
160
- * @typedef {{
161
- * bundleSpec: string // path to bundled code
162
- * }} BundleSpec
163
- * @typedef {{
164
- * bundle: Bundle
165
- * }} BundleRef
166
- * @typedef {{
167
- * bundleName: string
168
- * }} BundleName
169
- * @typedef {(SourceSpec | BundleSpec | BundleRef | BundleName ) & {
170
169
  * bundleID?: BundleID,
171
- * creationOptions?: Record<string, any>,
170
+ * creationOptions?: StaticVatOptions,
172
171
  * parameters?: Record<string, any>,
173
- * }} SwingSetConfigProperties
172
+ * }} VatConfigOptions
173
+ */
174
+ /**
175
+ * @template [Fields=object]
176
+ * @typedef {(SourceSpec | BundleSpec | BundleName | BundleRef) & Fields} SwingSetConfigProperties
174
177
  */
175
178
 
176
179
  /**
177
- * @typedef {Record<string, SwingSetConfigProperties>} SwingSetConfigDescriptor
180
+ * @template [Fields=object]
181
+ * @typedef {Record<string, SwingSetConfigProperties<Fields>>} SwingSetConfigDescriptor
178
182
  * Where the property name is the name of the vat. Note that
179
183
  * the `bootstrap` property names the vat that should be used as the bootstrap vat. Although a swingset
180
184
  * configuration can designate any vat as its bootstrap vat, `loadBasedir` will always look for a file named
@@ -188,7 +192,7 @@ export {};
188
192
  * `devDependencies` of the surrounding `package.json` should be accessible to
189
193
  * bundles.
190
194
  * @property {string} [bundleCachePath] if present, SwingSet will use a bundle cache at this path
191
- * @property {SwingSetConfigDescriptor} vats
195
+ * @property {SwingSetConfigDescriptor<VatConfigOptions>} vats
192
196
  * @property {SwingSetConfigDescriptor} [bundles]
193
197
  * @property {BundleFormat} [bundleFormat] the bundle source / import bundle
194
198
  * format.
@@ -206,7 +210,7 @@ export {};
206
210
  */
207
211
 
208
212
  /**
209
- * @typedef {{ bundleName: string} | { bundle: Bundle } | { bundleID: BundleID } } SourceOfBundle
213
+ * @typedef {BundleName | BundleRef | {bundleID: BundleID}} SourceOfBundle
210
214
  */
211
215
  /**
212
216
  * @typedef { import('@agoric/swing-store').KVStore } KVStore
@@ -295,12 +299,8 @@ export {};
295
299
  * Vat Creation and Management
296
300
  *
297
301
  * @typedef { string } BundleID
298
- * @typedef {any} BundleCap
302
+ * @typedef { any } BundleCap
299
303
  * @typedef { { moduleFormat: 'endoZipBase64', endoZipBase64: string, endoZipBase64Sha512: string } } EndoZipBase64Bundle
300
- *
301
- * @typedef { unknown } Meter
302
- *
303
- * E(vatAdminService).createVat(bundle, options: DynamicVatOptions)
304
304
  */
305
305
 
306
306
  /**
@@ -326,8 +326,6 @@ export {};
326
326
  * types are then defined as amendments to this base type.
327
327
  *
328
328
  * @typedef { object } BaseVatOptions
329
- * @property { string } name
330
- * @property { * } [vatParameters]
331
329
  * @property { boolean } [enableSetup]
332
330
  * If true, permits the vat to construct itself using the
333
331
  * `setup()` API, which bypasses the imposition of LiveSlots but
@@ -346,6 +344,10 @@ export {};
346
344
  * outbound syscalls so that the vat's internal state can be
347
345
  * reconstructed via replay. If false, no such record is kept.
348
346
  * Defaults to true.
347
+ * @property { ManagerType } [managerType]
348
+ * @property { boolean } [neverReap]
349
+ * If true, disables automatic bringOutYourDead deliveries to a vat.
350
+ * Defaults to false.
349
351
  * @property { number | 'never' } [reapInterval]
350
352
  * Trigger a bringOutYourDead after the vat has received
351
353
  * this many deliveries. If the value is 'never',
@@ -360,7 +362,7 @@ export {};
360
362
  */
361
363
 
362
364
  /**
363
- * @typedef { { meter?: Meter } } OptMeter
365
+ * @typedef { { meter?: unknown } } OptMeter
364
366
  * If a meter is provided, the new dynamic vat is limited to a fixed
365
367
  * amount of computation and allocation that can occur during any
366
368
  * given crank. Peak stack frames are limited as well. In addition,
@@ -370,14 +372,13 @@ export {};
370
372
  * terminated. If undefined, the vat is unmetered. Static vats
371
373
  * cannot be metered.
372
374
  *
373
- * @typedef { { managerType?: ManagerType } } OptManagerType
374
- * @typedef { BaseVatOptions & OptMeter & OptManagerType } DynamicVatOptions
375
+ * @typedef { BaseVatOptions & { name: string, vatParameters?: object } & OptMeter } DynamicVatOptions
375
376
  *
376
377
  * config.vats[name].creationOptions: StaticVatOptions
377
378
  *
378
379
  * @typedef { { enableDisavow?: boolean } } OptEnableDisavow
379
380
  * @typedef { { nodeOptions?: string[] } } OptNodeOptions
380
- * @typedef { BaseVatOptions & OptManagerType & OptEnableDisavow & OptNodeOptions } StaticVatOptions
381
+ * @typedef { BaseVatOptions & OptEnableDisavow & OptNodeOptions } StaticVatOptions
381
382
  *
382
383
  * @typedef { { vatParameters?: object, upgradeMessage?: string } } VatUpgradeOptions
383
384
  * @typedef { { incarnationNumber: number } } VatUpgradeResults
@@ -29,7 +29,6 @@ export {};
29
29
  * @typedef { string } MeterID
30
30
  * @typedef { { meterID?: MeterID } } OptMeterID
31
31
  * @typedef { import('./types-external.js').BaseVatOptions } BaseVatOptions
32
- * @typedef { import('./types-external.js').OptManagerType } OptManagerType
33
32
  * @typedef { import('@agoric/swingset-liveslots').VatDeliveryObject } VatDeliveryObject
34
33
  * @typedef { import('@agoric/swingset-liveslots').VatDeliveryResult } VatDeliveryResult
35
34
  * @typedef { import('@agoric/swingset-liveslots').VatSyscallObject } VatSyscallObject
@@ -38,7 +37,7 @@ export {};
38
37
  *
39
38
  * // used by vatKeeper.setSourceAndOptions(source, RecordedVatOptions)
40
39
  *
41
- * @typedef { BaseVatOptions & OptMeterID & OptManagerType } InternalDynamicVatOptions
40
+ * @typedef { BaseVatOptions & OptMeterID } InternalDynamicVatOptions
42
41
  *
43
42
  * RecordedVatOptions is fully-specified, no optional fields
44
43
  *
@@ -112,7 +111,7 @@ export {};
112
111
  * enableDisavow: boolean,
113
112
  * useTranscript: boolean,
114
113
  * name: string,
115
- * sourcedConsole: Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>,
114
+ * sourcedConsole: import('@agoric/internal/src/js-utils.js').LimitedConsole,
116
115
  * enableSetup: boolean,
117
116
  * setup?: unknown,
118
117
  * retainSyscall?: boolean
@@ -14,6 +14,8 @@ import { makeScalarWeakMapStore } from '@agoric/store';
14
14
  import { TimeMath } from '@agoric/time';
15
15
 
16
16
  /**
17
+ * @import {LegacyWeakMap, WeakMapStore} from '@agoric/store';
18
+ * @import {MapStore} from '@agoric/swingset-liveslots';
17
19
  * @import {Passable, RemotableObject} from '@endo/pass-style';
18
20
  * @import {Key} from '@endo/patterns';
19
21
  */
@@ -1,6 +1,10 @@
1
1
  import { makeNodeBundleCache as wrappedMaker } from '@endo/bundle-source/cache.js';
2
2
  import styles from 'ansi-styles'; // less authority than 'chalk'
3
3
 
4
+ /**
5
+ * @import {EReturn} from '@endo/far';
6
+ */
7
+
4
8
  /** @type {typeof wrappedMaker} */
5
9
  export const makeNodeBundleCache = async (dest, options, loadModule, pid) => {
6
10
  const log = (...args) => {
@@ -17,7 +21,7 @@ export const makeNodeBundleCache = async (dest, options, loadModule, pid) => {
17
21
  };
18
22
  return wrappedMaker(dest, { log, ...options }, loadModule, pid);
19
23
  };
20
- /** @typedef {Awaited<ReturnType<typeof makeNodeBundleCache>>} BundleCache */
24
+ /** @typedef {EReturn<typeof makeNodeBundleCache>} BundleCache */
21
25
 
22
26
  /** @type {Map<string, Promise<BundleCache>>} */
23
27
  const providedCaches = new Map();
@@ -53,10 +53,25 @@ export const makeRunUtils = (controller, harness) => {
53
53
  };
54
54
 
55
55
  /**
56
- * @typedef {import('@endo/eventual-send').EProxy & {
57
- * sendOnly: (presence: unknown) => Record<string, (...args: any) => void>;
58
- * vat: (name: string) => Record<string, (...args: any) => Promise<any>>;
59
- * }} EVProxy
56
+ * @typedef EVProxyMethods
57
+ * @property {(presence: unknown) => Record<string, (...args: any) => Promise<void>>} sendOnly
58
+ * Returns a "methods proxy" for the presence that ignores the results of
59
+ * each method invocation.
60
+ * @property {(name: string) => Record<string, (...args: any) => Promise<any>>} vat
61
+ * Returns a "methods proxy" for the root object of the specified vat.
62
+ * So e.g. `EV.vat('foo').m(0)` becomes
63
+ * `controller.queueToVatRoot('foo', 'm', [0])`.
64
+ * @property {(presence: unknown) => Record<string, Promise<any>>} get
65
+ * Returns a "values proxy" for the presence for which each requested
66
+ * property manifests as a promise.
67
+ */
68
+ /**
69
+ * @typedef {import('@endo/eventual-send').EProxy & EVProxyMethods} EVProxy
70
+ * Given a presence, return a "methods proxy" for which each requested
71
+ * property manifests as a method that forwards its invocation through the
72
+ * controller to the presence as an invocation of an identically-named method
73
+ * with identical arguments (modulo passable translation).
74
+ * So e.g. `EV(x).m(0)` becomes `controller.queueToVatObject(x, 'm', [0])`.
60
75
  */
61
76
 
62
77
  // IMPORTANT WARNING TO USERS OF `EV`
@@ -103,52 +118,39 @@ export const makeRunUtils = (controller, harness) => {
103
118
  // promise that can remain pending indefinitely, possibly to be settled by a
104
119
  // future message delivery.
105
120
 
106
- /** @type {EVProxy} */
107
- // @ts-expect-error cast, approximate
108
- const EV = Object.assign(
109
- presence =>
110
- new Proxy(harden({}), {
111
- get: (_t, method, _rx) => {
112
- const boundMethod = (...args) =>
113
- queueAndRun(() =>
114
- controller.queueToVatObject(presence, method, args),
115
- );
116
- return harden(boundMethod);
117
- },
118
- }),
119
- {
120
- vat: vatName =>
121
- new Proxy(harden({}), {
122
- get: (_t, method, _rx) => {
123
- const boundMethod = (...args) =>
124
- queueAndRun(() =>
125
- controller.queueToVatRoot(vatName, method, args),
126
- );
127
- return harden(boundMethod);
128
- },
129
- }),
130
- sendOnly: presence =>
131
- new Proxy(harden({}), {
132
- get: (_t, method, _rx) => {
133
- const boundMethod = (...args) =>
134
- queueAndRun(
135
- () => controller.queueToVatObject(presence, method, args),
136
- true,
137
- );
138
- return harden(boundMethod);
139
- },
140
- }),
141
- get: presence =>
142
- new Proxy(harden({}), {
143
- get: (_t, pathElement, _rx) =>
144
- queueAndRun(() =>
145
- controller.queueToVatRoot('bootstrap', 'awaitVatObject', [
146
- presence,
147
- [pathElement],
148
- ]),
149
- ),
150
- }),
151
- },
121
+ /**
122
+ * @template {(typeof controller.queueToVatObject) | (typeof controller.queueToVatRoot)} T
123
+ * @param {T} invoker
124
+ * @param {Parameters<T>[0]} target
125
+ * @param {boolean} [voidResult]
126
+ */
127
+ const makeMethodsProxy = (invoker, target, voidResult = false) =>
128
+ new Proxy(harden({}), {
129
+ get: (_t, method, _rx) => {
130
+ const resultPolicy = voidResult ? 'none' : undefined;
131
+ const boundMethod = (...args) =>
132
+ queueAndRun(
133
+ () => invoker(target, method, args, resultPolicy),
134
+ voidResult,
135
+ );
136
+ return harden(boundMethod);
137
+ },
138
+ });
139
+
140
+ const EV = /** @type {EVProxy} */ (
141
+ Object.assign(
142
+ presence => makeMethodsProxy(controller.queueToVatObject, presence),
143
+ {
144
+ vat: vatName => makeMethodsProxy(controller.queueToVatRoot, vatName),
145
+ sendOnly: presence =>
146
+ makeMethodsProxy(controller.queueToVatObject, presence, true),
147
+ get: presence =>
148
+ new Proxy(harden({}), {
149
+ get: (_t, key, _rx) =>
150
+ EV.vat('bootstrap').awaitVatObject(presence, [key]),
151
+ }),
152
+ },
153
+ )
152
154
  );
153
155
  return harden({ queueAndRun, EV });
154
156
  };