@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.
- package/README.md +7 -2
- package/exported.js +2 -0
- package/package.json +35 -17
- package/src/action-types.d.ts +50 -5
- package/src/action-types.d.ts.map +1 -1
- package/src/action-types.js +73 -14
- package/src/batched-deliver.d.ts +9 -6
- package/src/batched-deliver.d.ts.map +1 -1
- package/src/batched-deliver.js +9 -3
- package/src/callback.d.ts +23 -16
- package/src/callback.d.ts.map +1 -1
- package/src/callback.js +48 -55
- package/src/chain-storage-paths.d.ts +2 -3
- package/src/chain-storage-paths.d.ts.map +1 -1
- package/src/chain-storage-paths.js +2 -3
- package/src/chain-utils.d.ts +25 -0
- package/src/chain-utils.d.ts.map +1 -0
- package/src/chain-utils.js +57 -0
- package/src/config.d.ts +24 -12
- package/src/config.d.ts.map +1 -1
- package/src/config.js +21 -10
- package/src/debug.d.ts +1 -1
- package/src/errors.d.ts +2 -0
- package/src/errors.d.ts.map +1 -0
- package/src/errors.js +16 -0
- package/src/index.d.ts +8 -1
- package/src/index.js +12 -2
- package/src/install-ses-debug.d.ts +2 -0
- package/src/install-ses-debug.d.ts.map +1 -0
- package/src/install-ses-debug.js +6 -0
- package/src/js-utils.d.ts +7 -0
- package/src/js-utils.d.ts.map +1 -0
- package/src/js-utils.js +89 -0
- package/src/lib-chainStorage.d.ts +42 -52
- package/src/lib-chainStorage.d.ts.map +1 -1
- package/src/lib-chainStorage.js +88 -77
- package/src/lib-nodejs/engine-gc.d.ts +3 -0
- package/src/lib-nodejs/engine-gc.d.ts.map +1 -0
- package/src/lib-nodejs/engine-gc.js +22 -0
- package/src/lib-nodejs/gc-and-finalize.d.ts +2 -0
- package/src/lib-nodejs/gc-and-finalize.d.ts.map +1 -0
- package/src/lib-nodejs/gc-and-finalize.js +91 -0
- package/src/lib-nodejs/spawnSubprocessWorker.d.ts +15 -0
- package/src/lib-nodejs/spawnSubprocessWorker.d.ts.map +1 -0
- package/src/lib-nodejs/spawnSubprocessWorker.js +89 -0
- package/src/lib-nodejs/waitUntilQuiescent.d.ts +2 -0
- package/src/lib-nodejs/waitUntilQuiescent.d.ts.map +1 -0
- package/src/lib-nodejs/waitUntilQuiescent.js +18 -0
- package/src/lib-nodejs/worker-protocol.d.ts +4 -0
- package/src/lib-nodejs/worker-protocol.d.ts.map +1 -0
- package/src/lib-nodejs/worker-protocol.js +54 -0
- package/src/magic-cookie-test-only.js +2 -2
- package/src/marshal.d.ts +20 -0
- package/src/marshal.d.ts.map +1 -0
- package/src/marshal.js +137 -0
- package/src/method-tools.d.ts +1 -0
- package/src/method-tools.d.ts.map +1 -1
- package/src/method-tools.js +29 -16
- package/src/netstring.d.ts +24 -0
- package/src/netstring.d.ts.map +1 -0
- package/src/netstring.js +124 -0
- package/src/node/buffer-line-transform.d.ts +17 -13
- package/src/node/buffer-line-transform.d.ts.map +1 -1
- package/src/node/buffer-line-transform.js +12 -9
- package/src/node/createBundles.d.ts.map +1 -1
- package/src/node/createBundles.js +12 -3
- package/src/node/fs-stream.d.ts +1 -1
- package/src/node/fs-stream.d.ts.map +1 -1
- package/src/node/fs-stream.js +42 -30
- package/src/node/shutdown.d.ts.map +1 -1
- package/src/node/shutdown.js +0 -1
- package/src/priority-senders.d.ts +1 -1
- package/src/priority-senders.d.ts.map +1 -1
- package/src/priority-senders.js +8 -5
- package/src/queue.d.ts +1 -1
- package/src/queue.d.ts.map +1 -1
- package/src/queue.js +7 -8
- package/src/scratch.d.ts +1 -1
- package/src/scratch.d.ts.map +1 -1
- package/src/ses-utils.d.ts +60 -0
- package/src/ses-utils.d.ts.map +1 -0
- package/src/ses-utils.js +346 -0
- package/src/storage-test-utils.d.ts +41 -84
- package/src/storage-test-utils.d.ts.map +1 -1
- package/src/storage-test-utils.js +169 -116
- package/src/tagged.d.ts +149 -0
- package/src/testing-utils.d.ts +2 -0
- package/src/testing-utils.d.ts.map +1 -1
- package/src/testing-utils.js +44 -5
- package/src/tokens.d.ts +34 -0
- package/src/tokens.d.ts.map +1 -0
- package/src/tokens.js +35 -0
- package/src/typeCheck.d.ts +9 -0
- package/src/typeCheck.d.ts.map +1 -0
- package/src/typeCheck.js +23 -0
- package/src/typeGuards.d.ts +2 -0
- package/src/typeGuards.d.ts.map +1 -1
- package/src/typeGuards.js +8 -0
- package/src/types-index.d.ts +1 -0
- package/src/types-index.js +2 -0
- package/src/types.d.ts +71 -18
- package/src/types.d.ts.map +1 -0
- package/src/types.ts +108 -0
- package/src/upgrade-api.d.ts +14 -4
- package/src/upgrade-api.d.ts.map +1 -1
- package/src/upgrade-api.js +50 -18
- package/CHANGELOG.md +0 -106
- package/src/utils.d.ts +0 -67
- package/src/utils.d.ts.map +0 -1
- package/src/utils.js +0 -451
|
@@ -1,101 +1,58 @@
|
|
|
1
|
-
export function slotToRemotable(_slotId: string, iface?: string): import("@endo/eventual-send").RemotableBrand<{}, {}>;
|
|
1
|
+
export function slotToRemotable(_slotId: string, iface?: string): import("@endo/pass-style").RemotableObject<string> & import("@endo/eventual-send").RemotableBrand<{}, {}>;
|
|
2
2
|
/**
|
|
3
|
-
* A basic marshaller whose unserializer produces Remotables. It can
|
|
4
|
-
*
|
|
3
|
+
* A basic marshaller whose unserializer produces Remotables. It can only
|
|
4
|
+
* serialize plain data, not Remotables.
|
|
5
5
|
*/
|
|
6
6
|
export const defaultMarshaller: {
|
|
7
|
-
toCapData: import("@endo/marshal
|
|
8
|
-
fromCapData: import("@endo/marshal
|
|
9
|
-
serialize: import("@endo/marshal
|
|
10
|
-
unserialize: import("@endo/marshal
|
|
7
|
+
toCapData: import("@endo/marshal").ToCapData<string>;
|
|
8
|
+
fromCapData: import("@endo/marshal").FromCapData<string>;
|
|
9
|
+
serialize: import("@endo/marshal").ToCapData<string>;
|
|
10
|
+
unserialize: import("@endo/marshal").FromCapData<string>;
|
|
11
11
|
};
|
|
12
|
-
export
|
|
13
|
-
export function makeFakeStorageKit(rootPath: string, rootOptions?: [
|
|
14
|
-
|
|
15
|
-
} | undefined][2]): {
|
|
16
|
-
rootNode: {
|
|
12
|
+
export const slotStringUnserialize: (capData: any) => any;
|
|
13
|
+
export function makeFakeStorageKit(rootPath: string, rootOptions?: Parameters<typeof makeChainStorageRoot>[2]): {
|
|
14
|
+
rootNode: import("@endo/exo").Guarded<{
|
|
17
15
|
getPath(): string;
|
|
18
|
-
getStoreKey(): Promise<
|
|
16
|
+
getStoreKey(): Promise<VStorageKey>;
|
|
19
17
|
makeChildNode(name: string, childNodeOptions?: {
|
|
20
|
-
sequence?: boolean
|
|
21
|
-
}
|
|
22
|
-
setValue(value: string): Promise<void>;
|
|
23
|
-
} & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
24
|
-
getPath(): string;
|
|
25
|
-
getStoreKey(): Promise<import("./lib-chainStorage.js").VStorageKey>;
|
|
26
|
-
makeChildNode(name: string, childNodeOptions?: {
|
|
27
|
-
sequence?: boolean | undefined;
|
|
28
|
-
} | undefined): import("./lib-chainStorage.js").StorageNode;
|
|
18
|
+
sequence?: boolean;
|
|
19
|
+
}): StorageNode;
|
|
29
20
|
setValue(value: string): Promise<void>;
|
|
30
21
|
}>;
|
|
31
22
|
data: Map<string, string>;
|
|
32
|
-
messages:
|
|
33
|
-
toStorage: (message:
|
|
23
|
+
messages: StorageMessage[];
|
|
24
|
+
toStorage: ((message: StorageMessage) => string | number | any[] | {
|
|
34
25
|
storeName: string;
|
|
35
26
|
storeSubkey: string;
|
|
36
|
-
} | null | undefined
|
|
27
|
+
} | null | undefined) & import("@endo/pass-style").RemotableObject<`Alleged: ${string}`> & import("@endo/eventual-send").RemotableBrand<{}, (message: StorageMessage) => string | number | any[] | {
|
|
28
|
+
storeName: string;
|
|
29
|
+
storeSubkey: string;
|
|
30
|
+
} | null | undefined>;
|
|
37
31
|
};
|
|
38
|
-
export function makeMockChainStorageRoot():
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
getBody: (path: string, marshaller?: import('./lib-chainStorage.js').Marshaller, index?: number | undefined) => unknown;
|
|
51
|
-
keys: () => string[];
|
|
52
|
-
getPath(): string;
|
|
53
|
-
getStoreKey(): Promise<import("./lib-chainStorage.js").VStorageKey>;
|
|
54
|
-
makeChildNode(name: string, childNodeOptions?: {
|
|
55
|
-
sequence?: boolean | undefined;
|
|
56
|
-
} | undefined): import("./lib-chainStorage.js").StorageNode;
|
|
57
|
-
setValue(value: string): Promise<void>;
|
|
58
|
-
} & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
32
|
+
export function makeMockChainStorageRoot(): MockChainStorageRoot;
|
|
33
|
+
export function documentStorageSchema(t: import("ava").ExecutionContext<unknown>, storage: MockChainStorageRoot | FakeStorageKit, opts: ({
|
|
34
|
+
note: string;
|
|
35
|
+
} | {
|
|
36
|
+
node: string;
|
|
37
|
+
owner: string;
|
|
38
|
+
}) & ({
|
|
39
|
+
pattern: string;
|
|
40
|
+
replacement: string;
|
|
41
|
+
} | {})): Promise<void>;
|
|
42
|
+
export type FakeStorageKit = ReturnType<typeof makeFakeStorageKit>;
|
|
43
|
+
export type MockChainStorageRootMethods = {
|
|
59
44
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* @param {string} path
|
|
66
|
-
* @param {import('./lib-chainStorage.js').Marshaller} marshaller
|
|
67
|
-
* @param {number} [index]
|
|
68
|
-
* @returns {unknown}
|
|
45
|
+
* Defaults to deserializing slot references into plain Remotable objects having
|
|
46
|
+
* the specified interface name (as from `Far(iface)`), but can accept a
|
|
47
|
+
* different marshaller for producing Remotables that e.g. embed the slot
|
|
48
|
+
* string in their iface name.
|
|
69
49
|
*/
|
|
70
|
-
getBody: (path: string, marshaller?:
|
|
50
|
+
getBody: (path: string, marshaller?: Marshaller, index?: number) => unknown;
|
|
71
51
|
keys: () => string[];
|
|
72
|
-
getPath(): string;
|
|
73
|
-
getStoreKey(): Promise<import("./lib-chainStorage.js").VStorageKey>;
|
|
74
|
-
makeChildNode(name: string, childNodeOptions?: {
|
|
75
|
-
sequence?: boolean | undefined;
|
|
76
|
-
} | undefined): import("./lib-chainStorage.js").StorageNode;
|
|
77
|
-
setValue(value: string): Promise<void>;
|
|
78
|
-
}>;
|
|
79
|
-
/**
|
|
80
|
-
* A map corresponding with a total function such that `get(key)`
|
|
81
|
-
* is assumed to always succeed.
|
|
82
|
-
*/
|
|
83
|
-
export type TotalMap<K, V> = {
|
|
84
|
-
[Symbol.iterator]: () => IterableIterator<[K, V]>;
|
|
85
|
-
[Symbol.toStringTag]: string;
|
|
86
|
-
entries: () => IterableIterator<[K, V]>;
|
|
87
|
-
keys: () => IterableIterator<K>;
|
|
88
|
-
values: () => IterableIterator<V>;
|
|
89
|
-
has: (key: K) => boolean;
|
|
90
|
-
size: number;
|
|
91
|
-
set: (key: K, value: V) => Map<K, V>;
|
|
92
|
-
clear: () => void;
|
|
93
|
-
delete: (key: K) => boolean;
|
|
94
|
-
forEach: (callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any) => void;
|
|
95
|
-
} & {
|
|
96
|
-
get: (key: K) => V;
|
|
97
52
|
};
|
|
98
|
-
export type
|
|
99
|
-
|
|
100
|
-
|
|
53
|
+
export type MockChainStorageRoot = StorageNode & MockChainStorageRootMethods;
|
|
54
|
+
import { makeChainStorageRoot } from './lib-chainStorage.js';
|
|
55
|
+
import type { StorageNode } from './lib-chainStorage.js';
|
|
56
|
+
import type { StorageMessage } from './lib-chainStorage.js';
|
|
57
|
+
import type { Marshaller } from './lib-chainStorage.js';
|
|
101
58
|
//# 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":"AAwBO,yCAHI,MAAM,UACN,MAAM,6GAGC;AAElB;;;GAGG;AACH;;;;;EAEG;AA4CH,8CAtBuB,GAAG,KAAK,GAAG,CAsB+B;AAU1D,6CAHI,MAAM,gBACN,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC;;;;;oBA2GjD,CAAA;;;;UAEiB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;;0BAjFxB,cAAc;;;0JAAd,cAAc;;;;EAqF7B;AAoBM,4CADO,oBAAoB,CA6BjC;AAQM,yCALI,OAAO,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,WACvC,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,iBAkCnD;6BAtFa,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;qCAjNJ,uBAAuB;iCAMF,uBAAuB;oCAAvB,uBAAuB;gCAAvB,uBAAuB"}
|
|
@@ -1,33 +1,23 @@
|
|
|
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';
|
|
5
|
+
import { unmarshalFromVstorage } from './marshal.js';
|
|
4
6
|
import { makeTracer } from './debug.js';
|
|
5
|
-
import {
|
|
6
|
-
isStreamCell,
|
|
7
|
-
makeChainStorageRoot,
|
|
8
|
-
unmarshalFromVstorage,
|
|
9
|
-
} from './lib-chainStorage.js';
|
|
7
|
+
import { isStreamCell, makeChainStorageRoot } from './lib-chainStorage.js';
|
|
10
8
|
import { bindAllMethods } from './method-tools.js';
|
|
11
|
-
|
|
12
|
-
const { Fail } = assert;
|
|
13
|
-
|
|
14
|
-
const trace = makeTracer('StorTU', false);
|
|
9
|
+
import { eventLoopIteration } from './testing-utils.js';
|
|
15
10
|
|
|
16
11
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
|
12
|
+
* @import {TotalMap} from './types.js';
|
|
13
|
+
* @import {Marshaller, StorageEntry, StorageMessage, StorageNode} from './lib-chainStorage.js';
|
|
26
14
|
*/
|
|
27
15
|
|
|
16
|
+
const trace = makeTracer('StorTU', false);
|
|
17
|
+
|
|
28
18
|
/**
|
|
29
|
-
* A convertSlotToVal function that produces basic Remotables. Assumes
|
|
30
|
-
*
|
|
19
|
+
* A convertSlotToVal function that produces basic Remotables. Assumes that all
|
|
20
|
+
* slots are Remotables (i.e. none are Promises).
|
|
31
21
|
*
|
|
32
22
|
* @param {string} _slotId
|
|
33
23
|
* @param {string} iface
|
|
@@ -36,34 +26,34 @@ export const slotToRemotable = (_slotId, iface = 'Remotable') =>
|
|
|
36
26
|
Remotable(iface);
|
|
37
27
|
|
|
38
28
|
/**
|
|
39
|
-
* A basic marshaller whose unserializer produces Remotables. It can
|
|
40
|
-
*
|
|
29
|
+
* A basic marshaller whose unserializer produces Remotables. It can only
|
|
30
|
+
* serialize plain data, not Remotables.
|
|
41
31
|
*/
|
|
42
32
|
export const defaultMarshaller = makeMarshal(undefined, slotToRemotable, {
|
|
43
33
|
serializeBodyFormat: 'smallcaps',
|
|
44
34
|
});
|
|
45
35
|
|
|
46
36
|
/**
|
|
47
|
-
* A deserializer which produces slot strings instead of Remotables,
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
37
|
+
* A deserializer which produces slot strings instead of Remotables, so if `a =
|
|
38
|
+
* Far('iface')`, and serializing `{ a }` into `capData` assigned it slot
|
|
39
|
+
* `board123`, then `slotStringUnserialize(capData)` would produce `{ a:
|
|
40
|
+
* 'board123' }`.
|
|
51
41
|
*
|
|
52
42
|
* This may be useful for display purposes.
|
|
53
43
|
*
|
|
54
44
|
* Limitations:
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
45
|
+
*
|
|
46
|
+
* - it cannot handle Symbols (registered or well-known)
|
|
47
|
+
* - it can handle BigInts, but serialized data that contains a particular unusual
|
|
48
|
+
* string will be unserialized into a BigInt by mistake
|
|
49
|
+
* - it cannot handle Promises, NaN, +/- Infinity, undefined, or other
|
|
50
|
+
* non-JSONable JavaScript values
|
|
61
51
|
*/
|
|
62
52
|
const makeSlotStringUnserialize = () => {
|
|
63
|
-
/** @type {
|
|
53
|
+
/** @type {(slot: string, iface: string) => any} */
|
|
64
54
|
const identitySlotToValFn = (slot, _) => Far('unk', { toJSON: () => slot });
|
|
65
55
|
const { fromCapData } = makeMarshal(undefined, identitySlotToValFn);
|
|
66
|
-
/** @type {
|
|
56
|
+
/** @type {(capData: any) => any} */
|
|
67
57
|
const unserialize = capData =>
|
|
68
58
|
JSON.parse(
|
|
69
59
|
JSON.stringify(fromCapData(capData), (_, val) => {
|
|
@@ -88,9 +78,9 @@ const makeSlotStringUnserialize = () => {
|
|
|
88
78
|
export const slotStringUnserialize = makeSlotStringUnserialize();
|
|
89
79
|
|
|
90
80
|
/**
|
|
91
|
-
* For testing, creates a chainStorage root node over an in-memory map
|
|
92
|
-
*
|
|
93
|
-
*
|
|
81
|
+
* For testing, creates a chainStorage root node over an in-memory map and
|
|
82
|
+
* exposes both the map and the sequence of received messages. The `sequence`
|
|
83
|
+
* option defaults to true.
|
|
94
84
|
*
|
|
95
85
|
* @param {string} rootPath
|
|
96
86
|
* @param {Parameters<typeof makeChainStorageRoot>[2]} [rootOptions]
|
|
@@ -116,84 +106,88 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
116
106
|
}
|
|
117
107
|
return childEntries;
|
|
118
108
|
};
|
|
119
|
-
/** @type {
|
|
109
|
+
/** @type {StorageMessage[]} */
|
|
120
110
|
const messages = [];
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
}
|
|
111
|
+
|
|
112
|
+
const toStorage = Far(
|
|
113
|
+
'ToStorage',
|
|
114
|
+
/** @param {StorageMessage} message */
|
|
115
|
+
message => {
|
|
116
|
+
messages.push(message);
|
|
117
|
+
switch (message.method) {
|
|
118
|
+
case 'getStoreKey': {
|
|
119
|
+
const [key] = message.args;
|
|
120
|
+
return { storeName: 'swingset', storeSubkey: `fake:${key}` };
|
|
157
121
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
122
|
+
case 'get': {
|
|
123
|
+
const [key] = message.args;
|
|
124
|
+
return data.has(key) ? data.get(key) : null;
|
|
125
|
+
}
|
|
126
|
+
case 'children': {
|
|
127
|
+
const [key] = message.args;
|
|
128
|
+
const childEntries = getChildEntries(`${key}.`);
|
|
129
|
+
return [...childEntries.keys()];
|
|
130
|
+
}
|
|
131
|
+
case 'entries': {
|
|
132
|
+
const [key] = message.args;
|
|
133
|
+
const childEntries = getChildEntries(`${key}.`);
|
|
134
|
+
return [...childEntries.entries()].map(entry =>
|
|
135
|
+
entry[1] != null ? entry : [entry[0]],
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
case 'set':
|
|
139
|
+
case 'setWithoutNotify': {
|
|
140
|
+
trace('toStorage set', message);
|
|
141
|
+
/** @type {StorageEntry[]} */
|
|
142
|
+
const newEntries = message.args;
|
|
143
|
+
for (const [key, value] of newEntries) {
|
|
144
|
+
if (value != null) {
|
|
145
|
+
data.set(key, value);
|
|
146
|
+
} else {
|
|
147
|
+
data.delete(key);
|
|
175
148
|
}
|
|
176
149
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case 'append': {
|
|
153
|
+
trace('toStorage append', message);
|
|
154
|
+
/** @type {StorageEntry[]} */
|
|
155
|
+
const newEntries = message.args;
|
|
156
|
+
for (const [key, value] of newEntries) {
|
|
157
|
+
value != null || Fail`attempt to append with no value`;
|
|
158
|
+
// In the absence of block boundaries, everything goes in a single StreamCell.
|
|
159
|
+
const oldVal = data.get(key);
|
|
160
|
+
let streamCell;
|
|
161
|
+
if (oldVal != null) {
|
|
162
|
+
try {
|
|
163
|
+
streamCell = JSON.parse(oldVal);
|
|
164
|
+
assert(isStreamCell(streamCell));
|
|
165
|
+
} catch (_err) {
|
|
166
|
+
streamCell = undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (streamCell === undefined) {
|
|
170
|
+
streamCell = {
|
|
171
|
+
blockHeight: '0',
|
|
172
|
+
values: oldVal != null ? [oldVal] : [],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
streamCell.values.push(value);
|
|
176
|
+
data.set(key, JSON.stringify(streamCell));
|
|
182
177
|
}
|
|
183
|
-
|
|
184
|
-
data.set(key, JSON.stringify(streamCell));
|
|
178
|
+
break;
|
|
185
179
|
}
|
|
186
|
-
|
|
180
|
+
case 'size':
|
|
181
|
+
// Intentionally incorrect because it counts non-child descendants,
|
|
182
|
+
// but nevertheless supports a "has children" test.
|
|
183
|
+
return [...data.keys()].filter(k =>
|
|
184
|
+
k.startsWith(`${message.args[0]}.`),
|
|
185
|
+
).length;
|
|
186
|
+
default:
|
|
187
|
+
throw Error(`unsupported method: ${message.method}`);
|
|
187
188
|
}
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
};
|
|
189
|
+
},
|
|
190
|
+
);
|
|
197
191
|
const rootNode = makeChainStorageRoot(toStorage, rootPath, resolvedOptions);
|
|
198
192
|
return {
|
|
199
193
|
rootNode,
|
|
@@ -204,26 +198,46 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => {
|
|
|
204
198
|
};
|
|
205
199
|
};
|
|
206
200
|
harden(makeFakeStorageKit);
|
|
207
|
-
/** @typedef {ReturnType<
|
|
201
|
+
/** @typedef {ReturnType<typeof makeFakeStorageKit>} FakeStorageKit */
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @typedef MockChainStorageRootMethods
|
|
205
|
+
* @property {(
|
|
206
|
+
* path: string,
|
|
207
|
+
* marshaller?: Marshaller,
|
|
208
|
+
* index?: number,
|
|
209
|
+
* ) => unknown} getBody
|
|
210
|
+
* Defaults to deserializing slot references into plain Remotable objects having
|
|
211
|
+
* the specified interface name (as from `Far(iface)`), but can accept a
|
|
212
|
+
* different marshaller for producing Remotables that e.g. embed the slot
|
|
213
|
+
* string in their iface name.
|
|
214
|
+
* @property {() => string[]} keys
|
|
215
|
+
*/
|
|
216
|
+
/** @typedef {StorageNode & MockChainStorageRootMethods} MockChainStorageRoot */
|
|
208
217
|
|
|
218
|
+
/** @returns {MockChainStorageRoot} */
|
|
209
219
|
export const makeMockChainStorageRoot = () => {
|
|
210
220
|
const { rootNode, data } = makeFakeStorageKit('mockChainStorageRoot');
|
|
211
221
|
return Far('mockChainStorage', {
|
|
212
222
|
...bindAllMethods(rootNode),
|
|
213
223
|
/**
|
|
214
|
-
* Defaults to deserializing slot references into plain Remotable
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
224
|
+
* Defaults to deserializing slot references into plain Remotable objects
|
|
225
|
+
* having the specified interface name (as from `Far(iface)`), but can
|
|
226
|
+
* accept a different marshaller for producing Remotables that e.g. embed
|
|
227
|
+
* the slot string in their iface name.
|
|
218
228
|
*
|
|
219
229
|
* @param {string} path
|
|
220
|
-
* @param {
|
|
230
|
+
* @param {Marshaller} marshaller
|
|
221
231
|
* @param {number} [index]
|
|
222
232
|
* @returns {unknown}
|
|
223
233
|
*/
|
|
224
234
|
getBody: (path, marshaller = defaultMarshaller, index = -1) => {
|
|
225
235
|
data.size || Fail`no data in storage`;
|
|
226
|
-
/**
|
|
236
|
+
/**
|
|
237
|
+
* @type {ReturnType<
|
|
238
|
+
* typeof import('@endo/marshal').makeMarshal
|
|
239
|
+
* >['fromCapData']}
|
|
240
|
+
*/
|
|
227
241
|
const fromCapData = (...args) =>
|
|
228
242
|
Reflect.apply(marshaller.fromCapData, marshaller, args);
|
|
229
243
|
return unmarshalFromVstorage(data, path, fromCapData, index);
|
|
@@ -231,4 +245,43 @@ export const makeMockChainStorageRoot = () => {
|
|
|
231
245
|
keys: () => [...data.keys()],
|
|
232
246
|
});
|
|
233
247
|
};
|
|
234
|
-
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @param {import('ava').ExecutionContext<unknown>} t
|
|
251
|
+
* @param {MockChainStorageRoot | FakeStorageKit} storage
|
|
252
|
+
* @param {({ note: string } | { node: string; owner: string }) &
|
|
253
|
+
* ({ pattern: string; replacement: string } | {})} opts
|
|
254
|
+
*/
|
|
255
|
+
export const documentStorageSchema = async (t, storage, opts) => {
|
|
256
|
+
// chainStorage publication is unsynchronized
|
|
257
|
+
await eventLoopIteration();
|
|
258
|
+
|
|
259
|
+
const [keys, getBody] =
|
|
260
|
+
'keys' in storage
|
|
261
|
+
? [storage.keys(), (/** @type {string} */ k) => storage.getBody(k)]
|
|
262
|
+
: [storage.data.keys(), (/** @type {string} */ k) => storage.data.get(k)];
|
|
263
|
+
|
|
264
|
+
const { pattern, replacement } =
|
|
265
|
+
'pattern' in opts
|
|
266
|
+
? opts
|
|
267
|
+
: { pattern: 'mockChainStorageRoot.', replacement: 'published.' };
|
|
268
|
+
const illustration = [...keys].sort().map(
|
|
269
|
+
/** @type {(k: string) => [string, unknown]} */
|
|
270
|
+
key => [key.replace(pattern, replacement), getBody(key)],
|
|
271
|
+
);
|
|
272
|
+
const pruned = illustration.filter(
|
|
273
|
+
'node' in opts
|
|
274
|
+
? ([key, _]) => key.startsWith(`published.${opts.node}`)
|
|
275
|
+
: _entry => true,
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
const note =
|
|
279
|
+
'note' in opts
|
|
280
|
+
? opts.note
|
|
281
|
+
: `Under "published", the "${opts.node}" node is delegated to ${opts.owner}.`;
|
|
282
|
+
const boilerplate = `
|
|
283
|
+
The example below illustrates the schema of the data published there.
|
|
284
|
+
|
|
285
|
+
See also board marshalling conventions (_to appear_).`;
|
|
286
|
+
t.snapshot(pruned, note + boilerplate);
|
|
287
|
+
};
|
package/src/tagged.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/** @file adapted from https://raw.githubusercontent.com/sindresorhus/type-fest/main/source/opaque.d.ts */
|
|
2
|
+
|
|
3
|
+
declare const tag: unique symbol;
|
|
4
|
+
|
|
5
|
+
export type TagContainer<Token> = {
|
|
6
|
+
readonly [tag]: Token;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type Tag<Token extends PropertyKey, TagMetadata> = TagContainer<{
|
|
10
|
+
[K in Token]: TagMetadata;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
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.)
|
|
15
|
+
|
|
16
|
+
A type returned by `Tagged` can be passed to `Tagged` again, to create a type with multiple tags.
|
|
17
|
+
|
|
18
|
+
[Read more about tagged types.](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d)
|
|
19
|
+
|
|
20
|
+
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.
|
|
21
|
+
|
|
22
|
+
A type `A` returned by `Tagged` is assignable to another type `B` returned by `Tagged` if and only if:
|
|
23
|
+
- the underlying (untagged) type of `A` is assignable to the underlying type of `B`;
|
|
24
|
+
- `A` contains at least all the tags `B` has;
|
|
25
|
+
- and the metadata type for each of `A`'s tags is assignable to the metadata type of `B`'s corresponding tag.
|
|
26
|
+
|
|
27
|
+
There have been several discussions about adding similar features to TypeScript. Unfortunately, nothing has (yet) moved forward:
|
|
28
|
+
- [Microsoft/TypeScript#202](https://github.com/microsoft/TypeScript/issues/202)
|
|
29
|
+
- [Microsoft/TypeScript#4895](https://github.com/microsoft/TypeScript/issues/4895)
|
|
30
|
+
- [Microsoft/TypeScript#33290](https://github.com/microsoft/TypeScript/pull/33290)
|
|
31
|
+
|
|
32
|
+
@example
|
|
33
|
+
```
|
|
34
|
+
import type {Tagged} from 'type-fest';
|
|
35
|
+
|
|
36
|
+
type AccountNumber = Tagged<number, 'AccountNumber'>;
|
|
37
|
+
type AccountBalance = Tagged<number, 'AccountBalance'>;
|
|
38
|
+
|
|
39
|
+
function createAccountNumber(): AccountNumber {
|
|
40
|
+
// As you can see, casting from a `number` (the underlying type being tagged) is allowed.
|
|
41
|
+
return 2 as AccountNumber;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getMoneyForAccount(accountNumber: AccountNumber): AccountBalance {
|
|
45
|
+
return 4 as AccountBalance;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// This will compile successfully.
|
|
49
|
+
getMoneyForAccount(createAccountNumber());
|
|
50
|
+
|
|
51
|
+
// But this won't, because it has to be explicitly passed as an `AccountNumber` type!
|
|
52
|
+
// Critically, you could not accidentally use an `AccountBalance` as an `AccountNumber`.
|
|
53
|
+
getMoneyForAccount(2);
|
|
54
|
+
|
|
55
|
+
// You can also use tagged values like their underlying, untagged type.
|
|
56
|
+
// I.e., this will compile successfully because an `AccountNumber` can be used as a regular `number`.
|
|
57
|
+
// In this sense, the underlying base type is not hidden, which differentiates tagged types from opaque types in other languages.
|
|
58
|
+
const accountNumber = createAccountNumber() + 2;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
@example
|
|
62
|
+
```
|
|
63
|
+
import type {Tagged} from 'type-fest';
|
|
64
|
+
|
|
65
|
+
// You can apply multiple tags to a type by using `Tagged` repeatedly.
|
|
66
|
+
type Url = Tagged<string, 'URL'>;
|
|
67
|
+
type SpecialCacheKey = Tagged<Url, 'SpecialCacheKey'>;
|
|
68
|
+
|
|
69
|
+
// 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.
|
|
70
|
+
type SpecialCacheKey2 = Tagged<string, 'URL' | 'SpecialCacheKey'>;
|
|
71
|
+
```
|
|
72
|
+
*/
|
|
73
|
+
export type Tagged<
|
|
74
|
+
Type,
|
|
75
|
+
TagName extends PropertyKey,
|
|
76
|
+
TagMetadata = never,
|
|
77
|
+
> = Type & Tag<TagName, TagMetadata>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
Given a type and a tag name, returns the metadata associated with that tag on that type.
|
|
81
|
+
|
|
82
|
+
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.
|
|
83
|
+
|
|
84
|
+
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).
|
|
85
|
+
|
|
86
|
+
@example
|
|
87
|
+
```
|
|
88
|
+
import type {Tagged} from 'type-fest';
|
|
89
|
+
|
|
90
|
+
type JsonOf<T> = Tagged<string, 'JSON', T>;
|
|
91
|
+
|
|
92
|
+
function stringify<T>(it: T) {
|
|
93
|
+
return JSON.stringify(it) as JsonOf<T>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function parse<T extends JsonOf<unknown>>(it: T) {
|
|
97
|
+
return JSON.parse(it) as GetTagMetadata<T, 'JSON'>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const x = stringify({ hello: 'world' });
|
|
101
|
+
const parsed = parse(x); // The type of `parsed` is { hello: string }
|
|
102
|
+
```
|
|
103
|
+
*/
|
|
104
|
+
export type GetTagMetadata<
|
|
105
|
+
Type extends Tag<TagName, unknown>,
|
|
106
|
+
TagName extends PropertyKey,
|
|
107
|
+
> = Type[typeof tag][TagName];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
Revert a tagged type back to its original type by removing all tags.
|
|
111
|
+
|
|
112
|
+
Why is this necessary?
|
|
113
|
+
|
|
114
|
+
1. Use a `Tagged` type as object keys
|
|
115
|
+
2. Prevent TS4058 error: "Return type of exported function has or is using name X from external module Y but cannot be named"
|
|
116
|
+
|
|
117
|
+
@example
|
|
118
|
+
```
|
|
119
|
+
import type {Tagged, UnwrapTagged} from 'type-fest';
|
|
120
|
+
|
|
121
|
+
type AccountType = Tagged<'SAVINGS' | 'CHECKING', 'AccountType'>;
|
|
122
|
+
|
|
123
|
+
const moneyByAccountType: Record<UnwrapTagged<AccountType>, number> = {
|
|
124
|
+
SAVINGS: 99,
|
|
125
|
+
CHECKING: 0.1
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Without UnwrapTagged, the following expression would throw a type error.
|
|
129
|
+
const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
|
|
130
|
+
|
|
131
|
+
// Attempting to pass an non-Tagged type to UnwrapTagged will raise a type error.
|
|
132
|
+
type WontWork = UnwrapTagged<string>;
|
|
133
|
+
```
|
|
134
|
+
*/
|
|
135
|
+
export type UnwrapTagged<TaggedType extends Tag<PropertyKey, any>> =
|
|
136
|
+
RemoveAllTags<TaggedType>;
|
|
137
|
+
|
|
138
|
+
type RemoveAllTags<T> =
|
|
139
|
+
T extends Tag<PropertyKey, any>
|
|
140
|
+
? {
|
|
141
|
+
[ThisTag in keyof T[typeof tag]]: T extends Tagged<
|
|
142
|
+
infer Type,
|
|
143
|
+
ThisTag,
|
|
144
|
+
T[typeof tag][ThisTag]
|
|
145
|
+
>
|
|
146
|
+
? RemoveAllTags<Type>
|
|
147
|
+
: never;
|
|
148
|
+
}[keyof T[typeof tag]]
|
|
149
|
+
: T;
|