@agoric/internal 0.3.3-other-dev-1f26562.0 → 0.3.3-other-dev-3eb1a1d.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 (110) hide show
  1. package/README.md +7 -2
  2. package/exported.js +2 -0
  3. package/package.json +35 -17
  4. package/src/action-types.d.ts +50 -5
  5. package/src/action-types.d.ts.map +1 -1
  6. package/src/action-types.js +73 -14
  7. package/src/batched-deliver.d.ts +9 -6
  8. package/src/batched-deliver.d.ts.map +1 -1
  9. package/src/batched-deliver.js +9 -3
  10. package/src/callback.d.ts +23 -16
  11. package/src/callback.d.ts.map +1 -1
  12. package/src/callback.js +48 -55
  13. package/src/chain-storage-paths.d.ts +2 -3
  14. package/src/chain-storage-paths.d.ts.map +1 -1
  15. package/src/chain-storage-paths.js +2 -3
  16. package/src/chain-utils.d.ts +25 -0
  17. package/src/chain-utils.d.ts.map +1 -0
  18. package/src/chain-utils.js +57 -0
  19. package/src/config.d.ts +24 -12
  20. package/src/config.d.ts.map +1 -1
  21. package/src/config.js +21 -10
  22. package/src/debug.d.ts +1 -1
  23. package/src/errors.d.ts +2 -0
  24. package/src/errors.d.ts.map +1 -0
  25. package/src/errors.js +16 -0
  26. package/src/index.d.ts +8 -1
  27. package/src/index.js +12 -2
  28. package/src/install-ses-debug.d.ts +2 -0
  29. package/src/install-ses-debug.d.ts.map +1 -0
  30. package/src/install-ses-debug.js +6 -0
  31. package/src/js-utils.d.ts +7 -0
  32. package/src/js-utils.d.ts.map +1 -0
  33. package/src/js-utils.js +89 -0
  34. package/src/lib-chainStorage.d.ts +42 -52
  35. package/src/lib-chainStorage.d.ts.map +1 -1
  36. package/src/lib-chainStorage.js +88 -77
  37. package/src/lib-nodejs/engine-gc.d.ts +3 -0
  38. package/src/lib-nodejs/engine-gc.d.ts.map +1 -0
  39. package/src/lib-nodejs/engine-gc.js +22 -0
  40. package/src/lib-nodejs/gc-and-finalize.d.ts +2 -0
  41. package/src/lib-nodejs/gc-and-finalize.d.ts.map +1 -0
  42. package/src/lib-nodejs/gc-and-finalize.js +91 -0
  43. package/src/lib-nodejs/spawnSubprocessWorker.d.ts +15 -0
  44. package/src/lib-nodejs/spawnSubprocessWorker.d.ts.map +1 -0
  45. package/src/lib-nodejs/spawnSubprocessWorker.js +89 -0
  46. package/src/lib-nodejs/waitUntilQuiescent.d.ts +2 -0
  47. package/src/lib-nodejs/waitUntilQuiescent.d.ts.map +1 -0
  48. package/src/lib-nodejs/waitUntilQuiescent.js +18 -0
  49. package/src/lib-nodejs/worker-protocol.d.ts +4 -0
  50. package/src/lib-nodejs/worker-protocol.d.ts.map +1 -0
  51. package/src/lib-nodejs/worker-protocol.js +54 -0
  52. package/src/magic-cookie-test-only.js +2 -2
  53. package/src/marshal.d.ts +20 -0
  54. package/src/marshal.d.ts.map +1 -0
  55. package/src/marshal.js +137 -0
  56. package/src/method-tools.d.ts +1 -0
  57. package/src/method-tools.d.ts.map +1 -1
  58. package/src/method-tools.js +29 -16
  59. package/src/netstring.d.ts +24 -0
  60. package/src/netstring.d.ts.map +1 -0
  61. package/src/netstring.js +124 -0
  62. package/src/node/buffer-line-transform.d.ts +17 -13
  63. package/src/node/buffer-line-transform.d.ts.map +1 -1
  64. package/src/node/buffer-line-transform.js +12 -9
  65. package/src/node/createBundles.d.ts.map +1 -1
  66. package/src/node/createBundles.js +12 -3
  67. package/src/node/fs-stream.d.ts +1 -1
  68. package/src/node/fs-stream.d.ts.map +1 -1
  69. package/src/node/fs-stream.js +42 -30
  70. package/src/node/shutdown.d.ts.map +1 -1
  71. package/src/node/shutdown.js +0 -1
  72. package/src/priority-senders.d.ts +1 -1
  73. package/src/priority-senders.d.ts.map +1 -1
  74. package/src/priority-senders.js +8 -5
  75. package/src/queue.d.ts +1 -1
  76. package/src/queue.d.ts.map +1 -1
  77. package/src/queue.js +7 -8
  78. package/src/scratch.d.ts +1 -1
  79. package/src/scratch.d.ts.map +1 -1
  80. package/src/ses-utils.d.ts +60 -0
  81. package/src/ses-utils.d.ts.map +1 -0
  82. package/src/ses-utils.js +346 -0
  83. package/src/storage-test-utils.d.ts +41 -84
  84. package/src/storage-test-utils.d.ts.map +1 -1
  85. package/src/storage-test-utils.js +169 -116
  86. package/src/tagged.d.ts +149 -0
  87. package/src/testing-utils.d.ts +2 -0
  88. package/src/testing-utils.d.ts.map +1 -1
  89. package/src/testing-utils.js +44 -5
  90. package/src/tokens.d.ts +34 -0
  91. package/src/tokens.d.ts.map +1 -0
  92. package/src/tokens.js +35 -0
  93. package/src/typeCheck.d.ts +9 -0
  94. package/src/typeCheck.d.ts.map +1 -0
  95. package/src/typeCheck.js +23 -0
  96. package/src/typeGuards.d.ts +2 -0
  97. package/src/typeGuards.d.ts.map +1 -1
  98. package/src/typeGuards.js +8 -0
  99. package/src/types-index.d.ts +1 -0
  100. package/src/types-index.js +2 -0
  101. package/src/types.d.ts +71 -18
  102. package/src/types.d.ts.map +1 -0
  103. package/src/types.ts +108 -0
  104. package/src/upgrade-api.d.ts +14 -4
  105. package/src/upgrade-api.d.ts.map +1 -1
  106. package/src/upgrade-api.js +50 -18
  107. package/CHANGELOG.md +0 -106
  108. package/src/utils.d.ts +0 -67
  109. package/src/utils.d.ts.map +0 -1
  110. package/src/utils.js +0 -451
@@ -1,10 +1,15 @@
1
1
  // @ts-check
2
2
 
3
- import { E } from '@endo/far';
4
- import { M, heapZone } from '@agoric/zone';
3
+ import { Fail } from '@endo/errors';
4
+ import { E, Far } from '@endo/far';
5
+ import { M } from '@endo/patterns';
6
+ import { makeHeapZone } from '@agoric/base-zone/heap.js';
5
7
  import * as cb from './callback.js';
6
8
 
7
- const { Fail } = assert;
9
+ /**
10
+ * @import {ERef} from '@endo/far';
11
+ * @import {PassableCap} from '@endo/marshal';
12
+ */
8
13
 
9
14
  /** @typedef {ReturnType<typeof import('@endo/marshal').makeMarshal>} Marshaller */
10
15
  /** @typedef {Pick<Marshaller, 'fromCapData'>} Unserializer */
@@ -29,7 +34,8 @@ const { Fail } = assert;
29
34
  /**
30
35
  * This represents a node in an IAVL tree.
31
36
  *
32
- * The active implementation is x/vstorage, an Agoric extension of the Cosmos SDK.
37
+ * The active implementation is x/vstorage, an Agoric extension of the Cosmos
38
+ * SDK.
33
39
  *
34
40
  * Vstorage is a hierarchical externally-reachable storage structure that
35
41
  * identifies children by restricted ASCII name and is associated with arbitrary
@@ -37,9 +43,13 @@ const { Fail } = assert;
37
43
  *
38
44
  * @typedef {object} StorageNode
39
45
  * @property {(data: string) => Promise<void>} setValue publishes some data
40
- * @property {() => string} getPath the chain storage path at which the node was constructed
46
+ * @property {() => string} getPath the chain storage path at which the node was
47
+ * constructed
41
48
  * @property {() => Promise<VStorageKey>} getStoreKey DEPRECATED use getPath
42
- * @property {(subPath: string, options?: {sequence?: boolean}) => StorageNode} makeChildNode
49
+ * @property {(
50
+ * subPath: string,
51
+ * options?: { sequence?: boolean },
52
+ * ) => StorageNode} makeChildNode
43
53
  */
44
54
 
45
55
  const ChainStorageNodeI = M.interface('StorageNode', {
@@ -53,9 +63,8 @@ const ChainStorageNodeI = M.interface('StorageNode', {
53
63
 
54
64
  /**
55
65
  * This is an imperfect heuristic to navigate the migration from value cells to
56
- * stream cells.
57
- * At time of writing, no legacy cells have the same shape as a stream cell,
58
- * and we do not intend to create any more legacy value cells.
66
+ * stream cells. At time of writing, no legacy cells have the same shape as a
67
+ * stream cell, and we do not intend to create any more legacy value cells.
59
68
  *
60
69
  * @param {any} cell
61
70
  * @returns {cell is StreamCell}
@@ -83,49 +92,20 @@ export const assertCapData = data => {
83
92
  };
84
93
  harden(assertCapData);
85
94
 
86
- /**
87
- * Read and unmarshal a value from a map representation of vstorage data
88
- *
89
- * @param {Map<string, string>} data
90
- * @param {string} key
91
- * @param {ReturnType<typeof import('@endo/marshal').makeMarshal>['fromCapData']} fromCapData
92
- * @param {number} [index=-1] index of the desired value in a deserialized stream cell
93
- */
94
- export const unmarshalFromVstorage = (data, key, fromCapData, index = -1) => {
95
- const serialized = data.get(key) || Fail`no data for ${key}`;
96
- assert.typeof(serialized, 'string');
97
-
98
- const streamCell = JSON.parse(serialized);
99
- if (!isStreamCell(streamCell)) {
100
- throw Fail`not a StreamCell: ${streamCell}`;
101
- }
102
-
103
- const { values } = streamCell;
104
- values.length > 0 || Fail`no StreamCell values: ${streamCell}`;
105
-
106
- const marshalled = values.at(index);
107
- assert.typeof(marshalled, 'string');
108
-
109
- /** @type {import("@endo/marshal").CapData<string>} */
110
- const capData = harden(JSON.parse(marshalled));
111
- assertCapData(capData);
112
-
113
- const unmarshalled = fromCapData(capData);
114
- return unmarshalled;
115
- };
116
- harden(unmarshalFromVstorage);
117
-
118
95
  /**
119
96
  * @typedef {object} StoredFacet
120
- * @property {() => Promise<string>} getPath the chain storage path at which the node was constructed
97
+ * @property {() => Promise<string>} getPath the chain storage path at which the
98
+ * node was constructed
121
99
  * @property {StorageNode['getStoreKey']} getStoreKey DEPRECATED use getPath
122
- * @property {() => Unserializer} getUnserializer get the unserializer for the stored data
100
+ * @property {() => Unserializer} getUnserializer get the unserializer for the
101
+ * stored data
123
102
  */
124
103
 
125
104
  // TODO: Formalize segment constraints.
126
105
  // Must be nonempty and disallow (unescaped) `.`, and for simplicity
127
106
  // (and future possibility of e.g. escaping) we currently limit to
128
107
  // ASCII alphanumeric plus underscore and dash.
108
+ // Should remain consistent with golang/cosmos/x/vstorage/types/path_keys.go
129
109
  const pathSegmentPattern = /^[a-zA-Z0-9_-]{1,100}$/;
130
110
 
131
111
  /** @type {(name: string) => void} */
@@ -138,44 +118,65 @@ harden(assertPathSegment);
138
118
  /**
139
119
  * Must match the switch in vstorage.go using `vstorageMessage` type
140
120
  *
141
- * @typedef { 'get' | 'getStoreKey' | 'has' | 'children' | 'entries' | 'values' |'size' } StorageGetByPathMessageMethod
142
- * @typedef { 'set' | 'setWithoutNotify' | 'append' } StorageUpdateEntriesMessageMethod
143
- * @typedef {StorageGetByPathMessageMethod | StorageUpdateEntriesMessageMethod } StorageMessageMethod
144
- * @typedef { [path: string] } StorageGetByPathMessageArgs
145
- * @typedef { [path: string, value?: string | null] } StorageEntry
146
- * @typedef { StorageEntry[] } StorageUpdateEntriesMessageArgs
121
+ * @typedef {'get'
122
+ * | 'getStoreKey'
123
+ * | 'has'
124
+ * | 'children'
125
+ * | 'entries'
126
+ * | 'values'
127
+ * | 'size'} StorageGetByPathMessageMethod
128
+ *
129
+ *
130
+ * @typedef {'set' | 'setWithoutNotify' | 'append'} StorageUpdateEntriesMessageMethod
131
+ *
132
+ *
133
+ * @typedef {StorageGetByPathMessageMethod
134
+ * | StorageUpdateEntriesMessageMethod} StorageMessageMethod
135
+ *
136
+ *
137
+ * @typedef {[path: string]} StorageGetByPathMessageArgs
138
+ *
139
+ * @typedef {[path: string, value?: string | null]} StorageEntry
140
+ *
141
+ * @typedef {StorageEntry[]} StorageUpdateEntriesMessageArgs
142
+ *
147
143
  * @typedef {{
148
- * method: StorageGetByPathMessageMethod;
149
- * args: StorageGetByPathMessageArgs;
150
- * } | {
151
- * method: StorageUpdateEntriesMessageMethod;
152
- * args: StorageUpdateEntriesMessageArgs;
153
- * }} StorageMessage
144
+ * method: StorageGetByPathMessageMethod;
145
+ * args: StorageGetByPathMessageArgs;
146
+ * }
147
+ * | {
148
+ * method: StorageUpdateEntriesMessageMethod;
149
+ * args: StorageUpdateEntriesMessageArgs;
150
+ * }} StorageMessage
154
151
  */
155
152
 
156
153
  /**
157
- * @param {import('@agoric/zone').Zone} zone
154
+ * @param {import('@agoric/base-zone').Zone} zone
158
155
  */
159
156
  export const prepareChainStorageNode = zone => {
160
157
  /**
161
158
  * Create a storage node for a given backing storage interface and path.
162
159
  *
163
- * @param {import('./callback').Callback<(message: StorageMessage) => any>} messenger a callback
164
- * for sending a storageMessage object to the storage implementation
165
- * (cf. golang/cosmos/x/vstorage/vstorage.go)
160
+ * @param {import('./types.js').Callback<
161
+ * (message: StorageMessage) => any
162
+ * >} messenger
163
+ * a callback for sending a storageMessage object to the storage
164
+ * implementation (cf. golang/cosmos/x/vstorage/vstorage.go)
166
165
  * @param {string} path
167
166
  * @param {object} [options]
168
- * @param {boolean} [options.sequence] set values with `append` messages rather than `set` messages
169
- * so the backing implementation employs a wrapping structure that
170
- * preserves each value set within a single block.
171
- * Child nodes default to inheriting this option from their parent.
167
+ * @param {boolean} [options.sequence] set values with `append` messages
168
+ * rather than `set` messages so the backing implementation employs a
169
+ * wrapping structure that preserves each value set within a single block.
170
+ * Child nodes default to inheriting this option from their parent.
172
171
  * @returns {StorageNode}
173
172
  */
174
173
  const makeChainStorageNode = zone.exoClass(
175
174
  'ChainStorageNode',
176
175
  ChainStorageNodeI,
177
176
  /**
178
- * @param {import('./callback').Callback<(message: StorageMessage) => any>} messenger
177
+ * @param {import('./types.js').Callback<
178
+ * (message: StorageMessage) => any
179
+ * >} messenger
179
180
  * @param {string} path
180
181
  * @param {object} [options]
181
182
  * @param {boolean} [options.sequence]
@@ -200,7 +201,12 @@ export const prepareChainStorageNode = zone => {
200
201
  args: [path],
201
202
  });
202
203
  },
203
- /** @type {(name: string, childNodeOptions?: {sequence?: boolean}) => StorageNode} */
204
+ /**
205
+ * @type {(
206
+ * name: string,
207
+ * childNodeOptions?: { sequence?: boolean },
208
+ * ) => StorageNode}
209
+ */
204
210
  makeChildNode(name, childNodeOptions = {}) {
205
211
  const { sequence, path, messenger } = this.state;
206
212
  assertPathSegment(name);
@@ -239,19 +245,20 @@ export const prepareChainStorageNode = zone => {
239
245
  return makeChainStorageNode;
240
246
  };
241
247
 
242
- const makeHeapChainStorageNode = prepareChainStorageNode(heapZone);
248
+ const makeHeapChainStorageNode = prepareChainStorageNode(makeHeapZone());
243
249
 
244
250
  /**
245
- * Create a heap-based root storage node for a given backing function and root path.
251
+ * Create a heap-based root storage node for a given backing function and root
252
+ * path.
246
253
  *
247
254
  * @param {(message: StorageMessage) => any} handleStorageMessage a function for
248
- * sending a storageMessage object to the storage implementation
249
- * (cf. golang/cosmos/x/vstorage/vstorage.go)
255
+ * sending a storageMessage object to the storage implementation (cf.
256
+ * golang/cosmos/x/vstorage/vstorage.go)
250
257
  * @param {string} rootPath
251
258
  * @param {object} [rootOptions]
252
259
  * @param {boolean} [rootOptions.sequence] employ a wrapping structure that
253
- * preserves each value set within a single block, and default child nodes
254
- * to do the same
260
+ * preserves each value set within a single block, and default child nodes to
261
+ * do the same
255
262
  */
256
263
  export function makeChainStorageRoot(
257
264
  handleStorageMessage,
@@ -266,11 +273,15 @@ export function makeChainStorageRoot(
266
273
  }
267
274
 
268
275
  /**
269
- * @returns {StorageNode} an object that confirms to StorageNode API but does not store anywhere.
276
+ * @returns {StorageNode} an object that confirms to StorageNode API but does
277
+ * not store anywhere.
270
278
  */
271
279
  const makeNullStorageNode = () => {
272
280
  // XXX re-use "ChainStorage" methods above which don't actually depend on chains
273
- return makeChainStorageRoot(() => null, 'null');
281
+ return makeChainStorageRoot(
282
+ Far('NullMessenger', () => null),
283
+ 'null',
284
+ );
274
285
  };
275
286
 
276
287
  /**
@@ -278,7 +289,7 @@ const makeNullStorageNode = () => {
278
289
  * falling back to an inert object with the correct interface (but incomplete
279
290
  * behavior) when that is unavailable.
280
291
  *
281
- * @param {import('@endo/far').ERef<StorageNode?>} storageNodeRef
292
+ * @param {ERef<StorageNode?>} storageNodeRef
282
293
  * @param {string} childName
283
294
  * @returns {Promise<StorageNode>}
284
295
  */
@@ -291,9 +302,9 @@ harden(makeStorageNodeChild);
291
302
 
292
303
  // TODO find a better module for this
293
304
  /**
294
- * @param {import('@endo/far').ERef<StorageNode>} storageNode
295
- * @param {import('@endo/far').ERef<Marshaller>} marshaller
296
- * @returns {(value: unknown) => Promise<void>}
305
+ * @param {ERef<StorageNode>} storageNode
306
+ * @param {ERef<Marshaller>} marshaller
307
+ * @returns {(value: PassableCap) => Promise<void>}
297
308
  */
298
309
  export const makeSerializeToStorage = (storageNode, marshaller) => {
299
310
  return async value => {
@@ -0,0 +1,3 @@
1
+ export default engineGC;
2
+ declare const engineGC: GCFunction;
3
+ //# sourceMappingURL=engine-gc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-gc.d.ts","sourceRoot":"","sources":["engine-gc.js"],"names":[],"mappings":";AAoBA,mCAAwB"}
@@ -0,0 +1,22 @@
1
+ import v8 from 'v8';
2
+ import vm from 'vm';
3
+
4
+ /* global globalThis */
5
+ let bestGC = globalThis.gc;
6
+ if (typeof bestGC !== 'function') {
7
+ // Node.js v8 wizardry.
8
+ v8.setFlagsFromString('--expose_gc');
9
+ bestGC = vm.runInNewContext('gc');
10
+ assert(bestGC);
11
+ // We leave --expose_gc turned on, otherwise AVA's shared workers
12
+ // may race and disable it before we manage to extract the
13
+ // binding. This won't cause 'gc' to be visible to new Compartments
14
+ // because SES strips out everything it doesn't recognize.
15
+
16
+ // // Hide the gc global from new contexts/workers.
17
+ // v8.setFlagsFromString('--no-expose_gc');
18
+ }
19
+
20
+ // Export a const.
21
+ const engineGC = bestGC;
22
+ export default engineGC;
@@ -0,0 +1,2 @@
1
+ export function makeGcAndFinalize(gcPower: any): () => Promise<void>;
2
+ //# sourceMappingURL=gc-and-finalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gc-and-finalize.d.ts","sourceRoot":"","sources":["gc-and-finalize.js"],"names":[],"mappings":"AAkEA,qEAwBC"}
@@ -0,0 +1,91 @@
1
+ /* global setImmediate */
2
+
3
+ /* A note on our GC terminology:
4
+ *
5
+ * We define four states for any JS object to be in:
6
+ *
7
+ * REACHABLE: There exists a path from some root (live export or top-level
8
+ * global) to this object, making it ineligible for collection. Userspace vat
9
+ * code has a strong reference to it (and userspace is not given access to
10
+ * WeakRef, so it has no weak reference that might be used to get access).
11
+ *
12
+ * UNREACHABLE: There is no strong reference from a root to the object.
13
+ * Userspace vat code has no means to access the object, although liveslots
14
+ * might (via a WeakRef). The object is eligible for collection, but that
15
+ * collection has not yet happened. The liveslots WeakRef is still alive: if
16
+ * it were to call `.deref()`, it would get the object.
17
+ *
18
+ * COLLECTED: The JS engine has performed enough GC to notice the
19
+ * unreachability of the object, and has collected it. The liveslots WeakRef
20
+ * is dead: `wr.deref() === undefined`. Neither liveslots nor userspace has
21
+ * any way to reach the object, and never will again. A finalizer callback
22
+ * has been queued, but not yet executed.
23
+ *
24
+ * FINALIZED: The JS engine has run the finalizer callback. Once the
25
+ * callback completes, the object is thoroughly dead and unremembered,
26
+ * and no longer exists in one of these four states.
27
+ *
28
+ * The transition from REACHABLE to UNREACHABLE always happens as a result of
29
+ * a message delivery or resolution notification (e.g when userspace
30
+ * overwrites a variable, deletes a Map entry, or a callback on the promise
31
+ * queue which closed over some objects is retired and deleted).
32
+ *
33
+ * The transition from UNREACHABLE to COLLECTED can happen spontaneously, as
34
+ * the JS engine decides it wants to perform GC. It will also happen
35
+ * deliberately if we provoke a GC call with a magic function like `gc()`
36
+ * (when Node.js imports `engine-gc`, which is morally-equivalent to
37
+ * running with `--expose-gc`, or when XS is configured to provide it as a
38
+ * C-level callback). We can force GC, but we cannot prevent it from happening
39
+ * at other times.
40
+ *
41
+ * FinalizationRegistry callbacks are defined to run on their own turn, so
42
+ * the transition from COLLECTED to FINALIZED occurs at a turn boundary.
43
+ * Node.js appears to schedule these finalizers on the timer/IO queue, not
44
+ * the promise/microtask queue. So under Node.js, you need a `setImmediate()`
45
+ * or two to ensure that finalizers have had a chance to run. XS is different
46
+ * but responds well to similar techniques.
47
+ */
48
+
49
+ /*
50
+ * `gcAndFinalize` must be defined in the start compartment. It uses
51
+ * platform-specific features to provide a function which provokes a full GC
52
+ * operation: all "UNREACHABLE" objects should transition to "COLLECTED"
53
+ * before it returns. In addition, `gcAndFinalize()` returns a Promise. This
54
+ * Promise will resolve (with `undefined`) after all FinalizationRegistry
55
+ * callbacks have executed, causing all COLLECTED objects to transition to
56
+ * FINALIZED. If the caller can manage call gcAndFinalize with an empty
57
+ * promise queue, then their .then callback will also start with an empty
58
+ * promise queue, and there will be minimal uncollected unreachable objects
59
+ * in the heap when it begins.
60
+ *
61
+ * `gcAndFinalize` depends upon platform-specific tools to provoke a GC sweep
62
+ * and wait for finalizers to run: a `gc()` function, and `setImmediate`. If
63
+ * these tools do not exist, this function will do nothing, and return a
64
+ * dummy pre-resolved Promise.
65
+ */
66
+
67
+ export function makeGcAndFinalize(gcPower) {
68
+ if (typeof gcPower !== 'function') {
69
+ if (gcPower !== false) {
70
+ // We weren't explicitly disabled, so warn.
71
+ console.warn(
72
+ Error(`no gcPower() function; skipping finalizer provocation`),
73
+ );
74
+ }
75
+ }
76
+ return async function gcAndFinalize() {
77
+ if (typeof gcPower !== 'function') {
78
+ return;
79
+ }
80
+
81
+ // on Node.js, GC seems to work better if the promise queue is empty first
82
+ await new Promise(setImmediate);
83
+ // on xsnap, we must do it twice for some reason
84
+ await new Promise(setImmediate);
85
+ gcPower();
86
+ // this gives finalizers a chance to run
87
+ await new Promise(setImmediate);
88
+ // Node.js seems to need another for promises to get cleared out
89
+ await new Promise(setImmediate);
90
+ };
91
+ }
@@ -0,0 +1,15 @@
1
+ export function startSubprocessWorker(execPath: any, procArgs?: any[], { netstringMaxChunkSize }?: {
2
+ netstringMaxChunkSize?: undefined;
3
+ }): {
4
+ fromChild: {
5
+ on: (...args: any[]) => import("stream").Transform;
6
+ };
7
+ toChild: {
8
+ write: (...args: any[]) => boolean;
9
+ };
10
+ terminate: () => void;
11
+ done: Promise<any>;
12
+ };
13
+ export type IOType = import("child_process").IOType;
14
+ export type Writable = import("stream").Writable;
15
+ //# sourceMappingURL=spawnSubprocessWorker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawnSubprocessWorker.d.ts","sourceRoot":"","sources":["spawnSubprocessWorker.js"],"names":[],"mappings":"AA8BA;;;;;;;;;;;EA0DC;qBApEa,OAAO,eAAe,EAAE,MAAM;uBAC9B,OAAO,QAAQ,EAAE,QAAQ"}
@@ -0,0 +1,89 @@
1
+ // this file is loaded by the controller, in the start compartment
2
+ import { spawn } from 'child_process';
3
+ import { makePromiseKit } from '@endo/promise-kit';
4
+ import { NonNullish } from '../errors.js';
5
+ import { arrayEncoderStream, arrayDecoderStream } from './worker-protocol.js';
6
+ import {
7
+ netstringEncoderStream,
8
+ netstringDecoderStream,
9
+ } from '../netstring.js';
10
+
11
+ // Start a subprocess from a given executable, and arrange a bidirectional
12
+ // message channel with a "supervisor" within that process. Return a {
13
+ // toChild, fromChild } pair of Streams which accept/emit hardened Arrays of
14
+ // JSON-serializable data.
15
+
16
+ // eslint-disable-next-line no-unused-vars
17
+ function parentLog(first, ...args) {
18
+ // console.error(`--parent: ${first}`, ...args);
19
+ }
20
+
21
+ /** @typedef {import('child_process').IOType} IOType */
22
+ /** @typedef {import('stream').Writable} Writable */
23
+
24
+ // we send on fd3, and receive on fd4. We pass fd1/2 (stdout/err) through, so
25
+ // console log/err from the child shows up normally. We don't use Node's
26
+ // built-in serialization feature ('ipc') because the child process won't
27
+ // always be Node.
28
+ /** @type {IOType[]} */
29
+ const stdio = harden(['inherit', 'inherit', 'inherit', 'pipe', 'pipe']);
30
+
31
+ export function startSubprocessWorker(
32
+ execPath,
33
+ procArgs = [],
34
+ { netstringMaxChunkSize = undefined } = {},
35
+ ) {
36
+ const proc = spawn(execPath, procArgs, { stdio });
37
+
38
+ const toChild = arrayEncoderStream();
39
+ toChild
40
+ .pipe(netstringEncoderStream())
41
+ .pipe(/** @type {Writable} */ (proc.stdio[3]));
42
+ // proc.stdio[4].setEncoding('utf-8');
43
+ const fromChild = NonNullish(proc.stdio[4])
44
+ .pipe(netstringDecoderStream(netstringMaxChunkSize))
45
+ .pipe(arrayDecoderStream());
46
+
47
+ // fromChild.addListener('data', data => parentLog(`fd4 data`, data));
48
+ // toChild.write('hello child');
49
+
50
+ const pk = makePromiseKit();
51
+
52
+ proc.once('exit', code => {
53
+ parentLog('child exit', code);
54
+ pk.resolve(code);
55
+ });
56
+ proc.once('error', e => {
57
+ parentLog('child error', e);
58
+ pk.reject(e);
59
+ });
60
+ parentLog(`waiting on child`);
61
+
62
+ function terminate() {
63
+ proc.kill();
64
+ }
65
+
66
+ // the Transform objects don't like being hardened, so we wrap the methods
67
+ // that get used
68
+ /* @type {typeof fromChild} */
69
+ const wrappedFromChild = {
70
+ on: (...args) =>
71
+ fromChild.on(
72
+ .../** @type {Parameters<(typeof fromChild)['on']>} */ (args),
73
+ ),
74
+ };
75
+ /* @type {typeof toChild} */
76
+ const wrappedToChild = {
77
+ write: (...args) =>
78
+ toChild.write(
79
+ .../** @type {Parameters<(typeof toChild)['write']>} */ (args),
80
+ ),
81
+ };
82
+
83
+ return harden({
84
+ fromChild: wrappedFromChild,
85
+ toChild: wrappedToChild,
86
+ terminate,
87
+ done: pk.promise,
88
+ });
89
+ }
@@ -0,0 +1,2 @@
1
+ export function waitUntilQuiescent(): Promise<void>;
2
+ //# sourceMappingURL=waitUntilQuiescent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waitUntilQuiescent.d.ts","sourceRoot":"","sources":["waitUntilQuiescent.js"],"names":[],"mappings":"AAMA,oDAWC"}
@@ -0,0 +1,18 @@
1
+ /* global setImmediate */
2
+ import { makePromiseKit } from '@endo/promise-kit';
3
+
4
+ // This can only be imported from the Start Compartment, where 'setImmediate'
5
+ // is available.
6
+
7
+ export function waitUntilQuiescent() {
8
+ // the delivery might cause some number of (native) Promises to be
9
+ // created and resolved, so we use the IO queue to detect when the
10
+ // Promise queue is empty. The IO queue (setImmediate and setTimeout) is
11
+ // lower-priority than the Promise queue on browsers and Node 11, but on
12
+ // Node 10 it is higher. So this trick requires Node 11.
13
+ // https://jsblog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
14
+ /** @type {import('@endo/promise-kit').PromiseKit<void>} */
15
+ const { promise: queueEmptyP, resolve } = makePromiseKit();
16
+ setImmediate(() => resolve());
17
+ return queueEmptyP;
18
+ }
@@ -0,0 +1,4 @@
1
+ export function arrayEncoderStream(): Transform;
2
+ export function arrayDecoderStream(): Transform;
3
+ import { Transform } from 'stream';
4
+ //# sourceMappingURL=worker-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-protocol.d.ts","sourceRoot":"","sources":["worker-protocol.js"],"names":[],"mappings":"AAMA,gDAqBC;AAED,gDAwBC;0BApDyB,QAAQ"}
@@ -0,0 +1,54 @@
1
+ /* eslint-env node */
2
+ import { Transform } from 'stream';
3
+
4
+ // Transform objects which convert from hardened Arrays of JSON-serializable
5
+ // data into Buffers suitable for netstring conversion.
6
+
7
+ export function arrayEncoderStream() {
8
+ /**
9
+ * @param {any} object
10
+ * @param {BufferEncoding} encoding
11
+ * @param {any} callback
12
+ * @this {{ push: (b: Buffer) => void }}
13
+ */
14
+ function transform(object, encoding, callback) {
15
+ if (!Array.isArray(object)) {
16
+ throw Error('stream requires Arrays');
17
+ }
18
+ let err;
19
+ try {
20
+ this.push(Buffer.from(JSON.stringify(object)));
21
+ } catch (e) {
22
+ err = e;
23
+ }
24
+ callback(err);
25
+ }
26
+ // Array in, Buffer out, hence writableObjectMode
27
+ return new Transform({ transform, writableObjectMode: true });
28
+ }
29
+
30
+ export function arrayDecoderStream() {
31
+ /**
32
+ * @param {Buffer} buf
33
+ * @param {BufferEncoding} encoding
34
+ * @param {any} callback
35
+ * @this {{ push: (b: Buffer) => void }}
36
+ */
37
+ function transform(buf, encoding, callback) {
38
+ let err;
39
+ try {
40
+ if (!Buffer.isBuffer(buf)) {
41
+ throw Error('stream expects Buffers');
42
+ }
43
+ this.push(JSON.parse(buf.toString()));
44
+ } catch (e) {
45
+ err = e;
46
+ }
47
+ // this Transform is a one-to-one conversion of Buffer into Array, so we
48
+ // always consume the input each time we're called
49
+ callback(err);
50
+ }
51
+
52
+ // Buffer in, Array out, hence readableObjectMode
53
+ return new Transform({ transform, readableObjectMode: true });
54
+ }
@@ -3,8 +3,8 @@
3
3
  const cookie = harden({});
4
4
 
5
5
  /**
6
- * Facilitate static analysis to prevent
7
- * demo/test facilities from being bundled in production.
6
+ * Facilitate static analysis to prevent demo/test facilities from being bundled
7
+ * in production.
8
8
  */
9
9
  export const notForProductionUse = () => {
10
10
  return cookie;
@@ -0,0 +1,20 @@
1
+ export function makeBoardRemote({ boardId, iface }: {
2
+ boardId: string | null;
3
+ iface?: string;
4
+ }): BoardRemote;
5
+ export function slotToBoardRemote(boardId: string, iface: string): BoardRemote;
6
+ export function boardSlottingMarshaller(slotToVal?: ((slot: string, iface: string) => any) | undefined): Omit<import("@endo/marshal").Marshal<string | null>, "serialize" | "unserialize">;
7
+ export function unmarshalFromVstorage(data: Map<string, string>, key: string, fromCapData: ReturnType<typeof import("@endo/marshal").makeMarshal>["fromCapData"], index: number): any;
8
+ export function makeHistoryReviver(entries: [string, string][], slotToVal?: ((slot: string, iface?: string) => any) | undefined): {
9
+ getItem: (key: string) => any;
10
+ children: (prefix: string) => string[];
11
+ has: (k: string) => boolean;
12
+ };
13
+ /**
14
+ * Should be a union with Remotable, but that's `any`, making this type
15
+ * meaningless
16
+ */
17
+ export type BoardRemote = {
18
+ getBoardId: () => string | null;
19
+ };
20
+ //# sourceMappingURL=marshal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marshal.d.ts","sourceRoot":"","sources":["marshal.js"],"names":[],"mappings":"AAiBO,oDAHI;IAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,WAAW,CAKvB;AAMM,2CAHI,MAAM,SACN,MAAM,eAGoB;AAqB9B,4DANW,MAAM,SAAS,MAAM,KAAK,GAAG,gBAClC,IAAI,CAChB,OAAW,eAAe,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAClD,WAAe,GAAG,aAAa,CAC5B,CAMH;AA6BM,4CATI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,OACnB,MAAM,eACN,UAAU,CACpB,cAAkB,eAAe,EAAE,WAAW,CAC3C,CAAC,aAAa,CAAC,SACR,MAAM,GAEJ,GAAG,CAwBf;AASM,4CAHI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,sBACX,MAAM,UAAU,MAAM,KAAK,GAAG;mBAQlC,MAAM;uBAEN,MAAM;aAYN,MAAM;EAInB;;;;;0BA9HY;IAAE,UAAU,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;CAAE"}