@agoric/internal 0.4.0 → 0.4.1-upgrade-23-dev-bd79330.0.bd79330
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/README.md +1 -4
- package/package.json +13 -11
- package/src/action-types.d.ts +47 -20
- package/src/action-types.d.ts.map +1 -1
- package/src/action-types.js +19 -19
- package/src/ava-force-exit.d.mts +2 -0
- package/src/ava-force-exit.d.mts.map +1 -0
- package/src/ava-force-exit.mjs +6 -0
- package/src/batched-deliver.d.ts +6 -2
- package/src/batched-deliver.d.ts.map +1 -1
- package/src/batched-deliver.js +7 -3
- package/src/build-cache-types.d.ts +33 -0
- package/src/build-cache-types.d.ts.map +1 -0
- package/src/build-cache-types.js +42 -0
- package/src/build-cache.d.ts +12 -0
- package/src/build-cache.d.ts.map +1 -0
- package/src/build-cache.js +184 -0
- package/src/callback.d.ts +9 -11
- package/src/callback.d.ts.map +1 -1
- package/src/callback.js +16 -10
- package/src/chain-storage-paths.d.ts.map +1 -1
- package/src/chain-storage-paths.js +0 -2
- package/src/chain-utils.d.ts +3 -1
- package/src/chain-utils.d.ts.map +1 -1
- package/src/chain-utils.js +6 -1
- package/src/config.d.ts +22 -3
- package/src/config.d.ts.map +1 -1
- package/src/config.js +25 -3
- package/src/debug.d.ts +4 -1
- package/src/debug.d.ts.map +1 -1
- package/src/debug.js +26 -15
- package/src/index.d.ts +2 -1
- package/src/index.js +10 -3
- package/src/js-utils.d.ts +7 -3
- package/src/js-utils.d.ts.map +1 -1
- package/src/js-utils.js +24 -3
- package/src/keyMirror.d.ts +3 -0
- package/src/keyMirror.d.ts.map +1 -0
- package/src/keyMirror.js +45 -0
- package/src/kv-store.d.ts +33 -0
- package/src/kv-store.d.ts.map +1 -0
- package/src/kv-store.js +257 -0
- package/src/lib-chainStorage.d.ts +23 -12
- package/src/lib-chainStorage.d.ts.map +1 -1
- package/src/lib-chainStorage.js +18 -18
- package/src/lib-nodejs/ava-unhandled-rejection.d.ts +18 -3
- package/src/lib-nodejs/ava-unhandled-rejection.d.ts.map +1 -1
- package/src/lib-nodejs/ava-unhandled-rejection.js +211 -20
- package/src/lib-nodejs/engine-gc.js +2 -2
- package/src/lib-nodejs/spawnSubprocessWorker.d.ts +0 -2
- package/src/lib-nodejs/spawnSubprocessWorker.d.ts.map +1 -1
- package/src/lib-nodejs/spawnSubprocessWorker.js +8 -7
- package/src/lib-nodejs/waitUntilQuiescent.d.ts +3 -0
- package/src/lib-nodejs/waitUntilQuiescent.d.ts.map +1 -1
- package/src/lib-nodejs/waitUntilQuiescent.js +5 -1
- package/src/lib-nodejs/worker-protocol.d.ts +1 -1
- package/src/lib-nodejs/worker-protocol.d.ts.map +1 -1
- package/src/lib-nodejs/worker-protocol.js +5 -5
- package/src/magic-cookie-test-only.d.ts.map +1 -1
- package/src/magic-cookie-test-only.js +0 -2
- package/src/marshal/board-client-utils.d.ts +19 -0
- package/src/marshal/board-client-utils.d.ts.map +1 -0
- package/src/{marshal.js → marshal/board-client-utils.js} +27 -52
- package/src/marshal/cap-data.d.ts +11 -0
- package/src/marshal/cap-data.d.ts.map +1 -0
- package/src/marshal/cap-data.js +19 -0
- package/src/marshal/inaccessible-val.d.ts +2 -0
- package/src/marshal/inaccessible-val.d.ts.map +1 -0
- package/src/marshal/inaccessible-val.js +15 -0
- package/src/marshal/pure-data.d.ts +8 -0
- package/src/marshal/pure-data.d.ts.map +1 -0
- package/src/marshal/pure-data.js +14 -0
- package/src/marshal/wrap-marshaller.d.ts +60 -0
- package/src/marshal/wrap-marshaller.d.ts.map +1 -0
- package/src/marshal/wrap-marshaller.js +432 -0
- package/src/module-utils.d.ts +1 -0
- package/src/module-utils.d.ts.map +1 -1
- package/src/module-utils.js +16 -0
- package/src/natural-sort.d.ts.map +1 -1
- package/src/natural-sort.js +48 -13
- package/src/netstring.d.ts +1 -1
- package/src/netstring.d.ts.map +1 -1
- package/src/netstring.js +5 -5
- package/src/node/buffer-line-transform.d.ts +10 -5
- package/src/node/buffer-line-transform.d.ts.map +1 -1
- package/src/node/buffer-line-transform.js +8 -4
- package/src/node/createBundles.d.ts.map +1 -1
- package/src/node/createBundles.js +3 -5
- package/src/node/fs-stream.d.ts +4 -1
- package/src/node/fs-stream.d.ts.map +1 -1
- package/src/node/fs-stream.js +58 -9
- package/src/node/read-json.d.ts +2 -0
- package/src/node/read-json.d.ts.map +1 -0
- package/src/node/read-json.js +18 -0
- package/src/node/shutdown.js +1 -1
- package/src/priority-senders.d.ts +2 -1
- package/src/priority-senders.d.ts.map +1 -1
- package/src/priority-senders.js +6 -4
- package/src/queue.d.ts.map +1 -1
- package/src/queue.js +0 -2
- package/src/ses-utils.d.ts +27 -5
- package/src/ses-utils.d.ts.map +1 -1
- package/src/ses-utils.js +115 -20
- package/src/storage-test-utils.d.ts +15 -5
- package/src/storage-test-utils.d.ts.map +1 -1
- package/src/storage-test-utils.js +62 -8
- package/src/tagged.d.ts +18 -1
- package/src/testing-utils.d.ts +4 -0
- package/src/testing-utils.d.ts.map +1 -1
- package/src/testing-utils.js +88 -2
- package/src/typeGuards.d.ts +6 -2
- package/src/typeGuards.d.ts.map +1 -1
- package/src/typeGuards.js +7 -4
- package/src/types-index.d.ts +1 -0
- package/src/types.d.ts +34 -19
- package/src/types.d.ts.map +1 -1
- package/src/types.js +173 -0
- package/src/upgrade-api.d.ts.map +1 -1
- package/src/upgrade-api.js +4 -3
- package/src/work-pool.d.ts +13 -0
- package/src/work-pool.d.ts.map +1 -0
- package/src/work-pool.js +233 -0
- package/vendor/anylogger.d.ts +98 -0
- package/vendor/anylogger.d.ts.map +1 -0
- package/vendor/anylogger.js +60 -0
- package/vendor/anylogger.ts +160 -0
- package/vendor/tsconfig.anylogger.json +15 -0
- package/exported.js +0 -2
- package/src/marshal.d.ts +0 -33
- package/src/marshal.d.ts.map +0 -1
- package/src/types.ts +0 -129
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ This package contains code that is required by agoric-sdk and not meant to be im
|
|
|
7
7
|
Like all `@agoric` packages it follows Semantic Versioning. Unlike the others, it will never have a stable API. In terms of [SemVer spec item 4](https://semver.org/#spec-item-4), it will never reach 1.0:
|
|
8
8
|
> Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
|
|
9
9
|
|
|
10
|
+
To keep down the size of [@endo/bundle-source](https://github.com/endojs/endo/tree/master/packages/bundle-source) bundles of source that imports from this package, modules that depend upon it should use deep imports (e.g., `import { defineName } from '@agoric/internal/src/js-utils.js';`) rather than importing the entire module.
|
|
10
11
|
|
|
11
12
|
# Design
|
|
12
13
|
|
|
@@ -19,7 +20,3 @@ It is meant to be a home for modules that have no dependencies on other packages
|
|
|
19
20
|
This package may not take dependencies on any others in this repository.
|
|
20
21
|
|
|
21
22
|
It must never export ambient types.
|
|
22
|
-
|
|
23
|
-
It should not be imported by deep imports. Eventually this will be enforced by [`exports`](https://nodejs.org/api/packages.html#exports) but the tooling isn't ready:
|
|
24
|
-
- https://github.com/import-js/eslint-plugin-import/issues/1810
|
|
25
|
-
- https://github.com/microsoft/TypeScript/issues/33079 (or some related problem with JSdoc types)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/internal",
|
|
3
|
-
"version": "0.4.0",
|
|
3
|
+
"version": "0.4.1-upgrade-23-dev-bd79330.0.bd79330",
|
|
4
4
|
"description": "Externally unsupported utilities internal to agoric-sdk",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -9,18 +9,19 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "exit 0",
|
|
12
|
-
"prepack": "yarn run -T
|
|
13
|
-
"postpack": "
|
|
12
|
+
"prepack": "yarn run -T prepack-package",
|
|
13
|
+
"postpack": "yarn run -T postpack-package",
|
|
14
14
|
"test": "ava",
|
|
15
15
|
"test:nyc": "exit 0",
|
|
16
16
|
"test:xs": "exit 0",
|
|
17
17
|
"lint-fix": "yarn lint:eslint --fix",
|
|
18
18
|
"lint": "yarn run -T run-s --continue-on-error 'lint:*'",
|
|
19
|
-
"lint:eslint": "
|
|
19
|
+
"lint:eslint": "node ../../scripts/eslint-repo.mjs .",
|
|
20
20
|
"lint:types": "yarn run -T tsc"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@agoric/base-zone": "0.2.0",
|
|
23
|
+
"@agoric/base-zone": "0.2.1-upgrade-23-dev-bd79330.0.bd79330",
|
|
24
|
+
"@endo/cache-map": "^1.1.0",
|
|
24
25
|
"@endo/common": "^1.2.13",
|
|
25
26
|
"@endo/compartment-mapper": "^1.6.3",
|
|
26
27
|
"@endo/errors": "^1.2.13",
|
|
@@ -33,15 +34,16 @@
|
|
|
33
34
|
"@endo/patterns": "^1.7.0",
|
|
34
35
|
"@endo/promise-kit": "^1.1.13",
|
|
35
36
|
"@endo/stream": "^1.2.13",
|
|
36
|
-
"
|
|
37
|
+
"import-meta-resolve": "^4.1.0",
|
|
37
38
|
"jessie.js": "^0.3.4"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
|
-
"@agoric/cosmic-proto": "0.5.0",
|
|
41
|
+
"@agoric/cosmic-proto": "0.5.1-upgrade-23-dev-bd79330.0.bd79330",
|
|
41
42
|
"@endo/exo": "^1.5.12",
|
|
42
43
|
"@endo/init": "^1.1.12",
|
|
44
|
+
"@endo/ses-ava": "^1.3.2",
|
|
43
45
|
"@fast-check/ava": "^2.0.1",
|
|
44
|
-
"ava": "^
|
|
46
|
+
"ava": "^6.4.1",
|
|
45
47
|
"tsd": "^0.33.0"
|
|
46
48
|
},
|
|
47
49
|
"ava": {
|
|
@@ -56,13 +58,13 @@
|
|
|
56
58
|
"license": "Apache-2.0",
|
|
57
59
|
"files": [
|
|
58
60
|
"src",
|
|
59
|
-
"
|
|
61
|
+
"vendor"
|
|
60
62
|
],
|
|
61
63
|
"publishConfig": {
|
|
62
64
|
"access": "public"
|
|
63
65
|
},
|
|
64
66
|
"typeCoverage": {
|
|
65
|
-
"atLeast":
|
|
67
|
+
"atLeast": 92.84
|
|
66
68
|
},
|
|
67
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "bd79330f78dae2faf9cc3d8b10063567700da07b"
|
|
68
70
|
}
|
package/src/action-types.d.ts
CHANGED
|
@@ -11,14 +11,28 @@
|
|
|
11
11
|
* - ../../cosmic-swingset/src/launch-chain.js
|
|
12
12
|
*/
|
|
13
13
|
export type SwingsetMessageType = (typeof SwingsetMessageType)[keyof typeof SwingsetMessageType];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Types of messages used for communication between a cosmos-sdk blockchain node
|
|
16
|
+
* and its paired swingset VM, especially for the ABCI lifecycle. See:
|
|
17
|
+
*
|
|
18
|
+
* - https://github.com/tendermint/tendermint/blob/v0.34.x/spec/abci/abci.md#block-execution
|
|
19
|
+
* - ../../../golang/cosmos/vm/action.go
|
|
20
|
+
* - ../../../golang/cosmos/app/app.go
|
|
21
|
+
* - ../../../golang/cosmos/x/swingset/abci.go
|
|
22
|
+
* - ../../../golang/cosmos/x/swingset/keeper/swing_store_exports_handler.go
|
|
23
|
+
* - ../../cosmic-swingset/src/chain-main.js
|
|
24
|
+
* - ../../cosmic-swingset/src/launch-chain.js
|
|
25
|
+
*
|
|
26
|
+
* @enum {(typeof SwingsetMessageType)[keyof typeof SwingsetMessageType]}
|
|
27
|
+
*/
|
|
28
|
+
export const SwingsetMessageType: import("./keyMirror.js").KeyMirrorResult<{
|
|
29
|
+
AG_COSMOS_INIT: null;
|
|
30
|
+
BEGIN_BLOCK: null;
|
|
31
|
+
END_BLOCK: null;
|
|
32
|
+
COMMIT_BLOCK: null;
|
|
33
|
+
AFTER_COMMIT_BLOCK: null;
|
|
34
|
+
SWING_STORE_EXPORT: null;
|
|
35
|
+
}>;
|
|
22
36
|
export const AG_COSMOS_INIT: "AG_COSMOS_INIT";
|
|
23
37
|
export const BEGIN_BLOCK: "BEGIN_BLOCK";
|
|
24
38
|
export const END_BLOCK: "END_BLOCK";
|
|
@@ -37,18 +51,31 @@ export const SWING_STORE_EXPORT: "SWING_STORE_EXPORT";
|
|
|
37
51
|
* - ../../../golang/cosmos/x/vibc/types/ibc_module.go
|
|
38
52
|
*/
|
|
39
53
|
export type QueuedActionType = (typeof QueuedActionType)[keyof typeof QueuedActionType];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
54
|
+
/**
|
|
55
|
+
* Types of "action" messages consumed by the swingset VM from actionQueue or
|
|
56
|
+
* highPriorityQueue during END_BLOCK. See:
|
|
57
|
+
*
|
|
58
|
+
* - ../../../golang/cosmos/x/swingset/keeper/msg_server.go
|
|
59
|
+
* - ../../../golang/cosmos/x/swingset/keeper/proposal.go
|
|
60
|
+
* - ../../../golang/cosmos/x/vbank/vbank.go
|
|
61
|
+
* - ../../../golang/cosmos/x/vibc/handler.go
|
|
62
|
+
* - ../../../golang/cosmos/x/vibc/keeper/triggers.go
|
|
63
|
+
* - ../../../golang/cosmos/x/vibc/types/ibc_module.go
|
|
64
|
+
*
|
|
65
|
+
* @enum {(typeof QueuedActionType)[keyof typeof QueuedActionType]}
|
|
66
|
+
*/
|
|
67
|
+
export const QueuedActionType: import("./keyMirror.js").KeyMirrorResult<{
|
|
68
|
+
CORE_EVAL: null;
|
|
69
|
+
DELIVER_INBOUND: null;
|
|
70
|
+
IBC_EVENT: null;
|
|
71
|
+
INSTALL_BUNDLE: null;
|
|
72
|
+
PLEASE_PROVISION: null;
|
|
73
|
+
VBANK_BALANCE_UPDATE: null;
|
|
74
|
+
WALLET_ACTION: null;
|
|
75
|
+
WALLET_SPEND_ACTION: null;
|
|
76
|
+
VTRANSFER_IBC_EVENT: null;
|
|
77
|
+
KERNEL_UPGRADE_EVENTS: null;
|
|
78
|
+
}>;
|
|
52
79
|
export const CORE_EVAL: "CORE_EVAL";
|
|
53
80
|
export const DELIVER_INBOUND: "DELIVER_INBOUND";
|
|
54
81
|
export const IBC_EVENT: "IBC_EVENT";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-types.d.ts","sourceRoot":"","sources":["action-types.js"],"names":[],"mappings":";;;;;;;;;;;;kCAcU,CAAC,OAAO,mBAAmB,EAAE,MAAM,OAAO,mBAAmB,CAAC
|
|
1
|
+
{"version":3,"file":"action-types.d.ts","sourceRoot":"","sources":["action-types.js"],"names":[],"mappings":";;;;;;;;;;;;kCAcU,CAAC,OAAO,mBAAmB,EAAE,MAAM,OAAO,mBAAmB,CAAC;AAZxE;;;;;;;;;;;;;GAaG;AACH;;;;;;;GAOG;;;;;;;;;;;;;;;;;;+BAwBO,CAAC,OAAO,gBAAgB,EAAE,MAAM,OAAO,gBAAgB,CAAC;AAXlE;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;GAWG"}
|
package/src/action-types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { keyMirror } from './keyMirror.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Types of messages used for communication between a cosmos-sdk blockchain node
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @enum {(typeof SwingsetMessageType)[keyof typeof SwingsetMessageType]}
|
|
16
16
|
*/
|
|
17
|
-
export const SwingsetMessageType =
|
|
18
|
-
AG_COSMOS_INIT:
|
|
19
|
-
BEGIN_BLOCK:
|
|
20
|
-
END_BLOCK:
|
|
21
|
-
COMMIT_BLOCK:
|
|
22
|
-
AFTER_COMMIT_BLOCK:
|
|
23
|
-
SWING_STORE_EXPORT:
|
|
17
|
+
export const SwingsetMessageType = keyMirror({
|
|
18
|
+
AG_COSMOS_INIT: null, // used to synchronize at process launch
|
|
19
|
+
BEGIN_BLOCK: null,
|
|
20
|
+
END_BLOCK: null,
|
|
21
|
+
COMMIT_BLOCK: null,
|
|
22
|
+
AFTER_COMMIT_BLOCK: null,
|
|
23
|
+
SWING_STORE_EXPORT: null, // used to synchronize data export
|
|
24
24
|
});
|
|
25
25
|
harden(SwingsetMessageType);
|
|
26
26
|
|
|
@@ -47,17 +47,17 @@ export const {
|
|
|
47
47
|
*
|
|
48
48
|
* @enum {(typeof QueuedActionType)[keyof typeof QueuedActionType]}
|
|
49
49
|
*/
|
|
50
|
-
export const QueuedActionType =
|
|
51
|
-
CORE_EVAL:
|
|
52
|
-
DELIVER_INBOUND:
|
|
53
|
-
IBC_EVENT:
|
|
54
|
-
INSTALL_BUNDLE:
|
|
55
|
-
PLEASE_PROVISION:
|
|
56
|
-
VBANK_BALANCE_UPDATE:
|
|
57
|
-
WALLET_ACTION:
|
|
58
|
-
WALLET_SPEND_ACTION:
|
|
59
|
-
VTRANSFER_IBC_EVENT:
|
|
60
|
-
KERNEL_UPGRADE_EVENTS:
|
|
50
|
+
export const QueuedActionType = keyMirror({
|
|
51
|
+
CORE_EVAL: null,
|
|
52
|
+
DELIVER_INBOUND: null,
|
|
53
|
+
IBC_EVENT: null,
|
|
54
|
+
INSTALL_BUNDLE: null,
|
|
55
|
+
PLEASE_PROVISION: null,
|
|
56
|
+
VBANK_BALANCE_UPDATE: null,
|
|
57
|
+
WALLET_ACTION: null,
|
|
58
|
+
WALLET_SPEND_ACTION: null,
|
|
59
|
+
VTRANSFER_IBC_EVENT: null,
|
|
60
|
+
KERNEL_UPGRADE_EVENTS: null,
|
|
61
61
|
});
|
|
62
62
|
harden(QueuedActionType);
|
|
63
63
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ava-force-exit.d.mts","sourceRoot":"","sources":["ava-force-exit.mjs"],"names":[],"mappings":""}
|
package/src/batched-deliver.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* @param {DeliverMessages} deliver
|
|
6
6
|
* @param {{
|
|
7
|
-
* clearTimeout:
|
|
8
|
-
* setTimeout:
|
|
7
|
+
* clearTimeout: clearTimeout;
|
|
8
|
+
* setTimeout: setTimeout;
|
|
9
9
|
* }} io
|
|
10
10
|
* @param {number} batchTimeoutMs
|
|
11
11
|
*/
|
|
@@ -13,6 +13,10 @@ export function makeBatchedDeliver(deliver: DeliverMessages, { clearTimeout, set
|
|
|
13
13
|
clearTimeout: typeof globalThis.clearTimeout;
|
|
14
14
|
setTimeout: typeof globalThis.setTimeout;
|
|
15
15
|
}, batchTimeoutMs?: number): (message: unknown[], ackNum: number) => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* @import {clearTimeout} from 'node:timers';
|
|
18
|
+
* @import {setTimeout} from 'node:timers';
|
|
19
|
+
*/
|
|
16
20
|
export const DEFAULT_BATCH_TIMEOUT_MS: 1000;
|
|
17
21
|
export type DeliverMessages = (message: unknown[], ackNum: number) => Promise<void>;
|
|
18
22
|
//# sourceMappingURL=batched-deliver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batched-deliver.d.ts","sourceRoot":"","sources":["batched-deliver.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"batched-deliver.d.ts","sourceRoot":"","sources":["batched-deliver.js"],"names":[],"mappings":"AASA;;GAEG;AAEH;;;;;;;GAOG;AACH,4CAPW,eAAe,gCACf;IACN,YAAY,iCAAe;IAC3B,UAAU,+BAAa;CACxB,mBACO,MAAM,aATM,OAAO,EAAE,UAAU,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAiDjE;AAzDD;;;GAGG;AAEH,uCAAwC,IAAI,CAAC;8BAGhC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC"}
|
package/src/batched-deliver.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
// @jessie-check
|
|
2
1
|
// @ts-check
|
|
3
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @import {clearTimeout} from 'node:timers';
|
|
5
|
+
* @import {setTimeout} from 'node:timers';
|
|
6
|
+
*/
|
|
7
|
+
|
|
4
8
|
export const DEFAULT_BATCH_TIMEOUT_MS = 1000;
|
|
5
9
|
|
|
6
10
|
/**
|
|
@@ -10,8 +14,8 @@ export const DEFAULT_BATCH_TIMEOUT_MS = 1000;
|
|
|
10
14
|
/**
|
|
11
15
|
* @param {DeliverMessages} deliver
|
|
12
16
|
* @param {{
|
|
13
|
-
* clearTimeout:
|
|
14
|
-
* setTimeout:
|
|
17
|
+
* clearTimeout: clearTimeout;
|
|
18
|
+
* setTimeout: setTimeout;
|
|
15
19
|
* }} io
|
|
16
20
|
* @param {number} batchTimeoutMs
|
|
17
21
|
*/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface LockLifecycleEvent {
|
|
2
|
+
key: string;
|
|
3
|
+
lockPath: string;
|
|
4
|
+
type: 'lock-acquired' | 'lock-released';
|
|
5
|
+
}
|
|
6
|
+
export interface LockWaitingEvent {
|
|
7
|
+
key: string;
|
|
8
|
+
lockPath: string;
|
|
9
|
+
type: 'lock-waiting';
|
|
10
|
+
waitedMs: number;
|
|
11
|
+
}
|
|
12
|
+
export interface LockBrokenEvent {
|
|
13
|
+
ageMs?: number;
|
|
14
|
+
key: string;
|
|
15
|
+
lockPath: string;
|
|
16
|
+
ownerPid?: number;
|
|
17
|
+
reason: 'dead-owner' | 'stale-age';
|
|
18
|
+
staleLockMs?: number;
|
|
19
|
+
type: 'lock-broken';
|
|
20
|
+
}
|
|
21
|
+
export type BuildCacheEvent = LockLifecycleEvent | LockWaitingEvent | LockBrokenEvent;
|
|
22
|
+
export interface DirectoryLockPowers {
|
|
23
|
+
acquireTimeoutMs: number;
|
|
24
|
+
delayMs: (ms: number) => Promise<unknown>;
|
|
25
|
+
fs: Pick<typeof import('node:fs/promises'), 'mkdir' | 'readFile' | 'rm' | 'stat' | 'writeFile'>;
|
|
26
|
+
isPidAlive: (pid: number) => boolean;
|
|
27
|
+
lockRoot: string;
|
|
28
|
+
now: () => number;
|
|
29
|
+
onEvent?: (event: BuildCacheEvent) => void;
|
|
30
|
+
pid: number;
|
|
31
|
+
staleLockMs: number;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=build-cache-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-cache-types.d.ts","sourceRoot":"","sources":["build-cache-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,eAAe,GAAG,eAAe,CAAC;CACzC;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,GAAG,WAAW,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GACvB,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,EAAE,EAAE,IAAI,CACN,cAAc,kBAAkB,CAAC,EACjC,OAAO,GAAG,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,WAAW,CACnD,CAAC;IACF,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function makeDirectoryLock(powers: DirectoryLockPowers): {
|
|
2
|
+
withLock: (key: string, body: () => Promise<any>) => Promise<any>;
|
|
3
|
+
};
|
|
4
|
+
export function writeFileAtomic({ fs, filePath, data, now, pid }: {
|
|
5
|
+
fs: Pick<typeof import("node:fs/promises"), "rename" | "writeFile">;
|
|
6
|
+
filePath: string;
|
|
7
|
+
data: string;
|
|
8
|
+
now: () => number;
|
|
9
|
+
pid: number;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
import type { DirectoryLockPowers } from './build-cache-types.js';
|
|
12
|
+
//# sourceMappingURL=build-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-cache.d.ts","sourceRoot":"","sources":["build-cache.js"],"names":[],"mappings":"AAUO,0CAFI,mBAAmB;oBAkEjB,MAAM,QACN,MAAM,OAAO,CAAC,GAAG,CAAC;EAsF9B;AAgBM,kEAVI;IACN,EAAE,EAAE,IAAI,CAAC,iCAA0B,EAAE,QAAQ,GAAG,WAAW,CAAC,CAAC;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb,iBASH;yCAlLsD,wBAAwB"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/* eslint-env node */
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @import {BuildCacheEvent, DirectoryLockPowers} from './build-cache-types.js';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {DirectoryLockPowers} powers
|
|
10
|
+
*/
|
|
11
|
+
export const makeDirectoryLock = powers => {
|
|
12
|
+
const {
|
|
13
|
+
fs,
|
|
14
|
+
delayMs,
|
|
15
|
+
now,
|
|
16
|
+
pid,
|
|
17
|
+
isPidAlive,
|
|
18
|
+
lockRoot,
|
|
19
|
+
staleLockMs,
|
|
20
|
+
acquireTimeoutMs,
|
|
21
|
+
onEvent = () => {},
|
|
22
|
+
} = powers;
|
|
23
|
+
const safeEmit = event => {
|
|
24
|
+
try {
|
|
25
|
+
onEvent(event);
|
|
26
|
+
} catch {
|
|
27
|
+
// Event sinks must not interfere with cache lock correctness.
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** @param {string} dpath */
|
|
32
|
+
const mkdirUnlessExists = async dpath => {
|
|
33
|
+
await null; // avoid accidentally catching synchronous exceptions
|
|
34
|
+
try {
|
|
35
|
+
await fs.mkdir(dpath);
|
|
36
|
+
return true;
|
|
37
|
+
} catch (err) {
|
|
38
|
+
const e = /** @type {NodeJS.ErrnoException} */ (err);
|
|
39
|
+
if (e.code === 'EEXIST') {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** @param {string} fpath */
|
|
47
|
+
const statUnlessMissing = async fpath => {
|
|
48
|
+
await null; // avoid accidentally catching synchronous exceptions
|
|
49
|
+
try {
|
|
50
|
+
return await fs.stat(fpath);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const e = /** @type {NodeJS.ErrnoException} */ (err);
|
|
53
|
+
if (e.code === 'ENOENT') {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** @param {string} fpath */
|
|
61
|
+
const readUnlessMissing = async fpath => {
|
|
62
|
+
await null; // avoid accidentally catching synchronous exceptions
|
|
63
|
+
try {
|
|
64
|
+
return await fs.readFile(fpath, 'utf8');
|
|
65
|
+
} catch (err) {
|
|
66
|
+
const e = /** @type {NodeJS.ErrnoException} */ (err);
|
|
67
|
+
if (e.code === 'ENOENT') {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @param {string} key
|
|
76
|
+
* @param {() => Promise<any>} body
|
|
77
|
+
*/
|
|
78
|
+
const withLock = async (key, body) => {
|
|
79
|
+
const lockPath = path.join(lockRoot, `${encodeURIComponent(key)}.lock`);
|
|
80
|
+
const ownerPath = path.join(lockPath, 'owner.json');
|
|
81
|
+
await fs.mkdir(lockRoot, { recursive: true });
|
|
82
|
+
const started = now();
|
|
83
|
+
|
|
84
|
+
const maybeBreakStaleLock = async () => {
|
|
85
|
+
const ownerText = await readUnlessMissing(ownerPath);
|
|
86
|
+
if (ownerText) {
|
|
87
|
+
try {
|
|
88
|
+
const ownerInfo = JSON.parse(ownerText);
|
|
89
|
+
if (
|
|
90
|
+
ownerInfo &&
|
|
91
|
+
typeof ownerInfo === 'object' &&
|
|
92
|
+
Number.isInteger(ownerInfo.pid) &&
|
|
93
|
+
!isPidAlive(ownerInfo.pid)
|
|
94
|
+
) {
|
|
95
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
96
|
+
safeEmit({
|
|
97
|
+
type: 'lock-broken',
|
|
98
|
+
key,
|
|
99
|
+
lockPath,
|
|
100
|
+
reason: 'dead-owner',
|
|
101
|
+
ownerPid: ownerInfo.pid,
|
|
102
|
+
});
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// rely on age-based lock breaking for malformed owner files
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const lockStats = await statUnlessMissing(lockPath);
|
|
111
|
+
if (!lockStats) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
const ageMs = now() - lockStats.mtimeMs;
|
|
115
|
+
if (ageMs >= staleLockMs) {
|
|
116
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
117
|
+
safeEmit({
|
|
118
|
+
type: 'lock-broken',
|
|
119
|
+
key,
|
|
120
|
+
lockPath,
|
|
121
|
+
reason: 'stale-age',
|
|
122
|
+
ageMs,
|
|
123
|
+
staleLockMs,
|
|
124
|
+
});
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return false;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
for (;;) {
|
|
132
|
+
if (await mkdirUnlessExists(lockPath)) {
|
|
133
|
+
await fs.writeFile(
|
|
134
|
+
ownerPath,
|
|
135
|
+
JSON.stringify({ pid, createdAt: now() }),
|
|
136
|
+
'utf8',
|
|
137
|
+
);
|
|
138
|
+
safeEmit({ type: 'lock-acquired', key, lockPath });
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
const recovered = await maybeBreakStaleLock();
|
|
142
|
+
if (recovered) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const waitedMs = now() - started;
|
|
146
|
+
safeEmit({ type: 'lock-waiting', key, lockPath, waitedMs });
|
|
147
|
+
if (waitedMs >= acquireTimeoutMs) {
|
|
148
|
+
throw Error(`Timed out waiting for cache lock ${lockPath}`);
|
|
149
|
+
}
|
|
150
|
+
await delayMs(20);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
return await body();
|
|
155
|
+
} finally {
|
|
156
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
157
|
+
safeEmit({ type: 'lock-released', key, lockPath });
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return harden({ withLock });
|
|
162
|
+
};
|
|
163
|
+
harden(makeDirectoryLock);
|
|
164
|
+
|
|
165
|
+
let atomicWriteSequence = 0;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {{
|
|
169
|
+
* fs: Pick<import('node:fs/promises'), 'rename' | 'writeFile'>;
|
|
170
|
+
* filePath: string;
|
|
171
|
+
* data: string;
|
|
172
|
+
* now: () => number;
|
|
173
|
+
* pid: number;
|
|
174
|
+
* }} options
|
|
175
|
+
* @throws {NodeJS.ErrnoException} when a unique temp file cannot be created
|
|
176
|
+
* or the atomic rename fails.
|
|
177
|
+
*/
|
|
178
|
+
export const writeFileAtomic = async ({ fs, filePath, data, now, pid }) => {
|
|
179
|
+
atomicWriteSequence += 1;
|
|
180
|
+
const tempPath = `${filePath}.${pid}.${now()}.${atomicWriteSequence}.tmp`;
|
|
181
|
+
await fs.writeFile(tempPath, data, { flag: 'wx' });
|
|
182
|
+
await fs.rename(tempPath, filePath);
|
|
183
|
+
};
|
|
184
|
+
harden(writeFileAtomic);
|
package/src/callback.d.ts
CHANGED
|
@@ -5,26 +5,24 @@ export function makeFunctionCallback<I extends (...args: any[]) => any, T extend
|
|
|
5
5
|
export function makeSyncMethodCallback<I extends (...args: any[]) => any, P extends PropertyKey, T extends { [x in P]: (...args: [...B, ...Parameters<I>]) => ReturnType<I>; } = { [x in P]: I; }, B extends any[] = []>(target: T, methodName: P, ...bound: B): SyncCallback<I>;
|
|
6
6
|
export function makeMethodCallback<I extends (...args: any[]) => any, P extends PropertyKey, T extends ERef<{ [x in P]: (...args: [...B, ...Parameters<I>]) => ReturnType<I>; }> = ERef<{ [x in P]: I; }>, B extends any[] = []>(target: T, methodName: P, ...bound: B): Callback<I>;
|
|
7
7
|
export function isCallback(callback: any): callback is Callback<any>;
|
|
8
|
-
export function prepareAttenuator<M extends PropertyKey>(zone:
|
|
9
|
-
interfaceGuard?:
|
|
8
|
+
export function prepareAttenuator<M extends PropertyKey>(zone: Zone, methodNames: M[], { interfaceGuard, tag }?: {
|
|
9
|
+
interfaceGuard?: InterfaceGuard<{ [K in M]: MethodGuard; }> | undefined;
|
|
10
10
|
tag?: string | undefined;
|
|
11
11
|
}): (args_0: {
|
|
12
12
|
target?: any;
|
|
13
13
|
isSync?: boolean | undefined;
|
|
14
14
|
overrides?: { [K_1 in M]?: Callback<any> | null | undefined; } | undefined;
|
|
15
15
|
}) => import("@endo/exo").Guarded<{ [K_2 in M]: (this: any, ...args: any[]) => any; }>;
|
|
16
|
-
export function prepareGuardedAttenuator<G extends
|
|
16
|
+
export function prepareGuardedAttenuator<G extends InterfaceGuard>(zone: Zone, interfaceGuard: G, opts?: {
|
|
17
17
|
tag?: string | undefined;
|
|
18
18
|
}): MakeAttenuator<any>;
|
|
19
|
-
export type MakeAttenuator<T extends
|
|
20
|
-
interfaceGuard?: import("@endo/patterns").InterfaceGuard<{ [K in M]: import("@endo/patterns").MethodGuard; }> | undefined;
|
|
21
|
-
tag?: string | undefined;
|
|
22
|
-
}) => (args_0: {
|
|
23
|
-
target?: any;
|
|
24
|
-
isSync?: boolean | undefined;
|
|
25
|
-
overrides?: { [K_1 in M]?: Callback<any> | null | undefined; } | undefined;
|
|
26
|
-
}) => import("@endo/exo").Guarded<{ [K_2 in M]: (this: any, ...args: any[]) => any; }>)>>) => import("@endo/exo").Farable<T>;
|
|
19
|
+
export type MakeAttenuator<T extends Methods> = (...args: Parameters<ReturnType<typeof prepareAttenuator>>) => Farable<T>;
|
|
27
20
|
import type { SyncCallback } from './types.js';
|
|
28
21
|
import type { Callback } from './types.js';
|
|
29
22
|
import type { ERef } from '@endo/far';
|
|
23
|
+
import type { Zone } from '@agoric/base-zone';
|
|
24
|
+
import type { MethodGuard } from '@endo/patterns';
|
|
25
|
+
import type { InterfaceGuard } from '@endo/patterns';
|
|
26
|
+
import type { Methods } from '@endo/exo';
|
|
27
|
+
import type { Farable } from '@endo/exo';
|
|
30
28
|
//# sourceMappingURL=callback.d.ts.map
|
package/src/callback.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["callback.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["callback.js"],"names":[],"mappings":"AAuDO,yBALgC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,YAC3B,aAAa,CAAC,CAAC,WACf,UAAU,CAAC,CAAC,CAAC,GACX,UAAU,CAAC,CAAC,CAAC,CAQzB;AAWM,sBALgC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,YAC3B,SAAS,CAAC,CAAC,WACX,UAAU,CAAC,CAAC,CAAC,GACX,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAQ3C;AAaM,yCAPgC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,EAC+B,CAAC,SAAzD,CAAE,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAE,MAC7C,CAAC,SAAT,GAAG,EAAG,eACT,CAAC,YACD,CAAC,GACC,aAAa,CAAC,CAAC,CAQ3B;AAaM,qCAPgC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,EACqC,CAAC,SAA/D,KAAM,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAE,YACnD,CAAC,SAAT,GAAG,EAAG,eACT,CAAC,YACD,CAAC,GACC,SAAS,CAAC,CAAC,CAQvB;AAiBM,uCAXgC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,EACX,CAAC,SAAd,WAAY,EAGnB,CAAC,SAFK,GACP,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,GAC9D,MAAO,CAAC,cACS,CAAC,SAAT,GAAG,EAAG,eACT,CAAC,cACD,CAAC,YACD,CAAC,GACC,aAAa,CAAC,CAAC,CAW3B;AAiBM,mCAXgC,CAAC,SAA3B,CAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAI,EACX,CAAC,SAAd,WAAY,EAGlB,CAAC,SAFI,KAAM,GACb,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,GAC/D,CAAE,WAAY,CAAC,eACG,CAAC,SAAT,GAAG,EAAG,eACT,CAAC,cACD,CAAC,YACD,CAAC,GACC,SAAS,CAAC,CAAC,CAWvB;AAOM,qCAHI,GAAG,GACD,QAAQ,IAAI,SAAS,GAAG,CAAC,CAcrC;AAgBM,kCAVoB,CAAC,SAAd,WAAY,QACf,IAAI,eACJ,CAAC,EAAE,4BAEX;IAEU,cAAc,qBADrB,CAAC;IAGkB,GAAG;CAC3B;aAgEc,GAAG;;;uDArDgB,GAAG,WAAW,GAAG,EAAE,KAAK,GAAG,KAwF5D;AAYM,yCANuB,CAAC,SAAlB,cAAgB,QAClB,IAAI,kBACJ,CAAC,SAET;IAAsB,GAAG;CAAC,GAQT,cAAc,CAAC,GAAG,CAAC,CACtC;2BAvSsB,CAAC,SAAX,OAAS,IACT,CACZ,GAAO,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,KACtD,QAAQ,CAAC,CAAC;kCAdwB,YAAY;8BAAZ,YAAY;0BAP/B,WAAW;0BAGX,mBAAmB;iCAEZ,gBAAgB;oCADb,gBAAgB;6BAHvB,WAAW;6BACX,WAAW"}
|