@agoric/casting 0.4.2 → 0.4.3-calypso-dev-84eb287.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/README.md +3 -3
- package/package.json +25 -22
- package/src/casting-spec.d.ts +8 -8
- package/src/casting-spec.d.ts.map +1 -1
- package/src/casting-spec.js +7 -9
- package/src/change-follower.d.ts +1 -1
- package/src/change-follower.d.ts.map +1 -1
- package/src/change-follower.js +2 -2
- package/src/defaults.d.ts +2 -2
- package/src/defaults.d.ts.map +1 -1
- package/src/defaults.js +1 -1
- package/src/follower-cosmjs.d.ts +1 -1
- package/src/follower-cosmjs.d.ts.map +1 -1
- package/src/follower-cosmjs.js +39 -15
- package/src/follower.d.ts +1 -1
- package/src/follower.d.ts.map +1 -1
- package/src/follower.js +6 -6
- package/src/iterable.d.ts +12 -12
- package/src/iterable.d.ts.map +1 -1
- package/src/iterable.js +2 -1
- package/src/leader-netconfig.d.ts +2 -2
- package/src/leader-netconfig.d.ts.map +1 -1
- package/src/leader.d.ts +1 -1
- package/src/main.js +2 -0
- package/src/makeHttpClient.d.ts +2 -0
- package/src/makeHttpClient.d.ts.map +1 -0
- package/src/makeHttpClient.js +56 -0
- package/src/netconfig.d.ts.map +1 -1
- package/src/shuffle.d.ts +1 -1
- package/src/shuffle.d.ts.map +1 -1
- package/src/types.d.ts +13 -7
- package/src/types.d.ts.map +1 -1
- package/src/types.js +11 -8
- package/test/interpose-net-access.test.js +118 -0
- package/test/{test-mvp.js → mvp.test.js} +57 -1
- package/test/net-access-fixture.js +196 -0
- package/tsconfig.build.json +6 -0
- package/{jsconfig.json → tsconfig.json} +1 -0
- package/jsconfig.build.json +0 -12
- /package/test/{test-netconfig.js → netconfig.test.js} +0 -0
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ The `followerOpts` argument in `makeFollower(leader, key, followerOpts)` provide
|
|
|
42
42
|
- the `decode` option is a function to translate `buf: Uint8Array` into `data: string`
|
|
43
43
|
- (default) - interpret buf as a utf-8 string, then `JSON.parse` it
|
|
44
44
|
- the `unserializer` option can be
|
|
45
|
-
- (default) - release unserialized objects using
|
|
45
|
+
- (default) - release unserialized objects using [@endo/marshal](https://www.npmjs.com/package/@endo/marshal)'s `makeMarshal()`
|
|
46
46
|
- `null` - don't additionally unserialize data before releasing it
|
|
47
47
|
- any unserializer object supporting `E(unserializer).fromCapData(data)`
|
|
48
48
|
- the `crasher` option can be
|
|
@@ -65,8 +65,8 @@ The `followerOpts` argument in `makeFollower(leader, key, followerOpts)` provide
|
|
|
65
65
|
|
|
66
66
|
This package currently depends on:
|
|
67
67
|
- Hardened Javascript
|
|
68
|
-
-
|
|
69
|
-
-
|
|
68
|
+
- [@agoric/notifier](../notifier) async iterable adapters to implement `iterateLatest`
|
|
69
|
+
- [@endo/marshal](https://www.npmjs.com/package/@endo/marshal) for default object unserialization
|
|
70
70
|
- [CosmJS](https://github.com/cosmos/cosmjs) for proof verification, although [it does not yet support light client tracking of the validator set](https://github.com/cosmos/cosmjs/issues/492)
|
|
71
71
|
- a bespoke follower of [WebSocket Tendermint events](https://docs.tendermint.com/master/tendermint-core/subscription.html#legacy-streaming-api)
|
|
72
72
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/casting",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3-calypso-dev-84eb287.0+84eb287",
|
|
4
4
|
"description": "Agoric's OCap broadcasting system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.js",
|
|
7
7
|
"repository": "https://github.com/Agoric/agoric-sdk",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "exit 0",
|
|
10
|
-
"prepack": "tsc --build
|
|
10
|
+
"prepack": "tsc --build tsconfig.build.json",
|
|
11
11
|
"postpack": "git clean -f '*.d.ts*'",
|
|
12
12
|
"demo": "node -e 'import(\"./test/fake-rpc-server.js\").then(ns => ns.develop())'",
|
|
13
13
|
"test": "ava",
|
|
@@ -15,33 +15,33 @@
|
|
|
15
15
|
"test:xs": "exit 0",
|
|
16
16
|
"lint-fix": "yarn lint:eslint --fix",
|
|
17
17
|
"lint": "run-s --continue-on-error lint:*",
|
|
18
|
-
"lint:types": "tsc
|
|
18
|
+
"lint:types": "tsc",
|
|
19
19
|
"lint:eslint": "eslint --ext .js,.ts ."
|
|
20
20
|
},
|
|
21
21
|
"keywords": [],
|
|
22
22
|
"author": "Agoric",
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agoric/internal": "
|
|
26
|
-
"@agoric/notifier": "
|
|
27
|
-
"@agoric/
|
|
28
|
-
"@
|
|
29
|
-
"@cosmjs/
|
|
30
|
-
"@cosmjs/
|
|
31
|
-
"@cosmjs/
|
|
32
|
-
"@
|
|
33
|
-
"@endo/
|
|
34
|
-
"@endo/
|
|
35
|
-
"@endo/
|
|
36
|
-
"@endo/
|
|
37
|
-
"@endo/promise-kit": "^0.2.56",
|
|
25
|
+
"@agoric/internal": "0.3.3-calypso-dev-84eb287.0+84eb287",
|
|
26
|
+
"@agoric/notifier": "0.6.3-calypso-dev-84eb287.0+84eb287",
|
|
27
|
+
"@agoric/store": "0.9.3-calypso-dev-84eb287.0+84eb287",
|
|
28
|
+
"@cosmjs/encoding": "^0.32.3",
|
|
29
|
+
"@cosmjs/proto-signing": "^0.32.3",
|
|
30
|
+
"@cosmjs/stargate": "^0.32.3",
|
|
31
|
+
"@cosmjs/tendermint-rpc": "^0.32.3",
|
|
32
|
+
"@endo/far": "^1.1.2",
|
|
33
|
+
"@endo/init": "^1.1.2",
|
|
34
|
+
"@endo/lockdown": "^1.0.7",
|
|
35
|
+
"@endo/marshal": "^1.5.0",
|
|
36
|
+
"@endo/promise-kit": "^1.1.2",
|
|
38
37
|
"node-fetch": "^2.6.0"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
|
-
"@
|
|
40
|
+
"@agoric/cosmic-proto": "0.4.1-calypso-dev-84eb287.0+84eb287",
|
|
41
|
+
"@endo/ses-ava": "^1.2.2",
|
|
42
42
|
"@types/node-fetch": "^2.6.2",
|
|
43
|
-
"ava": "^5.
|
|
44
|
-
"c8": "^
|
|
43
|
+
"ava": "^5.3.0",
|
|
44
|
+
"c8": "^9.1.0",
|
|
45
45
|
"express": "^4.17.1",
|
|
46
46
|
"ws": "^7.2.0"
|
|
47
47
|
},
|
|
@@ -49,14 +49,17 @@
|
|
|
49
49
|
"access": "public"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
|
52
|
-
"node": "
|
|
52
|
+
"node": "^18.12 || ^20.9"
|
|
53
53
|
},
|
|
54
54
|
"ava": {
|
|
55
55
|
"files": [
|
|
56
|
-
"test
|
|
56
|
+
"test/**/*.test.*"
|
|
57
57
|
],
|
|
58
58
|
"timeout": "20m",
|
|
59
59
|
"workerThreads": false
|
|
60
60
|
},
|
|
61
|
-
"
|
|
61
|
+
"typeCoverage": {
|
|
62
|
+
"atLeast": 88.94
|
|
63
|
+
},
|
|
64
|
+
"gitHead": "84eb287915c8255d68e845a9b6e10c790f0d54cb"
|
|
62
65
|
}
|
package/src/casting-spec.d.ts
CHANGED
|
@@ -2,15 +2,15 @@ export function vstorageKeySpecToPath({ storeName, storeSubkey }: VStorageKey):
|
|
|
2
2
|
/**
|
|
3
3
|
* @param {string} storagePath
|
|
4
4
|
* @param {string} [storeName]
|
|
5
|
-
* @returns {import('./types').CastingSpec}
|
|
5
|
+
* @returns {import('./types.js').CastingSpec}
|
|
6
6
|
*/
|
|
7
|
-
export function DEFAULT_PATH_CONVERTER(storagePath: string, storeName?: string | undefined): import(
|
|
7
|
+
export function DEFAULT_PATH_CONVERTER(storagePath: string, storeName?: string | undefined): import("./types.js").CastingSpec;
|
|
8
8
|
/**
|
|
9
|
-
* @type {Record<string, (path: string) => import('./types').CastingSpec>}
|
|
9
|
+
* @type {Record<string, (path: string) => import('./types.js').CastingSpec>}
|
|
10
10
|
*/
|
|
11
|
-
export const pathPrefixToConverters: Record<string, (path: string) => import(
|
|
12
|
-
export function makeCastingSpecFromString(specString: string): import(
|
|
13
|
-
export function makeCastingSpecFromObject(specObj: any): import(
|
|
14
|
-
export function makeCastingSpecFromRef(specCap: ERef<any>): Promise<import(
|
|
15
|
-
export function makeCastingSpec(sourceP: ERef<unknown>): Promise<import(
|
|
11
|
+
export const pathPrefixToConverters: Record<string, (path: string) => import("./types.js").CastingSpec>;
|
|
12
|
+
export function makeCastingSpecFromString(specString: string): import("./types.js").CastingSpec;
|
|
13
|
+
export function makeCastingSpecFromObject(specObj: any): import("./types.js").CastingSpec;
|
|
14
|
+
export function makeCastingSpecFromRef(specCap: ERef<any>): Promise<import("./types.js").CastingSpec>;
|
|
15
|
+
export function makeCastingSpec(sourceP: ERef<unknown>): Promise<import("./types.js").CastingSpec>;
|
|
16
16
|
//# sourceMappingURL=casting-spec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"casting-spec.d.ts","sourceRoot":"","sources":["casting-spec.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"casting-spec.d.ts","sourceRoot":"","sources":["casting-spec.js"],"names":[],"mappings":"AA6CO,kEAHI,WAAW,GACT,MAAM,CAYlB;AAlCD;;;;GAIG;AACH,oDAJW,MAAM,mCAEJ,OAAO,YAAY,EAAE,WAAW,CAa5C;AAsBD;;GAEG;AACH,qCAFU,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,YAAY,EAAE,WAAW,CAAC,CAMzE;AAMI,sDAHI,MAAM,GACJ,OAAO,YAAY,EAAE,WAAW,CAc5C;AAQM,mDAHI,GAAG,GACD,OAAO,YAAY,EAAE,WAAW,CAmC5C;AAMM,gDAHI,IAAI,CAAC,GAAG,CAAC,GACP,OAAO,CAAC,OAAO,YAAY,EAAE,WAAW,CAAC,CAKrD;AAQM,yCAHI,IAAI,CAAC,OAAO,CAAC,GACX,OAAO,CAAC,OAAO,YAAY,EAAE,WAAW,CAAC,CAgBrD"}
|
package/src/casting-spec.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import * as encodingStar from '@cosmjs/encoding';
|
|
2
2
|
import { E, getInterfaceOf } from '@endo/far';
|
|
3
3
|
|
|
4
|
-
import './types.js';
|
|
5
|
-
|
|
6
4
|
const { toAscii } = encodingStar;
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
7
|
* @param {string} storagePath
|
|
10
|
-
* @returns {import('./types').CastingSpec}
|
|
8
|
+
* @returns {import('./types.js').CastingSpec}
|
|
11
9
|
*/
|
|
12
10
|
const swingsetPathToCastingSpec = storagePath =>
|
|
13
11
|
harden({
|
|
@@ -24,7 +22,7 @@ const NO_DATA_VALUE = new Uint8Array([255]);
|
|
|
24
22
|
/**
|
|
25
23
|
* @param {string} storagePath
|
|
26
24
|
* @param {string} [storeName]
|
|
27
|
-
* @returns {import('./types').CastingSpec}
|
|
25
|
+
* @returns {import('./types.js').CastingSpec}
|
|
28
26
|
*/
|
|
29
27
|
const vstoragePathToCastingSpec = (storagePath, storeName = 'vstorage') => {
|
|
30
28
|
const elems = storagePath ? storagePath.split('.') : [];
|
|
@@ -60,7 +58,7 @@ export const vstorageKeySpecToPath = ({ storeName, storeSubkey }) => {
|
|
|
60
58
|
export const DEFAULT_PATH_CONVERTER = vstoragePathToCastingSpec;
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
|
-
* @type {Record<string, (path: string) => import('./types').CastingSpec>}
|
|
61
|
+
* @type {Record<string, (path: string) => import('./types.js').CastingSpec>}
|
|
64
62
|
*/
|
|
65
63
|
export const pathPrefixToConverters = harden({
|
|
66
64
|
'swingset:': swingsetPathToCastingSpec,
|
|
@@ -70,7 +68,7 @@ export const pathPrefixToConverters = harden({
|
|
|
70
68
|
|
|
71
69
|
/**
|
|
72
70
|
* @param {string} specString
|
|
73
|
-
* @returns {import('./types').CastingSpec}
|
|
71
|
+
* @returns {import('./types.js').CastingSpec}
|
|
74
72
|
*/
|
|
75
73
|
export const makeCastingSpecFromString = specString => {
|
|
76
74
|
assert.typeof(specString, 'string');
|
|
@@ -90,7 +88,7 @@ const te = new TextEncoder();
|
|
|
90
88
|
|
|
91
89
|
/**
|
|
92
90
|
* @param {any} specObj
|
|
93
|
-
* @returns {import('./types').CastingSpec}
|
|
91
|
+
* @returns {import('./types.js').CastingSpec}
|
|
94
92
|
*/
|
|
95
93
|
export const makeCastingSpecFromObject = specObj => {
|
|
96
94
|
const {
|
|
@@ -129,7 +127,7 @@ export const makeCastingSpecFromObject = specObj => {
|
|
|
129
127
|
|
|
130
128
|
/**
|
|
131
129
|
* @param {ERef<any>} specCap
|
|
132
|
-
* @returns {Promise<import('./types').CastingSpec>}
|
|
130
|
+
* @returns {Promise<import('./types.js').CastingSpec>}
|
|
133
131
|
*/
|
|
134
132
|
export const makeCastingSpecFromRef = async specCap => {
|
|
135
133
|
const specObj = await E(specCap).getStoreKey();
|
|
@@ -140,7 +138,7 @@ export const makeCastingSpecFromRef = async specCap => {
|
|
|
140
138
|
* Create an abstract type from a given source representation
|
|
141
139
|
*
|
|
142
140
|
* @param {ERef<unknown>} sourceP
|
|
143
|
-
* @returns {Promise<import('./types').CastingSpec>}
|
|
141
|
+
* @returns {Promise<import('./types.js').CastingSpec>}
|
|
144
142
|
*/
|
|
145
143
|
export const makeCastingSpec = async sourceP => {
|
|
146
144
|
const spec = await sourceP;
|
package/src/change-follower.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function makePollingChangeFollower(leader: import(
|
|
1
|
+
export function makePollingChangeFollower(leader: import("./types.js").Leader): Promise<import("./types.js").Follower<import("./types.js").CastingChange>>;
|
|
2
2
|
//# sourceMappingURL=change-follower.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-follower.d.ts","sourceRoot":"","sources":["change-follower.js"],"names":[],"mappings":"AASO,kDAHI,OAAO,
|
|
1
|
+
{"version":3,"file":"change-follower.d.ts","sourceRoot":"","sources":["change-follower.js"],"names":[],"mappings":"AASO,kDAHI,OAAO,YAAY,EAAE,MAAM,GACzB,OAAO,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC,CAAC,CA6CtF"}
|
package/src/change-follower.js
CHANGED
|
@@ -4,8 +4,8 @@ import { DEFAULT_KEEP_POLLING } from './defaults.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Just return an unspecified allegedValue every poll period.
|
|
6
6
|
*
|
|
7
|
-
* @param {import('./types').Leader} leader
|
|
8
|
-
* @returns {Promise<import('./types.js').Follower<import('./types').CastingChange>>}
|
|
7
|
+
* @param {import('./types.js').Leader} leader
|
|
8
|
+
* @returns {Promise<import('./types.js').Follower<import('./types.js').CastingChange>>}
|
|
9
9
|
*/
|
|
10
10
|
export const makePollingChangeFollower = async leader => {
|
|
11
11
|
const { keepPolling = DEFAULT_KEEP_POLLING } = await E(leader).getOptions();
|
package/src/defaults.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export function MAKE_DEFAULT_DECODER(): (str: any) => any;
|
|
|
15
15
|
/**
|
|
16
16
|
* Unserialize the JSONable data.
|
|
17
17
|
*
|
|
18
|
-
* @type {() => import('./types').Unserializer}
|
|
18
|
+
* @type {() => import('./types.js').Unserializer}
|
|
19
19
|
*/
|
|
20
|
-
export const MAKE_DEFAULT_UNSERIALIZER: () => import(
|
|
20
|
+
export const MAKE_DEFAULT_UNSERIALIZER: () => import("./types.js").Unserializer;
|
|
21
21
|
//# sourceMappingURL=defaults.d.ts.map
|
package/src/defaults.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["defaults.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,yDAA0D;AAE1D,uCAAwC;AAExC,mDAAoD;AAEpD,6CAA8C;AAUvC,0BAHI,MAAM,GACJ,
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["defaults.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,yDAA0D;AAE1D,uCAAwC;AAExC,mDAAoD;AAEpD,6CAA8C;AAUvC,0BAHI,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAEgD;AAMnE,qCAHI,MAAM,oCAKhB;AAOM,8HAEN;AAQM,sCAHI,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAMzB;AAUM,8CALI,MAAM,OACN,GAAG,iCAED,OAAO,CAAC,IAAI,CAAC,CASzB;AAOM,wCAFM,OAAO,CAAC,OAAO,CAAC,CAGgD;AAEtE,0DAaN;AAED;;;;GAIG;AACH,wCAFU,MAAM,OAAO,YAAY,EAAE,YAAY,CA2B/C"}
|
package/src/defaults.js
CHANGED
|
@@ -95,7 +95,7 @@ export const MAKE_DEFAULT_DECODER = () => {
|
|
|
95
95
|
/**
|
|
96
96
|
* Unserialize the JSONable data.
|
|
97
97
|
*
|
|
98
|
-
* @type {() => import('./types').Unserializer}
|
|
98
|
+
* @type {() => import('./types.js').Unserializer}
|
|
99
99
|
*/
|
|
100
100
|
export const MAKE_DEFAULT_UNSERIALIZER = () => {
|
|
101
101
|
const ifaceAllegedPrefix = 'Alleged: ';
|
package/src/follower-cosmjs.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function makeCosmjsFollower<T>(sourceP: any, leaderOrMaker?: import("./types.js").LeaderOrMaker | undefined, options?: import("./types.js").FollowerOptions | undefined): ValueFollower<T>;
|
|
2
|
-
export type ValueFollower<T> = import(
|
|
2
|
+
export type ValueFollower<T> = import("./types.js").Follower<import("./types.js").ValueFollowerElement<T>>;
|
|
3
3
|
/**
|
|
4
4
|
* The response of an ABCI query to Tendermint.
|
|
5
5
|
* This is a subset of `tendermint34.AbciQueryResponse` in order
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"follower-cosmjs.d.ts","sourceRoot":"","sources":["follower-cosmjs.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"follower-cosmjs.d.ts","sourceRoot":"","sources":["follower-cosmjs.js"],"names":[],"mappings":"AAyGO,mCANM,CAAC,WACH,GAAG,+HAGD,aAAa,CAAC,CAAC,CAAC,CAsf5B;0BAnkBa,CAAC,IAAW,OAAO,YAAY,EAAE,QAAQ,CAAC,OAAO,YAAY,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;;;;;;iCAIxF;IACZ,QAAY,CAAC,KAAK,EAAE,UAAU,CAAC;IAC/B,QAAY,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB"}
|
package/src/follower-cosmjs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
/// <reference types="ses"/>
|
|
2
|
-
/* eslint-disable no-await-in-loop, @jessie.js/no-nested-await */
|
|
1
|
+
/// <reference types="ses" />
|
|
3
2
|
|
|
4
3
|
import { E, Far } from '@endo/far';
|
|
5
4
|
import * as tendermint34 from '@cosmjs/tendermint-rpc';
|
|
@@ -11,6 +10,15 @@ import { MAKE_DEFAULT_DECODER, MAKE_DEFAULT_UNSERIALIZER } from './defaults.js';
|
|
|
11
10
|
import { makeCastingSpec } from './casting-spec.js';
|
|
12
11
|
import { makeLeader as defaultMakeLeader } from './leader-netconfig.js';
|
|
13
12
|
|
|
13
|
+
// A lot of cosmjs classes end up hardened through instances shared by this
|
|
14
|
+
// package so preemptively harden them all.
|
|
15
|
+
// However we cannot directly harden a module namespace object (exotic behavior
|
|
16
|
+
// for bindings) so spread the namespace instead
|
|
17
|
+
harden({
|
|
18
|
+
tendermint34: { ...tendermint34 },
|
|
19
|
+
stargateStar: { ...stargateStar },
|
|
20
|
+
});
|
|
21
|
+
|
|
14
22
|
const { QueryClient } = stargateStar;
|
|
15
23
|
const { Tendermint34Client } = tendermint34;
|
|
16
24
|
const { details: X, quote: q, Fail } = assert;
|
|
@@ -91,8 +99,8 @@ const proofs = ['strict', 'none', 'optimistic'];
|
|
|
91
99
|
/**
|
|
92
100
|
* @template T
|
|
93
101
|
* @param {any} sourceP
|
|
94
|
-
* @param {import('./types').LeaderOrMaker} [leaderOrMaker]
|
|
95
|
-
* @param {import('./types').FollowerOptions} [options]
|
|
102
|
+
* @param {import('./types.js').LeaderOrMaker} [leaderOrMaker]
|
|
103
|
+
* @param {import('./types.js').FollowerOptions} [options]
|
|
96
104
|
* @returns {ValueFollower<T>}
|
|
97
105
|
*/
|
|
98
106
|
export const makeCosmjsFollower = (
|
|
@@ -240,6 +248,7 @@ export const makeCosmjsFollower = (
|
|
|
240
248
|
* @returns {Promise<QueryStoreResponse>}
|
|
241
249
|
*/
|
|
242
250
|
const tryGetDataAtHeight = async blockHeight => {
|
|
251
|
+
await null;
|
|
243
252
|
if (proof === 'strict') {
|
|
244
253
|
// Crash hard if we can't prove.
|
|
245
254
|
return getProvenDataAtHeight(blockHeight).catch(crash);
|
|
@@ -274,6 +283,7 @@ export const makeCosmjsFollower = (
|
|
|
274
283
|
* @param {number} [blockHeight] desired height, or the latest height if not set
|
|
275
284
|
*/
|
|
276
285
|
const getDataAtHeight = async blockHeight => {
|
|
286
|
+
await null;
|
|
277
287
|
for (let attempt = 0; ; attempt += 1) {
|
|
278
288
|
try {
|
|
279
289
|
// AWAIT
|
|
@@ -330,11 +340,16 @@ export const makeCosmjsFollower = (
|
|
|
330
340
|
blockHeight,
|
|
331
341
|
currentBlockHeight,
|
|
332
342
|
) => {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
343
|
+
await null;
|
|
344
|
+
try {
|
|
345
|
+
// AWAIT
|
|
346
|
+
const value = await /** @type {T} */ (
|
|
347
|
+
unserializer ? E(unserializer).fromCapData(data) : data
|
|
348
|
+
);
|
|
349
|
+
return { value, blockHeight, currentBlockHeight };
|
|
350
|
+
} catch (e) {
|
|
351
|
+
return { blockHeight, currentBlockHeight, error: e, value: undefined };
|
|
352
|
+
}
|
|
338
353
|
};
|
|
339
354
|
|
|
340
355
|
/**
|
|
@@ -351,6 +366,7 @@ export const makeCosmjsFollower = (
|
|
|
351
366
|
);
|
|
352
367
|
}
|
|
353
368
|
}
|
|
369
|
+
harden(allValuesFromCell);
|
|
354
370
|
|
|
355
371
|
/**
|
|
356
372
|
* @param {import('./types.js').StreamCell<T>} streamCell
|
|
@@ -366,6 +382,7 @@ export const makeCosmjsFollower = (
|
|
|
366
382
|
);
|
|
367
383
|
}
|
|
368
384
|
}
|
|
385
|
+
harden(reverseValuesFromCell);
|
|
369
386
|
|
|
370
387
|
/**
|
|
371
388
|
* @param {import('./types.js').StreamCell<T>} streamCell
|
|
@@ -383,6 +400,7 @@ export const makeCosmjsFollower = (
|
|
|
383
400
|
);
|
|
384
401
|
}
|
|
385
402
|
}
|
|
403
|
+
harden(lastValueFromCell);
|
|
386
404
|
|
|
387
405
|
/**
|
|
388
406
|
* @yields {ValueFollowerElement<T>}
|
|
@@ -391,6 +409,7 @@ export const makeCosmjsFollower = (
|
|
|
391
409
|
/** @type {number | undefined} the last known latest height */
|
|
392
410
|
let lastHeight;
|
|
393
411
|
let lastValue;
|
|
412
|
+
await null;
|
|
394
413
|
for (;;) {
|
|
395
414
|
const latest = await getDataAtHeight();
|
|
396
415
|
if (lastHeight && latest.height <= lastHeight) {
|
|
@@ -427,6 +446,7 @@ export const makeCosmjsFollower = (
|
|
|
427
446
|
lastValue = latest.value;
|
|
428
447
|
}
|
|
429
448
|
}
|
|
449
|
+
harden(getLatestIterable);
|
|
430
450
|
|
|
431
451
|
/**
|
|
432
452
|
* @param {number} [cursorBlockHeight]
|
|
@@ -441,11 +461,13 @@ export const makeCosmjsFollower = (
|
|
|
441
461
|
// block.
|
|
442
462
|
// If the block has no corresponding data, wait for the first block to
|
|
443
463
|
// contain data.
|
|
464
|
+
await null;
|
|
444
465
|
for (;;) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
466
|
+
let thisHeight;
|
|
467
|
+
({ value: cursorData, height: thisHeight } =
|
|
468
|
+
await getDataAtHeight(cursorBlockHeight));
|
|
448
469
|
if (cursorData.length !== 0) {
|
|
470
|
+
cursorBlockHeight = thisHeight;
|
|
449
471
|
const cursorStreamCell = streamCellForData(
|
|
450
472
|
cursorBlockHeight,
|
|
451
473
|
cursorData,
|
|
@@ -543,6 +565,7 @@ export const makeCosmjsFollower = (
|
|
|
543
565
|
cursorData = currentData;
|
|
544
566
|
}
|
|
545
567
|
}
|
|
568
|
+
harden(getEachIterableAtHeight);
|
|
546
569
|
|
|
547
570
|
/**
|
|
548
571
|
* @param {number} [cursorBlockHeight]
|
|
@@ -553,10 +576,10 @@ export const makeCosmjsFollower = (
|
|
|
553
576
|
// cursorBlockHeight) so we know not to emit duplicates
|
|
554
577
|
// of that cell.
|
|
555
578
|
let cursorData;
|
|
579
|
+
await null;
|
|
556
580
|
while (cursorBlockHeight === undefined || cursorBlockHeight > 0) {
|
|
557
|
-
({ value: cursorData, height: cursorBlockHeight } =
|
|
558
|
-
cursorBlockHeight
|
|
559
|
-
));
|
|
581
|
+
({ value: cursorData, height: cursorBlockHeight } =
|
|
582
|
+
await getDataAtHeight(cursorBlockHeight));
|
|
560
583
|
if (cursorData.length === 0) {
|
|
561
584
|
// No data at the cursor height, so signal beginning of stream.
|
|
562
585
|
return;
|
|
@@ -566,6 +589,7 @@ export const makeCosmjsFollower = (
|
|
|
566
589
|
cursorBlockHeight = cursorStreamCell.blockHeight - 1;
|
|
567
590
|
}
|
|
568
591
|
}
|
|
592
|
+
harden(getReverseIterableAtHeight);
|
|
569
593
|
|
|
570
594
|
/** @type {ValueFollower<T>} */
|
|
571
595
|
return Far('chain follower', {
|
package/src/follower.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function makeFollower<T>(specP: ERef<import(
|
|
1
|
+
export function makeFollower<T>(specP: ERef<import("./types.js").CastingSpec> | string, leaderOrMaker?: import("./types.js").LeaderOrMaker | undefined, options?: import("./types.js").FollowerOptions | undefined): Promise<import("./follower-cosmjs.js").ValueFollower<T>>;
|
|
2
2
|
//# sourceMappingURL=follower.d.ts.map
|
package/src/follower.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"follower.d.ts","sourceRoot":"","sources":["follower.js"],"names":[],"mappings":"AA4DO,
|
|
1
|
+
{"version":3,"file":"follower.d.ts","sourceRoot":"","sources":["follower.js"],"names":[],"mappings":"AA4DO,6BANM,CAAC,SACH,IAAI,CAAC,OAAO,YAAY,EAAE,WAAW,CAAC,GAAG,MAAM,+HAG7C,OAAO,CAAC,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CASpE"}
|
package/src/follower.js
CHANGED
|
@@ -11,12 +11,12 @@ import { makeCastingSpec } from './casting-spec.js';
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @template T
|
|
14
|
-
* @param {ERef<import('./types').CastingSpec>} spec
|
|
14
|
+
* @param {ERef<import('./types.js').CastingSpec>} spec
|
|
15
15
|
*/
|
|
16
16
|
const makeSubscriptionFollower = spec => {
|
|
17
17
|
const transform = value =>
|
|
18
18
|
harden({ value, blockHeight: NaN, currentBlockHeight: NaN });
|
|
19
|
-
/** @type {import('./types').Follower<import('./types.js').ValueFollowerElement<T>>} */
|
|
19
|
+
/** @type {import('./types.js').Follower<import('./types.js').ValueFollowerElement<T>>} */
|
|
20
20
|
const follower = Far('subscription/notifier follower', {
|
|
21
21
|
getLatestIterable: async () => {
|
|
22
22
|
const { notifier, subscription } = await spec;
|
|
@@ -53,10 +53,10 @@ const makeSubscriptionFollower = spec => {
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* @template T
|
|
56
|
-
* @param {ERef<import('./types').CastingSpec> | string} specP
|
|
57
|
-
* @param {import('./types').LeaderOrMaker} [leaderOrMaker]
|
|
58
|
-
* @param {import('./types').FollowerOptions} [options]
|
|
59
|
-
* @returns {Promise<import('./follower-cosmjs').ValueFollower<T>>}
|
|
56
|
+
* @param {ERef<import('./types.js').CastingSpec> | string} specP
|
|
57
|
+
* @param {import('./types.js').LeaderOrMaker} [leaderOrMaker]
|
|
58
|
+
* @param {import('./types.js').FollowerOptions} [options]
|
|
59
|
+
* @returns {Promise<import('./follower-cosmjs.js').ValueFollower<T>>}
|
|
60
60
|
*/
|
|
61
61
|
export const makeFollower = async (specP, leaderOrMaker, options) => {
|
|
62
62
|
const spec = await makeCastingSpec(specP);
|
package/src/iterable.d.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
export function mapAsyncIterable<TIn, TOut>(iterable: AsyncIterable<TIn>, transform: (value: TIn) => TOut): AsyncIterable<TOut>;
|
|
2
|
-
export function iterateLatest<T>(follower: ERef<import("./types").Follower<T>>): {
|
|
2
|
+
export function iterateLatest<T>(follower: ERef<import("./types.js").Follower<T>>): {
|
|
3
3
|
/** @returns {AsyncIterator<T>} */
|
|
4
|
-
[Symbol.asyncIterator]: () => AsyncIterator<T
|
|
5
|
-
} & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
4
|
+
[Symbol.asyncIterator]: () => AsyncIterator<T>;
|
|
5
|
+
} & import("@endo/pass-style").RemotableObject<`Alleged: ${string}`> & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
6
6
|
/** @returns {AsyncIterator<T>} */
|
|
7
|
-
[Symbol.asyncIterator]: () => AsyncIterator<T
|
|
7
|
+
[Symbol.asyncIterator]: () => AsyncIterator<T>;
|
|
8
8
|
}>;
|
|
9
|
-
export function iterateEach<T>(follower: ERef<import("./types").Follower<T>>, options?: import("./types").IterateEachOptions | undefined): {
|
|
9
|
+
export function iterateEach<T>(follower: ERef<import("./types.js").Follower<T>>, options?: import("./types.js").IterateEachOptions | undefined): {
|
|
10
10
|
/** @returns {AsyncIterator<T>} */
|
|
11
|
-
[Symbol.asyncIterator]: () => AsyncIterator<T
|
|
12
|
-
} & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
11
|
+
[Symbol.asyncIterator]: () => AsyncIterator<T>;
|
|
12
|
+
} & import("@endo/pass-style").RemotableObject<`Alleged: ${string}`> & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
13
13
|
/** @returns {AsyncIterator<T>} */
|
|
14
|
-
[Symbol.asyncIterator]: () => AsyncIterator<T
|
|
14
|
+
[Symbol.asyncIterator]: () => AsyncIterator<T>;
|
|
15
15
|
}>;
|
|
16
|
-
export function iterateReverse<T>(follower: ERef<import("./types").Follower<T>>, options?: import("./types").IterateEachOptions | undefined): {
|
|
16
|
+
export function iterateReverse<T>(follower: ERef<import("./types.js").Follower<T>>, options?: import("./types.js").IterateEachOptions | undefined): {
|
|
17
17
|
/** @returns {AsyncIterator<T>} */
|
|
18
|
-
[Symbol.asyncIterator]: () => AsyncIterator<T
|
|
19
|
-
} & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
18
|
+
[Symbol.asyncIterator]: () => AsyncIterator<T>;
|
|
19
|
+
} & import("@endo/pass-style").RemotableObject<`Alleged: ${string}`> & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
20
20
|
/** @returns {AsyncIterator<T>} */
|
|
21
|
-
[Symbol.asyncIterator]: () => AsyncIterator<T
|
|
21
|
+
[Symbol.asyncIterator]: () => AsyncIterator<T>;
|
|
22
22
|
}>;
|
|
23
23
|
export { subscribeEach, subscribeLatest } from "@agoric/notifier/subscribe.js";
|
|
24
24
|
//# sourceMappingURL=iterable.d.ts.map
|
package/src/iterable.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iterable.d.ts","sourceRoot":"","sources":["iterable.js"],"names":[],"mappings":"AAWO,
|
|
1
|
+
{"version":3,"file":"iterable.d.ts","sourceRoot":"","sources":["iterable.js"],"names":[],"mappings":"AAWO,iCANM,GAAG,EACH,IAAI,YACN,aAAa,CAAC,GAAG,CAAC,aAClB,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAClB,aAAa,CAAC,IAAI,CAAC,CAU/B;AAQM,8BAHM,CAAC,YACH,IAAI,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAK7C,kCAAkC;kCAApB,aAAa,CAAC,CAAC,CAAC;;IAA9B,kCAAkC;kCAApB,aAAa,CAAC,CAAC,CAAC;GAQ9B;AASG,4BAJM,CAAC,YACH,IAAI,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAM7C,kCAAkC;kCAApB,aAAa,CAAC,CAAC,CAAC;;IAA9B,kCAAkC;kCAApB,aAAa,CAAC,CAAC,CAAC;GAQ9B;AAOG,+BAJM,CAAC,YACH,IAAI,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAM7C,kCAAkC;kCAApB,aAAa,CAAC,CAAC,CAAC;;IAA9B,kCAAkC;kCAApB,aAAa,CAAC,CAAC,CAAC;GAQ9B"}
|
package/src/iterable.js
CHANGED
|
@@ -15,6 +15,7 @@ export const mapAsyncIterable = (iterable, transform) => {
|
|
|
15
15
|
yield transform(value);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
harden(transformGenerator);
|
|
18
19
|
return transformGenerator();
|
|
19
20
|
};
|
|
20
21
|
|
|
@@ -22,7 +23,7 @@ export const mapAsyncIterable = (iterable, transform) => {
|
|
|
22
23
|
* TODO: Remove this function when we have an @endo/publish-kit that suppports pull topics
|
|
23
24
|
*
|
|
24
25
|
* @template T
|
|
25
|
-
* @param {ERef<import('./types').Follower<T>>} follower
|
|
26
|
+
* @param {ERef<import('./types.js').Follower<T>>} follower
|
|
26
27
|
*/
|
|
27
28
|
export const iterateLatest = follower =>
|
|
28
29
|
// For now, just pass through the iterable.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function makeLeaderFromRpcAddresses(rpcAddrs: string[], leaderOptions?: import("./types.js").LeaderOptions | undefined): import(
|
|
1
|
+
export function makeLeaderFromRpcAddresses(rpcAddrs: string[], leaderOptions?: import("./types.js").LeaderOptions | undefined): import("./types.js").Leader;
|
|
2
2
|
export function makeLeaderFromNetworkConfig(netconfigURL: string, options?: import("./types.js").LeaderOptions | undefined): Promise<any>;
|
|
3
|
-
export function makeLeader(bootstrap?: string | undefined, options?: import("./types.js").LeaderOptions | undefined): ERef<import(
|
|
3
|
+
export function makeLeader(bootstrap?: string | undefined, options?: import("./types.js").LeaderOptions | undefined): ERef<import("./types.js").Leader>;
|
|
4
4
|
//# sourceMappingURL=leader-netconfig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leader-netconfig.d.ts","sourceRoot":"","sources":["leader-netconfig.js"],"names":[],"mappings":"AAgBO,qDAJI,MAAM,EAAE,mEAEN,OAAO,YAAY,EAAE,MAAM,CAevC;AAMM,0DAHI,MAAM,0EAoChB;AAOM,sHAFM,
|
|
1
|
+
{"version":3,"file":"leader-netconfig.d.ts","sourceRoot":"","sources":["leader-netconfig.js"],"names":[],"mappings":"AAgBO,qDAJI,MAAM,EAAE,mEAEN,OAAO,YAAY,EAAE,MAAM,CAevC;AAMM,0DAHI,MAAM,0EAoChB;AAOM,sHAFM,IAAI,CAAC,OAAO,YAAY,EAAE,MAAM,CAAC,CAO7C"}
|
package/src/leader.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function makeRoundRobinLeader(endpoints: string[], leaderOptions?: import(
|
|
1
|
+
export function makeRoundRobinLeader(endpoints: string[], leaderOptions?: import("./types.js").LeaderOptions): import("./types.js").Leader;
|
|
2
2
|
//# sourceMappingURL=leader.d.ts.map
|
package/src/main.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"makeHttpClient.d.ts","sourceRoot":"","sources":["makeHttpClient.js"],"names":[],"mappings":"AA2BO,oCAJI,MAAM,SACN,OAAO,MAAM,CAAC,KAAK,GACjB,OAAO,wBAAwB,EAAE,SAAS,CA8BtD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
const { freeze } = Object;
|
|
4
|
+
|
|
5
|
+
const filterBadStatus = res => {
|
|
6
|
+
if (res.status >= 400) {
|
|
7
|
+
throw new Error(`Bad status on response: ${res.status}`);
|
|
8
|
+
}
|
|
9
|
+
return res;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Make an RpcClient using explicit access to the network.
|
|
14
|
+
*
|
|
15
|
+
* The RpcClient implementations included in cosmjs
|
|
16
|
+
* such as {@link https://cosmos.github.io/cosmjs/latest/tendermint-rpc/classes/HttpClient.html HttpClient}
|
|
17
|
+
* use ambient authority (fetch or axios) for network access.
|
|
18
|
+
*
|
|
19
|
+
* To facilitate cooperation without vulnerability,
|
|
20
|
+
* as well as unit testing, etc. this RpcClient maker takes
|
|
21
|
+
* network access as a parameter, following
|
|
22
|
+
* {@link https://github.com/Agoric/agoric-sdk/wiki/OCap-Discipline|OCap Discipline}.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} url
|
|
25
|
+
* @param {typeof window.fetch} fetch
|
|
26
|
+
* @returns {import('@cosmjs/tendermint-rpc').RpcClient}
|
|
27
|
+
*/
|
|
28
|
+
export const makeHttpClient = (url, fetch) => {
|
|
29
|
+
const headers = {}; // XXX needed?
|
|
30
|
+
|
|
31
|
+
// based on cosmjs 0.30.1:
|
|
32
|
+
// https://github.com/cosmos/cosmjs/blob/33271bc51cdc865cadb647a1b7ab55d873637f39/packages/tendermint-rpc/src/rpcclients/http.ts#L37
|
|
33
|
+
// https://github.com/cosmos/cosmjs/blob/33271bc51cdc865cadb647a1b7ab55d873637f39/packages/tendermint-rpc/src/rpcclients/httpclient.ts#L25
|
|
34
|
+
return freeze({
|
|
35
|
+
disconnect: () => {
|
|
36
|
+
// nothing to be done
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {import('@cosmjs/json-rpc').JsonRpcRequest} request
|
|
41
|
+
*/
|
|
42
|
+
execute: async request => {
|
|
43
|
+
const settings = {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
body: request ? JSON.stringify(request) : undefined,
|
|
46
|
+
headers: {
|
|
47
|
+
'Content-Type': 'application/json',
|
|
48
|
+
...headers,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return fetch(url, settings)
|
|
52
|
+
.then(filterBadStatus)
|
|
53
|
+
.then(res => res.json());
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
};
|
package/src/netconfig.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"netconfig.d.ts","sourceRoot":"","sources":["netconfig.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,kEAWE;AAQK,8CAJI,OAAO,
|
|
1
|
+
{"version":3,"file":"netconfig.d.ts","sourceRoot":"","sources":["netconfig.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,kEAWE;AAQK,8CAJI,OAAO,GACL,QAAQ,QAAQ,IAAI,aAAa,CAIL;;;;;;;;;;cA3B3B,MAAM,EAAE;;;;eACR,MAAM"}
|
package/src/shuffle.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function shuffle<T>(a: T
|
|
1
|
+
export function shuffle<T>(a: Array<T>): void;
|
|
2
2
|
//# sourceMappingURL=shuffle.d.ts.map
|
package/src/shuffle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shuffle.d.ts","sourceRoot":"","sources":["shuffle.js"],"names":[],"mappings":"AAMO,
|
|
1
|
+
{"version":3,"file":"shuffle.d.ts","sourceRoot":"","sources":["shuffle.js"],"names":[],"mappings":"AAMO,wBAHM,CAAC,KACH,KAAK,CAAC,CAAC,CAAC,QASlB"}
|
package/src/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export type ERef<T> = import('@endo/far').ERef<T>;
|
|
2
1
|
export type LeaderOptions = {
|
|
3
2
|
retryCallback?: ((where: string, err: any, attempt?: number) => Promise<void>) | null | undefined;
|
|
4
3
|
jitter?: ((where: string) => Promise<void>) | undefined;
|
|
@@ -21,19 +20,24 @@ export type Follower<T> = {
|
|
|
21
20
|
getEachIterable: (options?: IterateEachOptions) => Promise<AsyncIterable<T>>;
|
|
22
21
|
getReverseIterable: (options?: IterateEachOptions) => Promise<AsyncIterable<T>>;
|
|
23
22
|
};
|
|
24
|
-
export type
|
|
25
|
-
value: T;
|
|
23
|
+
export type ValueFollowerBase = {
|
|
26
24
|
blockHeight: number;
|
|
27
25
|
currentBlockHeight: number;
|
|
28
26
|
};
|
|
29
|
-
export type
|
|
27
|
+
export type ValueFollowerElement<T> = ValueFollowerBase & ({
|
|
28
|
+
value: T;
|
|
29
|
+
} | {
|
|
30
|
+
value: undefined;
|
|
31
|
+
error: any;
|
|
32
|
+
});
|
|
33
|
+
export type Unserializer = Pick<import("@endo/marshal").Marshal<unknown>, "fromCapData" | "unserialize">;
|
|
30
34
|
export type Crasher = {
|
|
31
35
|
crash: (...args: unknown[]) => void;
|
|
32
36
|
};
|
|
33
37
|
export type FollowerOptions = {
|
|
34
38
|
unserializer?: import("@endo/far").FarRef<Unserializer, import("@endo/eventual-send").DataOnly<Unserializer>> | null | undefined;
|
|
35
39
|
decode?: ((text: string) => any) | undefined;
|
|
36
|
-
proof?: "
|
|
40
|
+
proof?: "none" | "strict" | "optimistic" | undefined;
|
|
37
41
|
crasher?: import("@endo/far").FarRef<Crasher, import("@endo/eventual-send").DataOnly<Crasher>> | undefined;
|
|
38
42
|
};
|
|
39
43
|
export type CastingSpec = {
|
|
@@ -41,8 +45,8 @@ export type CastingSpec = {
|
|
|
41
45
|
storeSubkey?: Uint8Array | undefined;
|
|
42
46
|
dataPrefixBytes?: Uint8Array | undefined;
|
|
43
47
|
noDataValue?: Uint8Array | undefined;
|
|
44
|
-
subscription?: ERef<Subscription<any>> | undefined;
|
|
45
|
-
notifier?: ERef<Notifier<any>> | undefined;
|
|
48
|
+
subscription?: globalThis.ERef<Subscription<any>> | undefined;
|
|
49
|
+
notifier?: globalThis.ERef<Notifier<any>> | undefined;
|
|
46
50
|
};
|
|
47
51
|
export type IterateEachOptions = {
|
|
48
52
|
height?: number | undefined;
|
|
@@ -51,4 +55,6 @@ export type StreamCell<T> = {
|
|
|
51
55
|
blockHeight: number;
|
|
52
56
|
values: Array<T>;
|
|
53
57
|
};
|
|
58
|
+
import type { Subscription } from '@agoric/notifier';
|
|
59
|
+
import type { Notifier } from '@agoric/notifier';
|
|
54
60
|
//# 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":";6BAW8B,MAAM,OAAO,GAAG,YAAY,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;sBAC5D,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;2BACxB,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC;;;;YAMnC,UAAU,EAAE;;;WAKZ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;YAC9D,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;gBAChC,MAAM,aAAa;kBACnB,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC;kBAC9E,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;;4BAG7D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;qBAGpC,CAAC;uBAEA,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;qBAC/B,CAAC,OAAO,CAAC,EAAE,kBAAkB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;wBAC3D,CAAC,OAAO,CAAC,EAAE,kBAAkB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;;;iBAK3D,MAAM;wBACN,MAAM;;iCAKP,CAAC,IACD,iBAAiB,GAAG,CAAC;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC;2BAIrE,IAAI,CAAC,OAAO,eAAe,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,CAAC;;WAK5E,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI;;;;qBAMrB,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;uBAqBtB,CAAC;iBAEA,MAAM;YACN,KAAK,CAAC,CAAC,CAAC;;kCAnFmB,kBAAkB;8BAAlB,kBAAkB"}
|
package/src/types.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @jessie-check
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
import '@agoric/notifier';
|
|
5
|
-
|
|
3
|
+
// Ensure this is a module.
|
|
6
4
|
export {};
|
|
7
5
|
|
|
8
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* @import {Notifier, Subscription} from '@agoric/notifier';
|
|
8
|
+
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {object} LeaderOptions
|
|
@@ -40,14 +40,17 @@ export {};
|
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* @
|
|
44
|
-
* @template T
|
|
45
|
-
* @typedef {object} ValueFollowerElement
|
|
46
|
-
* @property {T} value
|
|
43
|
+
* @typedef {object} ValueFollowerBase
|
|
47
44
|
* @property {number} blockHeight
|
|
48
45
|
* @property {number} currentBlockHeight
|
|
49
46
|
*/
|
|
50
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @see {ChangeFollower}
|
|
50
|
+
* @template T
|
|
51
|
+
* @typedef {ValueFollowerBase & ({ value: T } | { value: undefined, error: any })} ValueFollowerElement
|
|
52
|
+
*/
|
|
53
|
+
|
|
51
54
|
/**
|
|
52
55
|
* @typedef {Pick<import('@endo/marshal').Marshal<unknown>, 'fromCapData' | 'unserialize'>} Unserializer
|
|
53
56
|
*/
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/* global globalThis */
|
|
3
|
+
import anyTest from 'ava';
|
|
4
|
+
import {
|
|
5
|
+
createProtobufRpcClient,
|
|
6
|
+
QueryClient,
|
|
7
|
+
setupBankExtension,
|
|
8
|
+
} from '@cosmjs/stargate';
|
|
9
|
+
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
|
|
10
|
+
import {
|
|
11
|
+
QueryChildrenRequest,
|
|
12
|
+
QueryChildrenResponse,
|
|
13
|
+
} from '@agoric/cosmic-proto/vstorage/query.js';
|
|
14
|
+
|
|
15
|
+
import { makeHttpClient } from '../src/makeHttpClient.js';
|
|
16
|
+
import { captureIO, replayIO, web1, web2 } from './net-access-fixture.js';
|
|
17
|
+
|
|
18
|
+
/** @type {import('ava').TestFn<Awaited<ReturnType<typeof makeTestContext>>>} */
|
|
19
|
+
const test = /** @type {any} */ (anyTest);
|
|
20
|
+
|
|
21
|
+
const RECORDING = false;
|
|
22
|
+
|
|
23
|
+
const makeTestContext = async () => {
|
|
24
|
+
return { fetch: globalThis.fetch };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
test.before(async t => {
|
|
28
|
+
t.context = await makeTestContext();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const scenario1 = {
|
|
32
|
+
endpoint: 'https://emerynet.rpc.agoric.net/',
|
|
33
|
+
request: {
|
|
34
|
+
id: 1,
|
|
35
|
+
method: 'no-such-method',
|
|
36
|
+
params: [],
|
|
37
|
+
},
|
|
38
|
+
gov2: {
|
|
39
|
+
addr: 'agoric140dmkrz2e42ergjj7gyvejhzmjzurvqeq82ang',
|
|
40
|
+
balance: { amount: '25050000', denom: 'uist' },
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
test('interpose net access', async t => {
|
|
45
|
+
const fetchMock = replayIO(web1);
|
|
46
|
+
const rpcClient = makeHttpClient(scenario1.endpoint, fetchMock);
|
|
47
|
+
|
|
48
|
+
t.log('raw JSON RPC');
|
|
49
|
+
const res = await rpcClient.execute({
|
|
50
|
+
...scenario1.request,
|
|
51
|
+
jsonrpc: '2.0',
|
|
52
|
+
});
|
|
53
|
+
t.like(res, { error: { message: 'Method not found' } });
|
|
54
|
+
|
|
55
|
+
t.log('Cosmos SDK RPC: balance query');
|
|
56
|
+
const tmClient = await Tendermint34Client.create(rpcClient);
|
|
57
|
+
const qClient = new QueryClient(tmClient);
|
|
58
|
+
const ext = setupBankExtension(qClient);
|
|
59
|
+
const actual = await ext.bank.balance(
|
|
60
|
+
scenario1.gov2.addr,
|
|
61
|
+
scenario1.gov2.balance.denom,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
t.deepEqual(actual, scenario1.gov2.balance);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const scenario2 = {
|
|
68
|
+
endpoint: 'https://emerynet.rpc.agoric.net/',
|
|
69
|
+
children: [
|
|
70
|
+
'activityhash',
|
|
71
|
+
'beansOwing',
|
|
72
|
+
'egress',
|
|
73
|
+
'highPrioritySenders',
|
|
74
|
+
'published',
|
|
75
|
+
'swingStore',
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// XXX open code until https://github.com/Agoric/agoric-sdk/issues/9200
|
|
80
|
+
class QueryClientImpl {
|
|
81
|
+
rpc;
|
|
82
|
+
|
|
83
|
+
service;
|
|
84
|
+
|
|
85
|
+
constructor(rpc, opts) {
|
|
86
|
+
this.service = opts?.service || 'agoric.vstorage.Query';
|
|
87
|
+
this.rpc = rpc;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
Children(request) {
|
|
91
|
+
const reqData = QueryChildrenRequest.encode(request).finish();
|
|
92
|
+
const promise = this.rpc.request(this.service, 'Children', reqData);
|
|
93
|
+
return promise.then(respData => QueryChildrenResponse.decode(respData));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
test(`vstorage query: Children (RECORDING: ${RECORDING})`, async t => {
|
|
98
|
+
const { context: io } = t;
|
|
99
|
+
|
|
100
|
+
const { fetch: fetchMock, web } = io.recording
|
|
101
|
+
? captureIO(io.fetch)
|
|
102
|
+
: { fetch: replayIO(web2), web: new Map() };
|
|
103
|
+
const rpcClient = makeHttpClient(scenario2.endpoint, fetchMock);
|
|
104
|
+
|
|
105
|
+
const tmClient = await Tendermint34Client.create(rpcClient);
|
|
106
|
+
const qClient = new QueryClient(tmClient);
|
|
107
|
+
const rpc = createProtobufRpcClient(qClient);
|
|
108
|
+
const queryService = new QueryClientImpl(rpc);
|
|
109
|
+
|
|
110
|
+
const children = await queryService.Children({ path: '' });
|
|
111
|
+
if (io.recording) {
|
|
112
|
+
t.snapshot(web);
|
|
113
|
+
}
|
|
114
|
+
t.deepEqual(children, {
|
|
115
|
+
children: scenario2.children,
|
|
116
|
+
pagination: undefined,
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import './lockdown.js';
|
|
4
|
+
|
|
5
|
+
import { makeMarshal } from '@endo/marshal';
|
|
3
6
|
import { test } from './prepare-test-env-ava.js';
|
|
4
7
|
|
|
5
8
|
import {
|
|
@@ -167,6 +170,59 @@ test('unrecognized proof', async t => {
|
|
|
167
170
|
);
|
|
168
171
|
});
|
|
169
172
|
|
|
173
|
+
test('yields error on bad capdata without terminating', async t => {
|
|
174
|
+
const marshal = makeMarshal();
|
|
175
|
+
const improperlyMarshalledData = { bad: 'data' };
|
|
176
|
+
const properlyMarshalledData = { foo: 'bar' };
|
|
177
|
+
const fakeValues = [
|
|
178
|
+
improperlyMarshalledData,
|
|
179
|
+
marshal.toCapData(harden(properlyMarshalledData)),
|
|
180
|
+
];
|
|
181
|
+
t.plan(4);
|
|
182
|
+
const options = { batchSize: 1, marshaller: { toCapData: data => data } };
|
|
183
|
+
const { controller, PORT } = await t.context.startFakeServer(
|
|
184
|
+
t,
|
|
185
|
+
fakeValues,
|
|
186
|
+
options,
|
|
187
|
+
);
|
|
188
|
+
controller.advance(0);
|
|
189
|
+
/** @type {import('../src/types.js').LeaderOptions} */
|
|
190
|
+
const lo = {
|
|
191
|
+
retryCallback: null, // fail fast, no retries
|
|
192
|
+
keepPolling: () => delay(1000).then(() => true), // poll really quickly
|
|
193
|
+
jitter: null, // no jitter
|
|
194
|
+
};
|
|
195
|
+
/** @type {import('../src/types.js').FollowerOptions} */
|
|
196
|
+
const so = {
|
|
197
|
+
proof: 'none',
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const leader = makeLeader(`http://localhost:${PORT}/network-config`, lo);
|
|
201
|
+
const castingSpec = makeCastingSpec(':mailbox.agoric1foobarbaz');
|
|
202
|
+
const follower = await makeFollower(castingSpec, leader, so);
|
|
203
|
+
let i = 0;
|
|
204
|
+
|
|
205
|
+
for await (const { value, error } of iterateEach(follower)) {
|
|
206
|
+
if (i === 0) {
|
|
207
|
+
t.log(`value from follower, should be undefined:`, value);
|
|
208
|
+
t.log(`error from follower, should be defined:`, error);
|
|
209
|
+
|
|
210
|
+
t.deepEqual(value, undefined);
|
|
211
|
+
t.assert(typeof error === 'object');
|
|
212
|
+
|
|
213
|
+
i += 1;
|
|
214
|
+
controller.advance(1);
|
|
215
|
+
} else if (i === 1) {
|
|
216
|
+
t.log(`value from follower, should be defined:`, value);
|
|
217
|
+
t.log(`error from follower, should be undefined:`, error);
|
|
218
|
+
|
|
219
|
+
t.deepEqual(value, properlyMarshalledData);
|
|
220
|
+
t.deepEqual(error, undefined);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
170
226
|
test.before(t => {
|
|
171
227
|
t.context.cleanups = [];
|
|
172
228
|
t.context.startFakeServer = startFakeServer;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
const { stringify: jq } = JSON;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file to regenerate
|
|
5
|
+
* 1. set RECORDING=true in interpose-net-access.test.js
|
|
6
|
+
* 2. run: yarn test test/interpose-net-access.test.js --update-snapshots
|
|
7
|
+
* 3. for each map in interpose-net-access.test.js.md, copy it and
|
|
8
|
+
* 4. replace all occurences of => with : and paste as args to Object.fromEntries()
|
|
9
|
+
* 5. change RECORDING back to false
|
|
10
|
+
*/
|
|
11
|
+
export const web1 = new Map([
|
|
12
|
+
[
|
|
13
|
+
jq([
|
|
14
|
+
'https://emerynet.rpc.agoric.net/',
|
|
15
|
+
{
|
|
16
|
+
method: 'POST',
|
|
17
|
+
body: jq({
|
|
18
|
+
id: 1208387614,
|
|
19
|
+
method: 'no-such-method',
|
|
20
|
+
params: [],
|
|
21
|
+
jsonrpc: '2.0',
|
|
22
|
+
}),
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
},
|
|
25
|
+
]),
|
|
26
|
+
{
|
|
27
|
+
error: {
|
|
28
|
+
code: -32601,
|
|
29
|
+
message: 'Method not found',
|
|
30
|
+
},
|
|
31
|
+
id: 1208387614,
|
|
32
|
+
jsonrpc: '2.0',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
jq([
|
|
37
|
+
'https://emerynet.rpc.agoric.net/',
|
|
38
|
+
{
|
|
39
|
+
method: 'POST',
|
|
40
|
+
body: jq({
|
|
41
|
+
jsonrpc: '2.0',
|
|
42
|
+
id: 797030719,
|
|
43
|
+
method: 'abci_query',
|
|
44
|
+
params: {
|
|
45
|
+
path: '/cosmos.bank.v1beta1.Query/Balance',
|
|
46
|
+
data: '0a2d61676f726963313430646d6b727a326534326572676a6a37677976656a687a6d6a7a7572767165713832616e67120475697374',
|
|
47
|
+
prove: false,
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
headers: { 'Content-Type': 'application/json' },
|
|
51
|
+
},
|
|
52
|
+
]),
|
|
53
|
+
{
|
|
54
|
+
id: 797030719,
|
|
55
|
+
jsonrpc: '2.0',
|
|
56
|
+
result: {
|
|
57
|
+
response: {
|
|
58
|
+
code: 0,
|
|
59
|
+
codespace: '',
|
|
60
|
+
height: '123985',
|
|
61
|
+
index: '0',
|
|
62
|
+
info: '',
|
|
63
|
+
key: null,
|
|
64
|
+
log: '',
|
|
65
|
+
proofOps: null,
|
|
66
|
+
value: 'ChAKBHVpc3QSCDI1MDUwMDAw',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
export const web2 = new Map([
|
|
74
|
+
[
|
|
75
|
+
jq([
|
|
76
|
+
'https://emerynet.rpc.agoric.net/',
|
|
77
|
+
{
|
|
78
|
+
method: 'POST',
|
|
79
|
+
body: jq({
|
|
80
|
+
jsonrpc: '2.0',
|
|
81
|
+
id: 1757612624,
|
|
82
|
+
method: 'abci_query',
|
|
83
|
+
params: {
|
|
84
|
+
path: '/agoric.vstorage.Query/Children',
|
|
85
|
+
data: '',
|
|
86
|
+
prove: false,
|
|
87
|
+
},
|
|
88
|
+
}),
|
|
89
|
+
headers: { 'Content-Type': 'application/json' },
|
|
90
|
+
},
|
|
91
|
+
]),
|
|
92
|
+
{
|
|
93
|
+
id: 1757612624,
|
|
94
|
+
jsonrpc: '2.0',
|
|
95
|
+
result: {
|
|
96
|
+
response: {
|
|
97
|
+
code: 0,
|
|
98
|
+
codespace: '',
|
|
99
|
+
height: '123985',
|
|
100
|
+
index: '0',
|
|
101
|
+
info: '',
|
|
102
|
+
key: null,
|
|
103
|
+
log: '',
|
|
104
|
+
proofOps: null,
|
|
105
|
+
value:
|
|
106
|
+
'CgxhY3Rpdml0eWhhc2gKCmJlYW5zT3dpbmcKBmVncmVzcwoTaGlnaFByaW9yaXR5U2VuZGVycwoJcHVibGlzaGVkCgpzd2luZ1N0b3Jl',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @param {string} str
|
|
115
|
+
* ack: https://stackoverflow.com/a/7616484
|
|
116
|
+
*/
|
|
117
|
+
const hashCode = str => {
|
|
118
|
+
let hash = 0;
|
|
119
|
+
let i;
|
|
120
|
+
let chr;
|
|
121
|
+
if (str.length === 0) return hash;
|
|
122
|
+
for (i = 0; i < str.length; i += 1) {
|
|
123
|
+
chr = str.charCodeAt(i);
|
|
124
|
+
// eslint-disable-next-line no-bitwise
|
|
125
|
+
hash = (hash << 5) - hash + chr;
|
|
126
|
+
// eslint-disable-next-line no-bitwise
|
|
127
|
+
hash |= 0; // Convert to 32bit integer
|
|
128
|
+
}
|
|
129
|
+
return hash;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Normalize JSON RPC request ID
|
|
134
|
+
*
|
|
135
|
+
* tendermint-rpc generates ids using ambient access to Math.random()
|
|
136
|
+
* So we normalize them to a hash of the rest of the JSON.
|
|
137
|
+
*
|
|
138
|
+
* Earlier, we tried a sequence number, but it was non-deterministic
|
|
139
|
+
* with multiple interleaved requests.
|
|
140
|
+
*
|
|
141
|
+
* @param {string} argsKey
|
|
142
|
+
*/
|
|
143
|
+
const normalizeID = argsKey => {
|
|
144
|
+
// arbitrary string unlikely to occur in a request. from `pwgen 16 -1`
|
|
145
|
+
const placeholder = 'Ajaz1chei7ohnguv';
|
|
146
|
+
|
|
147
|
+
const noid = argsKey.replace(/\\"id\\":\d+/, `\\"id\\":${placeholder}`);
|
|
148
|
+
const id = Math.abs(hashCode(noid));
|
|
149
|
+
return noid.replace(placeholder, `${id}`);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Wrap `fetch` to capture JSON RPC IO traffic.
|
|
154
|
+
*
|
|
155
|
+
* @param {typeof window.fetch} fetch
|
|
156
|
+
* returns wraped fetch along with a .web map for use with {@link replayIO}
|
|
157
|
+
*/
|
|
158
|
+
export const captureIO = fetch => {
|
|
159
|
+
const web = new Map();
|
|
160
|
+
/** @type {typeof window.fetch} */
|
|
161
|
+
// @ts-expect-error mock
|
|
162
|
+
const f = async (...args) => {
|
|
163
|
+
const key = normalizeID(JSON.stringify(args));
|
|
164
|
+
const resp = await fetch(...args);
|
|
165
|
+
return {
|
|
166
|
+
json: async () => {
|
|
167
|
+
const data = await resp.json();
|
|
168
|
+
web.set(key, data);
|
|
169
|
+
return data;
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
return { fetch: f, web };
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Replay captured JSON RPC IO.
|
|
178
|
+
*
|
|
179
|
+
* @param {Map<string, any>} web map from
|
|
180
|
+
* JSON-stringified fetch args to fetched JSON data.
|
|
181
|
+
*/
|
|
182
|
+
export const replayIO = web => {
|
|
183
|
+
/** @type {typeof window.fetch} */
|
|
184
|
+
// @ts-expect-error mock
|
|
185
|
+
const f = async (...args) => {
|
|
186
|
+
const key = normalizeID(JSON.stringify(args));
|
|
187
|
+
const data = web.get(key);
|
|
188
|
+
if (!data) {
|
|
189
|
+
throw Error(`no data for ${key}`);
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
json: async () => data,
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
return f;
|
|
196
|
+
};
|
package/jsconfig.build.json
DELETED
|
File without changes
|