@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 +20 -19
- package/src/exports.d.ts +0 -1
- package/src/heap.d.ts +1 -1
- package/src/heap.d.ts.map +1 -1
- package/src/heap.js +3 -2
- package/src/index.d.ts +1 -0
- package/src/index.js +3 -0
- package/src/is-passable.d.ts +2 -1
- package/src/is-passable.d.ts.map +1 -1
- package/src/is-passable.js +7 -18
- package/src/keys.d.ts +1 -1
- package/src/make-once.d.ts +2 -2
- package/src/make-once.d.ts.map +1 -1
- package/src/make-once.js +2 -2
- package/src/prepare-attenuator.d.ts +31 -0
- package/src/prepare-attenuator.d.ts.map +1 -0
- package/src/prepare-attenuator.js +170 -0
- package/src/prepare-revocable.d.ts +18 -8
- package/src/prepare-revocable.d.ts.map +1 -1
- package/src/prepare-revocable.js +81 -54
- package/src/types.d.ts +15 -11
- package/src/types.d.ts.map +1 -1
- package/src/types.js +14 -2
- package/src/watch-promise.d.ts +29 -0
- package/src/watch-promise.d.ts.map +1 -0
- package/src/watch-promise.js +81 -0
- package/test/{test-exos.js → exos.test.js} +0 -1
- package/test/prepare-attenuator.test.js +110 -0
- package/test/{test-prepare-revocable.js → prepare-revocable.test.js} +17 -13
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +1 -3
- package/zone-helpers.d.ts +1 -0
- package/zone-helpers.js +1 -0
- /package/test/{test-make-once.js → make-once.test.js} +0 -0
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/base-zone",
|
|
3
|
-
"version": "0.1.1-
|
|
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
|
|
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
|
|
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-
|
|
31
|
-
"@endo/common": "^1.
|
|
32
|
-
"@endo/
|
|
33
|
-
"@endo/
|
|
34
|
-
"@endo/
|
|
35
|
-
"@endo/
|
|
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.
|
|
39
|
-
"@endo/ses-ava": "^1.
|
|
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": "
|
|
47
|
+
"node": "^20.9 || ^22.11"
|
|
47
48
|
},
|
|
48
49
|
"ava": {
|
|
49
50
|
"files": [
|
|
50
|
-
"test
|
|
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":
|
|
60
|
+
"atLeast": 93.22
|
|
60
61
|
},
|
|
61
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "fbe72e72107f9997f788674e668c660d92ec4492"
|
|
62
63
|
}
|
package/src/exports.d.ts
CHANGED
package/src/heap.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function makeHeapZone(baseLabel?: string
|
|
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,
|
|
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/
|
|
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 {
|
|
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
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';
|
package/src/is-passable.d.ts
CHANGED
package/src/is-passable.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-passable.d.ts","sourceRoot":"","sources":["is-passable.js"],"names":[],"mappings":"
|
|
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"}
|
package/src/is-passable.js
CHANGED
|
@@ -1,23 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isPassable as realIsPassable } from '@endo/pass-style';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
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
package/src/make-once.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export function makeOnceKit(debugName: string, stores: import(
|
|
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:
|
|
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
|
package/src/make-once.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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:
|
|
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
|
|
2
|
-
export type
|
|
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
|
|
6
|
-
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
|
|
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<
|
|
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<
|
|
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":"
|
|
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"}
|
package/src/prepare-revocable.js
CHANGED
|
@@ -1,18 +1,47 @@
|
|
|
1
1
|
import { M } from '@endo/patterns';
|
|
2
|
-
import {
|
|
2
|
+
import { wrapperMethods } from './prepare-attenuator.js';
|
|
3
3
|
|
|
4
|
-
|
|
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}
|
|
36
|
+
* @typedef {object} RevokerFacet
|
|
8
37
|
* @property {() => boolean} revoke
|
|
9
38
|
*/
|
|
10
39
|
|
|
11
40
|
/**
|
|
12
|
-
* @template
|
|
41
|
+
* @template [U=any]
|
|
13
42
|
* @typedef {object} RevocableKit
|
|
14
|
-
* @property {
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
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 {
|
|
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 {
|
|
87
|
+
* @param {RevocableKitOptions<U>} [options]
|
|
88
|
+
* @returns {RevocableMakerKit<U>}
|
|
61
89
|
*/
|
|
62
|
-
export const
|
|
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 =
|
|
71
|
-
extraMethods =
|
|
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
|
-
|
|
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
|
-
|
|
133
|
+
stateShape: { underlying: M.opt(M.remotable('underlying')) },
|
|
134
|
+
receiveAmplifier: amp => {
|
|
135
|
+
amplifier = amp;
|
|
130
136
|
},
|
|
131
137
|
},
|
|
132
138
|
);
|
|
133
139
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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(
|
|
165
|
+
harden(prepareRevocableMakerKit);
|
package/src/types.d.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
export type KeyCategories =
|
|
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: <
|
|
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: <
|
|
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: <
|
|
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
|
package/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"
|
|
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);
|
|
@@ -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 {
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const { revoke, makeRevocable } = prepareRevocableMakerKit(
|
|
42
|
+
zone,
|
|
43
|
+
'UpCounter',
|
|
44
|
+
['incr'],
|
|
45
|
+
);
|
|
44
46
|
|
|
45
|
-
const
|
|
46
|
-
makeRevocableUpCounterKit(makeUnderlyingUpCounter(x));
|
|
47
|
+
const makeUpCounter = x => makeRevocable(makeUnderlyingUpCounter(x));
|
|
47
48
|
|
|
48
|
-
const
|
|
49
|
+
const upCounter = makeUpCounter(3);
|
|
49
50
|
t.is(upCounter.incr(5), 8);
|
|
50
|
-
t.is(
|
|
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
|
|
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
|
-
|
|
93
|
-
|
|
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
|
|
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
package/zone-helpers.d.ts
CHANGED
package/zone-helpers.js
CHANGED
|
File without changes
|