@agoric/base-zone 0.1.1-u19.0 → 0.1.1-u21.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/CHANGELOG.md CHANGED
@@ -3,13 +3,15 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ### 0.1.1-u19.0 (2025-02-24)
6
+ ### 0.1.1-u21.0 (2025-06-19)
7
7
 
8
8
 
9
9
  ### Features
10
10
 
11
11
  * **base-zone:** add `zone.watchPromise` ([9ce80d0](https://github.com/Agoric/agoric-sdk/commit/9ce80d06c0a56471d2da9f372b0b2d93d31d159a))
12
12
  * **base-zone:** alt revocable api using amplifier ([#8977](https://github.com/Agoric/agoric-sdk/issues/8977)) ([5cdf6e3](https://github.com/Agoric/agoric-sdk/commit/5cdf6e3a8b4fbb5cb8e276e6efeec65d9c3d6623))
13
+ * **base-zone:** attenuator as simplified revocable ([#11314](https://github.com/Agoric/agoric-sdk/issues/11314)) ([c962ba0](https://github.com/Agoric/agoric-sdk/commit/c962ba0771022947027b9bd76339a3ab21406b20))
14
+ * **base-zone:** expose `makeRevocableKit` for pure Exos ([b0b2af0](https://github.com/Agoric/agoric-sdk/commit/b0b2af0a7b5f8402abf836e126a9d7d758fed7dc))
13
15
  * **base-zone:** new package ([b7bc677](https://github.com/Agoric/agoric-sdk/commit/b7bc677238eee5969ac0a95dc066434ef676216e))
14
16
  * **types:** generic zone.mapStore ([a9b055d](https://github.com/Agoric/agoric-sdk/commit/a9b055dcab34b9c9b136dd430e1e2251d80c5039))
15
17
  * **watchUtils:** handle non-storables ([8c27c67](https://github.com/Agoric/agoric-sdk/commit/8c27c6725ba7ef4b71d3ab0ccfdbddd755bcd926))
@@ -18,3 +20,4 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
18
20
  ### Bug Fixes
19
21
 
20
22
  * **base-zone,zone:** import `isPassable` from @endo/pass-style ([#9230](https://github.com/Agoric/agoric-sdk/issues/9230)) ([fbd8633](https://github.com/Agoric/agoric-sdk/commit/fbd8633ae9f8420a589dd9bc32925418f2dde060))
23
+ * **base-zone:** Oops. Forgot to export `prepareAttenuatorMaker` ([#11315](https://github.com/Agoric/agoric-sdk/issues/11315)) ([af493a9](https://github.com/Agoric/agoric-sdk/commit/af493a9026387fc69cbfd57486f00fd33608594d)), closes [#11314](https://github.com/Agoric/agoric-sdk/issues/11314) [#11314](https://github.com/Agoric/agoric-sdk/issues/11314)
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@agoric/base-zone",
3
- "version": "0.1.1-u19.0",
3
+ "version": "0.1.1-u21.0",
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",
10
+ "prepack": "yarn run -T tsc --build tsconfig.build.json",
11
11
  "postpack": "git clean -f '*.d.ts*' '*.tsbuildinfo'",
12
12
  "test": "ava",
13
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,24 +27,24 @@
27
27
  "author": "Agoric",
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@agoric/store": "^0.9.3-u19.0",
31
- "@endo/common": "^1.2.9",
32
- "@endo/errors": "^1.2.9",
33
- "@endo/exo": "^1.5.8",
34
- "@endo/far": "^1.1.10",
35
- "@endo/pass-style": "^1.4.8",
36
- "@endo/patterns": "^1.4.8"
30
+ "@agoric/store": "workspace:*",
31
+ "@endo/common": "^1.2.10",
32
+ "@endo/errors": "^1.2.10",
33
+ "@endo/exo": "^1.5.9",
34
+ "@endo/far": "^1.1.11",
35
+ "@endo/pass-style": "^1.5.0",
36
+ "@endo/patterns": "^1.5.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@endo/init": "^1.1.8",
40
- "@endo/ses-ava": "^1.2.9",
39
+ "@endo/init": "^1.1.9",
40
+ "@endo/ses-ava": "^1.2.10",
41
41
  "ava": "^5.3.0"
42
42
  },
43
43
  "publishConfig": {
44
44
  "access": "public"
45
45
  },
46
46
  "engines": {
47
- "node": "^18.12 || ^20.9"
47
+ "node": "^20.9 || ^22.11"
48
48
  },
49
49
  "ava": {
50
50
  "files": [
@@ -59,5 +59,5 @@
59
59
  "typeCoverage": {
60
60
  "atLeast": 91.4
61
61
  },
62
- "gitHead": "29e9704c375a06bb617027093b30d2d25faa6471"
62
+ "gitHead": "e4dd46857133403d584bcf822a81817b355532f9"
63
63
  }
@@ -1,2 +1,3 @@
1
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":"AAOO,qCAHI,GAAG,GACD,QAAQ,IAAI,QAAQ,CAE6B"}
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,5 +1,9 @@
1
1
  import { isPassable as realIsPassable } from '@endo/pass-style';
2
2
 
3
+ /**
4
+ * @import {Passable} from '@endo/pass-style';
5
+ */
6
+
3
7
  /**
4
8
  * @deprecated Import `isPassable` directly from `@endo/pass-style`
5
9
  * @param {any} specimen
@@ -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,10 +1,13 @@
1
- export function prepareRevocableMakerKit<U = any>(zone: import("@agoric/base-zone").Zone, uKindName: string, uMethodNames: (string | symbol)[], options?: RevocableKitOptions): RevocableMakerKit<U>;
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>;
2
4
  export type RevocableMakerKit<U = any> = {
3
5
  revoke: (revocable: U) => boolean;
4
6
  /**
5
7
  * Forwards to the underlying exo object, until revoked
6
8
  */
7
- makeRevocable: (underlying: U) => U;
9
+ makeRevocable: MakeRevocable<U>;
10
+ makeRevocableKit: MakeRevocableKit<U>;
8
11
  };
9
12
  export type RevokerFacet = {
10
13
  revoke: () => boolean;
@@ -14,7 +17,7 @@ export type RevocableKit<U = any> = {
14
17
  /**
15
18
  * Forwards to the underlying exo object, until revoked
16
19
  */
17
- revocable: U;
20
+ revocable: Partial<U>;
18
21
  };
19
22
  export type RevocableKitThis<U = any> = {
20
23
  facets: RevocableKit<U>;
@@ -33,11 +36,11 @@ export type RevocableKitOptions<U = any> = {
33
36
  * only on the synthesized interface guard for the revocable caretaker, and
34
37
  * do not necessarily correspond to any method of the underlying.
35
38
  */
36
- extraMethodGuards?: Record<string | symbol, import("@endo/patterns").MethodGuard> | undefined;
39
+ extraMethodGuards?: Record<PropertyKey, import("@endo/patterns").MethodGuard> | undefined;
37
40
  /**
38
41
  * Extra methods adding behavior only to the revocable caretaker, and
39
42
  * do not necessarily correspond to any methods of the underlying.
40
43
  */
41
- extraMethods?: Record<string | symbol, (this: RevocableKitThis<U>, ...args: any[]) => any> | undefined;
44
+ extraMethods?: Record<PropertyKey, (this: RevocableKitThis<U>, ...args: any[]) => any> | undefined;
42
45
  };
43
46
  //# sourceMappingURL=prepare-revocable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare-revocable.d.ts","sourceRoot":"","sources":["prepare-revocable.js"],"names":[],"mappings":"AAqEO,yCAVO,CAAC,cACJ,OAAO,mBAAmB,EAAE,IAAI,aAChC,MAAM,gBAEN,CAAC,MAAM,GAAC,MAAM,CAAC,EAAE,YAGjB,mBAAmB,GACjB,iBAAiB,CAAC,CAAC,CAAC,CAyGhC;8BArKa,CAAC;YAED,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO;;;;mBACzB,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC;;;YAMpB,MAAM,OAAO;;yBAIb,CAAC;aAED,YAAY;;;;eACZ,CAAC;;6BAKD,CAAC;YAED,YAAY,CAAC,CAAC,CAAC;WACf;QAAE,UAAU,EAAE,CAAC,CAAA;KAAE;;gCAIjB,CAAC;;;;;;;;;;;;;;;;kDAcH,gBAAgB,CAAC,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,15 +1,35 @@
1
- import { Fail, q } from '@endo/errors';
2
- import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
3
1
  import { M } from '@endo/patterns';
2
+ import { wrapperMethods } from './prepare-attenuator.js';
4
3
 
5
4
  /** @import {Amplify} from '@endo/exo'; */
6
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
+
7
26
  /**
8
27
  * @template [U=any]
9
28
  * @typedef {object} RevocableMakerKit
10
29
  * @property {(revocable: U) => boolean} revoke
11
- * @property {(underlying: U) => U} makeRevocable
30
+ * @property {MakeRevocable<U>} makeRevocable
12
31
  * Forwards to the underlying exo object, until revoked
32
+ * @property {MakeRevocableKit<U>} makeRevocableKit
13
33
  */
14
34
 
15
35
  /**
@@ -21,7 +41,7 @@ import { M } from '@endo/patterns';
21
41
  * @template [U=any]
22
42
  * @typedef {object} RevocableKit
23
43
  * @property {RevokerFacet} revoker
24
- * @property {U} revocable
44
+ * @property {Partial<U>} revocable
25
45
  * Forwards to the underlying exo object, until revoked
26
46
  */
27
47
 
@@ -39,14 +59,14 @@ import { M } from '@endo/patterns';
39
59
  * The `interfaceName` of the underlying interface guard.
40
60
  * Defaults to the `uKindName`.
41
61
  * @property {Record<
42
- * string|symbol,
62
+ * PropertyKey,
43
63
  * import('@endo/patterns').MethodGuard
44
64
  * >} [extraMethodGuards]
45
65
  * For guarding the `extraMethods`, if you include them below. These appear
46
66
  * only on the synthesized interface guard for the revocable caretaker, and
47
67
  * do not necessarily correspond to any method of the underlying.
48
68
  * @property {Record<
49
- * string|symbol,
69
+ * PropertyKey,
50
70
  * (this: RevocableKitThis<U>, ...args: any[]) => any
51
71
  * >} [extraMethods]
52
72
  * Extra methods adding behavior only to the revocable caretaker, and
@@ -61,10 +81,10 @@ import { M } from '@endo/patterns';
61
81
  * @param {import('@agoric/base-zone').Zone} zone
62
82
  * @param {string} uKindName
63
83
  * The `kindName` of the underlying exo class
64
- * @param {(string|symbol)[]} uMethodNames
84
+ * @param {PropertyKey[]} uMethodNames
65
85
  * The method names of the underlying exo class that should be represented
66
86
  * by transparently-forwarding methods of the revocable caretaker.
67
- * @param {RevocableKitOptions} [options]
87
+ * @param {RevocableKitOptions<U>} [options]
68
88
  * @returns {RevocableMakerKit<U>}
69
89
  */
70
90
  export const prepareRevocableMakerKit = (
@@ -75,22 +95,16 @@ export const prepareRevocableMakerKit = (
75
95
  ) => {
76
96
  const {
77
97
  uInterfaceName = uKindName,
78
- extraMethodGuards = undefined,
79
- extraMethods = undefined,
98
+ extraMethodGuards = {},
99
+ extraMethods = {},
80
100
  } = options;
81
101
  const RevocableIKit = harden({
82
102
  revoker: M.interface(`${uInterfaceName}_revoker`, {
83
103
  revoke: M.call().returns(M.boolean()),
84
104
  }),
85
- revocable: M.interface(
86
- `${uInterfaceName}_revocable`,
87
- {
88
- ...extraMethodGuards,
89
- },
90
- {
91
- defaultGuards: 'raw',
92
- },
93
- ),
105
+ revocable: M.interface(`${uInterfaceName}_revocable`, extraMethodGuards, {
106
+ defaultGuards: 'raw',
107
+ }),
94
108
  });
95
109
 
96
110
  const revocableKindName = `${uKindName}_caretaker`;
@@ -101,9 +115,7 @@ export const prepareRevocableMakerKit = (
101
115
  const makeRevocableKit = zone.exoClassKit(
102
116
  revocableKindName,
103
117
  RevocableIKit,
104
- underlying => ({
105
- underlying,
106
- }),
118
+ underlying => ({ underlying }),
107
119
  {
108
120
  revoker: {
109
121
  revoke() {
@@ -115,30 +127,10 @@ export const prepareRevocableMakerKit = (
115
127
  return true;
116
128
  },
117
129
  },
118
- revocable: {
119
- ...fromUniqueEntries(
120
- uMethodNames.map(name => [
121
- name,
122
- {
123
- // Use concise method syntax for exo methods
124
- [name](...args) {
125
- // @ts-expect-error normal exo-this typing confusion
126
- const { underlying } = this.state;
127
- underlying !== undefined ||
128
- Fail`${q(revocableKindName)} revoked`;
129
- return underlying[name](...args);
130
- },
131
- // @ts-expect-error using possible symbol as index type
132
- }[name],
133
- ]),
134
- ),
135
- ...extraMethods,
136
- },
130
+ revocable: wrapperMethods(revocableKindName, uMethodNames, extraMethods),
137
131
  },
138
132
  {
139
- stateShape: {
140
- underlying: M.opt(M.remotable('underlying')),
141
- },
133
+ stateShape: { underlying: M.opt(M.remotable('underlying')) },
142
134
  receiveAmplifier: amp => {
143
135
  amplifier = amp;
144
136
  },
@@ -146,12 +138,9 @@ export const prepareRevocableMakerKit = (
146
138
  );
147
139
 
148
140
  /**
149
- * @param {U} underlying
150
- * @returns {U}
141
+ * @type {MakeRevocable}
151
142
  */
152
- const makeRevocable = underlying =>
153
- // @ts-expect-error some confusion about UU vs Guarded<U> I think
154
- makeRevocableKit(underlying).revocable;
143
+ const makeRevocable = underlying => makeRevocableKit(underlying).revocable;
155
144
 
156
145
  /**
157
146
  * @param {U} revocable
@@ -169,6 +158,8 @@ export const prepareRevocableMakerKit = (
169
158
  return harden({
170
159
  revoke,
171
160
  makeRevocable,
161
+ /** @type {MakeRevocableKit} */
162
+ makeRevocableKit,
172
163
  });
173
164
  };
174
165
  harden(prepareRevocableMakerKit);
package/src/types.d.ts CHANGED
@@ -60,5 +60,10 @@ export type Stores = {
60
60
  import { makeExo } from '@endo/exo';
61
61
  import { defineExoClass } from '@endo/exo';
62
62
  import { defineExoClassKit } from '@endo/exo';
63
+ import type { StoreOptions } from '@agoric/store';
63
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';
64
69
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"4BAac,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,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;;;;cAC/D,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC;;;;kBACzD,CAAC,CAAC,EAAE,CAAC,EACd,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;;;;kBAEnD,CAAC,CAAC,EACX,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,YAAY,CAAC,CAAC,CAAC;;wBAxCH,WAAW;+BAAX,WAAW;kCAAX,WAAW;6BAEzC,oBAAoB"}
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
@@ -7,6 +7,7 @@ import { watchPromise } from './watch-promise.js';
7
7
  export {};
8
8
 
9
9
  /**
10
+ * @import {MapStore, SetStore, StoreOptions, WeakMapStore, WeakSetStore} from '@agoric/store';
10
11
  * @import {Key} from '@endo/patterns';
11
12
  * @import {Passable} from '@endo/pass-style';
12
13
  */
@@ -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
+ });
@@ -1 +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-revocable.js","./src/types.js","./src/watch-promise.js"],"version":"5.8.1-rc"}
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.8.3"}
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';