@agoric/base-zone 0.1.1-dev-f8c06e6.0 → 0.1.1-dev-c962ba0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/base-zone",
3
- "version": "0.1.1-dev-f8c06e6.0+f8c06e6",
3
+ "version": "0.1.1-dev-c962ba0.0+c962ba0",
4
4
  "description": "Allocation zone abstraction library and heap implementation",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/Agoric/agoric-sdk",
@@ -27,7 +27,7 @@
27
27
  "author": "Agoric",
28
28
  "license": "Apache-2.0",
29
29
  "dependencies": {
30
- "@agoric/store": "0.9.3-dev-f8c06e6.0+f8c06e6",
30
+ "@agoric/store": "0.9.3-dev-c962ba0.0+c962ba0",
31
31
  "@endo/common": "^1.2.10",
32
32
  "@endo/errors": "^1.2.10",
33
33
  "@endo/exo": "^1.5.9",
@@ -59,5 +59,5 @@
59
59
  "typeCoverage": {
60
60
  "atLeast": 91.4
61
61
  },
62
- "gitHead": "f8c06e6e6f0108a8fddcf045d8454916bd2060e8"
62
+ "gitHead": "c962ba0771022947027b9bd76339a3ab21406b20"
63
63
  }
@@ -0,0 +1,27 @@
1
+ export function prepareAttenuatorMaker<U = any>(zone: import("@agoric/base-zone").Zone, uKindName: string, uMethodNames: (string | symbol)[], options?: AttenuatorOptions<U>): MakeAttenuator;
2
+ export type MakeAttenuator<U = any> = (underlying: U) => U;
3
+ export type AttenuatorThis<U = any> = {
4
+ self: U;
5
+ state: {
6
+ underlying: U;
7
+ };
8
+ };
9
+ export type AttenuatorOptions<U = any> = {
10
+ /**
11
+ * The `interfaceName` of the underlying interface guard.
12
+ * Defaults to the `uKindName`.
13
+ */
14
+ uInterfaceName?: string | undefined;
15
+ /**
16
+ * For guarding the `extraMethods`, if you include them below. These appear
17
+ * only on the synthesized interface guard for the attenuator, and
18
+ * do not necessarily correspond to any method of the underlying.
19
+ */
20
+ extraMethodGuards?: Record<string | symbol, import("@endo/patterns").MethodGuard> | undefined;
21
+ /**
22
+ * Extra methods adding behavior only to the attenuator, and
23
+ * do not necessarily correspond to any methods of the underlying.
24
+ */
25
+ extraMethods?: Record<string | symbol, (this: AttenuatorThis<U>, ...args: any[]) => any> | undefined;
26
+ };
27
+ //# sourceMappingURL=prepare-attenuator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-attenuator.d.ts","sourceRoot":"","sources":["prepare-attenuator.js"],"names":[],"mappings":"AAsEO,uCAVO,CAAC,cACJ,OAAO,mBAAmB,EAAE,IAAI,aAChC,MAAM,gBAEN,CAAC,MAAM,GAAC,MAAM,CAAC,EAAE,YAGjB,iBAAiB,CAAC,CAAC,CAAC,GAClB,cAAc,CA6D1B;2BA3Ga,CAAC,uBAEJ,CAAC,KACC,CAAC;2BAIA,CAAC;UAED,CAAC;WACD;QAAE,UAAU,EAAE,CAAC,CAAA;KAAE;;8BAIjB,CAAC;;;;;;;;;;;;;;;;kDAcH,cAAc,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,KAAK,GAAG"}
@@ -0,0 +1,131 @@
1
+ import { Fail, q } from '@endo/errors';
2
+ import { fromUniqueEntries } from '@endo/common/from-unique-entries.js';
3
+ import { M } from '@endo/patterns';
4
+
5
+ // This attenuator implementation is just a simplification of the
6
+ // revocable kit implementation in prepare-revocable.js. The revocable kit
7
+ // provides both attenuation and revocation, since we can have both for the
8
+ // price of just one level of indirection. But if you don't need revocation,
9
+ // the revocable kit has more API complexity than you need.
10
+ //
11
+ // We could have built `prepareAttenuatorMaker` as a trivial wrapper around
12
+ // `prepareRevocableMakerKit`. But then we'd have the weird artifact that the
13
+ // `extraMethods` would see a `{ state, facets: { revocable, revoker }}` context
14
+ // rather than a `{ state, self }` context. So instead, we copied and edited it
15
+ // down. Please co-maintain these two modules.
16
+
17
+ // Because the attenuator just uses an exo class rather than a class kit,
18
+ // it cannot support the privilege separation of a distinct revoker facet.
19
+ // But it can still support `selfRevoke` as a separate `extraMethod`, as shown
20
+ // in a testcase at `prepare-attenuator.test.js`
21
+
22
+ /**
23
+ * @template [U=any]
24
+ * @callback MakeAttenuator
25
+ * @param {U} underlying
26
+ * @returns {U}
27
+ */
28
+
29
+ /**
30
+ * @template [U=any]
31
+ * @typedef {object} AttenuatorThis
32
+ * @property {U} self
33
+ * @property {{ underlying: U }} state
34
+ */
35
+
36
+ /**
37
+ * @template [U=any]
38
+ * @typedef {object} AttenuatorOptions
39
+ * @property {string} [uInterfaceName]
40
+ * The `interfaceName` of the underlying interface guard.
41
+ * Defaults to the `uKindName`.
42
+ * @property {Record<
43
+ * string|symbol,
44
+ * import('@endo/patterns').MethodGuard
45
+ * >} [extraMethodGuards]
46
+ * For guarding the `extraMethods`, if you include them below. These appear
47
+ * only on the synthesized interface guard for the attenuator, and
48
+ * do not necessarily correspond to any method of the underlying.
49
+ * @property {Record<
50
+ * string|symbol,
51
+ * (this: AttenuatorThis<U>, ...args: any[]) => any
52
+ * >} [extraMethods]
53
+ * Extra methods adding behavior only to the attenuator, and
54
+ * do not necessarily correspond to any methods of the underlying.
55
+ */
56
+
57
+ /**
58
+ * Make an exo class for wrapping an underlying exo class,
59
+ * where the wrapper is an attenuator of the underlying.
60
+ *
61
+ * @template [U=any]
62
+ * @param {import('@agoric/base-zone').Zone} zone
63
+ * @param {string} uKindName
64
+ * The `kindName` of the underlying exo class
65
+ * @param {(string|symbol)[]} uMethodNames
66
+ * The method names of the underlying exo class that should be represented
67
+ * by transparently-forwarding methods of the attenuator.
68
+ * @param {AttenuatorOptions<U>} [options]
69
+ * @returns {MakeAttenuator}
70
+ */
71
+ export const prepareAttenuatorMaker = (
72
+ zone,
73
+ uKindName,
74
+ uMethodNames,
75
+ options = {},
76
+ ) => {
77
+ const {
78
+ uInterfaceName = uKindName,
79
+ extraMethodGuards = undefined,
80
+ extraMethods = undefined,
81
+ } = options;
82
+ const AttenuatorI = M.interface(
83
+ `${uInterfaceName}_attenuator`,
84
+ {
85
+ ...extraMethodGuards,
86
+ },
87
+ {
88
+ defaultGuards: 'raw',
89
+ },
90
+ );
91
+
92
+ const attenuatorKindName = `${uKindName}_attenuator`;
93
+
94
+ return zone.exoClass(
95
+ attenuatorKindName,
96
+ AttenuatorI,
97
+ underlying => ({
98
+ underlying,
99
+ }),
100
+ {
101
+ ...fromUniqueEntries(
102
+ uMethodNames.map(name => [
103
+ name,
104
+ {
105
+ // Use concise method syntax for exo methods
106
+ [name](...args) {
107
+ // @ts-expect-error normal exo-this typing confusion
108
+ const { underlying } = this.state;
109
+
110
+ // Because attenuators still support someone adding `selfRevoke`
111
+ // as an `extraMethod`, this test is still useful. See the
112
+ // testcase in `prepare-attenuator.test.js`.
113
+ underlying !== undefined ||
114
+ Fail`${q(attenuatorKindName)} revoked`;
115
+
116
+ return underlying[name](...args);
117
+ },
118
+ // @ts-expect-error using possible symbol as index type
119
+ }[name],
120
+ ]),
121
+ ),
122
+ ...extraMethods,
123
+ },
124
+ {
125
+ stateShape: {
126
+ underlying: M.opt(M.remotable('underlying')),
127
+ },
128
+ },
129
+ );
130
+ };
131
+ harden(prepareAttenuatorMaker);
@@ -1,4 +1,4 @@
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: (string | symbol)[], options?: RevocableKitOptions<U>): RevocableMakerKit<U>;
2
2
  export type RevocableMakerKit<U = any> = {
3
3
  revoke: (revocable: U) => boolean;
4
4
  /**
@@ -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":"AA2EO,yCAVO,CAAC,cACJ,OAAO,mBAAmB,EAAE,IAAI,aAChC,MAAM,gBAEN,CAAC,MAAM,GAAC,MAAM,CAAC,EAAE,YAGjB,mBAAmB,CAAC,CAAC,CAAC,GACpB,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"}
@@ -4,6 +4,12 @@ import { M } from '@endo/patterns';
4
4
 
5
5
  /** @import {Amplify} from '@endo/exo'; */
6
6
 
7
+ // This revocable kit implementation provides for both attenuation and
8
+ // revocation, since both can be provided at the cost of one level of
9
+ // indirection. But if you just need attenuation without revocation, better to
10
+ // use the attenuator implementation in prepare-attenuator.js.
11
+ // Please co-maintain these two modules.
12
+
7
13
  /**
8
14
  * @template [U=any]
9
15
  * @typedef {object} RevocableMakerKit
@@ -64,7 +70,7 @@ import { M } from '@endo/patterns';
64
70
  * @param {(string|symbol)[]} uMethodNames
65
71
  * The method names of the underlying exo class that should be represented
66
72
  * by transparently-forwarding methods of the revocable caretaker.
67
- * @param {RevocableKitOptions} [options]
73
+ * @param {RevocableKitOptions<U>} [options]
68
74
  * @returns {RevocableMakerKit<U>}
69
75
  */
70
76
  export const prepareRevocableMakerKit = (
@@ -0,0 +1,108 @@
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
+ state.underlying = undefined;
91
+ return true;
92
+ },
93
+ },
94
+ },
95
+ );
96
+
97
+ const makeDownCounter = x => makeDownAttenuator(makeUnderlyingCounter(x));
98
+
99
+ const downCounter = makeDownCounter(3);
100
+ t.throws(() => downCounter.incr(1), {
101
+ message: 'downCounter.incr is not a function',
102
+ });
103
+ t.is(downCounter.decr(), 2);
104
+ t.is(downCounter.selfRevoke(), true);
105
+ t.throws(() => downCounter.decr(3), {
106
+ message: '"DownCounter_attenuator" revoked',
107
+ });
108
+ });
@@ -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.3"}
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"}