@agoric/zone 0.2.3-dev-ff34bdf.0 → 0.2.3-dev-c4e4693.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 CHANGED
@@ -12,18 +12,18 @@ An example of making a Zone-aware vat might look something like this:
12
12
 
13
13
  ```js
14
14
  import { makeDurableZone } from '@agoric/zone/durable.js';
15
- import { zoneFrobulator } from 'frob-package';
16
- import { zoneWidget } from 'widget-package';
15
+ import { prepareFrobulator } from 'frob-package';
16
+ import { prepareWidget } from 'widget-package';
17
17
 
18
18
  export const buildRootObject = (vatPowers, _args, baggage) => {
19
19
  const zone = makeDurableZone(baggage);
20
20
 
21
21
  // Ensure that Widgets cannot interfere with Frobs.
22
- const makeWidget = zoneWidget(zone.subZone('Widgets'));
22
+ const makeWidget = prepareWidget(zone.subZone('Widgets'));
23
23
 
24
24
  // Create a collection of frobulators.
25
25
  const frobZone = zone.subZone('Frobs');
26
- const makeFrobulator = zoneFrobulator(frobZone);
26
+ const makeFrobulator = prepareFrobulator(frobZone);
27
27
  const widgetToFrob = frobZone.mapStore('widgetToFrob');
28
28
 
29
29
  return Far('WidgetFrobulator', {
package/durable.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./src/durable.js";
2
+ //# sourceMappingURL=durable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["durable.js"],"names":[],"mappings":""}
package/heap.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "@agoric/base-zone/heap.js";
2
+ //# sourceMappingURL=heap.d.ts.map
package/heap.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heap.d.ts","sourceRoot":"","sources":["heap.js"],"names":[],"mappings":""}
package/heap.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // @jessie-check
2
2
 
3
- export * from './src/heap.js';
3
+ export * from '@agoric/base-zone/heap.js';
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": [
3
+ "./jsconfig.json",
4
+ "../../tsconfig-build-options.json"
5
+ ],
6
+ "exclude": [
7
+ "scripts",
8
+ "test",
9
+ "**/exports.js",
10
+ ]
11
+ }
package/jsconfig.json CHANGED
@@ -1,19 +1,10 @@
1
1
  // This file can contain .js-specific Typescript compiler config.
2
2
  {
3
- "compilerOptions": {
4
- "target": "esnext",
5
- "module": "esnext",
6
- "checkJs": true,
7
- "noEmit": true,
8
- "downlevelIteration": true,
9
- "strictNullChecks": true,
10
- "noImplicitThis": true,
11
- "moduleResolution": "node",
12
- },
3
+ "extends": "../../tsconfig.json",
13
4
  "include": [
14
5
  "*.js",
15
6
  "scripts",
16
- "src",
17
- "test",
7
+ "src/**/*.js",
8
+ "test/**/*.js",
18
9
  ],
19
10
  }
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "@agoric/zone",
3
- "version": "0.2.3-dev-ff34bdf.0+ff34bdf",
3
+ "version": "0.2.3-dev-c4e4693.0+c4e4693",
4
4
  "description": "Allocation zone abstraction for objects on the heap, persistent stores, etc.",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/Agoric/agoric-sdk",
7
7
  "main": "./src/index.js",
8
8
  "scripts": {
9
9
  "build": "exit 0",
10
+ "prepack": "tsc --build jsconfig.build.json",
11
+ "postpack": "git clean -f '*.d.ts*'",
10
12
  "test": "ava",
11
13
  "test:c8": "c8 $C8_OPTIONS ava --config=ava-nesm.config.js",
12
14
  "test:xs": "exit 0",
@@ -25,13 +27,13 @@
25
27
  "author": "Agoric",
26
28
  "license": "Apache-2.0",
27
29
  "dependencies": {
28
- "@agoric/vat-data": "0.5.3-dev-ff34bdf.0+ff34bdf",
29
- "@endo/exo": "^0.2.3",
30
+ "@agoric/base-zone": "0.1.1-dev-c4e4693.0+c4e4693",
31
+ "@agoric/vat-data": "0.5.3-dev-c4e4693.0+c4e4693",
30
32
  "@endo/far": "^0.2.19",
31
33
  "@endo/pass-style": "^0.1.4"
32
34
  },
33
35
  "devDependencies": {
34
- "@agoric/swingset-liveslots": "0.10.3-dev-ff34bdf.0+ff34bdf",
36
+ "@agoric/swingset-liveslots": "0.10.3-dev-c4e4693.0+c4e4693",
35
37
  "@endo/patterns": "^0.2.3",
36
38
  "ava": "^5.3.0"
37
39
  },
@@ -48,5 +50,5 @@
48
50
  "timeout": "20m",
49
51
  "workerThreads": false
50
52
  },
51
- "gitHead": "ff34bdfa02979097e93c09badddf53547cd8d721"
53
+ "gitHead": "c4e469386a2a8c813182dc84cc63c8a660d22ecc"
52
54
  }
@@ -0,0 +1,2 @@
1
+ export function makeDurableZone(baggage: import('@agoric/vat-data').Baggage, baseLabel?: string | undefined): import('.').Zone;
2
+ //# sourceMappingURL=durable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["durable.js"],"names":[],"mappings":"AA6EO,yCAJI,OAAO,kBAAkB,EAAE,OAAO,mCAEhC,OAAO,GAAG,EAAE,IAAI,CA2C5B"}
package/src/durable.js CHANGED
@@ -14,9 +14,11 @@ import {
14
14
  provideDurableWeakSetStore,
15
15
  } from '@agoric/vat-data';
16
16
 
17
- import { makeOnceKit } from './make-once.js';
18
- import { agoricVatDataKeys as keys } from './keys.js';
19
- import { isPassable } from './is-passable.js';
17
+ import {
18
+ agoricVatDataKeys as keys,
19
+ isPassable,
20
+ makeOnceKit,
21
+ } from '@agoric/base-zone';
20
22
 
21
23
  const { Fail } = assert;
22
24
 
@@ -0,0 +1,8 @@
1
+ /* eslint-disable import/export */
2
+
3
+ // Module Types //////////////////////////////////////////////////////
4
+ //
5
+ // Types exposed from modules.
6
+ //
7
+
8
+ export type { ExoZone, Stores, Zone } from '@agoric/base-zone/src/exports.js';
package/src/exports.js ADDED
@@ -0,0 +1,2 @@
1
+ // Just a dummy to use exports.d.ts and satisfy runtime imports.
2
+ export {};
package/src/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { makeHeapZone } from "@agoric/base-zone/heap.js";
2
+ export * from "./exports.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":""}
package/src/index.js CHANGED
@@ -1,38 +1,4 @@
1
- // @jessie-check
1
+ export { makeHeapZone } from '@agoric/base-zone/heap.js';
2
2
 
3
- import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo';
4
-
5
- export * from './heap.js';
6
-
7
- // References to allow the below typeofs to succeed.
8
- makeExo;
9
- defineExoClass;
10
- defineExoClassKit;
11
-
12
- /**
13
- * @typedef {ExoZone & Stores} Zone A bag of methods for creating defensible objects and
14
- * collections with the same allocation semantics (ephemeral, persistent, etc)
15
- */
16
-
17
- /**
18
- * @typedef {object} ExoZone
19
- * @property {typeof makeExo} exo create a singleton exo-object instance bound to this zone
20
- * @property {typeof defineExoClass} exoClass create a maker function that can be used to create exo-objects bound to this zone
21
- * @property {typeof defineExoClassKit} exoClassKit create a "kit" maker function that can be used to create a record of exo-objects sharing the same state
22
- * @property {<T>(key: string, maker: (key: string) => T) => T} makeOnce create or retrieve a singleton object bound to this zone
23
- * @property {(label: string, options?: StoreOptions) => Zone} subZone create a new Zone that can be passed to untrusted consumers without exposing the storage of the parent zone
24
- */
25
-
26
- /**
27
- * @typedef {object} Stores
28
- * @property {() => Stores} detached obtain store providers which are detached (the stores are anonymous rather than bound to `label` in the zone)
29
- * @property {(specimen: unknown) => boolean} isStorable return true if the specimen can be stored in the zone, whether as exo-object state or in a store
30
- * @property {<K,V>(label: string, options?: StoreOptions) => MapStore<K, V>} mapStore provide a Map-like store named `label` in the zone
31
- * @property {<K>(label: string, options?: StoreOptions) => SetStore<K>} setStore provide a Set-like store named `label` in the zone
32
- * @property {<K,V>(
33
- * label: string, options?: StoreOptions) => WeakMapStore<K, V>
34
- * } weakMapStore provide a WeakMap-like store named `label` in the zone
35
- * @property {<K>(
36
- * label: string, options?: StoreOptions) => WeakSetStore<K>
37
- * } weakSetStore provide a WeakSet-like store named `label` in the zone
38
- */
3
+ // eslint-disable-next-line import/export
4
+ export * from './exports.js';
@@ -0,0 +1,2 @@
1
+ export function makeVirtualZone(baseLabel?: string | undefined): import('.').Zone;
2
+ //# sourceMappingURL=virtual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.d.ts","sourceRoot":"","sources":["virtual.js"],"names":[],"mappings":"AAiEO,iEAFM,OAAO,GAAG,EAAE,IAAI,CA8B5B"}
package/src/virtual.js CHANGED
@@ -11,9 +11,11 @@ import {
11
11
  makeScalarBigWeakSetStore,
12
12
  } from '@agoric/vat-data';
13
13
 
14
- import { makeOnceKit } from './make-once.js';
15
- import { agoricVatDataKeys as keys } from './keys.js';
16
- import { isPassable } from './is-passable.js';
14
+ import {
15
+ agoricVatDataKeys as keys,
16
+ isPassable,
17
+ makeOnceKit,
18
+ } from '@agoric/base-zone';
17
19
 
18
20
  const emptyRecord = harden({});
19
21
  const initEmpty = harden(() => emptyRecord);
package/test/test-exos.js CHANGED
@@ -6,106 +6,20 @@ import {
6
6
  test,
7
7
  } from './prepare-test-env-ava.js';
8
8
 
9
- import { M } from '@endo/patterns';
10
9
  import * as vatData from '@agoric/vat-data';
11
10
 
11
+ import { agoricVatDataKeys as keys } from '@agoric/base-zone';
12
+ import {
13
+ agoricVatDataCompatibleKeys,
14
+ testFirstZoneIncarnation,
15
+ testSecondZoneIncarnation,
16
+ testGreeter,
17
+ } from '@agoric/base-zone/tools/testers.js';
18
+ import * as g from '@agoric/base-zone/tools/greeter.js';
19
+
12
20
  import { makeDurableZone } from '../durable.js';
13
21
  import { makeHeapZone } from '../heap.js';
14
22
  import { makeVirtualZone } from '../virtual.js';
15
- import { agoricVatDataKeys as keys } from '../src/keys.js';
16
-
17
- /** @typedef {import('../src/index.js').Zone} Zone */
18
-
19
- // CAUTION: Do not modify this list; it exists to ensure that future versions
20
- // of @agoric/zone are compatible with the baggage created by older versions,
21
- // including the legacy implementation of @agoric/vat-data.
22
- const agoricVatDataCompatibleKeys = [
23
- 'Greeter_kindHandle',
24
- 'GreeterKit_kindHandle',
25
- 'a_kindHandle',
26
- 'a_singleton',
27
- 'mappish',
28
- 'subsub',
29
- ].sort();
30
-
31
- const bindAllMethodsTo = (obj, that = obj) =>
32
- Object.fromEntries(
33
- Object.entries(obj).map(([name, fn]) => [name, fn.bind(that)]),
34
- );
35
-
36
- const greetGuard = M.interface('Greeter', {
37
- greet: M.call().optional(M.string()).returns(M.string()),
38
- });
39
- const greetFacet = {
40
- greet(greeting = 'Hello') {
41
- return `${greeting}, ${this.state.nick}`;
42
- },
43
- };
44
-
45
- const adminGuard = M.interface('GreeterAdmin', {
46
- setNick: M.call(M.string()).returns(),
47
- });
48
- const adminFacet = {
49
- setNick(nick) {
50
- this.state.nick = nick;
51
- },
52
- };
53
-
54
- const combinedGuard = M.interface('GreeterWithAdmin', {
55
- ...greetGuard.methodGuards,
56
- ...adminGuard.methodGuards,
57
- });
58
-
59
- const alreadyExceptionSpec = {
60
- message: /has already been used/,
61
- };
62
-
63
- const prepareGreeterSingleton = (zone, label, nick) => {
64
- const myThis = Object.freeze({ state: { nick } });
65
- return zone.exo(label, combinedGuard, {
66
- ...bindAllMethodsTo(greetFacet, myThis),
67
- ...bindAllMethodsTo(adminFacet, myThis),
68
- });
69
- };
70
-
71
- const prepareGreeter = zone =>
72
- zone.exoClass('Greeter', combinedGuard, nick => ({ nick }), {
73
- ...greetFacet,
74
- ...adminFacet,
75
- });
76
-
77
- const prepareGreeterKit = zone =>
78
- zone.exoClassKit(
79
- 'GreeterKit',
80
- { greeter: greetGuard, admin: adminGuard },
81
- nick => ({ nick }),
82
- {
83
- greeter: greetFacet,
84
- admin: adminFacet,
85
- },
86
- );
87
-
88
- const testGreeter = (t, nick, obj, adminObj = obj) => {
89
- t.is(obj.greet('Greetings'), `Greetings, ${nick}`);
90
- t.is(obj.greet(), `Hello, ${nick}`);
91
- adminObj.setNick(`${nick}2`);
92
- t.is(obj.greet('Greetings'), `Greetings, ${nick}2`);
93
- t.is(obj.greet(), `Hello, ${nick}2`);
94
- adminObj.setNick(nick);
95
- };
96
-
97
- /**
98
- * @template T
99
- * @param {import('ava').Assertions} t
100
- * @param {() => T} fn
101
- * @param {*} spec
102
- * @returns {T}
103
- */
104
- const secondThrows = (t, fn, spec = alreadyExceptionSpec) => {
105
- const ret = fn();
106
- t.throws(fn, spec);
107
- return ret;
108
- };
109
23
 
110
24
  /**
111
25
  * @param {import('ava').Assertions} t
@@ -115,20 +29,20 @@ const testFirstVatDataIncarnation = (t, baggage) => {
115
29
  const subBaggage = vatData.provideDurableMapStore(baggage, 'sub');
116
30
 
117
31
  const myThis = Object.freeze({ state: { nick: 'Singly' } });
118
- const singly = vatData.prepareExo(subBaggage, 'a', combinedGuard, {
119
- ...bindAllMethodsTo(greetFacet, myThis),
120
- ...bindAllMethodsTo(adminFacet, myThis),
32
+ const singly = vatData.prepareExo(subBaggage, 'a', g.combinedGuard, {
33
+ ...g.bindAllMethodsTo(g.greetFacet, myThis),
34
+ ...g.bindAllMethodsTo(g.adminFacet, myThis),
121
35
  });
122
36
  testGreeter(t, 'Singly', singly);
123
37
 
124
38
  const makeGreeter = vatData.prepareExoClass(
125
39
  subBaggage,
126
40
  'Greeter',
127
- combinedGuard,
41
+ g.combinedGuard,
128
42
  nick => ({ nick }),
129
43
  {
130
- ...greetFacet,
131
- ...adminFacet,
44
+ ...g.greetFacet,
45
+ ...g.adminFacet,
132
46
  },
133
47
  );
134
48
  const classy = makeGreeter('Classy');
@@ -137,11 +51,11 @@ const testFirstVatDataIncarnation = (t, baggage) => {
137
51
  const makeGreeterKit = vatData.prepareExoClassKit(
138
52
  subBaggage,
139
53
  'GreeterKit',
140
- { greeter: greetGuard, admin: adminGuard },
54
+ { greeter: g.greetGuard, admin: g.adminGuard },
141
55
  nick => ({ nick }),
142
56
  {
143
- greeter: greetFacet,
144
- admin: adminFacet,
57
+ greeter: g.greetFacet,
58
+ admin: g.adminFacet,
145
59
  },
146
60
  );
147
61
  const { greeter: kitty, admin: kittyAdmin } = makeGreeterKit('Kitty');
@@ -156,62 +70,6 @@ const testFirstVatDataIncarnation = (t, baggage) => {
156
70
  vatData.provideDurableMapStore(subBaggage, 'subsub');
157
71
  };
158
72
 
159
- /**
160
- * @param {import('ava').Assertions} t
161
- * @param {Zone} rootZone
162
- */
163
- const testFirstZoneIncarnation = (t, rootZone) => {
164
- const subZone = secondThrows(t, () => rootZone.subZone('sub'));
165
- const singly = secondThrows(t, () =>
166
- prepareGreeterSingleton(subZone, 'a', 'Singly'),
167
- );
168
- testGreeter(t, 'Singly', singly);
169
-
170
- const makeGreeter = secondThrows(t, () => prepareGreeter(subZone));
171
- const classy = makeGreeter('Classy');
172
- testGreeter(t, 'Classy', classy);
173
-
174
- const makeGreeterKit = secondThrows(t, () => prepareGreeterKit(subZone));
175
-
176
- const { greeter: kitty, admin: kittyAdmin } = makeGreeterKit('Kitty');
177
- testGreeter(t, 'Kitty', kitty, kittyAdmin);
178
-
179
- const mappish = secondThrows(t, () => subZone.mapStore('mappish'));
180
- mappish.init('singly', singly);
181
- mappish.init('classy', classy);
182
- mappish.init('kitty', kitty);
183
- mappish.init('kittyAdmin', kittyAdmin);
184
-
185
- secondThrows(t, () => subZone.subZone('subsub'));
186
- };
187
-
188
- /**
189
- * @param {import('ava').Assertions} t
190
- * @param {Zone} rootZone
191
- */
192
- const testSecondZoneIncarnation = (t, rootZone) => {
193
- const subZone = secondThrows(t, () => rootZone.subZone('sub'));
194
- const mappish = secondThrows(t, () => subZone.mapStore('mappish'));
195
-
196
- const singlyReload = secondThrows(t, () =>
197
- prepareGreeterSingleton(subZone, 'a', 'Singly'),
198
- );
199
- const makeGreeter = secondThrows(t, () => prepareGreeter(subZone));
200
- const makeGreeterKit = secondThrows(t, () => prepareGreeterKit(subZone));
201
-
202
- const singly = mappish.get('singly');
203
- t.is(singlyReload, singly);
204
- testGreeter(t, 'Singly', singly);
205
- testGreeter(t, 'Classy', mappish.get('classy'));
206
- testGreeter(t, 'Kitty', mappish.get('kitty'), mappish.get('kittyAdmin'));
207
-
208
- const classy2 = makeGreeter('Classy2');
209
- testGreeter(t, 'Classy2', classy2);
210
-
211
- const { greeter: kitty2, admin: kittyAdmin2 } = makeGreeterKit('Kitty2');
212
- testGreeter(t, 'Kitty2', kitty2, kittyAdmin2);
213
- };
214
-
215
73
  test('heapZone', t => {
216
74
  const zone = makeHeapZone();
217
75
  testFirstZoneIncarnation(t, zone);
package/virtual.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./src/virtual.js";
2
+ //# sourceMappingURL=virtual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.d.ts","sourceRoot":"","sources":["virtual.js"],"names":[],"mappings":""}
package/src/heap.js DELETED
@@ -1,62 +0,0 @@
1
- // @ts-check
2
- // @jessie-check
3
-
4
- import { Far } from '@endo/far';
5
- import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo';
6
- import {
7
- makeScalarMapStore,
8
- makeScalarSetStore,
9
- makeScalarWeakMapStore,
10
- makeScalarWeakSetStore,
11
- } from '@agoric/vat-data';
12
-
13
- import { makeOnceKit } from './make-once.js';
14
- import { agoricVatDataKeys as keys } from './keys.js';
15
- import { isPassable } from './is-passable.js';
16
-
17
- /**
18
- * @type {import('.').Stores}
19
- */
20
- const detachedHeapStores = Far('heapStores', {
21
- detached: () => detachedHeapStores,
22
- isStorable: isPassable,
23
-
24
- setStore: makeScalarSetStore,
25
- mapStore: makeScalarMapStore,
26
- weakMapStore: makeScalarWeakMapStore,
27
- weakSetStore: makeScalarWeakSetStore,
28
- });
29
-
30
- /**
31
- * Create a heap (in-memory) zone that uses the default exo and store implementations.
32
- *
33
- * @param {string} [baseLabel]
34
- * @returns {import('.').Zone}
35
- */
36
- export const makeHeapZone = (baseLabel = 'heapZone') => {
37
- const { makeOnce, wrapProvider } = makeOnceKit(baseLabel, detachedHeapStores);
38
-
39
- /**
40
- * @param {string} label
41
- * @param {any} _options
42
- */
43
- const makeSubZone = (label, _options) =>
44
- makeHeapZone(`${baseLabel}.${label}`);
45
-
46
- return Far('heapZone', {
47
- exo: wrapProvider(makeExo, keys.exo),
48
- exoClass: wrapProvider(defineExoClass, keys.exoClass),
49
- exoClassKit: wrapProvider(defineExoClassKit, keys.exoClassKit),
50
- subZone: wrapProvider(makeSubZone),
51
-
52
- makeOnce,
53
- detached: detachedHeapStores.detached,
54
- isStorable: detachedHeapStores.isStorable,
55
-
56
- mapStore: wrapProvider(detachedHeapStores.mapStore),
57
- setStore: wrapProvider(detachedHeapStores.setStore),
58
- weakMapStore: wrapProvider(detachedHeapStores.weakMapStore),
59
- weakSetStore: wrapProvider(detachedHeapStores.weakSetStore),
60
- });
61
- };
62
- harden(makeHeapZone);
@@ -1,23 +0,0 @@
1
- import { passStyleOf } from '@endo/pass-style';
2
-
3
- /**
4
- * Is `specimen` Passable? This returns true iff `passStyleOf(specimen)`
5
- * returns a string. This returns `false` iff `passStyleOf(specimen)` throws.
6
- * Under no normal circumstance should `isPassable(specimen)` throw.
7
- *
8
- * TODO implement an isPassable that does not rely on try/catch, and
9
- * move it to @endo/pass-style.
10
- * This implementation is just a standin until then
11
- *
12
- * @param {any} specimen
13
- * @returns {specimen is Passable}
14
- */
15
- export const isPassable = specimen => {
16
- try {
17
- // In fact, it never returns undefined. It either returns a
18
- // string or throws.
19
- return passStyleOf(specimen) !== undefined;
20
- } catch (_) {
21
- return false;
22
- }
23
- };
package/src/keys.js DELETED
@@ -1,14 +0,0 @@
1
- /** @param {string} label */
2
- const kind = label => `${label}_kindHandle`;
3
- /** @param {string} label */
4
- const singleton = label => `${label}_singleton`;
5
-
6
- /** @type {Record<'exoClass' | 'exoClassKit' | 'exo' | 'store' | 'zone', (label: string) => string[]>} */
7
- export const agoricVatDataKeys = {
8
- exoClass: label => harden([kind(label)]),
9
- exoClassKit: label => harden([kind(label)]),
10
- exo: label => harden([kind(label), singleton(label)]),
11
- store: label => harden([label]),
12
- zone: label => harden([label]),
13
- };
14
- harden(agoricVatDataKeys);
package/src/make-once.js DELETED
@@ -1,86 +0,0 @@
1
- // @ts-check
2
- const { Fail } = assert;
3
-
4
- /** @param {string} label */
5
- const defaultLabelToKeys = label => harden([label]);
6
- harden(defaultLabelToKeys);
7
-
8
- /**
9
- * @param {string} debugName Only used internally for diagnostics, not available to user code
10
- * @param {import('.').Stores} stores
11
- * @param {import('@agoric/swingset-liveslots').MapStore<string, any>} [backingStore]
12
- */
13
- export const makeOnceKit = (debugName, stores, backingStore = undefined) => {
14
- // We need a detached setStore so that it isn't persisted as part of the zone.
15
- // That way, our usedKeys are only tracked for the current incarnation, which
16
- // is what we want. Using `debugName` in the label is good for diagnostics,
17
- // and since it is only for a detached store, it should not be visible to the
18
- // backing store.
19
- const usedKeys = stores.detached().setStore(`${debugName} used keys`);
20
-
21
- /**
22
- * @param {string} key
23
- */
24
- const assertOnlyOnce = key => {
25
- typeof key === 'string' || Fail`key ${key} must be a string`;
26
- !usedKeys.has(key) ||
27
- Fail`key ${key} has already been used in this zone and incarnation`;
28
-
29
- // Mark this key as used. We make no attempt to recover from invalid makers
30
- // or backingStores.
31
- usedKeys.add(key);
32
- };
33
-
34
- /**
35
- * Ensure the wrapped function is only called once per incarnation. It is
36
- * expected to update the backing store directly.
37
- *
38
- * @template {(key: string, ...rest: unknown[]) => any} T
39
- * @param {T} provider
40
- * @param {(label: string) => string[]} [labelToKeys]
41
- * @returns {T}
42
- */
43
- const wrapProvider = (provider, labelToKeys = defaultLabelToKeys) => {
44
- /** @type {(...args: Parameters<T>) => ReturnType<T>} */
45
- const wrapper = (label, ...rest) => {
46
- for (const key of labelToKeys(label)) {
47
- assertOnlyOnce(key);
48
- }
49
- return provider(label, ...rest);
50
- };
51
- return /** @type {T} */ (wrapper);
52
- };
53
-
54
- /**
55
- * The best way to understand the purpose of `makeOnce` is to first understand
56
- * what `makeOnce` does on a durable zone. Used correctly, `makeOnce` should only
57
- * be called at most once on any zone,key pair during any vat incarnation.
58
- * Given that constraint, if there is already a value bound to that
59
- * zone,key pair, it must have been left there by a previous incarnation and
60
- * `makeOnce` will simply return it. If not, then `maker(key)` is called to
61
- * determine the initial value of that slot, which will normally be preserved
62
- * by similar calls to `makeOnce` in future incarnations --- though that will be
63
- * up to them.
64
- *
65
- * Also ensures the maker returns a storable value.
66
- *
67
- * @template V
68
- * @param {string} key The string name of the Zone slot to provide.
69
- * @param {(key: string) => V} maker Called to create a fresh value to fill an empty slot.
70
- * @returns {V} The value of the key's slot.
71
- */
72
- const makeOnce = (key, maker) => {
73
- assertOnlyOnce(key);
74
- if (backingStore && backingStore.has(key)) {
75
- return backingStore.get(key);
76
- }
77
- const value = maker(key);
78
- stores.isStorable(value) ||
79
- Fail`maker return value ${value} is not storable`;
80
- backingStore && backingStore.init(key, value);
81
- return value;
82
- };
83
-
84
- return harden({ makeOnce, wrapProvider });
85
- };
86
- harden(makeOnceKit);