@agoric/internal 0.3.3-other-dev-3eb1a1d.0 → 0.3.3-other-dev-d15096d.0.d15096d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -4
- package/package.json +29 -23
- package/src/action-types.d.ts +2 -1
- package/src/action-types.d.ts.map +1 -1
- package/src/action-types.js +4 -4
- package/src/batched-deliver.d.ts +6 -2
- package/src/batched-deliver.d.ts.map +1 -1
- package/src/batched-deliver.js +7 -2
- package/src/callback.d.ts +10 -12
- package/src/callback.d.ts.map +1 -1
- package/src/callback.js +23 -16
- package/src/chain-storage-paths.d.ts.map +1 -1
- package/src/chain-utils.d.ts +3 -1
- package/src/chain-utils.d.ts.map +1 -1
- package/src/chain-utils.js +6 -1
- package/src/cli-utils.d.ts +2 -0
- package/src/cli-utils.d.ts.map +1 -0
- package/src/cli-utils.js +21 -0
- package/src/config.d.ts +21 -4
- package/src/config.d.ts.map +1 -1
- package/src/config.js +25 -2
- package/src/debug.d.ts +4 -1
- package/src/debug.d.ts.map +1 -1
- package/src/debug.js +26 -13
- package/src/errors.d.ts +1 -1
- package/src/errors.d.ts.map +1 -1
- package/src/hex.d.ts +15 -0
- package/src/hex.d.ts.map +1 -0
- package/src/hex.js +105 -0
- package/src/index.d.ts +5 -3
- package/src/index.js +13 -4
- package/src/js-utils.d.ts +38 -1
- package/src/js-utils.d.ts.map +1 -1
- package/src/js-utils.js +184 -14
- package/src/lib-chainStorage.d.ts +45 -32
- package/src/lib-chainStorage.d.ts.map +1 -1
- package/src/lib-chainStorage.js +24 -32
- package/src/lib-nodejs/ava-unhandled-rejection.d.ts +13 -0
- package/src/lib-nodejs/ava-unhandled-rejection.d.ts.map +1 -0
- package/src/lib-nodejs/ava-unhandled-rejection.js +66 -0
- package/src/lib-nodejs/spawnSubprocessWorker.d.ts +0 -2
- package/src/lib-nodejs/spawnSubprocessWorker.d.ts.map +1 -1
- package/src/lib-nodejs/spawnSubprocessWorker.js +5 -3
- package/src/lib-nodejs/waitUntilQuiescent.d.ts +3 -0
- package/src/lib-nodejs/waitUntilQuiescent.d.ts.map +1 -1
- package/src/lib-nodejs/waitUntilQuiescent.js +5 -1
- package/src/marshal/board-client-utils.d.ts +19 -0
- package/src/marshal/board-client-utils.d.ts.map +1 -0
- package/src/{marshal.js → marshal/board-client-utils.js} +30 -36
- package/src/marshal/cap-data.d.ts +3 -0
- package/src/marshal/cap-data.d.ts.map +1 -0
- package/src/marshal/cap-data.js +20 -0
- package/src/marshal/inaccessible-val.d.ts +2 -0
- package/src/marshal/inaccessible-val.d.ts.map +1 -0
- package/src/marshal/inaccessible-val.js +15 -0
- package/src/marshal/pure-data.d.ts +8 -0
- package/src/marshal/pure-data.d.ts.map +1 -0
- package/src/marshal/pure-data.js +14 -0
- package/src/marshal/wrap-marshaller.d.ts +33 -0
- package/src/marshal/wrap-marshaller.d.ts.map +1 -0
- package/src/marshal/wrap-marshaller.js +439 -0
- package/src/method-tools.d.ts.map +1 -1
- package/src/method-tools.js +8 -50
- package/src/metrics.d.ts +183 -0
- package/src/metrics.d.ts.map +1 -0
- package/src/metrics.js +476 -0
- package/src/module-utils.d.ts +2 -0
- package/src/module-utils.d.ts.map +1 -0
- package/src/module-utils.js +27 -0
- package/src/natural-sort.d.ts +2 -0
- package/src/natural-sort.d.ts.map +1 -0
- package/src/natural-sort.js +83 -0
- package/src/netstring.d.ts +2 -2
- package/src/netstring.d.ts.map +1 -1
- package/src/netstring.js +1 -0
- package/src/node/buffer-line-transform.d.ts +12 -7
- package/src/node/buffer-line-transform.d.ts.map +1 -1
- package/src/node/buffer-line-transform.js +8 -4
- package/src/node/fs-stream.d.ts +4 -1
- package/src/node/fs-stream.d.ts.map +1 -1
- package/src/node/fs-stream.js +28 -27
- package/src/node/shutdown.d.ts.map +1 -1
- package/src/node/shutdown.js +2 -0
- package/src/priority-senders.d.ts +3 -1
- package/src/priority-senders.d.ts.map +1 -1
- package/src/priority-senders.js +7 -2
- package/src/queue.d.ts +1 -1
- package/src/queue.d.ts.map +1 -1
- package/src/ses-utils.d.ts +24 -5
- package/src/ses-utils.d.ts.map +1 -1
- package/src/ses-utils.js +189 -15
- package/src/storage-test-utils.d.ts +25 -7
- package/src/storage-test-utils.d.ts.map +1 -1
- package/src/storage-test-utils.js +141 -22
- package/src/tagged.d.ts +4 -1
- package/src/testing-utils.js +1 -1
- package/src/tmpDir.d.ts +2 -0
- package/src/tmpDir.d.ts.map +1 -0
- package/src/tmpDir.js +17 -0
- package/src/tokens.d.ts.map +1 -1
- package/src/typeGuards.d.ts +19 -0
- package/src/typeGuards.d.ts.map +1 -1
- package/src/typeGuards.js +16 -0
- package/src/types.d.ts +30 -17
- package/src/types.d.ts.map +1 -1
- package/src/types.ts +43 -18
- package/src/work-pool.d.ts +13 -0
- package/src/work-pool.d.ts.map +1 -0
- package/src/work-pool.js +233 -0
- package/src/marshal.d.ts +0 -20
- package/src/marshal.d.ts.map +0 -1
package/src/ses-utils.js
CHANGED
|
@@ -5,15 +5,41 @@
|
|
|
5
5
|
* either directly or indirectly (e.g. by @endo imports).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { objectMap } from '@endo/common/object-map.js';
|
|
9
|
+
import { objectMetaMap } from '@endo/common/object-meta-map.js';
|
|
10
|
+
import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
|
|
11
|
+
import { q, b, Fail, makeError, annotateError, X } from '@endo/errors';
|
|
12
|
+
import { deeplyFulfilled, isPrimitive } from '@endo/pass-style';
|
|
10
13
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
11
14
|
import { makeQueue } from '@endo/stream';
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
16
|
+
// @ts-ignore TS7016 The 'jessie.js' library may need to update its package.json or typings
|
|
12
17
|
import { asyncGenerate } from 'jessie.js';
|
|
18
|
+
import { logLevels } from './js-utils.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @import {LimitedConsole} from './js-utils.js';
|
|
22
|
+
* @import {AsyncQueue} from '@endo/stream';
|
|
23
|
+
* @import {PromiseKit} from '@endo/promise-kit';
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** @import {ERef} from '@endo/far'; */
|
|
27
|
+
/** @import {RemotableBrand} from '@endo/eventual-send'; */
|
|
28
|
+
/** @import {Primitive, RemotableObject} from '@endo/pass-style'; */
|
|
29
|
+
/** @import {Permit, Attenuated} from './types.js'; */
|
|
30
|
+
|
|
31
|
+
export { objectMap, objectMetaMap, fromUniqueEntries };
|
|
13
32
|
|
|
14
33
|
const { fromEntries, keys, values } = Object;
|
|
15
34
|
|
|
16
|
-
/** @
|
|
35
|
+
/** @param {(level: string) => (...args: unknown[]) => void} makeLogger */
|
|
36
|
+
export const makeLimitedConsole = makeLogger => {
|
|
37
|
+
const limitedConsole = /** @type {any} */ (
|
|
38
|
+
fromEntries(logLevels.map(level => [level, makeLogger(level)]))
|
|
39
|
+
);
|
|
40
|
+
return /** @type {LimitedConsole} */ (harden(limitedConsole));
|
|
41
|
+
};
|
|
42
|
+
harden(makeLimitedConsole);
|
|
17
43
|
|
|
18
44
|
/**
|
|
19
45
|
* @template T
|
|
@@ -37,9 +63,11 @@ const { fromEntries, keys, values } = Object;
|
|
|
37
63
|
* @template T
|
|
38
64
|
* @typedef {T extends PromiseLike<any>
|
|
39
65
|
* ? Awaited<T>
|
|
40
|
-
* : T extends
|
|
41
|
-
* ?
|
|
42
|
-
* :
|
|
66
|
+
* : T extends RemotableBrand<any, any> | RemotableObject
|
|
67
|
+
* ? T
|
|
68
|
+
* : T extends {}
|
|
69
|
+
* ? Simplify<DeeplyAwaitedObject<T>>
|
|
70
|
+
* : Awaited<T>} DeeplyAwaited
|
|
43
71
|
*/
|
|
44
72
|
|
|
45
73
|
/**
|
|
@@ -50,7 +78,7 @@ const { fromEntries, keys, values } = Object;
|
|
|
50
78
|
* @type {<T extends {}>(unfulfilledTerms: T) => Promise<DeeplyAwaited<T>>}
|
|
51
79
|
*/
|
|
52
80
|
export const deeplyFulfilledObject = async obj => {
|
|
53
|
-
|
|
81
|
+
!isPrimitive(obj) || Fail`param must be an object`;
|
|
54
82
|
return deeplyFulfilled(obj);
|
|
55
83
|
};
|
|
56
84
|
|
|
@@ -69,6 +97,101 @@ const makeAggregateError =
|
|
|
69
97
|
});
|
|
70
98
|
};
|
|
71
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Assert that a string has a prefix, and return the part that follows it.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} prefix
|
|
104
|
+
* @param {string} str
|
|
105
|
+
* @returns {string}
|
|
106
|
+
*/
|
|
107
|
+
export const stripPrefix = (prefix, str) => {
|
|
108
|
+
str.startsWith(prefix) || Fail`${str} is missing prefix ${q(prefix)}`;
|
|
109
|
+
return str.slice(prefix.length);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Throw an error with an own "code" data property, supporting identification
|
|
114
|
+
* without parsing `message`. Note that such errors are not Passable and thus
|
|
115
|
+
* cannot appear inside a Passable structure, and even at top level the "code"
|
|
116
|
+
* property will be silently dropped by marshalling.
|
|
117
|
+
*
|
|
118
|
+
* @template {string} Code
|
|
119
|
+
* @param {Parameters<typeof makeError>[0]} details
|
|
120
|
+
* @param {Code} code
|
|
121
|
+
* @param {Parameters<typeof makeError>[2] & {
|
|
122
|
+
* constructor?: Parameters<typeof makeError>[1];
|
|
123
|
+
* }} [opts]
|
|
124
|
+
*/
|
|
125
|
+
export const throwErrorCode = (details, code, opts) => {
|
|
126
|
+
const err = makeError(details, opts?.constructor, {
|
|
127
|
+
...opts,
|
|
128
|
+
sanitize: false,
|
|
129
|
+
});
|
|
130
|
+
Object.defineProperty(err, 'code', { value: code, enumerable: true });
|
|
131
|
+
harden(err);
|
|
132
|
+
throw err;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Synchronusly invoke a function with the opportunity to handle any error
|
|
137
|
+
* similarly to a Promise `catch` callback (e.g., substituting a non-error
|
|
138
|
+
* returned value or throwing a possibly-new error). This is useful for (among
|
|
139
|
+
* other things) replacing generic error messages with specific ones (as in
|
|
140
|
+
* {@see tryJsonParse}).
|
|
141
|
+
*
|
|
142
|
+
* @template {(...args: any[]) => any} F
|
|
143
|
+
* @template [U=ReturnType<F>]
|
|
144
|
+
* @param {F} fn to invoke
|
|
145
|
+
* @param {(err: Error) => U} transformError callback to receive any error from
|
|
146
|
+
* invoking `fn` and either return a substitute value or throw a potentially
|
|
147
|
+
* new error
|
|
148
|
+
* @param {Parameters<F>} args for `fn`
|
|
149
|
+
* @returns {ReturnType<F> | U}
|
|
150
|
+
*/
|
|
151
|
+
export const tryNow = (fn, transformError, ...args) => {
|
|
152
|
+
try {
|
|
153
|
+
return fn(...args);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
try {
|
|
156
|
+
return transformError(err);
|
|
157
|
+
} catch (newErr) {
|
|
158
|
+
// Try to associate `err` with `newErr`.
|
|
159
|
+
if (!newErr.cause) {
|
|
160
|
+
const desc = {
|
|
161
|
+
value: err,
|
|
162
|
+
configurable: true,
|
|
163
|
+
enumerable: false,
|
|
164
|
+
writable: true,
|
|
165
|
+
};
|
|
166
|
+
if (!Reflect.defineProperty(newErr, 'cause', desc)) {
|
|
167
|
+
assert.note(newErr, err.message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
throw newErr;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Parse JSON text, or handle an error by e.g. substituting a default value or
|
|
177
|
+
* replacing it with one bearing a non-generic message.
|
|
178
|
+
*
|
|
179
|
+
* @param {string} jsonText
|
|
180
|
+
* @param {string | ((err: Error) => unknown)} onError an error message or
|
|
181
|
+
* callback
|
|
182
|
+
*/
|
|
183
|
+
export const tryJsonParse = (jsonText, onError) => {
|
|
184
|
+
const transformError =
|
|
185
|
+
typeof onError === 'function'
|
|
186
|
+
? onError
|
|
187
|
+
: err => Fail([`${onError}: ${err.message} for input `, ''], jsonText);
|
|
188
|
+
return tryNow(() => {
|
|
189
|
+
const type = typeof jsonText;
|
|
190
|
+
type === 'string' || Fail`Input must be a string, not ${b(type)}`;
|
|
191
|
+
return JSON.parse(jsonText);
|
|
192
|
+
}, transformError);
|
|
193
|
+
};
|
|
194
|
+
|
|
72
195
|
/**
|
|
73
196
|
* @template T
|
|
74
197
|
* @param {readonly (T | PromiseLike<T>)[]} items
|
|
@@ -163,6 +286,61 @@ export const assertAllDefined = obj => {
|
|
|
163
286
|
}
|
|
164
287
|
};
|
|
165
288
|
|
|
289
|
+
/**
|
|
290
|
+
* Attenuate `specimen` to only properties allowed by `permit`.
|
|
291
|
+
*
|
|
292
|
+
* @template T
|
|
293
|
+
* @template {Permit<T>} P
|
|
294
|
+
* @param {T} specimen
|
|
295
|
+
* @param {P} permit
|
|
296
|
+
* @param {<U, SubP extends Permit<U>>(attenuation: U, permit: SubP) => U} [transform]
|
|
297
|
+
* used to replace the results of recursive picks (but not blanket permits)
|
|
298
|
+
* @returns {Attenuated<T, P>}
|
|
299
|
+
*/
|
|
300
|
+
export const attenuate = (specimen, permit, transform = x => x) => {
|
|
301
|
+
// Fast-path for no attenuation.
|
|
302
|
+
if (permit === true || typeof permit === 'string') {
|
|
303
|
+
return /** @type {Attenuated<T, P>} */ (specimen);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** @type {string[]} */
|
|
307
|
+
const path = [];
|
|
308
|
+
/**
|
|
309
|
+
* @template SubT
|
|
310
|
+
* @template {Exclude<Permit<SubT>, Primitive>} SubP
|
|
311
|
+
* @type {(specimen: SubT, permit: SubP) => Attenuated<SubT, SubP>}
|
|
312
|
+
*/
|
|
313
|
+
const extract = (subSpecimen, subPermit) => {
|
|
314
|
+
if (subPermit === null || typeof subPermit !== 'object') {
|
|
315
|
+
throw path.length === 0
|
|
316
|
+
? Fail`invalid permit: ${q(permit)}`
|
|
317
|
+
: Fail`invalid permit at path ${q(path)}: ${q(subPermit)}`;
|
|
318
|
+
} else if (subSpecimen === null || typeof subSpecimen !== 'object') {
|
|
319
|
+
throw path.length === 0
|
|
320
|
+
? Fail`specimen must be an object for permit ${q(permit)}`
|
|
321
|
+
: Fail`specimen at path ${q(path)} must be an object for permit ${q(subPermit)}`;
|
|
322
|
+
}
|
|
323
|
+
const picks = Object.entries(subPermit).map(([subKey, deepPermit]) => {
|
|
324
|
+
if (!Object.hasOwn(subSpecimen, subKey)) {
|
|
325
|
+
throw Fail`specimen is missing path ${q(path.concat(subKey))}`;
|
|
326
|
+
}
|
|
327
|
+
const deepSpecimen = Reflect.get(subSpecimen, subKey);
|
|
328
|
+
if (deepPermit === true || typeof deepPermit === 'string') {
|
|
329
|
+
return [subKey, deepSpecimen];
|
|
330
|
+
}
|
|
331
|
+
path.push(subKey);
|
|
332
|
+
const extracted = extract(/** @type {any} */ (deepSpecimen), deepPermit);
|
|
333
|
+
const entry = [subKey, extracted];
|
|
334
|
+
path.pop();
|
|
335
|
+
return entry;
|
|
336
|
+
});
|
|
337
|
+
return transform(Object.fromEntries(picks), subPermit);
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// @ts-expect-error cast
|
|
341
|
+
return extract(specimen, permit);
|
|
342
|
+
};
|
|
343
|
+
|
|
166
344
|
/** @type {IteratorResult<undefined, never>} */
|
|
167
345
|
const notDone = harden({ done: false, value: undefined });
|
|
168
346
|
|
|
@@ -244,7 +422,7 @@ export const synchronizedTee = (sourceStream, readerCount) => {
|
|
|
244
422
|
* (value: PromiseLike<IteratorResult<T>>) => void
|
|
245
423
|
* >} QueuePayload
|
|
246
424
|
*/
|
|
247
|
-
/** @type {
|
|
425
|
+
/** @type {AsyncQueue<QueuePayload>[]} */
|
|
248
426
|
const queues = [];
|
|
249
427
|
|
|
250
428
|
/** @returns {Promise<void>} */
|
|
@@ -298,7 +476,7 @@ export const synchronizedTee = (sourceStream, readerCount) => {
|
|
|
298
476
|
};
|
|
299
477
|
|
|
300
478
|
const readers = Array.from({ length: readerCount }).map(() => {
|
|
301
|
-
/** @type {
|
|
479
|
+
/** @type {AsyncQueue<QueuePayload>} */
|
|
302
480
|
const queue = makeQueue();
|
|
303
481
|
queues.push(queue);
|
|
304
482
|
|
|
@@ -306,9 +484,7 @@ export const synchronizedTee = (sourceStream, readerCount) => {
|
|
|
306
484
|
const reader = harden({
|
|
307
485
|
async next() {
|
|
308
486
|
/**
|
|
309
|
-
* @type {
|
|
310
|
-
* IteratorResult<T>
|
|
311
|
-
* >}
|
|
487
|
+
* @type {PromiseKit<IteratorResult<T>>}
|
|
312
488
|
*/
|
|
313
489
|
const { promise, resolve } = makePromiseKit();
|
|
314
490
|
queue.put({ value: resolve, done: false });
|
|
@@ -316,9 +492,7 @@ export const synchronizedTee = (sourceStream, readerCount) => {
|
|
|
316
492
|
},
|
|
317
493
|
async return() {
|
|
318
494
|
/**
|
|
319
|
-
* @type {
|
|
320
|
-
* IteratorResult<T>
|
|
321
|
-
* >}
|
|
495
|
+
* @type {PromiseKit<IteratorResult<T>>}
|
|
322
496
|
*/
|
|
323
497
|
const { promise, resolve } = makePromiseKit();
|
|
324
498
|
queue.put({ value: resolve, done: true });
|
|
@@ -9,8 +9,21 @@ export const defaultMarshaller: {
|
|
|
9
9
|
serialize: import("@endo/marshal").ToCapData<string>;
|
|
10
10
|
unserialize: import("@endo/marshal").FromCapData<string>;
|
|
11
11
|
};
|
|
12
|
+
export namespace defaultSerializer {
|
|
13
|
+
let parse: (text: string) => unknown;
|
|
14
|
+
let stringify: (obj: any) => string;
|
|
15
|
+
}
|
|
12
16
|
export const slotStringUnserialize: (capData: any) => any;
|
|
13
|
-
export function
|
|
17
|
+
export function makeAsyncQueue<T>(): {
|
|
18
|
+
enqueue: (data: T) => void;
|
|
19
|
+
iterable: {
|
|
20
|
+
[Symbol.asyncIterator](): AsyncGenerator<Awaited<T> | undefined, void, unknown>;
|
|
21
|
+
};
|
|
22
|
+
cancel: () => boolean;
|
|
23
|
+
};
|
|
24
|
+
export function makeFakeStorageKit(rootPath: string, rootOptions?: Parameters<typeof makeChainStorageRoot>[2], { eachMessage }?: {
|
|
25
|
+
eachMessage?: (m: StorageMessage) => void;
|
|
26
|
+
}): {
|
|
14
27
|
rootNode: import("@endo/exo").Guarded<{
|
|
15
28
|
getPath(): string;
|
|
16
29
|
getStoreKey(): Promise<VStorageKey>;
|
|
@@ -20,17 +33,19 @@ export function makeFakeStorageKit(rootPath: string, rootOptions?: Parameters<ty
|
|
|
20
33
|
setValue(value: string): Promise<void>;
|
|
21
34
|
}>;
|
|
22
35
|
data: Map<string, string>;
|
|
36
|
+
updateNewCellBlockHeight: (blockHeight?: number) => void;
|
|
37
|
+
getValues: (path: string) => string[];
|
|
23
38
|
messages: StorageMessage[];
|
|
24
|
-
toStorage: ((message: StorageMessage) => string | number | any[] | {
|
|
39
|
+
toStorage: ((message: StorageMessage) => string | number | true | any[] | {
|
|
25
40
|
storeName: string;
|
|
26
41
|
storeSubkey: string;
|
|
27
|
-
} | null
|
|
42
|
+
} | null) & import("@endo/pass-style").RemotableObject<`Alleged: ${string}`> & import("@endo/eventual-send").RemotableBrand<{}, (message: StorageMessage) => string | number | true | any[] | {
|
|
28
43
|
storeName: string;
|
|
29
44
|
storeSubkey: string;
|
|
30
|
-
} | null
|
|
45
|
+
} | null>;
|
|
31
46
|
};
|
|
32
47
|
export function makeMockChainStorageRoot(): MockChainStorageRoot;
|
|
33
|
-
export function documentStorageSchema(t:
|
|
48
|
+
export function documentStorageSchema(t: ExecutionContext<unknown>, storage: MockChainStorageRoot | FakeStorageKit, opts: ({
|
|
34
49
|
note: string;
|
|
35
50
|
} | {
|
|
36
51
|
node: string;
|
|
@@ -38,7 +53,9 @@ export function documentStorageSchema(t: import("ava").ExecutionContext<unknown>
|
|
|
38
53
|
}) & ({
|
|
39
54
|
pattern: string;
|
|
40
55
|
replacement: string;
|
|
41
|
-
} | {})
|
|
56
|
+
} | {}) & {
|
|
57
|
+
showValue?: (v: string) => unknown;
|
|
58
|
+
}): Promise<void>;
|
|
42
59
|
export type FakeStorageKit = ReturnType<typeof makeFakeStorageKit>;
|
|
43
60
|
export type MockChainStorageRootMethods = {
|
|
44
61
|
/**
|
|
@@ -52,7 +69,8 @@ export type MockChainStorageRootMethods = {
|
|
|
52
69
|
};
|
|
53
70
|
export type MockChainStorageRoot = StorageNode & MockChainStorageRootMethods;
|
|
54
71
|
import { makeChainStorageRoot } from './lib-chainStorage.js';
|
|
55
|
-
import type { StorageNode } from './lib-chainStorage.js';
|
|
56
72
|
import type { StorageMessage } from './lib-chainStorage.js';
|
|
73
|
+
import type { StorageNode } from './lib-chainStorage.js';
|
|
74
|
+
import type { ExecutionContext } from 'ava';
|
|
57
75
|
import type { Marshaller } from './lib-chainStorage.js';
|
|
58
76
|
//# sourceMappingURL=storage-test-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-test-utils.d.ts","sourceRoot":"","sources":["storage-test-utils.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storage-test-utils.d.ts","sourceRoot":"","sources":["storage-test-utils.js"],"names":[],"mappings":"AA0BO,yCAHI,MAAM,UACN,MAAM,6GAGC;AAElB;;;GAGG;AACH;;;;;EAEG;;eAMU,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO;mBAEzB,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM;;AA8CjC,8CAtBuB,GAAG,KAAK,GAAG,CAsB+B;AAa1D,+BAFM,CAAC;oBASA,CAAC;;;;;EA6Bd;AAWM,6CAJI,MAAM,gBACN,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC,oBAC1C;IAAE,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,CAAA;CAAE;;;;;oBAwD3B,CAAC;;;;UA4FT,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;;sBAd3B,MAAM,KACJ,MAAM,EAAE;;0BA/FP,cAAc;;;8IAAd,cAAc;;;;EAkH7B;AAoBM,4CADO,oBAAoB,CA2BjC;AAUM,yCAPI,iBAAiB,OAAO,CAAC,WACzB,oBAAoB,GAAG,cAAc,QACrC,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9D,CAAK;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,EAAE,CAAC,GAAG;IAChD,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;CACpC,iBAkDL;6BAtGa,UAAU,CAAC,OAAO,kBAAkB,CAAC;;;;;;;;aAIrC,CACT,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,UAAU,EACvB,KAAK,CAAC,EAAE,MAAM,KACX,OAAO;UAKD,MAAM,MAAM,EAAE;;mCAEd,WAAW,GAAG,2BAA2B;qCAxTJ,uBAAuB;oCAOU,uBAAuB;iCAAvB,uBAAuB;sCACxE,KAAK;gCAD4C,uBAAuB"}
|
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
import { Fail } from '@endo/errors';
|
|
3
3
|
import { Far } from '@endo/far';
|
|
4
4
|
import { makeMarshal, Remotable } from '@endo/marshal';
|
|
5
|
-
import { unmarshalFromVstorage } from './marshal.js';
|
|
6
5
|
import { makeTracer } from './debug.js';
|
|
6
|
+
import { NonNullish } from './errors.js';
|
|
7
7
|
import { isStreamCell, makeChainStorageRoot } from './lib-chainStorage.js';
|
|
8
|
+
import { unmarshalFromVstorage } from './marshal/board-client-utils.js';
|
|
8
9
|
import { bindAllMethods } from './method-tools.js';
|
|
9
10
|
import { eventLoopIteration } from './testing-utils.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* @import {TotalMap} from './types.js';
|
|
13
|
-
* @import {Marshaller, StorageEntry, StorageMessage, StorageNode} from './lib-chainStorage.js';
|
|
14
|
+
* @import {Marshaller, StorageEntry, StorageMessage, StorageNode, StreamCell} from './lib-chainStorage.js';
|
|
15
|
+
* @import {ExecutionContext} from 'ava';
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
18
|
const trace = makeTracer('StorTU', false);
|
|
@@ -33,6 +35,16 @@ export const defaultMarshaller = makeMarshal(undefined, slotToRemotable, {
|
|
|
33
35
|
serializeBodyFormat: 'smallcaps',
|
|
34
36
|
});
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Serialize/deserialize functions using {@link defaultMarshaller}
|
|
40
|
+
*/
|
|
41
|
+
export const defaultSerializer = {
|
|
42
|
+
/** @type {(text: string) => unknown} */
|
|
43
|
+
parse: txt => defaultMarshaller.fromCapData(JSON.parse(txt)),
|
|
44
|
+
/** @type {(obj: any) => string} */
|
|
45
|
+
stringify: obj => JSON.stringify(defaultMarshaller.toCapData(obj)),
|
|
46
|
+
};
|
|
47
|
+
|
|
36
48
|
/**
|
|
37
49
|
* A deserializer which produces slot strings instead of Remotables, so if `a =
|
|
38
50
|
* Far('iface')`, and serializing `{ a }` into `capData` assigned it slot
|
|
@@ -77,6 +89,55 @@ const makeSlotStringUnserialize = () => {
|
|
|
77
89
|
};
|
|
78
90
|
export const slotStringUnserialize = makeSlotStringUnserialize();
|
|
79
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @example to iterate over storage messages
|
|
94
|
+
*
|
|
95
|
+
* ```js
|
|
96
|
+
* const q = makeAsyncQueue<StorageMessage>();
|
|
97
|
+
* const storage = makeFakeStorageKit('published', undefined, { eachMessage: q.enqueue });
|
|
98
|
+
* for (const message of q.iterable) { ... }
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @template T
|
|
102
|
+
*/
|
|
103
|
+
export const makeAsyncQueue = () => {
|
|
104
|
+
/** @type {T[]} */
|
|
105
|
+
const queue = [];
|
|
106
|
+
/** @type {null | ((r: undefined) => void)} */
|
|
107
|
+
let resolve = null;
|
|
108
|
+
let done = false;
|
|
109
|
+
|
|
110
|
+
/** @param {T} data */
|
|
111
|
+
const enqueue = data => {
|
|
112
|
+
queue.push(data);
|
|
113
|
+
if (resolve) {
|
|
114
|
+
resolve(undefined);
|
|
115
|
+
resolve = null;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
let alreadyIterating = false;
|
|
120
|
+
const iterable = {
|
|
121
|
+
async *[Symbol.asyncIterator]() {
|
|
122
|
+
assert(!alreadyIterating, `AsyncQueue is already iterating`);
|
|
123
|
+
alreadyIterating = true;
|
|
124
|
+
await null;
|
|
125
|
+
while (!done) {
|
|
126
|
+
if (queue.length === 0) {
|
|
127
|
+
await new Promise(r => (resolve = r));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
while (queue.length > 0) {
|
|
131
|
+
yield queue.shift();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const cancel = () => (done = true);
|
|
138
|
+
return harden({ enqueue, iterable, cancel });
|
|
139
|
+
};
|
|
140
|
+
|
|
80
141
|
/**
|
|
81
142
|
* For testing, creates a chainStorage root node over an in-memory map and
|
|
82
143
|
* exposes both the map and the sequence of received messages. The `sequence`
|
|
@@ -84,11 +145,24 @@ export const slotStringUnserialize = makeSlotStringUnserialize();
|
|
|
84
145
|
*
|
|
85
146
|
* @param {string} rootPath
|
|
86
147
|
* @param {Parameters<typeof makeChainStorageRoot>[2]} [rootOptions]
|
|
148
|
+
* @param {{ eachMessage?: (m: StorageMessage) => void }} [spyOpts]
|
|
87
149
|
*/
|
|
88
|
-
export const makeFakeStorageKit = (
|
|
150
|
+
export const makeFakeStorageKit = (
|
|
151
|
+
rootPath,
|
|
152
|
+
rootOptions,
|
|
153
|
+
{ eachMessage } = {},
|
|
154
|
+
) => {
|
|
89
155
|
const resolvedOptions = { sequence: true, ...rootOptions };
|
|
90
156
|
/** @type {TotalMap<string, string>} */
|
|
91
157
|
const data = new Map();
|
|
158
|
+
let currentBlockHeight = 0;
|
|
159
|
+
|
|
160
|
+
const updateNewCellBlockHeight = (blockHeight = currentBlockHeight + 1) => {
|
|
161
|
+
blockHeight > currentBlockHeight ||
|
|
162
|
+
Fail`blockHeight ${blockHeight} must be greater than ${currentBlockHeight}`;
|
|
163
|
+
currentBlockHeight = blockHeight;
|
|
164
|
+
};
|
|
165
|
+
|
|
92
166
|
/** @param {string} prefix */
|
|
93
167
|
const getChildEntries = prefix => {
|
|
94
168
|
assert(prefix.endsWith('.'));
|
|
@@ -114,6 +188,7 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
114
188
|
/** @param {StorageMessage} message */
|
|
115
189
|
message => {
|
|
116
190
|
messages.push(message);
|
|
191
|
+
eachMessage?.(message);
|
|
117
192
|
switch (message.method) {
|
|
118
193
|
case 'getStoreKey': {
|
|
119
194
|
const [key] = message.args;
|
|
@@ -147,7 +222,7 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
147
222
|
data.delete(key);
|
|
148
223
|
}
|
|
149
224
|
}
|
|
150
|
-
|
|
225
|
+
return true;
|
|
151
226
|
}
|
|
152
227
|
case 'append': {
|
|
153
228
|
trace('toStorage append', message);
|
|
@@ -155,8 +230,10 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
155
230
|
const newEntries = message.args;
|
|
156
231
|
for (const [key, value] of newEntries) {
|
|
157
232
|
value != null || Fail`attempt to append with no value`;
|
|
158
|
-
|
|
159
|
-
|
|
233
|
+
|
|
234
|
+
/** @type {string | undefined} */
|
|
235
|
+
let oldVal = data.get(key);
|
|
236
|
+
/** @type {StreamCell | undefined} */
|
|
160
237
|
let streamCell;
|
|
161
238
|
if (oldVal != null) {
|
|
162
239
|
try {
|
|
@@ -165,17 +242,26 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
165
242
|
} catch (_err) {
|
|
166
243
|
streamCell = undefined;
|
|
167
244
|
}
|
|
245
|
+
// StreamCells reset at block boundaries.
|
|
246
|
+
if (
|
|
247
|
+
streamCell &&
|
|
248
|
+
Number(streamCell.blockHeight) !== currentBlockHeight
|
|
249
|
+
) {
|
|
250
|
+
streamCell = undefined;
|
|
251
|
+
oldVal = undefined;
|
|
252
|
+
}
|
|
168
253
|
}
|
|
254
|
+
|
|
169
255
|
if (streamCell === undefined) {
|
|
170
256
|
streamCell = {
|
|
171
|
-
blockHeight:
|
|
257
|
+
blockHeight: String(currentBlockHeight),
|
|
172
258
|
values: oldVal != null ? [oldVal] : [],
|
|
173
259
|
};
|
|
174
260
|
}
|
|
175
261
|
streamCell.values.push(value);
|
|
176
262
|
data.set(key, JSON.stringify(streamCell));
|
|
177
263
|
}
|
|
178
|
-
|
|
264
|
+
return true;
|
|
179
265
|
}
|
|
180
266
|
case 'size':
|
|
181
267
|
// Intentionally incorrect because it counts non-child descendants,
|
|
@@ -189,10 +275,27 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
189
275
|
},
|
|
190
276
|
);
|
|
191
277
|
const rootNode = makeChainStorageRoot(toStorage, rootPath, resolvedOptions);
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Get the values at a sequence node
|
|
281
|
+
*
|
|
282
|
+
* @param {string} path
|
|
283
|
+
* @returns {string[]}
|
|
284
|
+
*/
|
|
285
|
+
const getValues = path => {
|
|
286
|
+
assert(resolvedOptions.sequence);
|
|
287
|
+
const nodeData = data.get(path);
|
|
288
|
+
assert(nodeData, `no data at path ${path}`);
|
|
289
|
+
const wrapper = JSON.parse(nodeData);
|
|
290
|
+
return wrapper.values;
|
|
291
|
+
};
|
|
292
|
+
|
|
192
293
|
return {
|
|
193
294
|
rootNode,
|
|
194
|
-
|
|
295
|
+
|
|
195
296
|
data: /** @type {Map<string, string>} */ (data),
|
|
297
|
+
updateNewCellBlockHeight,
|
|
298
|
+
getValues,
|
|
196
299
|
messages,
|
|
197
300
|
toStorage,
|
|
198
301
|
};
|
|
@@ -234,9 +337,7 @@ export const makeMockChainStorageRoot = () => {
|
|
|
234
337
|
getBody: (path, marshaller = defaultMarshaller, index = -1) => {
|
|
235
338
|
data.size || Fail`no data in storage`;
|
|
236
339
|
/**
|
|
237
|
-
* @type {ReturnType<
|
|
238
|
-
* typeof import('@endo/marshal').makeMarshal
|
|
239
|
-
* >['fromCapData']}
|
|
340
|
+
* @type {ReturnType<typeof makeMarshal>['fromCapData']}
|
|
240
341
|
*/
|
|
241
342
|
const fromCapData = (...args) =>
|
|
242
343
|
Reflect.apply(marshaller.fromCapData, marshaller, args);
|
|
@@ -247,33 +348,51 @@ export const makeMockChainStorageRoot = () => {
|
|
|
247
348
|
};
|
|
248
349
|
|
|
249
350
|
/**
|
|
250
|
-
* @param {
|
|
351
|
+
* @param {ExecutionContext<unknown>} t
|
|
251
352
|
* @param {MockChainStorageRoot | FakeStorageKit} storage
|
|
252
353
|
* @param {({ note: string } | { node: string; owner: string }) &
|
|
253
|
-
* ({ pattern: string; replacement: string } | {})
|
|
354
|
+
* ({ pattern: string; replacement: string } | {}) & {
|
|
355
|
+
* showValue?: (v: string) => unknown;
|
|
356
|
+
* }} opts
|
|
254
357
|
*/
|
|
255
358
|
export const documentStorageSchema = async (t, storage, opts) => {
|
|
256
359
|
// chainStorage publication is unsynchronized
|
|
257
360
|
await eventLoopIteration();
|
|
258
361
|
|
|
362
|
+
const getLast = (/** @type {string} */ cell) =>
|
|
363
|
+
JSON.parse(cell).values.at(-1) || assert.fail();
|
|
364
|
+
const { showValue = s => s } = opts;
|
|
365
|
+
/** @type {(d: Map<string, string>, k: string) => unknown} */
|
|
366
|
+
const getBodyDefault = (d, k) => showValue(getLast(NonNullish(d.get(k))));
|
|
367
|
+
|
|
259
368
|
const [keys, getBody] =
|
|
260
369
|
'keys' in storage
|
|
261
370
|
? [storage.keys(), (/** @type {string} */ k) => storage.getBody(k)]
|
|
262
|
-
: [
|
|
371
|
+
: [
|
|
372
|
+
storage.data.keys(),
|
|
373
|
+
(/** @type {string} */ k) => getBodyDefault(storage.data, k),
|
|
374
|
+
];
|
|
263
375
|
|
|
264
376
|
const { pattern, replacement } =
|
|
265
377
|
'pattern' in opts
|
|
266
378
|
? opts
|
|
267
379
|
: { pattern: 'mockChainStorageRoot.', replacement: 'published.' };
|
|
268
|
-
|
|
380
|
+
|
|
381
|
+
const pruned = [...keys]
|
|
382
|
+
.sort()
|
|
383
|
+
.filter(
|
|
384
|
+
'node' in opts
|
|
385
|
+
? key =>
|
|
386
|
+
key
|
|
387
|
+
.replace(pattern, replacement)
|
|
388
|
+
.startsWith(`published.${opts.node}`)
|
|
389
|
+
: _entry => true,
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
const illustration = pruned.map(
|
|
269
393
|
/** @type {(k: string) => [string, unknown]} */
|
|
270
394
|
key => [key.replace(pattern, replacement), getBody(key)],
|
|
271
395
|
);
|
|
272
|
-
const pruned = illustration.filter(
|
|
273
|
-
'node' in opts
|
|
274
|
-
? ([key, _]) => key.startsWith(`published.${opts.node}`)
|
|
275
|
-
: _entry => true,
|
|
276
|
-
);
|
|
277
396
|
|
|
278
397
|
const note =
|
|
279
398
|
'note' in opts
|
|
@@ -283,5 +402,5 @@ export const documentStorageSchema = async (t, storage, opts) => {
|
|
|
283
402
|
The example below illustrates the schema of the data published there.
|
|
284
403
|
|
|
285
404
|
See also board marshalling conventions (_to appear_).`;
|
|
286
|
-
t.snapshot(
|
|
405
|
+
t.snapshot(illustration, note + boilerplate);
|
|
287
406
|
};
|
package/src/tagged.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
/** @file adapted from https://raw.githubusercontent.com/sindresorhus/type-fest/main/source/
|
|
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 };
|
|
2
5
|
|
|
3
6
|
declare const tag: unique symbol;
|
|
4
7
|
|
package/src/testing-utils.js
CHANGED
|
@@ -28,7 +28,7 @@ const stringOrTag = value => {
|
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
30
|
* @param {MapStore} store
|
|
31
|
-
* @returns {object} tree of the contents of the
|
|
31
|
+
* @returns {object} tree of the contents of the store
|
|
32
32
|
*/
|
|
33
33
|
export const inspectMapStore = store => {
|
|
34
34
|
/** @type {Record<string, unknown>} */
|
package/src/tmpDir.d.ts
ADDED
|
@@ -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"}
|
package/src/tmpDir.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a `tmpDir` function that synchronously creates a temporary directory
|
|
3
|
+
* and a function for deleting it along with any added contents.
|
|
4
|
+
*
|
|
5
|
+
* @param {Pick<import('tmp'), 'dirSync'>} tmp
|
|
6
|
+
*/
|
|
7
|
+
export const makeTempDirFactory = tmp => {
|
|
8
|
+
/** @type {(prefix?: string) => [dirName: string, cleanup: () => void]} */
|
|
9
|
+
const tmpDir = prefix => {
|
|
10
|
+
const { name, removeCallback } = tmp.dirSync({
|
|
11
|
+
prefix,
|
|
12
|
+
unsafeCleanup: true,
|
|
13
|
+
});
|
|
14
|
+
return [name, removeCallback];
|
|
15
|
+
};
|
|
16
|
+
return tmpDir;
|
|
17
|
+
};
|
package/src/tokens.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["tokens.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;2BAEc,KAAK,GAAG,KAAK;AAA3B,4CAA4C;AAE5C;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["tokens.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;2BAEc,KAAK,GAAG,KAAK;AAA3B,4CAA4C;AAE5C;;;GAGG;AACH,mBAAY,KAAK,CAAC"}
|