@agoric/internal 0.3.3-other-dev-8f8782b.0 → 0.3.3-other-dev-fbe72e7.0.fbe72e7

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 (131) hide show
  1. package/README.md +7 -2
  2. package/exported.js +2 -0
  3. package/package.json +41 -19
  4. package/src/action-types.d.ts +51 -5
  5. package/src/action-types.d.ts.map +1 -1
  6. package/src/action-types.js +74 -15
  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 +24 -17
  11. package/src/callback.d.ts.map +1 -1
  12. package/src/callback.js +55 -61
  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 +27 -0
  17. package/src/chain-utils.d.ts.map +1 -0
  18. package/src/chain-utils.js +62 -0
  19. package/src/cli-utils.d.ts +2 -0
  20. package/src/cli-utils.d.ts.map +1 -0
  21. package/src/cli-utils.js +21 -0
  22. package/src/config.d.ts +22 -12
  23. package/src/config.d.ts.map +1 -1
  24. package/src/config.js +23 -10
  25. package/src/debug.d.ts +1 -1
  26. package/src/errors.d.ts +2 -0
  27. package/src/errors.d.ts.map +1 -0
  28. package/src/errors.js +16 -0
  29. package/src/hex.d.ts +15 -0
  30. package/src/hex.d.ts.map +1 -0
  31. package/src/hex.js +105 -0
  32. package/src/index.d.ts +10 -1
  33. package/src/index.js +13 -2
  34. package/src/install-ses-debug.d.ts +2 -0
  35. package/src/install-ses-debug.d.ts.map +1 -0
  36. package/src/install-ses-debug.js +6 -0
  37. package/src/js-utils.d.ts +40 -0
  38. package/src/js-utils.d.ts.map +1 -0
  39. package/src/js-utils.js +237 -0
  40. package/src/lib-chainStorage.d.ts +59 -67
  41. package/src/lib-chainStorage.d.ts.map +1 -1
  42. package/src/lib-chainStorage.js +95 -92
  43. package/src/lib-nodejs/ava-unhandled-rejection.d.ts +13 -0
  44. package/src/lib-nodejs/ava-unhandled-rejection.d.ts.map +1 -0
  45. package/src/lib-nodejs/ava-unhandled-rejection.js +66 -0
  46. package/src/lib-nodejs/engine-gc.d.ts +3 -0
  47. package/src/lib-nodejs/engine-gc.d.ts.map +1 -0
  48. package/src/lib-nodejs/engine-gc.js +22 -0
  49. package/src/lib-nodejs/gc-and-finalize.d.ts +2 -0
  50. package/src/lib-nodejs/gc-and-finalize.d.ts.map +1 -0
  51. package/src/lib-nodejs/gc-and-finalize.js +91 -0
  52. package/src/lib-nodejs/spawnSubprocessWorker.d.ts +15 -0
  53. package/src/lib-nodejs/spawnSubprocessWorker.d.ts.map +1 -0
  54. package/src/lib-nodejs/spawnSubprocessWorker.js +89 -0
  55. package/src/lib-nodejs/waitUntilQuiescent.d.ts +2 -0
  56. package/src/lib-nodejs/waitUntilQuiescent.d.ts.map +1 -0
  57. package/src/lib-nodejs/waitUntilQuiescent.js +18 -0
  58. package/src/lib-nodejs/worker-protocol.d.ts +4 -0
  59. package/src/lib-nodejs/worker-protocol.d.ts.map +1 -0
  60. package/src/lib-nodejs/worker-protocol.js +54 -0
  61. package/src/magic-cookie-test-only.js +2 -2
  62. package/src/marshal.d.ts +33 -0
  63. package/src/marshal.d.ts.map +1 -0
  64. package/src/marshal.js +156 -0
  65. package/src/method-tools.d.ts +1 -0
  66. package/src/method-tools.d.ts.map +1 -1
  67. package/src/method-tools.js +33 -62
  68. package/src/metrics.d.ts +183 -0
  69. package/src/metrics.d.ts.map +1 -0
  70. package/src/metrics.js +476 -0
  71. package/src/module-utils.d.ts +2 -0
  72. package/src/module-utils.d.ts.map +1 -0
  73. package/src/module-utils.js +27 -0
  74. package/src/natural-sort.d.ts +2 -0
  75. package/src/natural-sort.d.ts.map +1 -0
  76. package/src/natural-sort.js +48 -0
  77. package/src/netstring.d.ts +24 -0
  78. package/src/netstring.d.ts.map +1 -0
  79. package/src/netstring.js +125 -0
  80. package/src/node/buffer-line-transform.d.ts +20 -16
  81. package/src/node/buffer-line-transform.d.ts.map +1 -1
  82. package/src/node/buffer-line-transform.js +12 -9
  83. package/src/node/createBundles.d.ts.map +1 -1
  84. package/src/node/createBundles.js +12 -3
  85. package/src/node/fs-stream.d.ts +1 -1
  86. package/src/node/fs-stream.d.ts.map +1 -1
  87. package/src/node/fs-stream.js +48 -37
  88. package/src/node/shutdown.d.ts.map +1 -1
  89. package/src/node/shutdown.js +0 -1
  90. package/src/priority-senders.d.ts +2 -1
  91. package/src/priority-senders.d.ts.map +1 -1
  92. package/src/priority-senders.js +10 -4
  93. package/src/queue.d.ts +1 -1
  94. package/src/queue.d.ts.map +1 -1
  95. package/src/queue.js +7 -8
  96. package/src/scratch.d.ts +1 -1
  97. package/src/scratch.d.ts.map +1 -1
  98. package/src/ses-utils.d.ts +68 -0
  99. package/src/ses-utils.d.ts.map +1 -0
  100. package/src/ses-utils.js +422 -0
  101. package/src/storage-test-utils.d.ts +49 -84
  102. package/src/storage-test-utils.d.ts.map +1 -1
  103. package/src/storage-test-utils.js +234 -116
  104. package/src/tagged.d.ts +152 -0
  105. package/src/testing-utils.d.ts +2 -0
  106. package/src/testing-utils.d.ts.map +1 -1
  107. package/src/testing-utils.js +44 -5
  108. package/src/tmpDir.d.ts +2 -0
  109. package/src/tmpDir.d.ts.map +1 -0
  110. package/src/tmpDir.js +17 -0
  111. package/src/tokens.d.ts +34 -0
  112. package/src/tokens.d.ts.map +1 -0
  113. package/src/tokens.js +35 -0
  114. package/src/typeCheck.d.ts +9 -0
  115. package/src/typeCheck.d.ts.map +1 -0
  116. package/src/typeCheck.js +23 -0
  117. package/src/typeGuards.d.ts +17 -0
  118. package/src/typeGuards.d.ts.map +1 -1
  119. package/src/typeGuards.js +20 -0
  120. package/src/types-index.d.ts +1 -0
  121. package/src/types-index.js +2 -0
  122. package/src/types.d.ts +83 -18
  123. package/src/types.d.ts.map +1 -0
  124. package/src/types.ts +129 -0
  125. package/src/upgrade-api.d.ts +14 -4
  126. package/src/upgrade-api.d.ts.map +1 -1
  127. package/src/upgrade-api.js +50 -18
  128. package/CHANGELOG.md +0 -106
  129. package/src/utils.d.ts +0 -67
  130. package/src/utils.d.ts.map +0 -1
  131. package/src/utils.js +0 -451
@@ -1,33 +1,24 @@
1
1
  // @ts-check
2
+ import { Fail } from '@endo/errors';
2
3
  import { Far } from '@endo/far';
3
4
  import { makeMarshal, Remotable } from '@endo/marshal';
4
5
  import { makeTracer } from './debug.js';
5
- import {
6
- isStreamCell,
7
- makeChainStorageRoot,
8
- unmarshalFromVstorage,
9
- } from './lib-chainStorage.js';
6
+ import { NonNullish } from './errors.js';
7
+ import { isStreamCell, makeChainStorageRoot } from './lib-chainStorage.js';
8
+ import { unmarshalFromVstorage } from './marshal.js';
10
9
  import { bindAllMethods } from './method-tools.js';
11
-
12
- const { Fail } = assert;
13
-
14
- const trace = makeTracer('StorTU', false);
10
+ import { eventLoopIteration } from './testing-utils.js';
15
11
 
16
12
  /**
17
- * A map corresponding with a total function such that `get(key)`
18
- * is assumed to always succeed.
19
- *
20
- * @template K, V
21
- * @typedef {{[k in Exclude<keyof Map<K, V>, 'get'>]: Map<K, V>[k]} & {get: (key: K) => V}} TotalMap
22
- */
23
- /**
24
- * @template T
25
- * @typedef {T extends Map<infer K, infer V> ? TotalMap<K, V> : never} TotalMapFrom
13
+ * @import {TotalMap} from './types.js';
14
+ * @import {Marshaller, StorageEntry, StorageMessage, StorageNode, StreamCell} from './lib-chainStorage.js';
26
15
  */
27
16
 
17
+ const trace = makeTracer('StorTU', false);
18
+
28
19
  /**
29
- * A convertSlotToVal function that produces basic Remotables. Assumes
30
- * that all slots are Remotables (i.e. none are Promises).
20
+ * A convertSlotToVal function that produces basic Remotables. Assumes that all
21
+ * slots are Remotables (i.e. none are Promises).
31
22
  *
32
23
  * @param {string} _slotId
33
24
  * @param {string} iface
@@ -36,34 +27,44 @@ export const slotToRemotable = (_slotId, iface = 'Remotable') =>
36
27
  Remotable(iface);
37
28
 
38
29
  /**
39
- * A basic marshaller whose unserializer produces Remotables. It can
40
- * only serialize plain data, not Remotables.
30
+ * A basic marshaller whose unserializer produces Remotables. It can only
31
+ * serialize plain data, not Remotables.
41
32
  */
42
33
  export const defaultMarshaller = makeMarshal(undefined, slotToRemotable, {
43
34
  serializeBodyFormat: 'smallcaps',
44
35
  });
45
36
 
46
37
  /**
47
- * A deserializer which produces slot strings instead of Remotables,
48
- * so if `a = Far('iface')`, and serializing `{ a }` into `capData`
49
- * assigned it slot `board123`, then `slotStringUnserialize(capData)`
50
- * would produce `{ a: 'board123' }`.
38
+ * Serialize/deserialize functions using {@link defaultMarshaller}
39
+ */
40
+ export const defaultSerializer = {
41
+ /** @type {(text: string) => unknown} */
42
+ parse: txt => defaultMarshaller.fromCapData(JSON.parse(txt)),
43
+ /** @type {(obj: any) => string} */
44
+ stringify: obj => JSON.stringify(defaultMarshaller.toCapData(obj)),
45
+ };
46
+
47
+ /**
48
+ * A deserializer which produces slot strings instead of Remotables, so if `a =
49
+ * Far('iface')`, and serializing `{ a }` into `capData` assigned it slot
50
+ * `board123`, then `slotStringUnserialize(capData)` would produce `{ a:
51
+ * 'board123' }`.
51
52
  *
52
53
  * This may be useful for display purposes.
53
54
  *
54
55
  * Limitations:
55
- * * it cannot handle Symbols (registered or well-known)
56
- * * it can handle BigInts, but serialized data that contains a
57
- * particular unusual string will be unserialized into a BigInt by
58
- * mistake
59
- * * it cannot handle Promises, NaN, +/- Infinity, undefined, or
60
- * other non-JSONable JavaScript values
56
+ *
57
+ * - it cannot handle Symbols (registered or well-known)
58
+ * - it can handle BigInts, but serialized data that contains a particular unusual
59
+ * string will be unserialized into a BigInt by mistake
60
+ * - it cannot handle Promises, NaN, +/- Infinity, undefined, or other
61
+ * non-JSONable JavaScript values
61
62
  */
62
63
  const makeSlotStringUnserialize = () => {
63
- /** @type { (slot: string, iface: string) => any } */
64
+ /** @type {(slot: string, iface: string) => any} */
64
65
  const identitySlotToValFn = (slot, _) => Far('unk', { toJSON: () => slot });
65
66
  const { fromCapData } = makeMarshal(undefined, identitySlotToValFn);
66
- /** @type { (capData: any) => any } */
67
+ /** @type {(capData: any) => any} */
67
68
  const unserialize = capData =>
68
69
  JSON.parse(
69
70
  JSON.stringify(fromCapData(capData), (_, val) => {
@@ -88,9 +89,9 @@ const makeSlotStringUnserialize = () => {
88
89
  export const slotStringUnserialize = makeSlotStringUnserialize();
89
90
 
90
91
  /**
91
- * For testing, creates a chainStorage root node over an in-memory map
92
- * and exposes both the map and the sequence of received messages.
93
- * The `sequence` option defaults to true.
92
+ * For testing, creates a chainStorage root node over an in-memory map and
93
+ * exposes both the map and the sequence of received messages. The `sequence`
94
+ * option defaults to true.
94
95
  *
95
96
  * @param {string} rootPath
96
97
  * @param {Parameters<typeof makeChainStorageRoot>[2]} [rootOptions]
@@ -99,6 +100,14 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
99
100
  const resolvedOptions = { sequence: true, ...rootOptions };
100
101
  /** @type {TotalMap<string, string>} */
101
102
  const data = new Map();
103
+ let currentBlockHeight = 0;
104
+
105
+ const updateNewCellBlockHeight = (blockHeight = currentBlockHeight + 1) => {
106
+ blockHeight > currentBlockHeight ||
107
+ Fail`blockHeight ${blockHeight} must be greater than ${currentBlockHeight}`;
108
+ currentBlockHeight = blockHeight;
109
+ };
110
+
102
111
  /** @param {string} prefix */
103
112
  const getChildEntries = prefix => {
104
113
  assert(prefix.endsWith('.'));
@@ -116,114 +125,166 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
116
125
  }
117
126
  return childEntries;
118
127
  };
119
- /** @type {import('../src/lib-chainStorage.js').StorageMessage[]} */
128
+ /** @type {StorageMessage[]} */
120
129
  const messages = [];
121
- /** @param {import('../src/lib-chainStorage.js').StorageMessage} message */
122
- // eslint-disable-next-line consistent-return
123
- const toStorage = message => {
124
- messages.push(message);
125
- switch (message.method) {
126
- case 'getStoreKey': {
127
- const [key] = message.args;
128
- return { storeName: 'swingset', storeSubkey: `fake:${key}` };
129
- }
130
- case 'get': {
131
- const [key] = message.args;
132
- return data.has(key) ? data.get(key) : null;
133
- }
134
- case 'children': {
135
- const [key] = message.args;
136
- const childEntries = getChildEntries(`${key}.`);
137
- return [...childEntries.keys()];
138
- }
139
- case 'entries': {
140
- const [key] = message.args;
141
- const childEntries = getChildEntries(`${key}.`);
142
- return [...childEntries.entries()].map(entry =>
143
- entry[1] != null ? entry : [entry[0]],
144
- );
145
- }
146
- case 'set':
147
- case 'setWithoutNotify': {
148
- trace('toStorage set', message);
149
- /** @type {import('../src/lib-chainStorage.js').StorageEntry[]} */
150
- const newEntries = message.args;
151
- for (const [key, value] of newEntries) {
152
- if (value != null) {
153
- data.set(key, value);
154
- } else {
155
- data.delete(key);
156
- }
130
+
131
+ const toStorage = Far(
132
+ 'ToStorage',
133
+ /** @param {StorageMessage} message */
134
+ message => {
135
+ messages.push(message);
136
+ switch (message.method) {
137
+ case 'getStoreKey': {
138
+ const [key] = message.args;
139
+ return { storeName: 'swingset', storeSubkey: `fake:${key}` };
157
140
  }
158
- break;
159
- }
160
- case 'append': {
161
- trace('toStorage append', message);
162
- /** @type {import('../src/lib-chainStorage.js').StorageEntry[]} */
163
- const newEntries = message.args;
164
- for (const [key, value] of newEntries) {
165
- value != null || Fail`attempt to append with no value`;
166
- // In the absence of block boundaries, everything goes in a single StreamCell.
167
- const oldVal = data.get(key);
168
- let streamCell;
169
- if (oldVal != null) {
170
- try {
171
- streamCell = JSON.parse(oldVal);
172
- assert(isStreamCell(streamCell));
173
- } catch (_err) {
174
- streamCell = undefined;
141
+ case 'get': {
142
+ const [key] = message.args;
143
+ return data.has(key) ? data.get(key) : null;
144
+ }
145
+ case 'children': {
146
+ const [key] = message.args;
147
+ const childEntries = getChildEntries(`${key}.`);
148
+ return [...childEntries.keys()];
149
+ }
150
+ case 'entries': {
151
+ const [key] = message.args;
152
+ const childEntries = getChildEntries(`${key}.`);
153
+ return [...childEntries.entries()].map(entry =>
154
+ entry[1] != null ? entry : [entry[0]],
155
+ );
156
+ }
157
+ case 'set':
158
+ case 'setWithoutNotify': {
159
+ trace('toStorage set', message);
160
+ /** @type {StorageEntry[]} */
161
+ const newEntries = message.args;
162
+ for (const [key, value] of newEntries) {
163
+ if (value != null) {
164
+ data.set(key, value);
165
+ } else {
166
+ data.delete(key);
175
167
  }
176
168
  }
177
- if (streamCell === undefined) {
178
- streamCell = {
179
- blockHeight: '0',
180
- values: oldVal != null ? [oldVal] : [],
181
- };
169
+ return true;
170
+ }
171
+ case 'append': {
172
+ trace('toStorage append', message);
173
+ /** @type {StorageEntry[]} */
174
+ const newEntries = message.args;
175
+ for (const [key, value] of newEntries) {
176
+ value != null || Fail`attempt to append with no value`;
177
+
178
+ /** @type {string | undefined} */
179
+ let oldVal = data.get(key);
180
+ /** @type {StreamCell | undefined} */
181
+ let streamCell;
182
+ if (oldVal != null) {
183
+ try {
184
+ streamCell = JSON.parse(oldVal);
185
+ assert(isStreamCell(streamCell));
186
+ } catch (_err) {
187
+ streamCell = undefined;
188
+ }
189
+ // StreamCells reset at block boundaries.
190
+ if (
191
+ streamCell &&
192
+ Number(streamCell.blockHeight) !== currentBlockHeight
193
+ ) {
194
+ streamCell = undefined;
195
+ oldVal = undefined;
196
+ }
197
+ }
198
+
199
+ if (streamCell === undefined) {
200
+ streamCell = {
201
+ blockHeight: String(currentBlockHeight),
202
+ values: oldVal != null ? [oldVal] : [],
203
+ };
204
+ }
205
+ streamCell.values.push(value);
206
+ data.set(key, JSON.stringify(streamCell));
182
207
  }
183
- streamCell.values.push(value);
184
- data.set(key, JSON.stringify(streamCell));
208
+ return true;
185
209
  }
186
- break;
210
+ case 'size':
211
+ // Intentionally incorrect because it counts non-child descendants,
212
+ // but nevertheless supports a "has children" test.
213
+ return [...data.keys()].filter(k =>
214
+ k.startsWith(`${message.args[0]}.`),
215
+ ).length;
216
+ default:
217
+ throw Error(`unsupported method: ${message.method}`);
187
218
  }
188
- case 'size':
189
- // Intentionally incorrect because it counts non-child descendants,
190
- // but nevertheless supports a "has children" test.
191
- return [...data.keys()].filter(k => k.startsWith(`${message.args[0]}.`))
192
- .length;
193
- default:
194
- throw Error(`unsupported method: ${message.method}`);
195
- }
196
- };
219
+ },
220
+ );
197
221
  const rootNode = makeChainStorageRoot(toStorage, rootPath, resolvedOptions);
222
+
223
+ /**
224
+ * Get the values at a sequence node
225
+ *
226
+ * @param {string} path
227
+ * @returns {string[]}
228
+ */
229
+ const getValues = path => {
230
+ assert(resolvedOptions.sequence);
231
+ const nodeData = data.get(path);
232
+ assert(nodeData, `no data at path ${path}`);
233
+ const wrapper = JSON.parse(nodeData);
234
+ return wrapper.values;
235
+ };
236
+
198
237
  return {
199
238
  rootNode,
200
239
  // eslint-disable-next-line object-shorthand
201
240
  data: /** @type {Map<string, string>} */ (data),
241
+ updateNewCellBlockHeight,
242
+ getValues,
202
243
  messages,
203
244
  toStorage,
204
245
  };
205
246
  };
206
247
  harden(makeFakeStorageKit);
207
- /** @typedef {ReturnType< typeof makeFakeStorageKit>} FakeStorageKit */
248
+ /** @typedef {ReturnType<typeof makeFakeStorageKit>} FakeStorageKit */
249
+
250
+ /**
251
+ * @typedef MockChainStorageRootMethods
252
+ * @property {(
253
+ * path: string,
254
+ * marshaller?: Marshaller,
255
+ * index?: number,
256
+ * ) => unknown} getBody
257
+ * Defaults to deserializing slot references into plain Remotable objects having
258
+ * the specified interface name (as from `Far(iface)`), but can accept a
259
+ * different marshaller for producing Remotables that e.g. embed the slot
260
+ * string in their iface name.
261
+ * @property {() => string[]} keys
262
+ */
263
+ /** @typedef {StorageNode & MockChainStorageRootMethods} MockChainStorageRoot */
208
264
 
265
+ /** @returns {MockChainStorageRoot} */
209
266
  export const makeMockChainStorageRoot = () => {
210
267
  const { rootNode, data } = makeFakeStorageKit('mockChainStorageRoot');
211
268
  return Far('mockChainStorage', {
212
269
  ...bindAllMethods(rootNode),
213
270
  /**
214
- * Defaults to deserializing slot references into plain Remotable
215
- * objects having the specified interface name (as from `Far(iface)`),
216
- * but can accept a different marshaller for producing Remotables
217
- * that e.g. embed the slot string in their iface name.
271
+ * Defaults to deserializing slot references into plain Remotable objects
272
+ * having the specified interface name (as from `Far(iface)`), but can
273
+ * accept a different marshaller for producing Remotables that e.g. embed
274
+ * the slot string in their iface name.
218
275
  *
219
276
  * @param {string} path
220
- * @param {import('./lib-chainStorage.js').Marshaller} marshaller
277
+ * @param {Marshaller} marshaller
221
278
  * @param {number} [index]
222
279
  * @returns {unknown}
223
280
  */
224
281
  getBody: (path, marshaller = defaultMarshaller, index = -1) => {
225
282
  data.size || Fail`no data in storage`;
226
- /** @type {ReturnType<typeof import('@endo/marshal').makeMarshal>['fromCapData']} */
283
+ /**
284
+ * @type {ReturnType<
285
+ * typeof import('@endo/marshal').makeMarshal
286
+ * >['fromCapData']}
287
+ */
227
288
  const fromCapData = (...args) =>
228
289
  Reflect.apply(marshaller.fromCapData, marshaller, args);
229
290
  return unmarshalFromVstorage(data, path, fromCapData, index);
@@ -231,4 +292,61 @@ export const makeMockChainStorageRoot = () => {
231
292
  keys: () => [...data.keys()],
232
293
  });
233
294
  };
234
- /** @typedef {ReturnType<typeof makeMockChainStorageRoot>} MockChainStorageRoot */
295
+
296
+ /**
297
+ * @param {import('ava').ExecutionContext<unknown>} t
298
+ * @param {MockChainStorageRoot | FakeStorageKit} storage
299
+ * @param {({ note: string } | { node: string; owner: string }) &
300
+ * ({ pattern: string; replacement: string } | {}) & {
301
+ * showValue?: (v: string) => unknown;
302
+ * }} opts
303
+ */
304
+ export const documentStorageSchema = async (t, storage, opts) => {
305
+ // chainStorage publication is unsynchronized
306
+ await eventLoopIteration();
307
+
308
+ const getLast = (/** @type {string} */ cell) =>
309
+ JSON.parse(cell).values.at(-1) || assert.fail();
310
+ const { showValue = s => s } = opts;
311
+ /** @type {(d: Map<string, string>, k: string) => unknown} */
312
+ const getBodyDefault = (d, k) => showValue(getLast(NonNullish(d.get(k))));
313
+
314
+ const [keys, getBody] =
315
+ 'keys' in storage
316
+ ? [storage.keys(), (/** @type {string} */ k) => storage.getBody(k)]
317
+ : [
318
+ storage.data.keys(),
319
+ (/** @type {string} */ k) => getBodyDefault(storage.data, k),
320
+ ];
321
+
322
+ const { pattern, replacement } =
323
+ 'pattern' in opts
324
+ ? opts
325
+ : { pattern: 'mockChainStorageRoot.', replacement: 'published.' };
326
+
327
+ const pruned = [...keys]
328
+ .sort()
329
+ .filter(
330
+ 'node' in opts
331
+ ? key =>
332
+ key
333
+ .replace(pattern, replacement)
334
+ .startsWith(`published.${opts.node}`)
335
+ : _entry => true,
336
+ );
337
+
338
+ const illustration = pruned.map(
339
+ /** @type {(k: string) => [string, unknown]} */
340
+ key => [key.replace(pattern, replacement), getBody(key)],
341
+ );
342
+
343
+ const note =
344
+ 'note' in opts
345
+ ? opts.note
346
+ : `Under "published", the "${opts.node}" node is delegated to ${opts.owner}.`;
347
+ const boilerplate = `
348
+ The example below illustrates the schema of the data published there.
349
+
350
+ See also board marshalling conventions (_to appear_).`;
351
+ t.snapshot(illustration, note + boilerplate);
352
+ };
@@ -0,0 +1,152 @@
1
+ /** @file adapted from https://raw.githubusercontent.com/sindresorhus/type-fest/main/source/tagged.d.ts */
2
+
3
+ // different name to avoid confusion with pass-style "tagged"
4
+ export { Tagged as TypeTag };
5
+
6
+ declare const tag: unique symbol;
7
+
8
+ export type TagContainer<Token> = {
9
+ readonly [tag]: Token;
10
+ };
11
+
12
+ type Tag<Token extends PropertyKey, TagMetadata> = TagContainer<{
13
+ [K in Token]: TagMetadata;
14
+ }>;
15
+
16
+ /**
17
+ Attach a "tag" to an arbitrary type. This allows you to create distinct types, that aren't assignable to one another, for distinct concepts in your program that should not be interchangeable, even if their runtime values have the same type. (See examples.)
18
+
19
+ A type returned by `Tagged` can be passed to `Tagged` again, to create a type with multiple tags.
20
+
21
+ [Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
22
+
23
+ A tag's name is usually a string (and must be a string, number, or symbol), but each application of a tag can also contain an arbitrary type as its "metadata". See {@link GetTagMetadata} for examples and explanation.
24
+
25
+ A type `A` returned by `Tagged` is assignable to another type `B` returned by `Tagged` if and only if:
26
+ - the underlying (untagged) type of `A` is assignable to the underlying type of `B`;
27
+ - `A` contains at least all the tags `B` has;
28
+ - and the metadata type for each of `A`'s tags is assignable to the metadata type of `B`'s corresponding tag.
29
+
30
+ There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
31
+ - [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
32
+ - [Microsoft/TypeScript#4895](https://github.com/microsoft/TypeScript/issues/4895)
33
+ - [Microsoft/TypeScript#33290](https://github.com/microsoft/TypeScript/pull/33290)
34
+
35
+ @example
36
+ ```
37
+ import type {Tagged} from 'type-fest';
38
+
39
+ type AccountNumber = Tagged<number, 'AccountNumber'>;
40
+ type AccountBalance = Tagged<number, 'AccountBalance'>;
41
+
42
+ function createAccountNumber(): AccountNumber {
43
+ // As you can see, casting from a `number` (the underlying type being tagged) is allowed.
44
+ return 2 as AccountNumber;
45
+ }
46
+
47
+ function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance {
48
+ return 4 as AccountBalance;
49
+ }
50
+
51
+ // This will compile successfully.
52
+ getMoneyForAccount(createAccountNumber());
53
+
54
+ // But this won't, because it has to be explicitly passed as an `AccountNumber` type!
55
+ // Critically, you could not accidentally use an `AccountBalance` as an `AccountNumber`.
56
+ getMoneyForAccount(2);
57
+
58
+ // You can also use tagged values like their underlying, untagged type.
59
+ // I.e., this will compile successfully because an `AccountNumber` can be used as a regular `number`.
60
+ // In this sense, the underlying base type is not hidden, which differentiates tagged types from opaque types in other languages.
61
+ const accountNumber = createAccountNumber() + 2;
62
+ ```
63
+
64
+ @example
65
+ ```
66
+ import type {Tagged} from 'type-fest';
67
+
68
+ // You can apply multiple tags to a type by using `Tagged` repeatedly.
69
+ type Url = Tagged<string, 'URL'>;
70
+ type SpecialCacheKey = Tagged<Url, 'SpecialCacheKey'>;
71
+
72
+ // You can also pass a union of tag names, so this is equivalent to the above, although it doesn't give you the ability to assign distinct metadata to each tag.
73
+ type SpecialCacheKey2 = Tagged<string, 'URL' | 'SpecialCacheKey'>;
74
+ ```
75
+ */
76
+ export type Tagged<
77
+ Type,
78
+ TagName extends PropertyKey,
79
+ TagMetadata = never,
80
+ > = Type & Tag<TagName, TagMetadata>;
81
+
82
+ /**
83
+ Given a type and a tag name, returns the metadata associated with that tag on that type.
84
+
85
+ In the example below, one could use `Tagged<string, 'JSON'>` to represent "a string that is valid JSON". That type might be useful -- for instance, it communicates that the value can be safely passed to `JSON.parse` without it throwing an exception. However, it doesn't indicate what type of value will be produced on parse (which is sometimes known). `JsonOf<T>` solves this; it represents "a string that is valid JSON and that, if parsed, would produce a value of type T". The type T is held in the metadata associated with the `'JSON'` tag.
86
+
87
+ This article explains more about [how tag metadata works and when it can be useful](https://medium.com/@ethanresnick/advanced-typescript-tagged-types-improved-with-type-level-metadata-5072fc125fcf).
88
+
89
+ @example
90
+ ```
91
+ import type {Tagged} from 'type-fest';
92
+
93
+ type JsonOf<T> = Tagged<string, 'JSON', T>;
94
+
95
+ function stringify<T>(it: T) {
96
+ return JSON.stringify(it) as JsonOf<T>;
97
+ }
98
+
99
+ function parse<T extends JsonOf<unknown>>(it: T) {
100
+ return JSON.parse(it) as GetTagMetadata<T, 'JSON'>;
101
+ }
102
+
103
+ const x = stringify({ hello: 'world' });
104
+ const parsed = parse(x); // The type of `parsed` is { hello: string }
105
+ ```
106
+ */
107
+ export type GetTagMetadata<
108
+ Type extends Tag<TagName, unknown>,
109
+ TagName extends PropertyKey,
110
+ > = Type[typeof tag][TagName];
111
+
112
+ /**
113
+ Revert a tagged type back to its original type by removing all tags.
114
+
115
+ Why is this necessary?
116
+
117
+ 1. Use a `Tagged` type as object keys
118
+ 2. Prevent TS4058 error: "Return type of exported function has or is using name X from external module Y but cannot be named"
119
+
120
+ @example
121
+ ```
122
+ import type {Tagged, UnwrapTagged} from 'type-fest';
123
+
124
+ type AccountType = Tagged<'SAVINGS' | 'CHECKING', 'AccountType'>;
125
+
126
+ const moneyByAccountType: Record<UnwrapTagged<AccountType>, number> = {
127
+ SAVINGS: 99,
128
+ CHECKING: 0.1
129
+ };
130
+
131
+ // Without UnwrapTagged, the following expression would throw a type error.
132
+ const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
133
+
134
+ // Attempting to pass an non-Tagged type to UnwrapTagged will raise a type error.
135
+ type WontWork = UnwrapTagged<string>;
136
+ ```
137
+ */
138
+ export type UnwrapTagged<TaggedType extends Tag<PropertyKey, any>> =
139
+ RemoveAllTags<TaggedType>;
140
+
141
+ type RemoveAllTags<T> =
142
+ T extends Tag<PropertyKey, any>
143
+ ? {
144
+ [ThisTag in keyof T[typeof tag]]: T extends Tagged<
145
+ infer Type,
146
+ ThisTag,
147
+ T[typeof tag][ThisTag]
148
+ >
149
+ ? RemoveAllTags<Type>
150
+ : never;
151
+ }[keyof T[typeof tag]]
152
+ : T;
@@ -1,2 +1,4 @@
1
1
  export function eventLoopIteration(): Promise<any>;
2
+ export function inspectMapStore(store: MapStore): object;
3
+ import type { MapStore } from '@agoric/store';
2
4
  //# sourceMappingURL=testing-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing-utils.d.ts","sourceRoot":"","sources":["testing-utils.js"],"names":[],"mappings":"AAWO,mDACwC"}
1
+ {"version":3,"file":"testing-utils.d.ts","sourceRoot":"","sources":["testing-utils.js"],"names":[],"mappings":"AAeO,mDACwC;AAgBxC,uCAHI,QAAQ,GACN,MAAM,CAqBlB;8BA7C2B,eAAe"}
@@ -1,14 +1,53 @@
1
- /** @file note this cannot be called test-utils.js due to https://github.com/Agoric/agoric-sdk/issues/7503 */
1
+ // @ts-check
2
+ /**
3
+ * @file note this cannot be called test-utils.js due to
4
+ * https://github.com/Agoric/agoric-sdk/issues/7503
5
+ */
2
6
  /* global setImmediate */
7
+ /** @import {MapStore} from '@agoric/store'; */
3
8
 
4
9
  /**
5
10
  * A workaround for some issues with fake time in tests.
6
11
  *
7
- * Lines of test code can depend on async promises outside the test
8
- * resolving before they run. Awaiting this function result ensures
9
- * that all promises that can do resolve.
10
- * Note that this doesn't mean all outstanding promises.
12
+ * Lines of test code can depend on async promises outside the test resolving
13
+ * before they run. Awaiting this function result ensures that all promises that
14
+ * can do resolve. Note that this doesn't mean all outstanding promises.
11
15
  */
12
16
  export const eventLoopIteration = async () =>
13
17
  new Promise(resolve => setImmediate(resolve));
14
18
  harden(eventLoopIteration);
19
+
20
+ /** @type {(value: any) => string} */
21
+ const stringOrTag = value => {
22
+ if (typeof value === 'string') {
23
+ return value;
24
+ } else if (typeof value === 'object' && Symbol.toStringTag in value) {
25
+ return value[Symbol.toStringTag];
26
+ }
27
+ return String(value);
28
+ };
29
+ /**
30
+ * @param {MapStore} store
31
+ * @returns {object} tree of the contents of the store
32
+ */
33
+ export const inspectMapStore = store => {
34
+ /** @type {Record<string, unknown>} */
35
+ const obj = {};
36
+ for (const key of store.keys()) {
37
+ const value = store.get(key);
38
+ const hasKeys = typeof value === 'object' && 'keys' in value;
39
+ const index = stringOrTag(key);
40
+ if (hasKeys && 'get' in value) {
41
+ obj[index] = inspectMapStore(value);
42
+ } else if (hasKeys) {
43
+ obj[index] = Array.from(value.keys());
44
+ } else {
45
+ obj[index] =
46
+ value instanceof Object && Symbol.toStringTag in value
47
+ ? value[Symbol.toStringTag]
48
+ : value;
49
+ }
50
+ }
51
+ return obj;
52
+ };
53
+ harden(inspectMapStore);
@@ -0,0 +1,2 @@
1
+ export function makeTempDirFactory(tmp: Pick<typeof import("tmp"), "dirSync">): (prefix?: string) => [dirName: string, cleanup: () => void];
2
+ //# sourceMappingURL=tmpDir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmpDir.d.ts","sourceRoot":"","sources":["tmpDir.js"],"names":[],"mappings":"AAMO,wCAFI,IAAI,CAAC,oBAAa,EAAE,SAAS,CAAC,aAGlB,MAAM,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,CASvE"}