@hub3js/core 0.59.0 → 0.59.1-next.1
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/dist/builders/action.d.ts +22 -0
- package/dist/builders/action.d.ts.map +1 -0
- package/dist/builders/mod.d.ts +5 -0
- package/dist/builders/mod.d.ts.map +1 -0
- package/dist/builders/namespace.d.ts +47 -0
- package/dist/builders/namespace.d.ts.map +1 -0
- package/dist/builders/provider.d.ts +37 -0
- package/dist/builders/provider.d.ts.map +1 -0
- package/dist/builders/types.d.ts +23 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/hub/helpers.d.ts +6 -0
- package/dist/hub/helpers.d.ts.map +1 -0
- package/dist/hub/hub.d.ts +44 -0
- package/dist/hub/hub.d.ts.map +1 -0
- package/dist/hub/mod.d.ts +9 -0
- package/dist/hub/mod.d.ts.map +1 -0
- package/dist/hub/namespaces/errors.d.ts +5 -0
- package/dist/hub/namespaces/errors.d.ts.map +1 -0
- package/dist/hub/namespaces/mod.d.ts +3 -0
- package/dist/hub/namespaces/mod.d.ts.map +1 -0
- package/dist/hub/namespaces/namespace.d.ts +148 -0
- package/dist/hub/namespaces/namespace.d.ts.map +1 -0
- package/dist/hub/namespaces/types.d.ts +36 -0
- package/dist/hub/namespaces/types.d.ts.map +1 -0
- package/dist/hub/provider/mod.d.ts +3 -0
- package/dist/hub/provider/mod.d.ts.map +1 -0
- package/dist/hub/provider/provider.d.ts +102 -0
- package/dist/hub/provider/provider.d.ts.map +1 -0
- package/dist/hub/provider/types.d.ts +28 -0
- package/dist/hub/provider/types.d.ts.map +1 -0
- package/dist/hub/store/events.d.ts +54 -0
- package/dist/hub/store/events.d.ts.map +1 -0
- package/dist/hub/store/extend.d.ts +14 -0
- package/dist/hub/store/extend.d.ts.map +1 -0
- package/dist/hub/store/hub.d.ts +11 -0
- package/dist/hub/store/hub.d.ts.map +1 -0
- package/dist/hub/store/mod.d.ts +8 -0
- package/dist/hub/store/mod.d.ts.map +1 -0
- package/dist/hub/store/mod.js +1 -1
- package/dist/hub/store/mod.js.map +2 -2
- package/dist/hub/store/namespaces.d.ts +38 -0
- package/dist/hub/store/namespaces.d.ts.map +1 -0
- package/dist/hub/store/providers.d.ts +84 -0
- package/dist/hub/store/providers.d.ts.map +1 -0
- package/dist/hub/store/selectors.d.ts +18 -0
- package/dist/hub/store/selectors.d.ts.map +1 -0
- package/dist/hub/store/store.d.ts +14 -0
- package/dist/hub/store/store.d.ts.map +1 -0
- package/dist/hub/types.d.ts +5 -0
- package/dist/hub/types.d.ts.map +1 -0
- package/dist/mod.d.ts +5 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +1 -1
- package/dist/mod.js.map +4 -4
- package/dist/test-utils/fixtures.d.ts +4 -0
- package/dist/test-utils/fixtures.d.ts.map +1 -0
- package/dist/test-utils/mod.d.ts +2 -0
- package/dist/test-utils/mod.d.ts.map +1 -0
- package/dist/test-utils/mod.js +2 -0
- package/dist/test-utils/mod.js.map +7 -0
- package/dist/utils/mod.d.ts +3 -0
- package/dist/utils/mod.d.ts.map +1 -0
- package/dist/utils/mod.js +1 -1
- package/dist/utils/mod.js.map +4 -4
- package/dist/utils/versions.d.ts +50 -0
- package/dist/utils/versions.d.ts.map +1 -0
- package/package.json +9 -60
- package/src/builders/action.test.ts +225 -0
- package/src/builders/action.ts +1 -1
- package/src/builders/namespace.ts +1 -1
- package/src/builders/provider.ts +59 -19
- package/src/builders/types.ts +6 -4
- package/src/hub/hub.test.ts +108 -0
- package/src/hub/hub.ts +26 -9
- package/src/hub/mod.ts +2 -1
- package/src/hub/namespaces/namespace.ts +2 -2
- package/src/hub/namespaces/types.ts +1 -1
- package/src/hub/provider/mod.ts +1 -2
- package/src/hub/provider/provider.test.ts +64 -19
- package/src/hub/provider/provider.ts +43 -92
- package/src/hub/provider/types.ts +14 -31
- package/src/hub/store/mod.ts +1 -0
- package/src/hub/store/providers.ts +32 -18
- package/src/mod.ts +2 -21
- package/src/test-utils/mod.ts +1 -0
- package/src/utils/mod.ts +2 -8
- package/src/utils/versions.test.ts +0 -1
- package/src/utils/versions.ts +71 -44
- package/dist/legacy/mod.js +0 -2
- package/dist/legacy/mod.js.map +0 -7
- package/dist/namespaces/common/mod.js +0 -2
- package/dist/namespaces/common/mod.js.map +0 -7
- package/dist/namespaces/cosmos/mod.js +0 -2
- package/dist/namespaces/cosmos/mod.js.map +0 -7
- package/dist/namespaces/evm/mod.js +0 -2
- package/dist/namespaces/evm/mod.js.map +0 -7
- package/dist/namespaces/solana/mod.js +0 -2
- package/dist/namespaces/solana/mod.js.map +0 -7
- package/dist/namespaces/starknet/mod.js +0 -2
- package/dist/namespaces/starknet/mod.js.map +0 -7
- package/dist/namespaces/sui/mod.js +0 -2
- package/dist/namespaces/sui/mod.js.map +0 -7
- package/dist/namespaces/tron/mod.js +0 -2
- package/dist/namespaces/tron/mod.js.map +0 -7
- package/dist/namespaces/utxo/mod.js +0 -2
- package/dist/namespaces/utxo/mod.js.map +0 -7
- package/dist/namespaces/xrpl/mod.js +0 -2
- package/dist/namespaces/xrpl/mod.js.map +0 -7
- package/legacy/package.json +0 -8
- package/namespaces/common/package.json +0 -8
- package/namespaces/cosmos/package.json +0 -8
- package/namespaces/evm/package.json +0 -8
- package/namespaces/solana/package.json +0 -8
- package/namespaces/starknet/package.json +0 -8
- package/namespaces/sui/package.json +0 -8
- package/namespaces/tron/package.json +0 -8
- package/namespaces/utxo/package.json +0 -8
- package/namespaces/xrpl/package.json +0 -8
- package/src/legacy/helpers.ts +0 -75
- package/src/legacy/mod.ts +0 -44
- package/src/legacy/persistor.ts +0 -19
- package/src/legacy/types.ts +0 -303
- package/src/legacy/utils.ts +0 -20
- package/src/legacy/wallet.ts +0 -552
- package/src/namespaces/common/actions.ts +0 -12
- package/src/namespaces/common/after.ts +0 -8
- package/src/namespaces/common/and.ts +0 -42
- package/src/namespaces/common/before.ts +0 -9
- package/src/namespaces/common/builders.ts +0 -14
- package/src/namespaces/common/helpers.ts +0 -10
- package/src/namespaces/common/hooks/changeAccountSubscriber.test.ts +0 -173
- package/src/namespaces/common/hooks/changeAccountSubscriber.ts +0 -236
- package/src/namespaces/common/mod.ts +0 -23
- package/src/namespaces/common/or.ts +0 -17
- package/src/namespaces/common/types.ts +0 -27
- package/src/namespaces/common/utils.ts +0 -43
- package/src/namespaces/cosmos/actions.ts +0 -3
- package/src/namespaces/cosmos/after.ts +0 -3
- package/src/namespaces/cosmos/and.ts +0 -5
- package/src/namespaces/cosmos/before.ts +0 -3
- package/src/namespaces/cosmos/builders.ts +0 -15
- package/src/namespaces/cosmos/constants.ts +0 -1
- package/src/namespaces/cosmos/mod.ts +0 -15
- package/src/namespaces/cosmos/types.ts +0 -31
- package/src/namespaces/cosmos/utils.ts +0 -21
- package/src/namespaces/evm/actions.ts +0 -134
- package/src/namespaces/evm/after.ts +0 -3
- package/src/namespaces/evm/and.ts +0 -5
- package/src/namespaces/evm/before.ts +0 -3
- package/src/namespaces/evm/builders.ts +0 -52
- package/src/namespaces/evm/constants.ts +0 -2
- package/src/namespaces/evm/eip1193.ts +0 -1415
- package/src/namespaces/evm/hooks.ts +0 -43
- package/src/namespaces/evm/mod.ts +0 -10
- package/src/namespaces/evm/types.ts +0 -36
- package/src/namespaces/evm/utils.ts +0 -106
- package/src/namespaces/solana/actions.ts +0 -44
- package/src/namespaces/solana/after.ts +0 -3
- package/src/namespaces/solana/and.ts +0 -5
- package/src/namespaces/solana/before.ts +0 -3
- package/src/namespaces/solana/builders.ts +0 -40
- package/src/namespaces/solana/constants.ts +0 -2
- package/src/namespaces/solana/hooks.ts +0 -10
- package/src/namespaces/solana/mod.ts +0 -10
- package/src/namespaces/solana/types.ts +0 -25
- package/src/namespaces/solana/utils.ts +0 -36
- package/src/namespaces/starknet/actions.ts +0 -19
- package/src/namespaces/starknet/after.ts +0 -3
- package/src/namespaces/starknet/and.ts +0 -5
- package/src/namespaces/starknet/before.ts +0 -3
- package/src/namespaces/starknet/builders.ts +0 -18
- package/src/namespaces/starknet/constants.ts +0 -8
- package/src/namespaces/starknet/mod.ts +0 -9
- package/src/namespaces/starknet/types.ts +0 -18
- package/src/namespaces/starknet/utils.ts +0 -35
- package/src/namespaces/sui/actions.ts +0 -27
- package/src/namespaces/sui/builders.ts +0 -77
- package/src/namespaces/sui/constants.ts +0 -8
- package/src/namespaces/sui/hooks.ts +0 -10
- package/src/namespaces/sui/mod.ts +0 -8
- package/src/namespaces/sui/types.ts +0 -25
- package/src/namespaces/sui/utils.ts +0 -56
- package/src/namespaces/tron/actions.ts +0 -3
- package/src/namespaces/tron/after.ts +0 -3
- package/src/namespaces/tron/and.ts +0 -5
- package/src/namespaces/tron/before.ts +0 -3
- package/src/namespaces/tron/builders.ts +0 -15
- package/src/namespaces/tron/constants.ts +0 -8
- package/src/namespaces/tron/mod.ts +0 -8
- package/src/namespaces/tron/types.ts +0 -14
- package/src/namespaces/tron/utils.ts +0 -18
- package/src/namespaces/utxo/actions.ts +0 -3
- package/src/namespaces/utxo/after.ts +0 -3
- package/src/namespaces/utxo/and.ts +0 -5
- package/src/namespaces/utxo/before.ts +0 -3
- package/src/namespaces/utxo/builders.ts +0 -12
- package/src/namespaces/utxo/constants.ts +0 -2
- package/src/namespaces/utxo/mod.ts +0 -8
- package/src/namespaces/utxo/types.ts +0 -14
- package/src/namespaces/utxo/utils.ts +0 -18
- package/src/namespaces/xrpl/builders.ts +0 -14
- package/src/namespaces/xrpl/constants.ts +0 -7
- package/src/namespaces/xrpl/mod.ts +0 -5
- package/src/namespaces/xrpl/types.ts +0 -16
- package/src/namespaces/xrpl/utils.ts +0 -15
- package/src/types/accounts.ts +0 -12
- package/src/types/mod.ts +0 -1
- package/src/types/utils.ts +0 -7
- /package/src/{types/actions.ts → hub/types.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hub3js/core",
|
|
3
|
-
"version": "0.59.
|
|
3
|
+
"version": "0.59.1-next.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"source": "./src/mod.ts",
|
|
@@ -11,64 +11,26 @@
|
|
|
11
11
|
"types": "./dist/mod.d.ts",
|
|
12
12
|
"default": "./dist/mod.js"
|
|
13
13
|
},
|
|
14
|
-
"./legacy": {
|
|
15
|
-
"types": "./dist/legacy/mod.d.ts",
|
|
16
|
-
"default": "./dist/legacy/mod.js"
|
|
17
|
-
},
|
|
18
|
-
"./utils": {
|
|
19
|
-
"types": "./dist/utils/mod.d.ts",
|
|
20
|
-
"default": "./dist/utils/mod.js"
|
|
21
|
-
},
|
|
22
14
|
"./store": {
|
|
23
15
|
"types": "./dist/hub/store/mod.d.ts",
|
|
24
16
|
"default": "./dist/hub/store/mod.js"
|
|
25
17
|
},
|
|
26
|
-
"./
|
|
27
|
-
"types": "./dist/
|
|
28
|
-
"default": "./dist/
|
|
29
|
-
},
|
|
30
|
-
"./namespaces/cosmos": {
|
|
31
|
-
"types": "./dist/namespaces/cosmos/mod.d.ts",
|
|
32
|
-
"default": "./dist/namespaces/cosmos/mod.js"
|
|
33
|
-
},
|
|
34
|
-
"./namespaces/evm": {
|
|
35
|
-
"types": "./dist/namespaces/evm/mod.d.ts",
|
|
36
|
-
"default": "./dist/namespaces/evm/mod.js"
|
|
37
|
-
},
|
|
38
|
-
"./namespaces/solana": {
|
|
39
|
-
"types": "./dist/namespaces/solana/mod.d.ts",
|
|
40
|
-
"default": "./dist/namespaces/solana/mod.js"
|
|
41
|
-
},
|
|
42
|
-
"./namespaces/starknet": {
|
|
43
|
-
"types": "./dist/namespaces/starknet/mod.d.ts",
|
|
44
|
-
"default": "./dist/namespaces/starknet/mod.js"
|
|
45
|
-
},
|
|
46
|
-
"./namespaces/sui": {
|
|
47
|
-
"types": "./dist/namespaces/sui/mod.d.ts",
|
|
48
|
-
"default": "./dist/namespaces/sui/mod.js"
|
|
49
|
-
},
|
|
50
|
-
"./namespaces/utxo": {
|
|
51
|
-
"types": "./dist/namespaces/utxo/mod.d.ts",
|
|
52
|
-
"default": "./dist/namespaces/utxo/mod.js"
|
|
53
|
-
},
|
|
54
|
-
"./namespaces/tron": {
|
|
55
|
-
"types": "./dist/namespaces/tron/mod.d.ts",
|
|
56
|
-
"default": "./dist/namespaces/tron/mod.js"
|
|
18
|
+
"./utils": {
|
|
19
|
+
"types": "./dist/utils/mod.d.ts",
|
|
20
|
+
"default": "./dist/utils/mod.js"
|
|
57
21
|
},
|
|
58
|
-
"./
|
|
59
|
-
"types": "./dist/
|
|
60
|
-
"default": "./dist/
|
|
22
|
+
"./test-utils": {
|
|
23
|
+
"types": "./dist/test-utils/mod.d.ts",
|
|
24
|
+
"default": "./dist/test-utils/mod.js"
|
|
61
25
|
}
|
|
62
26
|
},
|
|
63
27
|
"files": [
|
|
64
28
|
"dist",
|
|
65
29
|
"src",
|
|
66
|
-
"legacy",
|
|
67
|
-
"namespaces",
|
|
68
30
|
"store"
|
|
69
31
|
],
|
|
70
32
|
"scripts": {
|
|
71
|
-
"build": "yarn run rangutopia library build --inputs src/mod.ts,src/
|
|
33
|
+
"build": "yarn run rangutopia library build --inputs src/mod.ts,src/hub/store/mod.ts,src/utils/mod.ts,src/test-utils/mod.ts",
|
|
72
34
|
"ts-check": "tsc --declaration --emitDeclarationOnly -p tsconfig.json",
|
|
73
35
|
"clean": "rimraf dist",
|
|
74
36
|
"format": "prettier --write '{.,src}/**/*.{ts,tsx}'",
|
|
@@ -76,24 +38,11 @@
|
|
|
76
38
|
"test": "vitest",
|
|
77
39
|
"coverage": "vitest run --coverage"
|
|
78
40
|
},
|
|
79
|
-
"peerDependencies": {
|
|
80
|
-
"@mysten/wallet-standard": "^0.13.26",
|
|
81
|
-
"@types/react": "^17.0.0 || ^18.0.0",
|
|
82
|
-
"react": "^17.0.0 || ^18.0.0",
|
|
83
|
-
"react-dom": "^17.0.0 || ^18.0.0",
|
|
84
|
-
"xrpl": "^4.2.0"
|
|
85
|
-
},
|
|
86
41
|
"dependencies": {
|
|
87
|
-
"@chain-registry/types": "2.0.110",
|
|
88
|
-
"caip": "^1.1.1",
|
|
89
42
|
"immer": "^10.0.4",
|
|
90
|
-
"rango-types": "^0.
|
|
43
|
+
"rango-types": "^0.5.0",
|
|
91
44
|
"zustand": "^4.5.2"
|
|
92
45
|
},
|
|
93
|
-
"devDependencies": {
|
|
94
|
-
"@mysten/wallet-standard": "^0.13.26",
|
|
95
|
-
"xrpl": "^4.2.0"
|
|
96
|
-
},
|
|
97
46
|
"publishConfig": {
|
|
98
47
|
"access": "public"
|
|
99
48
|
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import type { Context } from '../hub/namespaces/mod.js';
|
|
2
|
+
import type { FunctionWithContext } from '../hub/types.js';
|
|
3
|
+
|
|
4
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
5
|
+
|
|
6
|
+
import { garbageWalletMetaData } from '../test-utils/fixtures.js';
|
|
7
|
+
|
|
8
|
+
import { ActionBuilder } from './action.js';
|
|
9
|
+
import { NamespaceBuilder } from './namespace.js';
|
|
10
|
+
import { ProviderBuilder } from './provider.js';
|
|
11
|
+
|
|
12
|
+
interface TestEvmActions {
|
|
13
|
+
connect: (chain: string) => Promise<{ accounts: string[]; network: string }>;
|
|
14
|
+
disconnect: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface TestSolanaActions {
|
|
18
|
+
connect: () => Promise<string[]>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('Provider built from multiple namespaces', () => {
|
|
22
|
+
const walletName = 'garbage-wallet';
|
|
23
|
+
|
|
24
|
+
test('connect runs the right action on each registered namespace', async () => {
|
|
25
|
+
const spyOnEvmConnect = vi.fn();
|
|
26
|
+
const evmConnect: FunctionWithContext<
|
|
27
|
+
TestEvmActions['connect'],
|
|
28
|
+
Context
|
|
29
|
+
> = async () => {
|
|
30
|
+
spyOnEvmConnect();
|
|
31
|
+
return {
|
|
32
|
+
accounts: ['eip155:0x1:0x000000000000000000000000000000000000dead'],
|
|
33
|
+
network: 'eth',
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const spyOnSolanaConnect = vi.fn();
|
|
38
|
+
const solanaConnect: FunctionWithContext<
|
|
39
|
+
TestSolanaActions['connect'],
|
|
40
|
+
Context
|
|
41
|
+
> = async () => {
|
|
42
|
+
spyOnSolanaConnect();
|
|
43
|
+
return ['solana:mainnet:1nc1nerator11111111111111111111111111111111'];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const evmNamespace = new NamespaceBuilder<TestEvmActions>('evm', walletName)
|
|
47
|
+
.action('connect', evmConnect)
|
|
48
|
+
.build();
|
|
49
|
+
const solanaNamespace = new NamespaceBuilder<TestSolanaActions>(
|
|
50
|
+
'solana',
|
|
51
|
+
walletName,
|
|
52
|
+
)
|
|
53
|
+
.action('connect', solanaConnect)
|
|
54
|
+
.build();
|
|
55
|
+
|
|
56
|
+
const wallet = new ProviderBuilder(walletName)
|
|
57
|
+
.add('evm', evmNamespace)
|
|
58
|
+
.add('solana', solanaNamespace)
|
|
59
|
+
.config('metadata', garbageWalletMetaData)
|
|
60
|
+
.build();
|
|
61
|
+
|
|
62
|
+
const evmResult = await wallet.get('evm')?.connect('0x1');
|
|
63
|
+
const solanaResult = await wallet.get('solana')?.connect();
|
|
64
|
+
|
|
65
|
+
expect(evmResult?.accounts).toStrictEqual([
|
|
66
|
+
'eip155:0x1:0x000000000000000000000000000000000000dead',
|
|
67
|
+
]);
|
|
68
|
+
expect(solanaResult).toStrictEqual([
|
|
69
|
+
'solana:mainnet:1nc1nerator11111111111111111111111111111111',
|
|
70
|
+
]);
|
|
71
|
+
expect(spyOnEvmConnect).toBeCalledTimes(1);
|
|
72
|
+
expect(spyOnSolanaConnect).toBeCalledTimes(1);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('ActionBuilder integration with namespace', () => {
|
|
77
|
+
const walletName = 'garbage-wallet';
|
|
78
|
+
|
|
79
|
+
test('and-then transforms the action result; after hook runs', async () => {
|
|
80
|
+
const spyOnConnect = vi.fn();
|
|
81
|
+
const evmConnect: FunctionWithContext<
|
|
82
|
+
TestEvmActions['connect'],
|
|
83
|
+
Context
|
|
84
|
+
> = async () => {
|
|
85
|
+
spyOnConnect();
|
|
86
|
+
return {
|
|
87
|
+
accounts: [
|
|
88
|
+
'0x000000000000000000000000000000000000dead',
|
|
89
|
+
'0x0000000000000000000000000000000000000000',
|
|
90
|
+
],
|
|
91
|
+
network: 'eth',
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const andConnect = vi.fn(
|
|
96
|
+
(_context, result: { network: string; accounts: string[] }) => ({
|
|
97
|
+
network: result.network,
|
|
98
|
+
accounts: result.accounts.map((account) => `eip155:0x1:${account}`),
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const evmDisconnect = vi.fn();
|
|
103
|
+
const afterDisconnect = vi.fn();
|
|
104
|
+
|
|
105
|
+
const connectAction = new ActionBuilder<TestEvmActions, 'connect'>(
|
|
106
|
+
'connect',
|
|
107
|
+
)
|
|
108
|
+
.action(evmConnect)
|
|
109
|
+
.and(andConnect)
|
|
110
|
+
.build();
|
|
111
|
+
|
|
112
|
+
const disconnectAction = new ActionBuilder<TestEvmActions, 'disconnect'>(
|
|
113
|
+
'disconnect',
|
|
114
|
+
)
|
|
115
|
+
.action(evmDisconnect)
|
|
116
|
+
.after(afterDisconnect)
|
|
117
|
+
.build();
|
|
118
|
+
|
|
119
|
+
const evmNamespace = new NamespaceBuilder<TestEvmActions>('evm', walletName)
|
|
120
|
+
.action(connectAction)
|
|
121
|
+
.action(disconnectAction)
|
|
122
|
+
.build();
|
|
123
|
+
|
|
124
|
+
const wallet = new ProviderBuilder(walletName)
|
|
125
|
+
.add('evm', evmNamespace)
|
|
126
|
+
.config('metadata', garbageWalletMetaData)
|
|
127
|
+
.build();
|
|
128
|
+
|
|
129
|
+
const evmResult = await wallet.get('evm')?.connect('0x1');
|
|
130
|
+
|
|
131
|
+
expect(evmResult?.accounts).toStrictEqual([
|
|
132
|
+
'eip155:0x1:0x000000000000000000000000000000000000dead',
|
|
133
|
+
'eip155:0x1:0x0000000000000000000000000000000000000000',
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
await wallet.get('evm')?.connect('0x1');
|
|
137
|
+
wallet.get('evm')?.disconnect();
|
|
138
|
+
|
|
139
|
+
expect(spyOnConnect).toBeCalledTimes(2);
|
|
140
|
+
expect(andConnect).toBeCalledTimes(2);
|
|
141
|
+
expect(evmDisconnect).toBeCalledTimes(1);
|
|
142
|
+
expect(afterDisconnect).toBeCalledTimes(1);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test('and runs on success; or runs on throw; throw without or propagates', async () => {
|
|
146
|
+
const spyOnSuccessAndAction = vi.fn((_ctx, value) => value);
|
|
147
|
+
const spyOnThrowAndAction = vi.fn();
|
|
148
|
+
const spyOnThrowAndActionWithOr = vi.fn();
|
|
149
|
+
const spyOnSuccessOrAction = vi.fn();
|
|
150
|
+
const spyOnThrowOrAction = vi.fn();
|
|
151
|
+
|
|
152
|
+
interface GarbageActions {
|
|
153
|
+
successfulAction: () => string;
|
|
154
|
+
throwErrorAction: () => void;
|
|
155
|
+
throwErrorActionWithOr: () => void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const successfulAction = new ActionBuilder<
|
|
159
|
+
GarbageActions,
|
|
160
|
+
'successfulAction'
|
|
161
|
+
>('successfulAction')
|
|
162
|
+
.action(() => 'yay!')
|
|
163
|
+
.and(spyOnSuccessAndAction)
|
|
164
|
+
.or(spyOnSuccessOrAction)
|
|
165
|
+
.build();
|
|
166
|
+
|
|
167
|
+
const throwErrorAction = new ActionBuilder<
|
|
168
|
+
GarbageActions,
|
|
169
|
+
'throwErrorAction'
|
|
170
|
+
>('throwErrorAction')
|
|
171
|
+
.action(() => {
|
|
172
|
+
throw new Error('whatever');
|
|
173
|
+
})
|
|
174
|
+
.and(spyOnThrowAndAction)
|
|
175
|
+
.build();
|
|
176
|
+
|
|
177
|
+
const throwErrorActionWithOr = new ActionBuilder<
|
|
178
|
+
GarbageActions,
|
|
179
|
+
'throwErrorActionWithOr'
|
|
180
|
+
>('throwErrorActionWithOr')
|
|
181
|
+
.action(() => {
|
|
182
|
+
throw new Error('whatever');
|
|
183
|
+
})
|
|
184
|
+
.and(spyOnThrowAndActionWithOr)
|
|
185
|
+
.or(spyOnThrowOrAction)
|
|
186
|
+
.build();
|
|
187
|
+
|
|
188
|
+
const namespace = new NamespaceBuilder<GarbageActions>('evm', walletName)
|
|
189
|
+
.action(successfulAction)
|
|
190
|
+
.action(throwErrorAction)
|
|
191
|
+
.action(throwErrorActionWithOr)
|
|
192
|
+
.build();
|
|
193
|
+
|
|
194
|
+
namespace.successfulAction();
|
|
195
|
+
expect(spyOnSuccessAndAction).toBeCalledTimes(1);
|
|
196
|
+
expect(spyOnSuccessAndAction).toHaveLastReturnedWith('yay!');
|
|
197
|
+
expect(spyOnSuccessOrAction).toBeCalledTimes(0);
|
|
198
|
+
|
|
199
|
+
expect(() => namespace.throwErrorAction()).toThrowError();
|
|
200
|
+
expect(spyOnThrowAndAction).toBeCalledTimes(0);
|
|
201
|
+
|
|
202
|
+
namespace.throwErrorActionWithOr();
|
|
203
|
+
expect(spyOnThrowAndActionWithOr).toBeCalledTimes(0);
|
|
204
|
+
expect(spyOnThrowOrAction).toBeCalledTimes(1);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("'action-name' in namespace returns true for registered actions", () => {
|
|
208
|
+
interface GarbageActions {
|
|
209
|
+
garbageAction: () => string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const garbageAction = new ActionBuilder<GarbageActions, 'garbageAction'>(
|
|
213
|
+
'garbageAction',
|
|
214
|
+
)
|
|
215
|
+
.action(() => 'yay!')
|
|
216
|
+
.build();
|
|
217
|
+
|
|
218
|
+
const namespace = new NamespaceBuilder<GarbageActions>('evm', walletName)
|
|
219
|
+
.action(garbageAction)
|
|
220
|
+
.build();
|
|
221
|
+
|
|
222
|
+
expect('garbageAction' in namespace).toBe(true);
|
|
223
|
+
expect('init' in namespace).toBe(true);
|
|
224
|
+
});
|
|
225
|
+
});
|
package/src/builders/action.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Actions, Context, Operators } from '../hub/namespaces/types.js';
|
|
2
|
-
import type { AnyFunction, FunctionWithContext } from '../types
|
|
2
|
+
import type { AnyFunction, FunctionWithContext } from '../hub/types.js';
|
|
3
3
|
|
|
4
4
|
export interface ActionByBuilder<T, Context> {
|
|
5
5
|
actionName: keyof T;
|
|
@@ -2,7 +2,7 @@ import type { ActionByBuilder } from './action.js';
|
|
|
2
2
|
import type { ProxiedNamespace } from './types.js';
|
|
3
3
|
import type { Actions, ActionsMap, Context } from '../hub/namespaces/mod.js';
|
|
4
4
|
import type { NamespaceConfig } from '../hub/store/mod.js';
|
|
5
|
-
import type { FunctionWithContext } from '../types
|
|
5
|
+
import type { FunctionWithContext } from '../hub/types.js';
|
|
6
6
|
|
|
7
7
|
import { Namespace } from '../hub/mod.js';
|
|
8
8
|
|
package/src/builders/provider.ts
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ProxiedNamespace } from './types.js';
|
|
2
|
+
import type { Actions } from '../hub/namespaces/mod.js';
|
|
2
3
|
import type {
|
|
3
|
-
CommonNamespaces,
|
|
4
4
|
ExtendableInternalActions,
|
|
5
5
|
ProviderBuilderOptions,
|
|
6
|
+
RegisteredNamespaces,
|
|
6
7
|
} from '../hub/provider/mod.js';
|
|
7
8
|
import type { ProviderConfig } from '../hub/store/mod.js';
|
|
8
9
|
|
|
9
10
|
import { Provider } from '../hub/provider/mod.js';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Fluent builder for `Provider`. Each `.add(key, namespace)` call accumulates
|
|
14
|
+
* the registered namespace map into the `TNS` generic, so the resulting
|
|
15
|
+
* `Provider<TNS>` knows exactly which namespaces it owns.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const phantom = new ProviderBuilder('phantom')
|
|
20
|
+
* .config('metadata', meta)
|
|
21
|
+
* .add('evm', evmNamespace) // adds { evm: EvmActions }
|
|
22
|
+
* .add('solana', solanaNamespace) // adds { solana: SolanaActions }
|
|
23
|
+
* .build();
|
|
24
|
+
* // Provider<{ evm: EvmActions; solana: SolanaActions }>
|
|
25
|
+
* ```
|
|
26
|
+
* `{}` is intentional: identity element under intersection so the first
|
|
27
|
+
* `.add(K, T)` produces `{} & Record<K, T> = Record<K, T>` and subsequent calls
|
|
28
|
+
* accumulate cleanly. Not the unsafe "any non-nullish" usage the rule targets.
|
|
29
|
+
*/
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
31
|
+
export class ProviderBuilder<TNS = {}> {
|
|
12
32
|
#id: string;
|
|
13
|
-
|
|
33
|
+
/*
|
|
34
|
+
* Internal storage is opaque — types are recovered when `build()` produces
|
|
35
|
+
* the `Provider<TNS>`.
|
|
36
|
+
*/
|
|
37
|
+
#namespaces = new Map<string, unknown>();
|
|
14
38
|
#methods: ExtendableInternalActions = {};
|
|
15
|
-
#configs: Partial<ProviderConfig
|
|
39
|
+
#configs: Partial<ProviderConfig<TNS>> = {};
|
|
16
40
|
#options: Partial<ProviderBuilderOptions>;
|
|
17
41
|
|
|
18
42
|
constructor(id: string, options?: ProviderBuilderOptions) {
|
|
@@ -20,42 +44,58 @@ export class ProviderBuilder {
|
|
|
20
44
|
this.#options = options || {};
|
|
21
45
|
}
|
|
22
46
|
|
|
23
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Register a namespace under `id`. Captures both the key and the namespace's
|
|
49
|
+
* action interface into the builder's `TNS` so subsequent operations are
|
|
50
|
+
* statically typed against the accumulated set.
|
|
51
|
+
*/
|
|
52
|
+
public add<const K extends string, T extends Actions<T>>(
|
|
24
53
|
id: K,
|
|
25
|
-
namespace:
|
|
26
|
-
) {
|
|
54
|
+
namespace: ProxiedNamespace<T>,
|
|
55
|
+
): ProviderBuilder<TNS & Record<K, T>> {
|
|
27
56
|
if (this.#options.store) {
|
|
28
57
|
namespace.store(this.#options.store);
|
|
29
58
|
}
|
|
30
59
|
this.#namespaces.set(id, namespace);
|
|
31
|
-
return this
|
|
60
|
+
return this as unknown as ProviderBuilder<TNS & Record<K, T>>;
|
|
32
61
|
}
|
|
33
62
|
|
|
34
|
-
public config<K extends keyof ProviderConfig
|
|
63
|
+
public config<K extends keyof ProviderConfig<TNS>>(
|
|
35
64
|
name: K,
|
|
36
|
-
value: ProviderConfig[K],
|
|
37
|
-
) {
|
|
65
|
+
value: ProviderConfig<TNS>[K],
|
|
66
|
+
): this {
|
|
38
67
|
this.#configs[name] = value;
|
|
39
68
|
return this;
|
|
40
69
|
}
|
|
41
70
|
|
|
42
|
-
public init(cb: Exclude<ExtendableInternalActions['init'], undefined>) {
|
|
71
|
+
public init(cb: Exclude<ExtendableInternalActions['init'], undefined>): this {
|
|
43
72
|
this.#methods.init = cb;
|
|
44
73
|
return this;
|
|
45
74
|
}
|
|
46
75
|
|
|
47
|
-
public build(): Provider {
|
|
76
|
+
public build(): Provider<TNS> {
|
|
48
77
|
if (this.#isConfigsValid(this.#configs)) {
|
|
49
|
-
return new Provider(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
78
|
+
return new Provider<TNS>(
|
|
79
|
+
this.#id,
|
|
80
|
+
/*
|
|
81
|
+
* The runtime map is keyed by `string`; we re-view it through the
|
|
82
|
+
* builder's accumulated `TNS` for the typed `Provider` API.
|
|
83
|
+
*/
|
|
84
|
+
this.#namespaces as unknown as RegisteredNamespaces<TNS>,
|
|
85
|
+
this.#configs,
|
|
86
|
+
{
|
|
87
|
+
extendInternalActions: this.#methods,
|
|
88
|
+
store: this.#options.store,
|
|
89
|
+
},
|
|
90
|
+
);
|
|
53
91
|
}
|
|
54
92
|
|
|
55
93
|
throw new Error('You need to set all required configs.');
|
|
56
94
|
}
|
|
57
95
|
|
|
58
|
-
#isConfigsValid(
|
|
96
|
+
#isConfigsValid(
|
|
97
|
+
config: Partial<ProviderConfig<TNS>>,
|
|
98
|
+
): config is ProviderConfig<TNS> {
|
|
59
99
|
return !!config.metadata;
|
|
60
100
|
}
|
|
61
101
|
}
|
package/src/builders/types.ts
CHANGED
|
@@ -16,11 +16,13 @@ export type ProxiedNamespace<T extends Actions<T>> = T &
|
|
|
16
16
|
NamespacePublicValues;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Map a key into the corresponding proxied namespace inside a namespace set.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* type List = { evm: EvmActions; solana: SolanaActions };
|
|
24
|
+
* FindProxiedNamespace<'solana', List>; // ProxiedNamespace<SolanaActions>
|
|
25
|
+
* ```
|
|
24
26
|
*/
|
|
25
27
|
export type FindProxiedNamespace<K extends keyof T, T> =
|
|
26
28
|
T[K] extends Actions<T[K]> ? ProxiedNamespace<T[K]> : never;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { Store } from './store/mod.js';
|
|
2
|
+
|
|
3
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { NamespaceBuilder } from '../builders/namespace.js';
|
|
6
|
+
import { ProviderBuilder } from '../builders/provider.js';
|
|
7
|
+
import { garbageWalletMetaData } from '../test-utils/fixtures.js';
|
|
8
|
+
|
|
9
|
+
import { Hub } from './hub.js';
|
|
10
|
+
import { createStore } from './store/mod.js';
|
|
11
|
+
|
|
12
|
+
interface TestEvmActions {
|
|
13
|
+
connect: (chain: string) => Promise<{ accounts: string[]; network: string }>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const buildEvmProvider = (id: string) => {
|
|
17
|
+
const evmNamespace = new NamespaceBuilder<TestEvmActions>('eip155', id)
|
|
18
|
+
.action('connect', async () => ({
|
|
19
|
+
accounts: ['eip155:0x1:0x000000000000000000000000000000000000dead'],
|
|
20
|
+
network: 'eth',
|
|
21
|
+
}))
|
|
22
|
+
.build();
|
|
23
|
+
|
|
24
|
+
return new ProviderBuilder(id)
|
|
25
|
+
.config('metadata', garbageWalletMetaData)
|
|
26
|
+
.add('evm', evmNamespace)
|
|
27
|
+
.build();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('Hub', () => {
|
|
31
|
+
let store: Store;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
store = createStore();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('add registers the provider in both the hub and the store', () => {
|
|
38
|
+
const provider = buildEvmProvider('wallet-a');
|
|
39
|
+
const hub = new Hub({ store }).add(provider.id, provider);
|
|
40
|
+
|
|
41
|
+
expect(hub.get('wallet-a')).toBe(provider);
|
|
42
|
+
expect(store.getState().providers.list['wallet-a']).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('get returns undefined for an unknown provider id', () => {
|
|
46
|
+
const hub = new Hub({ store });
|
|
47
|
+
|
|
48
|
+
expect(hub.get('does-not-exist')).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('getAll returns every registered provider', () => {
|
|
52
|
+
const a = buildEvmProvider('wallet-a');
|
|
53
|
+
const b = buildEvmProvider('wallet-b');
|
|
54
|
+
const hub = new Hub({ store }).add(a.id, a).add(b.id, b);
|
|
55
|
+
|
|
56
|
+
const all = hub.getAll();
|
|
57
|
+
expect(all.size).toBe(2);
|
|
58
|
+
expect(all.get('wallet-a')).toBe(a);
|
|
59
|
+
expect(all.get('wallet-b')).toBe(b);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('remove clears the provider from both the hub and the store', () => {
|
|
63
|
+
const provider = buildEvmProvider('wallet-a');
|
|
64
|
+
const hub = new Hub({ store }).add(provider.id, provider);
|
|
65
|
+
|
|
66
|
+
expect(store.getState().providers.list['wallet-a']).toBeDefined();
|
|
67
|
+
|
|
68
|
+
hub.remove('wallet-a');
|
|
69
|
+
|
|
70
|
+
expect(hub.get('wallet-a')).toBeUndefined();
|
|
71
|
+
expect(store.getState().providers.list['wallet-a']).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('remove throws when the provider id is unknown', () => {
|
|
75
|
+
const hub = new Hub({ store });
|
|
76
|
+
|
|
77
|
+
expect(() => hub.remove('nope')).toThrowError(/Provider not found/);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('init runs each provider init exactly once', () => {
|
|
81
|
+
const initSpy = vi.fn();
|
|
82
|
+
const provider = new ProviderBuilder('wallet-a')
|
|
83
|
+
.config('metadata', garbageWalletMetaData)
|
|
84
|
+
.init(initSpy)
|
|
85
|
+
.build();
|
|
86
|
+
|
|
87
|
+
const hub = new Hub({ store }).add(provider.id, provider);
|
|
88
|
+
|
|
89
|
+
expect(initSpy).toBeCalledTimes(0);
|
|
90
|
+
|
|
91
|
+
hub.init();
|
|
92
|
+
hub.init();
|
|
93
|
+
|
|
94
|
+
expect(initSpy).toBeCalledTimes(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('state aggregates per-provider state and their namespaces', () => {
|
|
98
|
+
const provider = buildEvmProvider('wallet-a');
|
|
99
|
+
const hub = new Hub({ store }).add(provider.id, provider);
|
|
100
|
+
|
|
101
|
+
const state = hub.state();
|
|
102
|
+
expect(state['wallet-a']).toBeDefined();
|
|
103
|
+
expect(state['wallet-a'].installed).toBe(false);
|
|
104
|
+
expect(state['wallet-a'].connected).toBe(false);
|
|
105
|
+
expect(state['wallet-a'].namespaces).toHaveLength(1);
|
|
106
|
+
expect(state['wallet-a'].namespaces[0].connected).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
});
|