@agoric/base-zone 0.1.1-orchestration-dev-096c4e8.0 → 0.1.1-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.
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@agoric/base-zone",
3
- "version": "0.1.1-orchestration-dev-096c4e8.0+096c4e8",
3
+ "version": "0.1.1-other-dev-fbe72e7.0.fbe72e7",
4
4
  "description": "Allocation zone abstraction library and heap implementation",
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 tsconfig.build.json",
11
- "postpack": "git clean -f '*.d.ts*'",
10
+ "prepack": "yarn run -T tsc --build tsconfig.build.json",
11
+ "postpack": "git clean -f '*.d.*ts*' '*.tsbuildinfo'",
12
12
  "test": "ava",
13
- "test:c8": "c8 $C8_OPTIONS ava --config=ava-nesm.config.js",
13
+ "test:c8": "c8 --all ${C8_OPTIONS:-} ava",
14
14
  "test:xs": "exit 0",
15
15
  "lint-fix": "yarn lint:eslint --fix",
16
- "lint": "run-s --continue-on-error lint:*",
17
- "lint:types": "tsc",
18
- "lint:eslint": "eslint ."
16
+ "lint": "yarn run -T run-s --continue-on-error 'lint:*'",
17
+ "lint:types": "yarn run -T tsc",
18
+ "lint:eslint": "yarn run -T eslint ."
19
19
  },
20
20
  "exports": {
21
21
  ".": "./src/index.js",
@@ -27,27 +27,28 @@
27
27
  "author": "Agoric",
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@agoric/store": "0.9.3-orchestration-dev-096c4e8.0+096c4e8",
31
- "@endo/common": "^1.1.0",
32
- "@endo/exo": "^1.2.1",
33
- "@endo/far": "^1.0.4",
34
- "@endo/pass-style": "^1.2.0",
35
- "@endo/patterns": "^1.2.0"
30
+ "@agoric/store": "0.9.3-other-dev-fbe72e7.0.fbe72e7",
31
+ "@endo/common": "^1.2.13",
32
+ "@endo/errors": "^1.2.13",
33
+ "@endo/exo": "^1.5.12",
34
+ "@endo/far": "^1.1.14",
35
+ "@endo/pass-style": "^1.6.3",
36
+ "@endo/patterns": "^1.7.0"
36
37
  },
37
38
  "devDependencies": {
38
- "@endo/init": "^1.0.4",
39
- "@endo/ses-ava": "^1.1.2",
39
+ "@endo/init": "^1.1.12",
40
+ "@endo/ses-ava": "^1.3.2",
40
41
  "ava": "^5.3.0"
41
42
  },
42
43
  "publishConfig": {
43
44
  "access": "public"
44
45
  },
45
46
  "engines": {
46
- "node": ">=14.15.0"
47
+ "node": "^20.9 || ^22.11"
47
48
  },
48
49
  "ava": {
49
50
  "files": [
50
- "test/**/test-*.js"
51
+ "test/**/*.test.*"
51
52
  ],
52
53
  "require": [
53
54
  "@endo/init/debug.js"
@@ -56,7 +57,7 @@
56
57
  "workerThreads": false
57
58
  },
58
59
  "typeCoverage": {
59
- "atLeast": 89.25
60
+ "atLeast": 93.22
60
61
  },
61
- "gitHead": "096c4e8fce80e9a509b0e1a30fda11736c4570e1"
62
+ "gitHead": "fbe72e72107f9997f788674e668c660d92ec4492"
62
63
  }
package/src/exports.d.ts CHANGED
@@ -5,5 +5,4 @@
5
5
  // Types exposed from modules.
6
6
  //
7
7
 
8
- // @ts-expect-error TS1383: Only named exports may use 'export type'.
9
8
  export type * from './types.js';
package/src/heap.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export function makeHeapZone(baseLabel?: string | undefined): import('./types.js').Zone;
1
+ export function makeHeapZone(baseLabel?: string): import("./types.js").Zone;
2
2
  //# sourceMappingURL=heap.d.ts.map
package/src/heap.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"heap.d.ts","sourceRoot":"","sources":["heap.js"],"names":[],"mappings":"AAmCO,8DAFM,OAAO,YAAY,EAAE,IAAI,CA2BrC"}
1
+ {"version":3,"file":"heap.d.ts","sourceRoot":"","sources":["heap.js"],"names":[],"mappings":"AAmCO,yCAHI,MAAM,GACJ,OAAO,YAAY,EAAE,IAAI,CA4BrC"}
package/src/heap.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  // @jessie-check
3
3
 
4
- import { Far } from '@endo/far';
4
+ import { Far, isPassable } from '@endo/pass-style';
5
5
  import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo';
6
6
  import {
7
7
  makeScalarMapStore,
@@ -12,7 +12,7 @@ import {
12
12
 
13
13
  import { makeOnceKit } from './make-once.js';
14
14
  import { agoricVatDataKeys as keys } from './keys.js';
15
- import { isPassable } from './is-passable.js';
15
+ import { watchPromise } from './watch-promise.js';
16
16
 
17
17
  /**
18
18
  * @type {import('./types.js').Stores}
@@ -50,6 +50,7 @@ export const makeHeapZone = (baseLabel = 'heapZone') => {
50
50
  subZone: wrapProvider(makeSubZone),
51
51
 
52
52
  makeOnce,
53
+ watchPromise,
53
54
  detached: detachedHeapStores.detached,
54
55
  isStorable: detachedHeapStores.isStorable,
55
56
 
package/src/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from "./exports.js";
2
2
  export * from "./make-once.js";
3
3
  export * from "./keys.js";
4
4
  export * from "./is-passable.js";
5
+ export * from "./watch-promise.js";
5
6
  //# sourceMappingURL=index.d.ts.map
package/src/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // @jessie-check
2
2
 
3
+ /// <reference types="@agoric/store/exported.js" />
4
+
3
5
  // eslint-disable-next-line import/export
4
6
  export * from './exports.js';
5
7
 
@@ -7,3 +9,4 @@ export * from './exports.js';
7
9
  export * from './make-once.js';
8
10
  export * from './keys.js';
9
11
  export * from './is-passable.js';
12
+ export * from './watch-promise.js';
@@ -1,2 +1,3 @@
1
- export function isPassable(specimen: any): specimen is any;
1
+ export function isPassable(specimen: any): specimen is Passable;
2
+ import type { Passable } from '@endo/pass-style';
2
3
  //# sourceMappingURL=is-passable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"is-passable.d.ts","sourceRoot":"","sources":["is-passable.js"],"names":[],"mappings":"AAcO,qCAHI,GAAG,mBAWb"}
1
+ {"version":3,"file":"is-passable.d.ts","sourceRoot":"","sources":["is-passable.js"],"names":[],"mappings":"AAWO,qCAHI,GAAG,GACD,QAAQ,IAAI,QAAQ,CAE6B;8BARnC,kBAAkB"}
@@ -1,23 +1,12 @@
1
- import { passStyleOf } from '@endo/pass-style';
1
+ import { isPassable as realIsPassable } from '@endo/pass-style';
2
2
 
3
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
- *
4
+ * @import {Passable} from '@endo/pass-style';
5
+ */
6
+
7
+ /**
8
+ * @deprecated Import `isPassable` directly from `@endo/pass-style`
12
9
  * @param {any} specimen
13
10
  * @returns {specimen is Passable}
14
11
  */
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
- };
12
+ export const isPassable = specimen => realIsPassable(specimen);
package/src/keys.d.ts CHANGED
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @type {import('./types.js').KeyMakers}
5
5
  */
6
- export const agoricVatDataKeys: import('./types.js').KeyMakers;
6
+ export const agoricVatDataKeys: import("./types.js").KeyMakers;
7
7
  //# sourceMappingURL=keys.d.ts.map
@@ -1,5 +1,5 @@
1
- export function makeOnceKit(debugName: string, stores: import('./types.js').Stores, backingStore?: any): {
1
+ export function makeOnceKit(debugName: string, stores: import("./types.js").Stores, backingStore?: import("@agoric/swingset-liveslots").MapStore<string, any>): {
2
2
  makeOnce: <V>(key: string, maker: (key: string) => V) => V;
3
- wrapProvider: <T extends (key: string, ...rest: unknown[]) => any>(provider: T, labelToKeys?: ((label: string) => string[]) | undefined) => T;
3
+ wrapProvider: <T extends (key: string, ...rest: any[]) => any>(provider: T, labelToKeys?: (label: string) => string[]) => T;
4
4
  };
5
5
  //# sourceMappingURL=make-once.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"make-once.d.ts","sourceRoot":"","sources":["make-once.js"],"names":[],"mappings":"AAYO,uCAJI,MAAM,UACN,OAAO,YAAY,EAAE,MAAM;uBA0DzB,MAAM,eACA,MAAM;mCA/BH,MAAM,WAAW,OAAO,EAAE,KAAK,GAAG,sCAEnC,MAAM,KAAK,MAAM,EAAE;EA6CvC"}
1
+ {"version":3,"file":"make-once.d.ts","sourceRoot":"","sources":["make-once.js"],"names":[],"mappings":"AAYO,uCAJI,MAAM,UACN,OAAO,YAAY,EAAE,MAAM,iBAC3B,OAAO,4BAA4B,EAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;eAwDtD,CAAC,OACH,MAAM,SACN,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,KAChB,CAAC;mBAhCsC,CAAC,SAAxC,CAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,YACxC,CAAC,gBACD,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,KACzB,CAAC;EA4Cf"}
package/src/make-once.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @ts-check
2
- const { Fail } = assert;
2
+ import { Fail } from '@endo/errors';
3
3
 
4
4
  /** @param {string} label */
5
5
  const defaultLabelToKeys = label => harden([label]);
@@ -35,7 +35,7 @@ export const makeOnceKit = (debugName, stores, backingStore = undefined) => {
35
35
  * Ensure the wrapped function is only called once per incarnation. It is
36
36
  * expected to update the backing store directly.
37
37
  *
38
- * @template {(key: string, ...rest: unknown[]) => any} T
38
+ * @template {(key: string, ...rest: any[]) => any} T
39
39
  * @param {T} provider
40
40
  * @param {(label: string) => string[]} [labelToKeys]
41
41
  * @returns {T}
@@ -0,0 +1,31 @@
1
+ export function wrapperMethods(wrapperKindName: string, uMethodNames: PropertyKey[], extraMethods?: Record<PropertyKey, (...args: any[]) => any>): {
2
+ [x: string]: ((...args: any[]) => any) | ((...args: any[]) => any);
3
+ };
4
+ export function prepareAttenuatorMaker<U = any>(zone: import("@agoric/base-zone").Zone, uKindName: string, uMethodNames: (keyof U)[], options?: AttenuatorOptions<U>): MakeAttenuator;
5
+ export function attenuateOne<U extends unknown>(underlying: U, uMethodNames: (keyof U)[], options?: AttenuatorOptions<U>): Partial<U>;
6
+ export type MakeAttenuator<U = any> = (underlying: U) => Partial<U>;
7
+ export type AttenuatorThis<U = any> = {
8
+ self: Partial<U>;
9
+ state: {
10
+ underlying: U;
11
+ };
12
+ };
13
+ export type AttenuatorOptions<U = any> = {
14
+ /**
15
+ * The `interfaceName` of the underlying interface guard.
16
+ * Defaults to the `uKindName`.
17
+ */
18
+ uInterfaceName?: string | undefined;
19
+ /**
20
+ * For guarding the `extraMethods`, if you include them below. These appear
21
+ * only on the synthesized interface guard for the attenuator, and
22
+ * do not necessarily correspond to any method of the underlying.
23
+ */
24
+ extraMethodGuards?: Record<PropertyKey, import("@endo/patterns").MethodGuard> | undefined;
25
+ /**
26
+ * Extra methods adding behavior only to the attenuator, and
27
+ * do not necessarily correspond to any methods of the underlying.
28
+ */
29
+ extraMethods?: Record<PropertyKey, (this: AttenuatorThis<U>, ...args: any[]) => any> | undefined;
30
+ };
31
+ //# sourceMappingURL=prepare-attenuator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-attenuator.d.ts","sourceRoot":"","sources":["prepare-attenuator.js"],"names":[],"mappings":"AA2BO,gDAJI,MAAM,gBACN,WAAW,EAAE,iBACb,MAAM,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;4BAAd,GAAG,EAAE,KAAK,GAAG;EA6BlD;AAoDG,uCAVO,CAAC,cACJ,OAAO,mBAAmB,EAAE,IAAI,aAChC,MAAM,gBAEN,CAAC,MAAM,CAAC,CAAC,EAAE,YAGX,iBAAiB,CAAC,CAAC,CAAC,GAClB,cAAc,CA8B1B;AAqBM,6BANY,CAAC,8BACT,CAAC,gBACD,CAAC,MAAM,CAAC,CAAC,EAAE,YACX,iBAAiB,CAAC,CAAC,CAAC,GAClB,OAAO,CAAC,CAAC,CAAC,CAetB;2BA9Ga,CAAC,uBAEJ,CAAC,KACC,OAAO,CAAC,CAAC,CAAC;2BAIT,CAAC;UAED,OAAO,CAAC,CAAC,CAAC;WACV;QAAE,UAAU,EAAE,CAAC,CAAA;KAAE;;8BAIjB,CAAC;;;;;;;;;;;;;;;;8CAcH,cAAc,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,KAAK,GAAG"}
@@ -0,0 +1,170 @@
1
+ import { Fail, q } from '@endo/errors';
2
+ import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
3
+ import { M } from '@endo/patterns';
4
+ import { makeHeapZone } from './heap.js';
5
+
6
+ // This attenuator implementation is just a simplification of the
7
+ // revocable kit implementation in prepare-revocable.js. The revocable kit
8
+ // provides both attenuation and revocation, since we can have both for the
9
+ // price of just one level of indirection. But if you don't need revocation,
10
+ // the revocable kit has more API complexity than you need.
11
+ //
12
+ // We could have built `prepareAttenuatorMaker` as a trivial wrapper around
13
+ // `prepareRevocableMakerKit`. But then we'd have the weird artifact that the
14
+ // `extraMethods` would see a `{ state, facets: { revocable, revoker }}` context
15
+ // rather than a `{ state, self }` context. So instead, we copied and edited it
16
+ // down. Please co-maintain these two modules.
17
+
18
+ // Because the attenuator just uses an exo class rather than a class kit,
19
+ // it cannot support the privilege separation of a distinct revoker facet.
20
+ // But it can still support `selfRevoke` as a separate `extraMethod`, as shown
21
+ // in a testcase at `prepare-attenuator.test.js`
22
+
23
+ /**
24
+ * @param {string} wrapperKindName
25
+ * @param {PropertyKey[]} uMethodNames
26
+ * @param {Record<PropertyKey, (...args: any[]) => any>} [extraMethods]
27
+ */
28
+ export const wrapperMethods = (
29
+ wrapperKindName,
30
+ uMethodNames,
31
+ extraMethods = {},
32
+ ) =>
33
+ harden({
34
+ ...fromUniqueEntries(
35
+ uMethodNames.map(name => [
36
+ name,
37
+ {
38
+ // Use concise method syntax for exo methods
39
+ [name](...args) {
40
+ // @ts-expect-error normal exo-this typing confusion
41
+ const { underlying } = this.state;
42
+
43
+ // Because attenuators still support someone adding `selfRevoke`
44
+ // as an `extraMethod`, this test is still useful. See the
45
+ // testcase in `prepare-attenuator.test.js`.
46
+ underlying !== undefined || Fail`${q(wrapperKindName)} revoked`;
47
+
48
+ return underlying[name](...args);
49
+ },
50
+ // @ts-expect-error using possible symbol as index type
51
+ }[name],
52
+ ]),
53
+ ),
54
+ ...extraMethods,
55
+ });
56
+ harden(wrapperMethods);
57
+
58
+ /**
59
+ * @template [U=any]
60
+ * @callback MakeAttenuator
61
+ * @param {U} underlying
62
+ * @returns {Partial<U>}
63
+ */
64
+
65
+ /**
66
+ * @template [U=any]
67
+ * @typedef {object} AttenuatorThis
68
+ * @property {Partial<U>} self
69
+ * @property {{ underlying: U }} state
70
+ */
71
+
72
+ /**
73
+ * @template [U=any]
74
+ * @typedef {object} AttenuatorOptions
75
+ * @property {string} [uInterfaceName]
76
+ * The `interfaceName` of the underlying interface guard.
77
+ * Defaults to the `uKindName`.
78
+ * @property {Record<
79
+ * PropertyKey,
80
+ * import('@endo/patterns').MethodGuard
81
+ * >} [extraMethodGuards]
82
+ * For guarding the `extraMethods`, if you include them below. These appear
83
+ * only on the synthesized interface guard for the attenuator, and
84
+ * do not necessarily correspond to any method of the underlying.
85
+ * @property {Record<
86
+ * PropertyKey,
87
+ * (this: AttenuatorThis<U>, ...args: any[]) => any
88
+ * >} [extraMethods]
89
+ * Extra methods adding behavior only to the attenuator, and
90
+ * do not necessarily correspond to any methods of the underlying.
91
+ */
92
+
93
+ /**
94
+ * Make an exo class for wrapping an underlying exo class,
95
+ * where the wrapper is an attenuator of the underlying.
96
+ *
97
+ * @template [U=any]
98
+ * @param {import('@agoric/base-zone').Zone} zone
99
+ * @param {string} uKindName
100
+ * The `kindName` of the underlying exo class
101
+ * @param {(keyof U)[]} uMethodNames
102
+ * The method names of the underlying exo class that should be represented
103
+ * by transparently-forwarding methods of the attenuator.
104
+ * @param {AttenuatorOptions<U>} [options]
105
+ * @returns {MakeAttenuator}
106
+ */
107
+ export const prepareAttenuatorMaker = (
108
+ zone,
109
+ uKindName,
110
+ uMethodNames,
111
+ options = {},
112
+ ) => {
113
+ const {
114
+ uInterfaceName = uKindName,
115
+ extraMethodGuards = {},
116
+ extraMethods = {},
117
+ } = options;
118
+ const AttenuatorI = M.interface(
119
+ `${uInterfaceName}_attenuator`,
120
+ extraMethodGuards,
121
+ { defaultGuards: 'raw' },
122
+ );
123
+
124
+ const attenuatorKindName = `${uKindName}_attenuator`;
125
+
126
+ return zone.exoClass(
127
+ attenuatorKindName,
128
+ AttenuatorI,
129
+ underlying => ({ underlying }),
130
+ wrapperMethods(attenuatorKindName, uMethodNames, extraMethods),
131
+ {
132
+ stateShape: { underlying: M.opt(M.remotable('underlying')) },
133
+ },
134
+ );
135
+ };
136
+ harden(prepareAttenuatorMaker);
137
+
138
+ // cf. https://endojs.github.io/endo/functions/_endo_pass_style.Remotable.html
139
+ const RemotablePrefixRE = /^(Alleged: |DebugName: )/;
140
+
141
+ /**
142
+ * A convenience above `prepareAttenuatorMaker` for doing a singleton
143
+ * ephemeral attenuator, i.e., a new attenuator instance (and hidden class)
144
+ * that is allocated in the heap zone, and therefore ephemeral. The underlying
145
+ * can be durable or not, with no conflict with the attenuator being
146
+ * ephemeral. The price of this convenience is the allocation of the hidden
147
+ * class and wrapper methods per `attenuateOne` call, i.e., per attenuator
148
+ * instance.
149
+ *
150
+ * @template {any} U
151
+ * @param {U} underlying
152
+ * @param {(keyof U)[]} uMethodNames
153
+ * @param {AttenuatorOptions<U>} [options]
154
+ * @returns {Partial<U>}
155
+ */
156
+ export const attenuateOne = (underlying, uMethodNames, options = undefined) => {
157
+ const heapZone = makeHeapZone();
158
+ const uKindName = (underlying[Symbol.toStringTag] || 'Underlying').replace(
159
+ RemotablePrefixRE,
160
+ '',
161
+ );
162
+ const makeAttenuator = prepareAttenuatorMaker(
163
+ heapZone,
164
+ uKindName,
165
+ uMethodNames,
166
+ options,
167
+ );
168
+ return makeAttenuator(underlying);
169
+ };
170
+ harden(attenuateOne);
@@ -1,13 +1,23 @@
1
- export function prepareRevocableKit<U extends unknown = any>(zone: import('@agoric/base-zone').Zone, uKindName: string, uMethodNames: (string | symbol)[], options?: RevocableKitOptions<any> | undefined): (underlying: U) => RevocableKit<U>;
2
- export type Revoker = {
1
+ export function prepareRevocableMakerKit<U = any>(zone: import("@agoric/base-zone").Zone, uKindName: string, uMethodNames: PropertyKey[], options?: RevocableKitOptions<U>): RevocableMakerKit<U>;
2
+ export type MakeRevocable<U = any> = (underlying: U) => Partial<U>;
3
+ export type MakeRevocableKit<U = any> = (underlying: U) => RevocableKit<U>;
4
+ export type RevocableMakerKit<U = any> = {
5
+ revoke: (revocable: U) => boolean;
6
+ /**
7
+ * Forwards to the underlying exo object, until revoked
8
+ */
9
+ makeRevocable: MakeRevocable<U>;
10
+ makeRevocableKit: MakeRevocableKit<U>;
11
+ };
12
+ export type RevokerFacet = {
3
13
  revoke: () => boolean;
4
14
  };
5
- export type RevocableKit<U extends unknown = any> = {
6
- revoker: Revoker;
15
+ export type RevocableKit<U = any> = {
16
+ revoker: RevokerFacet;
7
17
  /**
8
18
  * Forwards to the underlying exo object, until revoked
9
19
  */
10
- revocable: U;
20
+ revocable: Partial<U>;
11
21
  };
12
22
  export type RevocableKitThis<U = any> = {
13
23
  facets: RevocableKit<U>;
@@ -15,7 +25,7 @@ export type RevocableKitThis<U = any> = {
15
25
  underlying: U;
16
26
  };
17
27
  };
18
- export type RevocableKitOptions<U extends unknown = any> = {
28
+ export type RevocableKitOptions<U = any> = {
19
29
  /**
20
30
  * The `interfaceName` of the underlying interface guard.
21
31
  * Defaults to the `uKindName`.
@@ -26,11 +36,11 @@ export type RevocableKitOptions<U extends unknown = any> = {
26
36
  * only on the synthesized interface guard for the revocable caretaker, and
27
37
  * do not necessarily correspond to any method of the underlying.
28
38
  */
29
- extraMethodGuards?: Record<string | symbol, import("@endo/patterns").MethodGuard> | undefined;
39
+ extraMethodGuards?: Record<PropertyKey, import("@endo/patterns").MethodGuard> | undefined;
30
40
  /**
31
41
  * Extra methods adding behavior only to the revocable caretaker, and
32
42
  * do not necessarily correspond to any methods of the underlying.
33
43
  */
34
- extraMethods?: Record<string | symbol, (this: RevocableKitThis<U>, ...args: any[]) => any> | undefined;
44
+ extraMethods?: Record<PropertyKey, (this: RevocableKitThis<U>, ...args: any[]) => any> | undefined;
35
45
  };
36
46
  //# sourceMappingURL=prepare-revocable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare-revocable.d.ts","sourceRoot":"","sources":["prepare-revocable.js"],"names":[],"mappings":"AA6DO,mEATI,OAAO,mBAAmB,EAAE,IAAI,aAChC,MAAM,gBAEN,CAAC,MAAM,GAAC,MAAM,CAAC,EAAE,sFAiF3B;;YAjIa,MAAM,OAAO;;;aAMb,OAAO;;;;eACP,CAAC;;;YAOD,aAAa,CAAC,CAAC;WACf;QAAE,UAAU,EAAE,CAAC,CAAA;KAAE;;;;;;;;;;;;;;;;;;kDAkBnB,iBAAiB,CAAC,CAAC,WAAW,GAAG,EAAE,KAAK,GAAG"}
1
+ {"version":3,"file":"prepare-revocable.d.ts","sourceRoot":"","sources":["prepare-revocable.js"],"names":[],"mappings":"AAyFO,yCAVO,CAAC,cACJ,OAAO,mBAAmB,EAAE,IAAI,aAChC,MAAM,gBAEN,WAAW,EAAE,YAGb,mBAAmB,CAAC,CAAC,CAAC,GACpB,iBAAiB,CAAC,CAAC,CAAC,CA4EhC;0BAvJa,CAAC,uBAEJ,CAAC,KACC,OAAO,CAAC,CAAC,CAAC;6BAIT,CAAC,uBAEJ,CAAC,KACC,YAAY,CAAC,CAAC,CAAC;8BAId,CAAC;YAED,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO;;;;mBACzB,aAAa,CAAC,CAAC,CAAC;sBAEhB,gBAAgB,CAAC,CAAC,CAAC;;;YAKnB,MAAM,OAAO;;yBAIb,CAAC;aAED,YAAY;;;;eACZ,OAAO,CAAC,CAAC,CAAC;;6BAKV,CAAC;YAED,YAAY,CAAC,CAAC,CAAC;WACf;QAAE,UAAU,EAAE,CAAC,CAAA;KAAE;;gCAIjB,CAAC;;;;;;;;;;;;;;;;8CAcH,gBAAgB,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,KAAK,GAAG"}
@@ -1,18 +1,47 @@
1
1
  import { M } from '@endo/patterns';
2
- import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
2
+ import { wrapperMethods } from './prepare-attenuator.js';
3
3
 
4
- const { Fail, quote: q } = assert;
4
+ /** @import {Amplify} from '@endo/exo'; */
5
+
6
+ // This revocable kit implementation provides for both attenuation and
7
+ // revocation, since both can be provided at the cost of one level of
8
+ // indirection. But if you just need attenuation without revocation, better to
9
+ // use the attenuator implementation in prepare-attenuator.js.
10
+ // Please co-maintain these two modules.
11
+
12
+ /**
13
+ * @template [U=any]
14
+ * @callback MakeRevocable
15
+ * @param {U} underlying
16
+ * @returns {Partial<U>}
17
+ */
18
+
19
+ /**
20
+ * @template [U=any]
21
+ * @callback MakeRevocableKit
22
+ * @param {U} underlying
23
+ * @returns {RevocableKit<U>}
24
+ */
25
+
26
+ /**
27
+ * @template [U=any]
28
+ * @typedef {object} RevocableMakerKit
29
+ * @property {(revocable: U) => boolean} revoke
30
+ * @property {MakeRevocable<U>} makeRevocable
31
+ * Forwards to the underlying exo object, until revoked
32
+ * @property {MakeRevocableKit<U>} makeRevocableKit
33
+ */
5
34
 
6
35
  /**
7
- * @typedef {object} Revoker
36
+ * @typedef {object} RevokerFacet
8
37
  * @property {() => boolean} revoke
9
38
  */
10
39
 
11
40
  /**
12
- * @template {any} [U=any]
41
+ * @template [U=any]
13
42
  * @typedef {object} RevocableKit
14
- * @property {Revoker} revoker
15
- * @property {U} revocable
43
+ * @property {RevokerFacet} revoker
44
+ * @property {Partial<U>} revocable
16
45
  * Forwards to the underlying exo object, until revoked
17
46
  */
18
47
 
@@ -24,20 +53,20 @@ const { Fail, quote: q } = assert;
24
53
  */
25
54
 
26
55
  /**
27
- * @template {any} [U=any]
56
+ * @template [U=any]
28
57
  * @typedef {object} RevocableKitOptions
29
58
  * @property {string} [uInterfaceName]
30
59
  * The `interfaceName` of the underlying interface guard.
31
60
  * Defaults to the `uKindName`.
32
61
  * @property {Record<
33
- * string|symbol,
62
+ * PropertyKey,
34
63
  * import('@endo/patterns').MethodGuard
35
64
  * >} [extraMethodGuards]
36
65
  * For guarding the `extraMethods`, if you include them below. These appear
37
66
  * only on the synthesized interface guard for the revocable caretaker, and
38
67
  * do not necessarily correspond to any method of the underlying.
39
68
  * @property {Record<
40
- * string|symbol,
69
+ * PropertyKey,
41
70
  * (this: RevocableKitThis<U>, ...args: any[]) => any
42
71
  * >} [extraMethods]
43
72
  * Extra methods adding behavior only to the revocable caretaker, and
@@ -48,18 +77,17 @@ const { Fail, quote: q } = assert;
48
77
  * Make an exo class kit for wrapping an underlying exo class,
49
78
  * where the wrapper is a revocable forwarder.
50
79
  *
51
- * @deprecated Change to `prepareRevocableMakerKit` once #8977 happens
52
- * @template {any} [U=any]
80
+ * @template [U=any]
53
81
  * @param {import('@agoric/base-zone').Zone} zone
54
82
  * @param {string} uKindName
55
83
  * The `kindName` of the underlying exo class
56
- * @param {(string|symbol)[]} uMethodNames
84
+ * @param {PropertyKey[]} uMethodNames
57
85
  * The method names of the underlying exo class that should be represented
58
86
  * by transparently-forwarding methods of the revocable caretaker.
59
- * @param {RevocableKitOptions} [options]
60
- * @returns {(underlying: U) => RevocableKit<U>}
87
+ * @param {RevocableKitOptions<U>} [options]
88
+ * @returns {RevocableMakerKit<U>}
61
89
  */
62
- export const prepareRevocableKit = (
90
+ export const prepareRevocableMakerKit = (
63
91
  zone,
64
92
  uKindName,
65
93
  uMethodNames,
@@ -67,32 +95,27 @@ export const prepareRevocableKit = (
67
95
  ) => {
68
96
  const {
69
97
  uInterfaceName = uKindName,
70
- extraMethodGuards = undefined,
71
- extraMethods = undefined,
98
+ extraMethodGuards = {},
99
+ extraMethods = {},
72
100
  } = options;
73
101
  const RevocableIKit = harden({
74
102
  revoker: M.interface(`${uInterfaceName}_revoker`, {
75
103
  revoke: M.call().returns(M.boolean()),
76
104
  }),
77
- revocable: M.interface(
78
- `${uInterfaceName}_revocable`,
79
- {
80
- ...extraMethodGuards,
81
- },
82
- {
83
- defaultGuards: 'raw',
84
- },
85
- ),
105
+ revocable: M.interface(`${uInterfaceName}_revocable`, extraMethodGuards, {
106
+ defaultGuards: 'raw',
107
+ }),
86
108
  });
87
109
 
88
110
  const revocableKindName = `${uKindName}_caretaker`;
89
111
 
112
+ /** @type {Amplify<any>} */
113
+ let amplifier;
114
+
90
115
  const makeRevocableKit = zone.exoClassKit(
91
116
  revocableKindName,
92
117
  RevocableIKit,
93
- underlying => ({
94
- underlying,
95
- }),
118
+ underlying => ({ underlying }),
96
119
  {
97
120
  revoker: {
98
121
  revoke() {
@@ -104,35 +127,39 @@ export const prepareRevocableKit = (
104
127
  return true;
105
128
  },
106
129
  },
107
- revocable: {
108
- ...fromUniqueEntries(
109
- uMethodNames.map(name => [
110
- name,
111
- {
112
- // Use concise method syntax for exo methods
113
- [name](...args) {
114
- // @ts-expect-error normal exo-this typing confusion
115
- const { underlying } = this.state;
116
- underlying !== undefined ||
117
- Fail`${q(revocableKindName)} revoked`;
118
- return underlying[name](...args);
119
- },
120
- // @ts-expect-error using possible symbol as index type
121
- }[name],
122
- ]),
123
- ),
124
- ...extraMethods,
125
- },
130
+ revocable: wrapperMethods(revocableKindName, uMethodNames, extraMethods),
126
131
  },
127
132
  {
128
- stateShape: {
129
- underlying: M.opt(M.remotable('underlying')),
133
+ stateShape: { underlying: M.opt(M.remotable('underlying')) },
134
+ receiveAmplifier: amp => {
135
+ amplifier = amp;
130
136
  },
131
137
  },
132
138
  );
133
139
 
134
- // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
135
- // @ts-ignore parameter confusion
136
- return makeRevocableKit;
140
+ /**
141
+ * @type {MakeRevocable}
142
+ */
143
+ const makeRevocable = underlying => makeRevocableKit(underlying).revocable;
144
+
145
+ /**
146
+ * @param {U} revocable
147
+ * @returns {boolean}
148
+ */
149
+ const revoke = revocable => {
150
+ /** @type {RevocableKit<U>} */
151
+ const facets = amplifier(revocable);
152
+ if (facets === undefined) {
153
+ return false;
154
+ }
155
+ return facets.revoker.revoke();
156
+ };
157
+
158
+ return harden({
159
+ revoke,
160
+ makeRevocable,
161
+ /** @type {MakeRevocableKit} */
162
+ makeRevocableKit,
163
+ });
137
164
  };
138
- harden(prepareRevocableKit);
165
+ harden(prepareRevocableMakerKit);
package/src/types.d.ts CHANGED
@@ -1,11 +1,5 @@
1
- export type KeyCategories = 'exoClass' | 'exoClassKit' | 'exo' | 'store' | 'zone';
2
- export type KeyMakers = {
3
- exoClass: (label: string) => string[];
4
- exoClassKit: (label: string) => string[];
5
- exo: (label: string) => string[];
6
- store: (label: string) => string[];
7
- zone: (label: string) => string[];
8
- };
1
+ export type KeyCategories = "exoClass" | "exoClassKit" | "exo" | "store" | "zone";
2
+ export type KeyMakers = Record<KeyCategories, (label: string) => string[]>;
9
3
  /**
10
4
  * A bag of methods for creating defensible objects and
11
5
  * collections with the same allocation semantics (ephemeral, persistent, etc)
@@ -32,6 +26,10 @@ export type ExoZone = {
32
26
  * create a new Zone that can be passed to untrusted consumers without exposing the storage of the parent zone
33
27
  */
34
28
  subZone: (label: string, options?: StoreOptions) => Zone;
29
+ /**
30
+ * register a promise watcher created by this zone
31
+ */
32
+ watchPromise: typeof watchPromise;
35
33
  };
36
34
  export type Stores = {
37
35
  /**
@@ -49,17 +47,23 @@ export type Stores = {
49
47
  /**
50
48
  * provide a Set-like store named `label` in the zone
51
49
  */
52
- setStore: <K_1>(label: string, options?: StoreOptions) => SetStore<K_1>;
50
+ setStore: <K>(label: string, options?: StoreOptions) => SetStore<K>;
53
51
  /**
54
52
  * provide a WeakMap-like store named `label` in the zone
55
53
  */
56
- weakMapStore: <K_2, V_1>(label: string, options?: StoreOptions) => WeakMapStore<K_2, V_1>;
54
+ weakMapStore: <K, V>(label: string, options?: StoreOptions) => WeakMapStore<K, V>;
57
55
  /**
58
56
  * provide a WeakSet-like store named `label` in the zone
59
57
  */
60
- weakSetStore: <K_3>(label: string, options?: StoreOptions) => WeakSetStore<K_3>;
58
+ weakSetStore: <K>(label: string, options?: StoreOptions) => WeakSetStore<K>;
61
59
  };
62
60
  import { makeExo } from '@endo/exo';
63
61
  import { defineExoClass } from '@endo/exo';
64
62
  import { defineExoClassKit } from '@endo/exo';
63
+ import type { StoreOptions } from '@agoric/store';
64
+ import { watchPromise } from './watch-promise.js';
65
+ import type { MapStore } from '@agoric/store';
66
+ import type { SetStore } from '@agoric/store';
67
+ import type { WeakMapStore } from '@agoric/store';
68
+ import type { WeakSetStore } from '@agoric/store';
65
69
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"4BAGc,UAAU,GAAG,aAAa,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM;;sBACvB,MAAM,KAAK,MAAM,EAAE;yBAAnB,MAAM,KAAK,MAAM,EAAE;iBAAnB,MAAM,KAAK,MAAM,EAAE;mBAAnB,MAAM,KAAK,MAAM,EAAE;kBAAnB,MAAM,KAAK,MAAM,EAAE;;;;;;mBAGlD,OAAO,GAAG,MAAM;;;;;SAMf,cAAc;;;;cACd,qBAAqB;;;;iBACrB,wBAAwB;;;;uBACf,MAAM,eAAe,MAAM;;;;qBAC5B,MAAM,YAAY,YAAY,KAAK,IAAI;;;;;;cAK/C,MAAM,MAAM;;;;2BACD,OAAO,KAAK,OAAO;;;;4BACjB,MAAM,YAAY,YAAY;;;;2BAChC,MAAM,YAAY,YAAY;;;;oCAE3C,MAAM,YAAY,YAAY;;;;+BAG9B,MAAM,YAAY,YAAY;;wBA7BiB,WAAW;+BAAX,WAAW;kCAAX,WAAW"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"4BAcc,UAAU,GAAG,aAAa,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM;wBACrD,MAAM,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;;;;;mBAGnD,OAAO,GAAG,MAAM;;;;;SAMf,OAAO,OAAO;;;;cACd,OAAO,cAAc;;;;iBACrB,OAAO,iBAAiB;;;;cACxB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,KAAK,CAAC;;;;aAChD,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI;;;;kBAC/C,OAAO,YAAY;;;;;;cAKnB,MAAM,MAAM;;;;gBACZ,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO;;;;cAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,SAAS,CAAC,EAAE,CAAC,CAAC;;;;cAC/D,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,SAAS,CAAC,CAAC;;;;kBACzD,CAAC,CAAC,EAAE,CAAC,EACd,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,aAAa,CAAC,EAAE,CAAC,CAAC;;;;kBAEnD,CAAC,CAAC,EACX,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,aAAa,CAAC,CAAC;;wBAzCH,WAAW;+BAAX,WAAW;kCAAX,WAAW;kCAQS,eAAe;6BANjE,oBAAoB;8BAM8B,eAAe;8BAAf,eAAe;kCAAf,eAAe;kCAAf,eAAe"}
package/src/types.js CHANGED
@@ -1,5 +1,16 @@
1
1
  // eslint-disable-next-line no-unused-vars
2
2
  import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo';
3
+ // eslint-disable-next-line no-unused-vars
4
+ import { watchPromise } from './watch-promise.js';
5
+
6
+ // Ensure this is a module.
7
+ export {};
8
+
9
+ /**
10
+ * @import {MapStore, SetStore, StoreOptions, WeakMapStore, WeakSetStore} from '@agoric/store';
11
+ * @import {Key} from '@endo/patterns';
12
+ * @import {Passable} from '@endo/pass-style';
13
+ */
3
14
 
4
15
  /** @typedef {'exoClass' | 'exoClassKit' | 'exo' | 'store' | 'zone'} KeyCategories */
5
16
  /** @typedef {Record<KeyCategories, (label: string) => string[]>} KeyMakers */
@@ -16,15 +27,16 @@ import { makeExo, defineExoClass, defineExoClassKit } from '@endo/exo';
16
27
  * @property {typeof defineExoClassKit} exoClassKit create a "kit" maker function that can be used to create a record of exo-objects sharing the same state
17
28
  * @property {<T>(key: string, maker: (key: string) => T) => T} makeOnce create or retrieve a singleton object bound to this zone
18
29
  * @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
30
+ * @property {typeof watchPromise} watchPromise register a promise watcher created by this zone
19
31
  */
20
32
 
21
33
  /**
22
34
  * @typedef {object} Stores
23
35
  * @property {() => Stores} detached obtain store providers which are detached (the stores are anonymous rather than bound to `label` in the zone)
24
36
  * @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
25
- * @property {<K,V>(label: string, options?: StoreOptions) => MapStore<K, V>} mapStore provide a Map-like store named `label` in the zone
37
+ * @property {<K, V>(label: string, options?: StoreOptions) => MapStore<K, V>} mapStore provide a Map-like store named `label` in the zone
26
38
  * @property {<K>(label: string, options?: StoreOptions) => SetStore<K>} setStore provide a Set-like store named `label` in the zone
27
- * @property {<K,V>(
39
+ * @property {<K, V>(
28
40
  * label: string, options?: StoreOptions) => WeakMapStore<K, V>
29
41
  * } weakMapStore provide a WeakMap-like store named `label` in the zone
30
42
  * @property {<K>(
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A PromiseWatcher method guard callable with or more arguments, returning void.
3
+ */
4
+ export const PromiseWatcherHandler: import("@endo/patterns").MethodGuard;
5
+ /**
6
+ * A PromiseWatcher interface that has both onFulfilled and onRejected handlers.
7
+ */
8
+ export const PromiseWatcherI: import("@endo/patterns").InterfaceGuard<{
9
+ onFulfilled: import("@endo/patterns").MethodGuard;
10
+ onRejected: import("@endo/patterns").MethodGuard;
11
+ }>;
12
+ /**
13
+ * A PromiseWatcher interface that has only an onFulfilled handler.
14
+ */
15
+ export const PromiseWatcherFulfilledI: import("@endo/patterns").InterfaceGuard<{
16
+ onFulfilled: import("@endo/patterns").MethodGuard;
17
+ }>;
18
+ /**
19
+ * A PromiseWatcher interface that has only an onRejected handler.
20
+ */
21
+ export const PromiseWatcherRejectedI: import("@endo/patterns").InterfaceGuard<{
22
+ onRejected: import("@endo/patterns").MethodGuard;
23
+ }>;
24
+ export function watchPromise(p: Promise<any>, watcher: PromiseWatcher, ...watcherArgs: unknown[]): void;
25
+ export type PromiseWatcher = {
26
+ onFulfilled?: ((fulfilment: unknown, ...args: unknown[]) => void) | undefined;
27
+ onRejected?: ((reason: unknown, ...args: unknown[]) => void) | undefined;
28
+ };
29
+ //# sourceMappingURL=watch-promise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-promise.d.ts","sourceRoot":"","sources":["watch-promise.js"],"names":[],"mappings":"AAOA;;GAEG;AACH,yEAA6E;AAE7E;;GAEG;AACH;;;GAGG;AAEH;;GAEG;AACH;;GAEG;AAEH;;GAEG;AACH;;GAEG;AAuCI,gCALI,OAAO,CAAC,GAAG,CAAC,WACZ,cAAc,kBACX,OAAO,EAAA,GACR,IAAI,CAUhB;;gCA3C0B,OAAO,WAAW,OAAO,EAAE,KAAK,IAAI;2BACxC,OAAO,WAAW,OAAO,EAAE,KAAK,IAAI"}
@@ -0,0 +1,81 @@
1
+ // @ts-check
2
+ import { Fail } from '@endo/errors';
3
+ import { M } from '@endo/patterns';
4
+ import { E } from '@endo/far';
5
+
6
+ const { apply } = Reflect;
7
+
8
+ /**
9
+ * A PromiseWatcher method guard callable with or more arguments, returning void.
10
+ */
11
+ export const PromiseWatcherHandler = M.call(M.raw()).rest(M.raw()).returns();
12
+
13
+ /**
14
+ * A PromiseWatcher interface that has both onFulfilled and onRejected handlers.
15
+ */
16
+ export const PromiseWatcherI = M.interface('PromiseWatcher', {
17
+ onFulfilled: PromiseWatcherHandler,
18
+ onRejected: PromiseWatcherHandler,
19
+ });
20
+
21
+ /**
22
+ * A PromiseWatcher interface that has only an onFulfilled handler.
23
+ */
24
+ export const PromiseWatcherFulfilledI = M.interface('PromiseWatcherFulfilled', {
25
+ onFulfilled: PromiseWatcherHandler,
26
+ });
27
+
28
+ /**
29
+ * A PromiseWatcher interface that has only an onRejected handler.
30
+ */
31
+ export const PromiseWatcherRejectedI = M.interface('PromiseWatcherRejected', {
32
+ onRejected: PromiseWatcherHandler,
33
+ });
34
+
35
+ /**
36
+ * @typedef {object} PromiseWatcher
37
+ * @property {(fulfilment: unknown, ...args: unknown[]) => void} [onFulfilled]
38
+ * @property {(reason: unknown, ...args: unknown[]) => void} [onRejected]
39
+ */
40
+
41
+ /**
42
+ * Adapt a promise watcher method to E.when.
43
+ * @param {Record<PropertyKey, (...args: unknown[]) => unknown>} that
44
+ * @param {PropertyKey} prop
45
+ * @param {unknown[]} postArgs
46
+ */
47
+ const callMeMaybe = (that, prop, postArgs) => {
48
+ const fn = that[prop];
49
+ if (!fn) {
50
+ return undefined;
51
+ }
52
+ assert.typeof(fn, 'function');
53
+ /**
54
+ * @param {unknown} arg value or reason
55
+ */
56
+ const wrapped = arg => {
57
+ // Don't return a value, to prevent E.when from subscribing to a resulting
58
+ // promise.
59
+ apply(fn, that, [arg, ...postArgs]);
60
+ };
61
+ return wrapped;
62
+ };
63
+
64
+ /**
65
+ * Shim the promise watcher behaviour when VatData.watchPromise is not available.
66
+ *
67
+ * @param {Promise<any>} p
68
+ * @param {PromiseWatcher} watcher
69
+ * @param {...unknown} watcherArgs
70
+ * @returns {void}
71
+ */
72
+ export const watchPromise = (p, watcher, ...watcherArgs) => {
73
+ Promise.resolve(p) === p || Fail`watchPromise only watches promises`;
74
+ const onFulfilled = callMeMaybe(watcher, 'onFulfilled', watcherArgs);
75
+ const onRejected = callMeMaybe(watcher, 'onRejected', watcherArgs);
76
+ onFulfilled ||
77
+ onRejected ||
78
+ Fail`promise watcher must implement at least one handler method`;
79
+ void E.when(p, onFulfilled, onRejected);
80
+ };
81
+ harden(watchPromise);
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line import/order
2
1
  import { test } from './prepare-test-env-ava.js';
3
2
 
4
3
  import { makeHeapZone } from '../heap.js';
@@ -0,0 +1,110 @@
1
+ // Modeled on test-heap-classes.js
2
+
3
+ import { test } from './prepare-test-env-ava.js';
4
+
5
+ // eslint-disable-next-line import/order
6
+ import { M } from '@endo/patterns';
7
+ import { makeHeapZone } from '../src/heap.js';
8
+ import { prepareAttenuatorMaker } from '../src/prepare-attenuator.js';
9
+
10
+ const CounterI = M.interface('Counter', {
11
+ incr: M.call()
12
+ // TODO M.number() should not be needed to get a better error message
13
+ .optional(M.and(M.number(), M.gte(0)))
14
+ .returns(M.number()),
15
+ decr: M.call()
16
+ // TODO M.number() should not be needed to get a better error message
17
+ .optional(M.and(M.number(), M.gte(0)))
18
+ .returns(M.number()),
19
+ });
20
+
21
+ test('test attenuate defineVirtualExoClass', t => {
22
+ const zone = makeHeapZone('rootZone');
23
+
24
+ const makeUnderlyingCounter = zone.exoClass(
25
+ 'Counter',
26
+ CounterI,
27
+ /** @param {number} [x] */
28
+ (x = 0) => ({ x }),
29
+ {
30
+ incr(y = 1) {
31
+ const { state } = this;
32
+ state.x += y;
33
+ return state.x;
34
+ },
35
+ decr(y = 1) {
36
+ const { state } = this;
37
+ state.x -= y;
38
+ return state.x;
39
+ },
40
+ },
41
+ );
42
+
43
+ const makeUpAttenuator = prepareAttenuatorMaker(zone, 'UpCounter', ['incr']);
44
+
45
+ const makeUpCounter = x => makeUpAttenuator(makeUnderlyingCounter(x));
46
+
47
+ const upCounter = makeUpCounter(3);
48
+ t.is(upCounter.incr(5), 8);
49
+ t.throws(() => upCounter.decr(1), {
50
+ message: 'upCounter.decr is not a function',
51
+ });
52
+ });
53
+
54
+ test('test revoke defineVirtualExoClassKit', t => {
55
+ const zone = makeHeapZone('rootZone');
56
+
57
+ const makeUnderlyingCounter = zone.exoClass(
58
+ 'Counter',
59
+ CounterI,
60
+ /** @param {number} [x] */
61
+ (x = 0) => ({ x }),
62
+ {
63
+ incr(y = 1) {
64
+ const { state } = this;
65
+ state.x += y;
66
+ return state.x;
67
+ },
68
+ decr(y = 1) {
69
+ const { state } = this;
70
+ state.x -= y;
71
+ return state.x;
72
+ },
73
+ },
74
+ );
75
+
76
+ const makeDownAttenuator = prepareAttenuatorMaker(
77
+ zone,
78
+ 'DownCounter',
79
+ ['decr'],
80
+ {
81
+ extraMethodGuards: {
82
+ selfRevoke: M.call().returns(M.boolean()),
83
+ },
84
+ extraMethods: {
85
+ selfRevoke() {
86
+ const { state } = this;
87
+ if (state.underlying === undefined) {
88
+ return false;
89
+ }
90
+ // @ts-expect-error Setting this to `undefined` is purposely outside
91
+ // the type system.
92
+ state.underlying = undefined;
93
+ return true;
94
+ },
95
+ },
96
+ },
97
+ );
98
+
99
+ const makeDownCounter = x => makeDownAttenuator(makeUnderlyingCounter(x));
100
+
101
+ const downCounter = makeDownCounter(3);
102
+ t.throws(() => downCounter.incr(1), {
103
+ message: 'downCounter.incr is not a function',
104
+ });
105
+ t.is(downCounter.decr(), 2);
106
+ t.is(downCounter.selfRevoke(), true);
107
+ t.throws(() => downCounter.decr(3), {
108
+ message: '"DownCounter_attenuator" revoked',
109
+ });
110
+ });
@@ -5,7 +5,7 @@ import { test } from './prepare-test-env-ava.js';
5
5
  // eslint-disable-next-line import/order
6
6
  import { M } from '@endo/patterns';
7
7
  import { makeHeapZone } from '../src/heap.js';
8
- import { prepareRevocableKit } from '../src/prepare-revocable.js';
8
+ import { prepareRevocableMakerKit } from '../src/prepare-revocable.js';
9
9
 
10
10
  const UpCounterI = M.interface('UpCounter', {
11
11
  incr: M.call()
@@ -38,16 +38,17 @@ test('test revoke defineVirtualExoClass', t => {
38
38
  },
39
39
  );
40
40
 
41
- const makeRevocableUpCounterKit = prepareRevocableKit(zone, 'UpCounter', [
42
- 'incr',
43
- ]);
41
+ const { revoke, makeRevocable } = prepareRevocableMakerKit(
42
+ zone,
43
+ 'UpCounter',
44
+ ['incr'],
45
+ );
44
46
 
45
- const makeUpCounterKit = x =>
46
- makeRevocableUpCounterKit(makeUnderlyingUpCounter(x));
47
+ const makeUpCounter = x => makeRevocable(makeUnderlyingUpCounter(x));
47
48
 
48
- const { revoker, revocable: upCounter } = makeUpCounterKit(3);
49
+ const upCounter = makeUpCounter(3);
49
50
  t.is(upCounter.incr(5), 8);
50
- t.is(revoker.revoke(), true);
51
+ t.is(revoke(upCounter), true);
51
52
  t.throws(() => upCounter.incr(1), {
52
53
  message: '"UpCounter_caretaker" revoked',
53
54
  });
@@ -79,7 +80,7 @@ test('test revoke defineVirtualExoClassKit', t => {
79
80
  },
80
81
  );
81
82
 
82
- const makeRevocableUpCounterKit = prepareRevocableKit(
83
+ const { revoke, makeRevocable } = prepareRevocableMakerKit(
83
84
  zone,
84
85
  'UpCounter',
85
86
  ['incr'],
@@ -89,8 +90,12 @@ test('test revoke defineVirtualExoClassKit', t => {
89
90
  },
90
91
  extraMethods: {
91
92
  selfRevoke() {
92
- const { revoker } = this.facets;
93
- return revoker.revoke();
93
+ // Could directly use the revoker facet instead, but this
94
+ // should now be considered more of an internal detail that
95
+ // we should deemphasize. This tests the code pattern we wish
96
+ // to encourage.
97
+ const { revocable } = this.facets;
98
+ return revoke(revocable);
94
99
  },
95
100
  },
96
101
  },
@@ -98,8 +103,7 @@ test('test revoke defineVirtualExoClassKit', t => {
98
103
 
99
104
  const makeCounterKit = x => {
100
105
  const { up: upCounter, down: downCounter } = makeUnderlyingCounterKit(x);
101
- const { revocable: revocableUpCounter } =
102
- makeRevocableUpCounterKit(upCounter);
106
+ const revocableUpCounter = makeRevocable(upCounter);
103
107
  return harden({
104
108
  up: revocableUpCounter,
105
109
  down: downCounter,
@@ -0,0 +1 @@
1
+ {"root":["./heap.js","./zone-helpers.js","./src/heap.js","./src/index.js","./src/is-passable.js","./src/keys.js","./src/make-once.js","./src/prepare-attenuator.js","./src/prepare-revocable.js","./src/types.js","./src/watch-promise.js"],"version":"5.9.2"}
package/tsconfig.json CHANGED
@@ -1,9 +1,7 @@
1
1
  // This file can contain .js-specific Typescript compiler config.
2
2
  {
3
3
  "extends": "../../tsconfig.json",
4
- "compilerOptions": {
5
- "maxNodeModuleJsDepth": 2,
6
- },
4
+ "compilerOptions": {},
7
5
  "include": [
8
6
  "*.js",
9
7
  "scripts",
package/zone-helpers.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./src/prepare-revocable.js";
2
+ export * from "./src/prepare-attenuator.js";
2
3
  //# sourceMappingURL=zone-helpers.d.ts.map
package/zone-helpers.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from './src/prepare-revocable.js';
2
+ export * from './src/prepare-attenuator.js';
File without changes