@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 +3 -3
- package/src/prepare-attenuator.d.ts +27 -0
- package/src/prepare-attenuator.d.ts.map +1 -0
- package/src/prepare-attenuator.js +131 -0
- package/src/prepare-revocable.d.ts +1 -1
- package/src/prepare-revocable.d.ts.map +1 -1
- package/src/prepare-revocable.js +7 -1
- package/test/prepare-attenuator.test.js +108 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/base-zone",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
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-
|
|
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": "
|
|
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":"
|
|
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"}
|
package/src/prepare-revocable.js
CHANGED
|
@@ -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"}
|