@rango-dev/wallets-core 0.37.1-next.1 → 0.38.1-next.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.
Files changed (193) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/builders/action.d.ts +22 -0
  3. package/dist/builders/action.d.ts.map +1 -0
  4. package/dist/builders/mod.d.ts +5 -0
  5. package/dist/builders/mod.d.ts.map +1 -0
  6. package/dist/builders/namespace.d.ts +47 -0
  7. package/dist/builders/namespace.d.ts.map +1 -0
  8. package/dist/builders/provider.d.ts +13 -0
  9. package/dist/builders/provider.d.ts.map +1 -0
  10. package/dist/builders/types.d.ts +21 -0
  11. package/dist/builders/types.d.ts.map +1 -0
  12. package/dist/hub/helpers.d.ts +6 -0
  13. package/dist/hub/helpers.d.ts.map +1 -0
  14. package/dist/hub/hub.d.ts +28 -0
  15. package/dist/hub/hub.d.ts.map +1 -0
  16. package/dist/hub/mod.d.ts +7 -0
  17. package/dist/hub/mod.d.ts.map +1 -0
  18. package/dist/hub/namespaces/errors.d.ts +4 -0
  19. package/dist/hub/namespaces/errors.d.ts.map +1 -0
  20. package/dist/hub/namespaces/mod.d.ts +3 -0
  21. package/dist/hub/namespaces/mod.d.ts.map +1 -0
  22. package/dist/hub/namespaces/namespace.d.ts +146 -0
  23. package/dist/hub/namespaces/namespace.d.ts.map +1 -0
  24. package/dist/hub/namespaces/namespace.test.d.ts +2 -0
  25. package/dist/hub/namespaces/namespace.test.d.ts.map +1 -0
  26. package/dist/hub/namespaces/types.d.ts +33 -0
  27. package/dist/hub/namespaces/types.d.ts.map +1 -0
  28. package/dist/hub/provider/mod.d.ts +3 -0
  29. package/dist/hub/provider/mod.d.ts.map +1 -0
  30. package/dist/hub/provider/provider.d.ts +136 -0
  31. package/dist/hub/provider/provider.d.ts.map +1 -0
  32. package/dist/hub/provider/provider.test.d.ts +2 -0
  33. package/dist/hub/provider/provider.test.d.ts.map +1 -0
  34. package/dist/hub/provider/types.d.ts +28 -0
  35. package/dist/hub/provider/types.d.ts.map +1 -0
  36. package/dist/hub/store/hub.d.ts +11 -0
  37. package/dist/hub/store/hub.d.ts.map +1 -0
  38. package/dist/hub/store/mod.d.ts +6 -0
  39. package/dist/hub/store/mod.d.ts.map +1 -0
  40. package/dist/hub/store/namespaces.d.ts +34 -0
  41. package/dist/hub/store/namespaces.d.ts.map +1 -0
  42. package/dist/hub/store/providers.d.ts +45 -0
  43. package/dist/hub/store/providers.d.ts.map +1 -0
  44. package/dist/hub/store/selectors.d.ts +18 -0
  45. package/dist/hub/store/selectors.d.ts.map +1 -0
  46. package/dist/hub/store/store.d.ts +13 -0
  47. package/dist/hub/store/store.d.ts.map +1 -0
  48. package/dist/hub/store/store.test.d.ts +2 -0
  49. package/dist/hub/store/store.test.d.ts.map +1 -0
  50. package/dist/mod.d.ts +6 -1
  51. package/dist/mod.d.ts.map +1 -1
  52. package/dist/mod.js +1 -0
  53. package/dist/mod.js.map +4 -4
  54. package/dist/namespaces/common/actions.d.ts +4 -0
  55. package/dist/namespaces/common/actions.d.ts.map +1 -0
  56. package/dist/namespaces/common/after.d.ts +4 -0
  57. package/dist/namespaces/common/after.d.ts.map +1 -0
  58. package/dist/namespaces/common/and.d.ts +6 -0
  59. package/dist/namespaces/common/and.d.ts.map +1 -0
  60. package/dist/namespaces/common/before.d.ts +4 -0
  61. package/dist/namespaces/common/before.d.ts.map +1 -0
  62. package/dist/namespaces/common/builders.d.ts +4 -0
  63. package/dist/namespaces/common/builders.d.ts.map +1 -0
  64. package/dist/namespaces/common/helpers.d.ts +2 -0
  65. package/dist/namespaces/common/helpers.d.ts.map +1 -0
  66. package/dist/namespaces/common/mod.d.ts +6 -0
  67. package/dist/namespaces/common/mod.d.ts.map +1 -0
  68. package/dist/namespaces/common/mod.js +2 -0
  69. package/dist/namespaces/common/mod.js.map +7 -0
  70. package/dist/namespaces/common/types.d.ts +7 -0
  71. package/dist/namespaces/common/types.d.ts.map +1 -0
  72. package/dist/namespaces/cosmos/mod.d.ts +2 -0
  73. package/dist/namespaces/cosmos/mod.d.ts.map +1 -0
  74. package/dist/namespaces/cosmos/types.d.ts +4 -0
  75. package/dist/namespaces/cosmos/types.d.ts.map +1 -0
  76. package/dist/namespaces/evm/actions.d.ts +8 -0
  77. package/dist/namespaces/evm/actions.d.ts.map +1 -0
  78. package/dist/namespaces/evm/after.d.ts +2 -0
  79. package/dist/namespaces/evm/after.d.ts.map +1 -0
  80. package/dist/namespaces/evm/and.d.ts +3 -0
  81. package/dist/namespaces/evm/and.d.ts.map +1 -0
  82. package/dist/namespaces/evm/before.d.ts +2 -0
  83. package/dist/namespaces/evm/before.d.ts.map +1 -0
  84. package/dist/namespaces/evm/builders.d.ts +4 -0
  85. package/dist/namespaces/evm/builders.d.ts.map +1 -0
  86. package/dist/namespaces/evm/constants.d.ts +3 -0
  87. package/dist/namespaces/evm/constants.d.ts.map +1 -0
  88. package/dist/namespaces/evm/eip1193.d.ts +1228 -0
  89. package/dist/namespaces/evm/eip1193.d.ts.map +1 -0
  90. package/dist/namespaces/evm/mod.d.ts +9 -0
  91. package/dist/namespaces/evm/mod.d.ts.map +1 -0
  92. package/dist/namespaces/evm/mod.js +2 -0
  93. package/dist/namespaces/evm/mod.js.map +7 -0
  94. package/dist/namespaces/evm/types.d.ts +10 -0
  95. package/dist/namespaces/evm/types.d.ts.map +1 -0
  96. package/dist/namespaces/evm/utils.d.ts +9 -0
  97. package/dist/namespaces/evm/utils.d.ts.map +1 -0
  98. package/dist/namespaces/solana/actions.d.ts +6 -0
  99. package/dist/namespaces/solana/actions.d.ts.map +1 -0
  100. package/dist/namespaces/solana/after.d.ts +2 -0
  101. package/dist/namespaces/solana/after.d.ts.map +1 -0
  102. package/dist/namespaces/solana/and.d.ts +3 -0
  103. package/dist/namespaces/solana/and.d.ts.map +1 -0
  104. package/dist/namespaces/solana/before.d.ts +2 -0
  105. package/dist/namespaces/solana/before.d.ts.map +1 -0
  106. package/dist/namespaces/solana/builders.d.ts +4 -0
  107. package/dist/namespaces/solana/builders.d.ts.map +1 -0
  108. package/dist/namespaces/solana/constants.d.ts +3 -0
  109. package/dist/namespaces/solana/constants.d.ts.map +1 -0
  110. package/dist/namespaces/solana/mod.d.ts +8 -0
  111. package/dist/namespaces/solana/mod.d.ts.map +1 -0
  112. package/dist/namespaces/solana/mod.js +2 -0
  113. package/dist/namespaces/solana/mod.js.map +7 -0
  114. package/dist/namespaces/solana/types.d.ts +7 -0
  115. package/dist/namespaces/solana/types.d.ts.map +1 -0
  116. package/dist/test-utils/fixtures.d.ts +3 -0
  117. package/dist/test-utils/fixtures.d.ts.map +1 -0
  118. package/dist/types/accounts.d.ts +11 -0
  119. package/dist/types/accounts.d.ts.map +1 -0
  120. package/dist/types/actions.d.ts +5 -0
  121. package/dist/types/actions.d.ts.map +1 -0
  122. package/dist/types/utils.d.ts +7 -0
  123. package/dist/types/utils.d.ts.map +1 -0
  124. package/dist/utils/mod.d.ts +4 -0
  125. package/dist/utils/mod.d.ts.map +1 -0
  126. package/dist/utils/mod.js +2 -0
  127. package/dist/utils/mod.js.map +7 -0
  128. package/dist/utils/versions.d.ts +21 -0
  129. package/dist/utils/versions.d.ts.map +1 -0
  130. package/dist/utils/versions.test.d.ts +2 -0
  131. package/dist/utils/versions.test.d.ts.map +1 -0
  132. package/dist/wallets-core.build.json +1 -1
  133. package/package.json +25 -4
  134. package/src/builders/action.ts +86 -0
  135. package/src/builders/mod.ts +5 -0
  136. package/src/builders/namespace.ts +229 -0
  137. package/src/builders/provider.ts +61 -0
  138. package/src/builders/types.ts +29 -0
  139. package/src/hub/helpers.ts +11 -0
  140. package/src/hub/hub.ts +122 -0
  141. package/src/hub/mod.ts +10 -0
  142. package/src/hub/namespaces/errors.ts +8 -0
  143. package/src/hub/namespaces/mod.ts +9 -0
  144. package/src/hub/namespaces/namespace.test.ts +333 -0
  145. package/src/hub/namespaces/namespace.ts +443 -0
  146. package/src/hub/namespaces/types.ts +50 -0
  147. package/src/hub/provider/mod.ts +9 -0
  148. package/src/hub/provider/provider.test.ts +231 -0
  149. package/src/hub/provider/provider.ts +330 -0
  150. package/src/hub/provider/types.ts +37 -0
  151. package/src/hub/store/hub.ts +18 -0
  152. package/src/hub/store/mod.ts +8 -0
  153. package/src/hub/store/namespaces.ts +90 -0
  154. package/src/hub/store/providers.ts +97 -0
  155. package/src/hub/store/selectors.ts +59 -0
  156. package/src/hub/store/store.test.ts +32 -0
  157. package/src/hub/store/store.ts +26 -0
  158. package/src/mod.ts +35 -1
  159. package/src/namespaces/common/actions.ts +11 -0
  160. package/src/namespaces/common/after.ts +8 -0
  161. package/src/namespaces/common/and.ts +42 -0
  162. package/src/namespaces/common/before.ts +9 -0
  163. package/src/namespaces/common/builders.ts +19 -0
  164. package/src/namespaces/common/helpers.ts +10 -0
  165. package/src/namespaces/common/mod.ts +12 -0
  166. package/src/namespaces/common/types.ts +7 -0
  167. package/src/namespaces/cosmos/mod.ts +1 -0
  168. package/src/namespaces/cosmos/types.ts +10 -0
  169. package/src/namespaces/evm/actions.ts +97 -0
  170. package/src/namespaces/evm/after.ts +3 -0
  171. package/src/namespaces/evm/and.ts +5 -0
  172. package/src/namespaces/evm/before.ts +3 -0
  173. package/src/namespaces/evm/builders.ts +10 -0
  174. package/src/namespaces/evm/constants.ts +2 -0
  175. package/src/namespaces/evm/eip1193.ts +1414 -0
  176. package/src/namespaces/evm/mod.ts +9 -0
  177. package/src/namespaces/evm/types.ts +18 -0
  178. package/src/namespaces/evm/utils.ts +52 -0
  179. package/src/namespaces/solana/actions.ts +70 -0
  180. package/src/namespaces/solana/after.ts +3 -0
  181. package/src/namespaces/solana/and.ts +5 -0
  182. package/src/namespaces/solana/before.ts +3 -0
  183. package/src/namespaces/solana/builders.ts +10 -0
  184. package/src/namespaces/solana/constants.ts +2 -0
  185. package/src/namespaces/solana/mod.ts +8 -0
  186. package/src/namespaces/solana/types.ts +20 -0
  187. package/src/test-utils/fixtures.ts +9 -0
  188. package/src/types/accounts.ts +12 -0
  189. package/src/types/actions.ts +11 -0
  190. package/src/types/utils.ts +7 -0
  191. package/src/utils/mod.ts +8 -0
  192. package/src/utils/versions.test.ts +22 -0
  193. package/src/utils/versions.ts +63 -0
@@ -0,0 +1,231 @@
1
+ import type { EvmActions } from '../../namespaces/evm/types.js';
2
+ import type { SolanaActions } from '../../namespaces/solana/types.js';
3
+ import type { Store } from '../store/mod.js';
4
+
5
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
6
+
7
+ import { NamespaceBuilder } from '../../builders/namespace.js';
8
+ import { ProviderBuilder } from '../../builders/provider.js';
9
+ import { garbageWalletInfo } from '../../test-utils/fixtures.js';
10
+ import { createStore } from '../store/mod.js';
11
+
12
+ import { Provider } from './provider.js';
13
+
14
+ describe('check providers', () => {
15
+ let namespaces: {
16
+ evm: NamespaceBuilder<EvmActions>;
17
+ solana: NamespaceBuilder<SolanaActions>;
18
+ };
19
+ let namespacesMap: Map<any, any>;
20
+ let store: Store;
21
+
22
+ beforeEach(() => {
23
+ store = createStore();
24
+ const evmNamespace = new NamespaceBuilder<EvmActions>('eip155', 'garbage');
25
+ const solanaNamespace = new NamespaceBuilder<SolanaActions>(
26
+ 'solana',
27
+ 'garbage'
28
+ );
29
+
30
+ namespaces = {
31
+ evm: evmNamespace,
32
+ solana: solanaNamespace,
33
+ };
34
+
35
+ namespacesMap = new Map();
36
+ namespacesMap.set('evm', evmNamespace.build());
37
+ namespacesMap.set('solana', solanaNamespace.build());
38
+
39
+ return () => {
40
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
41
+ // @ts-ignore-next-line
42
+ (store = undefined), (namespaces = undefined);
43
+ };
44
+ });
45
+
46
+ test('Initialize providers correctly', () => {
47
+ const provider = new Provider('garbage', namespacesMap, {
48
+ info: garbageWalletInfo,
49
+ });
50
+
51
+ const allNamespaces = provider.getAll();
52
+
53
+ expect(allNamespaces.size).toBe(2);
54
+ });
55
+
56
+ test("throw an error if store hasn't set and try to access .state() and .info()", () => {
57
+ const provider = new Provider('garbage', namespacesMap, {
58
+ info: garbageWalletInfo,
59
+ });
60
+
61
+ expect(() => provider.state()).toThrowError();
62
+ expect(() => provider.info()).toThrowError();
63
+ });
64
+
65
+ test('access state correctly', () => {
66
+ const provider = new Provider(
67
+ 'garbage',
68
+ namespacesMap,
69
+ {
70
+ info: garbageWalletInfo,
71
+ },
72
+ {
73
+ store: createStore(),
74
+ }
75
+ );
76
+
77
+ const [getState, setState] = provider.state();
78
+
79
+ expect(getState().connected).toBe(false);
80
+ expect(getState('connected')).toBe(false);
81
+ expect(() => {
82
+ // @ts-expect-error intentionally using an state that doesn't exist.
83
+ getState('not_exist_state');
84
+ }).toThrowError();
85
+ expect(() => {
86
+ // @ts-expect-error intentionally using an state that doesn't exist and try to update.
87
+ setState('another_not_exist_state');
88
+ }).toThrowError();
89
+ });
90
+ test('update state properly', () => {
91
+ const store = createStore();
92
+ const provider = new Provider(
93
+ 'garbage',
94
+ namespacesMap,
95
+ {
96
+ info: garbageWalletInfo,
97
+ },
98
+ {
99
+ store,
100
+ }
101
+ );
102
+
103
+ const [getState, setState] = provider.state();
104
+
105
+ provider.store(store);
106
+ setState('installed', true);
107
+ const isInstalled = getState('installed');
108
+ expect(isInstalled).toBe(true);
109
+ });
110
+
111
+ test('run namespace actions from provider', async () => {
112
+ const { evm, solana } = namespaces;
113
+ solana.action('connect', async () => [
114
+ 'solana:mainnet:0x000000000000000000000000000000000000dead',
115
+ ]);
116
+ const testNamespaces = new Map();
117
+ testNamespaces.set('evm', evm.build());
118
+ testNamespaces.set('solana', solana.build());
119
+
120
+ const provider = new Provider('garbage', testNamespaces, {
121
+ info: garbageWalletInfo,
122
+ });
123
+
124
+ const result = await provider.get('solana')?.connect();
125
+
126
+ expect(result).toStrictEqual([
127
+ 'solana:mainnet:0x000000000000000000000000000000000000dead',
128
+ ]);
129
+ // Since we didn't add any action regarding connect for `evm`
130
+ await expect(async () =>
131
+ provider.get('evm')?.connect('0x1')
132
+ ).rejects.toThrowError();
133
+ });
134
+
135
+ test('sets config properly', () => {
136
+ const builder = new ProviderBuilder('garbage');
137
+ builder.config('info', garbageWalletInfo);
138
+ const provider = builder.build().store(store);
139
+
140
+ expect(provider.info()).toStrictEqual(garbageWalletInfo);
141
+ });
142
+
143
+ test('.init should works on Provider', () => {
144
+ const builder = new ProviderBuilder('garbage').config(
145
+ 'info',
146
+ garbageWalletInfo
147
+ );
148
+ let count = 0;
149
+ builder.init(() => {
150
+ count++;
151
+ });
152
+ const provider = builder.build().store(store);
153
+ expect(count).toBe(0);
154
+ provider.init();
155
+ provider.init();
156
+ provider.init();
157
+ expect(count).toBe(1);
158
+ });
159
+
160
+ test(".init shouldn't do anything when use hasn't set anything", () => {
161
+ const builder = new ProviderBuilder('garbage').config(
162
+ 'info',
163
+ garbageWalletInfo
164
+ );
165
+ const provider = builder.build().store(store);
166
+ expect(() => {
167
+ provider.init();
168
+ provider.init();
169
+ provider.init();
170
+ }).not.toThrow();
171
+ });
172
+
173
+ test('A provider can be found using its namespace', () => {
174
+ const builder = new ProviderBuilder('garbage', { store }).config(
175
+ 'info',
176
+ garbageWalletInfo
177
+ );
178
+
179
+ const { evm, solana } = namespaces;
180
+ builder.add('evm', evm.build()).add('solana', solana.build());
181
+ const provider = builder.build();
182
+
183
+ const result = provider.findByNamespace('solana');
184
+ expect(result).toBeDefined();
185
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
186
+ // @ts-ignore-next-line
187
+ expect(result?.namespaceId).toBe('solana');
188
+
189
+ const result2 = provider.findByNamespace('evm');
190
+ expect(result2).toBeUndefined();
191
+ });
192
+
193
+ test('`before/after` is calling with correct context ', () => {
194
+ const connect = vi.fn();
195
+ const before = vi.fn(function (context) {
196
+ const [, setState] = context.state();
197
+ setState('installed', true);
198
+ });
199
+ const after = vi.fn(function (context) {
200
+ const [, setState] = context.state();
201
+ setState('installed', false);
202
+ });
203
+
204
+ const { evm } = namespaces;
205
+ const evmNamespace = evm.action('connect', connect).build();
206
+
207
+ const builder = new ProviderBuilder('garbage', { store })
208
+ .add('evm', evmNamespace)
209
+ .config('info', garbageWalletInfo);
210
+ const provider = builder.build();
211
+
212
+ const [getState] = provider.state();
213
+ const result = provider.get('evm');
214
+
215
+ // Adding `after` then make it will run
216
+ provider.before('connect', before);
217
+ void result?.connect('whatever');
218
+
219
+ expect(connect).toBeCalledTimes(1);
220
+ expect(before).toBeCalledTimes(1);
221
+ expect(getState('installed')).toBe(true);
222
+
223
+ // Adding `after` then make it will run
224
+ provider.after('connect', after);
225
+ void result?.connect('whatever');
226
+ expect(connect).toBeCalledTimes(2);
227
+ expect(after).toBeCalledTimes(1);
228
+
229
+ expect(getState('installed')).toBe(false);
230
+ });
231
+ });
@@ -0,0 +1,330 @@
1
+ import type {
2
+ CommonNamespaces,
3
+ Context,
4
+ ExtendableInternalActions,
5
+ GetState,
6
+ RegisteredNamespaces,
7
+ SetState,
8
+ State,
9
+ } from './types.js';
10
+ import type { FindProxiedNamespace } from '../../builders/mod.js';
11
+ import type { AnyFunction, FunctionWithContext } from '../../types/actions.js';
12
+ import type { ProviderConfig, Store } from '../store/mod.js';
13
+
14
+ const VERSION = '1.0';
15
+
16
+ export class Provider {
17
+ public readonly id: string;
18
+ public readonly version = VERSION;
19
+
20
+ #namespaces: RegisteredNamespaces<keyof CommonNamespaces, CommonNamespaces>;
21
+ #initiated = false;
22
+ #extendInternalActions: ExtendableInternalActions = {};
23
+ #store: Store | undefined;
24
+ #configs: ProviderConfig;
25
+
26
+ constructor(
27
+ id: string,
28
+ namespaces: RegisteredNamespaces<keyof CommonNamespaces, CommonNamespaces>,
29
+ configs: ProviderConfig,
30
+ options?: {
31
+ /**
32
+ * There are some cases we need to have a behavior like initializing a provider which will be run when we are creating an instance.
33
+ * These internal steps and behaviors will be useful for library user to extend the behavior by running a specific code.
34
+ */
35
+ extendInternalActions?: ExtendableInternalActions;
36
+ store?: Store;
37
+ }
38
+ ) {
39
+ this.id = id;
40
+ this.#configs = configs;
41
+ // it should be only created here, to make sure `after/before` will work properly.
42
+ this.#extendInternalActions = options?.extendInternalActions || {};
43
+ this.#namespaces = namespaces;
44
+
45
+ if (options?.store) {
46
+ this.#store = options.store;
47
+ this.#setupStore();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * This is an special callback that will be called **only once**.
53
+ * We don't call this in `constructor` and developer should call this manually. we only ensure it will be called once.
54
+ *
55
+ * ```ts
56
+ * const myInit = () => { whatever; } *
57
+ * const provider = new Provider(..., {extendInternalActions: {init: myInit} });
58
+ *
59
+ * // Will run `myInit`
60
+ * provider.init()
61
+ *
62
+ * // Will not run `myInit` anymore.
63
+ * provider.init()
64
+ * provider.init()
65
+ * ```
66
+ */
67
+ public init(): void {
68
+ if (this.#initiated) {
69
+ return;
70
+ }
71
+
72
+ const definedInitByUser = this.#extendInternalActions.init;
73
+ if (definedInitByUser) {
74
+ definedInitByUser(this.#context());
75
+ }
76
+
77
+ this.#initiated = true;
78
+ }
79
+
80
+ /**
81
+ * Getting state of a provider
82
+ *
83
+ * **Note:**
84
+ * Each namespace has it's own state as well, in Legacy we didn't have this separation and all of them was accessible through Provider itself
85
+ * To be compatible with legacy, `getState` has a logic to guess the final state to produce same state as legacy.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const provider = new Provider(...);
90
+ * const [getState, setState] = provider.state();
91
+ *
92
+ * getState('installed');
93
+ * // or
94
+ * getState().installed;
95
+ * ```
96
+ *
97
+ */
98
+ public state(): [GetState, SetState] {
99
+ const store = this.#store;
100
+ if (!store) {
101
+ throw new Error(
102
+ `Any store detected for ${this.id}. You need to set your store using '.store' method first.`
103
+ );
104
+ }
105
+
106
+ /**
107
+ * State updater
108
+ */
109
+ const setState: SetState = (name, value) => {
110
+ switch (name) {
111
+ case 'installed':
112
+ return store.getState().providers.updateStatus(this.id, name, value);
113
+ default:
114
+ throw new Error(
115
+ `Unhandled state update for provider. (provider id: ${this.id}, state name: ${name})`
116
+ );
117
+ }
118
+ };
119
+
120
+ /**
121
+ * State getter
122
+ */
123
+ const getState: GetState = <K extends keyof State>(name?: K) => {
124
+ const state: State = store
125
+ .getState()
126
+ .providers.guessNamespacesState(this.id);
127
+
128
+ if (!name) {
129
+ return state;
130
+ }
131
+
132
+ switch (name) {
133
+ case 'installed':
134
+ case 'connected':
135
+ case 'connecting':
136
+ return state[name];
137
+ default:
138
+ throw new Error('Unhandled state for provider');
139
+ }
140
+ };
141
+
142
+ return [getState, setState];
143
+ }
144
+
145
+ /**
146
+ * For keeping state, we need a store. all the states will be write to/read from store.
147
+ *
148
+ * **Note: When you are setting an store for provider, it will be set for its namespaces automatically as well**
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * const myStore = createStore();
153
+ * const provider = new Provider(...);
154
+ * provider.store(myStore); // or it can be passed to Provider constructor;
155
+ * ```
156
+ */
157
+ public store(store: Store): this {
158
+ if (this.#store) {
159
+ console.warn(
160
+ "You've already set an store for your Provider. Old store will be replaced by the new one."
161
+ );
162
+ }
163
+ this.#store = store;
164
+ this.#setupStore();
165
+ return this;
166
+ }
167
+
168
+ /**
169
+ * Getting information about a provider which has been set on constructing Provider.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * const walletInfo = {name: "Garbage wallet", ...}
174
+ * const provider = new Provider(..., {info: walletInfo});
175
+ *
176
+ * provider.info();
177
+ * ```
178
+ */
179
+ public info(): ProviderConfig['info'] | undefined {
180
+ const store = this.#store;
181
+ if (!store) {
182
+ throw new Error(
183
+ 'You need to set your store using `.store` method first.'
184
+ );
185
+ }
186
+
187
+ return store.getState().providers.list[this.id].config.info;
188
+ }
189
+
190
+ /**
191
+ * A list of registered _proxied_ namespaces.
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * const provider = new Provider(...);
196
+ * const allNamespaces = provider.getAll();
197
+ * ```
198
+ */
199
+ public getAll(): RegisteredNamespaces<
200
+ keyof CommonNamespaces,
201
+ CommonNamespaces
202
+ > {
203
+ return this.#namespaces;
204
+ }
205
+
206
+ /**
207
+ * Get a registered namespace in provider by its **namespace key**.
208
+ *
209
+ * Note: difference between namespace key and namespace id is the first one is setting from a predefined list the second one can be anything and will be chosen by library's user.
210
+ *
211
+ * @param {string} id - evm, solana, cosmos, ... (CommonActions)
212
+ */
213
+ public get<K extends keyof CommonNamespaces>(
214
+ id: K
215
+ ): FindProxiedNamespace<K, CommonNamespaces> | undefined {
216
+ return this.#namespaces.get(id) as unknown as
217
+ | FindProxiedNamespace<K, CommonNamespaces>
218
+ | undefined;
219
+ }
220
+
221
+ /**
222
+ *
223
+ * Get a registered namespace by its **namespaceId**.
224
+ *
225
+ * Note: difference between namespace key and namespace id is the first one is setting from a predefined list the second one can be anything and will be chosen by library's user.
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * const provider = new Provider(...);
230
+ * provider.findByNamespace("whatever-id-i-set-for-namespace")
231
+ * ```
232
+ */
233
+ public findByNamespace<K extends keyof CommonNamespaces>(
234
+ namespaceLookingFor: K | string
235
+ ): FindProxiedNamespace<K, CommonNamespaces> | undefined {
236
+ // If we didn't found any match, we will return `undefined`.
237
+ let result: object | undefined = undefined;
238
+
239
+ this.#namespaces.forEach((namespace) => {
240
+ if (namespace.namespaceId === namespaceLookingFor) {
241
+ result = namespace;
242
+ }
243
+ });
244
+
245
+ return result;
246
+ }
247
+
248
+ /**
249
+ * Running a hook function _after_ a specific action for **all registered namespaces**.
250
+ *
251
+ * **Note:** the context can be set from outside as well. this is useful for Provider to set its context instead of namespace context.
252
+ *
253
+ * @example
254
+ * ```ts
255
+ * const provider = new Provider(...);
256
+ *
257
+ * provider.after("connect", (context) => {});
258
+ * ```
259
+ */
260
+ public before(
261
+ actionName: string,
262
+ hookFn: FunctionWithContext<AnyFunction, Context>
263
+ ): this {
264
+ this.#addHook('before', actionName, hookFn);
265
+ return this;
266
+ }
267
+
268
+ /**
269
+ * Running a hook function _before_ a specific action for **all registered namespaces**.
270
+ *
271
+ * **Note:** the context can be set from outside as well. this is useful for Provider to set its context instead of namespace context.
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * const provider = new Provider(...);
276
+ *
277
+ * provider.after("connect", (context) => {});
278
+ * ```
279
+ */
280
+ public after(
281
+ actionName: string,
282
+ hookFn: FunctionWithContext<AnyFunction, Context>
283
+ ): this {
284
+ this.#addHook('after', actionName, hookFn);
285
+ return this;
286
+ }
287
+
288
+ #addHook(
289
+ hookName: 'after' | 'before',
290
+ actionName: string,
291
+ cb: FunctionWithContext<AnyFunction, Context>
292
+ ): this {
293
+ const context = {
294
+ state: this.state.bind(this),
295
+ };
296
+
297
+ this.#namespaces.forEach((namespace) => {
298
+ if (hookName === 'after') {
299
+ namespace.after(actionName as any, cb, {
300
+ context,
301
+ });
302
+ } else if (hookName === 'before') {
303
+ namespace.before(actionName as any, cb, {
304
+ context,
305
+ });
306
+ } else {
307
+ throw new Error(`You hook name is invalid: ${hookName}`);
308
+ }
309
+ });
310
+
311
+ return this;
312
+ }
313
+
314
+ #setupStore(): void {
315
+ const store = this.#store;
316
+ if (!store) {
317
+ throw new Error('For setup store, you should set `store` first.');
318
+ }
319
+ store.getState().providers.addProvider(this.id, this.#configs);
320
+ this.#namespaces.forEach((provider) => {
321
+ provider.store(store);
322
+ });
323
+ }
324
+
325
+ #context(): Context {
326
+ return {
327
+ state: this.state.bind(this),
328
+ };
329
+ }
330
+ }
@@ -0,0 +1,37 @@
1
+ import type { LegacyState } from '../../legacy/mod.js';
2
+ import type { NamespaceInterface, Store } from '../../mod.js';
3
+ import type { CosmosActions } from '../../namespaces/cosmos/mod.js';
4
+ import type { EvmActions } from '../../namespaces/evm/mod.js';
5
+ import type { SolanaActions } from '../../namespaces/solana/mod.js';
6
+ import type { AnyFunction, FunctionWithContext } from '../../types/actions.js';
7
+
8
+ export type Context = {
9
+ state: () => [GetState, SetState];
10
+ };
11
+
12
+ export type State = Omit<LegacyState, 'reachable' | 'accounts' | 'network'>;
13
+ export type SetState = <K extends keyof Pick<State, 'installed'>>(
14
+ name: K,
15
+ value: State[K]
16
+ ) => void;
17
+ export type GetState = {
18
+ (): State;
19
+ <K extends keyof State>(name: K): State[K];
20
+ };
21
+
22
+ export interface CommonNamespaces {
23
+ evm: EvmActions;
24
+ solana: SolanaActions;
25
+ cosmos: CosmosActions;
26
+ }
27
+
28
+ export interface ExtendableInternalActions {
29
+ init?: FunctionWithContext<AnyFunction, Context>;
30
+ }
31
+
32
+ export type RegisteredNamespaces<K extends keyof T, T> = Map<
33
+ K,
34
+ NamespaceInterface<K, T>
35
+ >;
36
+
37
+ export type ProviderBuilderOptions = { store?: Store };
@@ -0,0 +1,18 @@
1
+ /************ Hub ************/
2
+
3
+ import type { State } from './mod.js';
4
+ import type { StateCreator } from 'zustand';
5
+
6
+ type HubConfig = object;
7
+
8
+ export interface HubStore {
9
+ config: HubConfig;
10
+ }
11
+
12
+ type HubStateCreator = StateCreator<State, [], [], HubStore>;
13
+
14
+ const hubStore: HubStateCreator = () => ({
15
+ config: {},
16
+ });
17
+
18
+ export { hubStore };
@@ -0,0 +1,8 @@
1
+ export {
2
+ guessProviderStateSelector,
3
+ namespaceStateSelector,
4
+ } from './selectors.js';
5
+ export type { Store, State } from './store.js';
6
+ export type { ProviderInfo, ProviderConfig } from './providers.js';
7
+ export type { NamespaceConfig, NamespaceData } from './namespaces.js';
8
+ export { createStore } from './store.js';
@@ -0,0 +1,90 @@
1
+ /************ Namespace ************/
2
+
3
+ import type { StateCreator } from 'zustand';
4
+
5
+ import { produce } from 'immer';
6
+
7
+ import { namespaceStateSelector, type State } from './mod.js';
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
10
+ export interface NamespaceConfig {
11
+ // Currently, namespace doesn't has any config.
12
+ }
13
+
14
+ export interface NamespaceData {
15
+ accounts: null | string[];
16
+ network: null | string;
17
+ connected: boolean;
18
+ connecting: boolean;
19
+ }
20
+
21
+ interface NamespaceInfo {
22
+ providerId: string;
23
+ namespaceId: string;
24
+ }
25
+
26
+ type NamespaceState = {
27
+ list: Record<
28
+ string,
29
+ {
30
+ info: NamespaceInfo;
31
+ data: NamespaceData;
32
+ error: unknown;
33
+ }
34
+ >;
35
+ };
36
+
37
+ interface NamespaceActions {
38
+ addNamespace: (id: string, config: NamespaceInfo) => void;
39
+ updateStatus: <K extends keyof NamespaceData>(
40
+ id: string,
41
+ key: K,
42
+ value: NamespaceData[K]
43
+ ) => void;
44
+ }
45
+ interface NamespaceSelectors {
46
+ getNamespaceData(storeId: string): NamespaceData;
47
+ }
48
+
49
+ export type NamespaceStore = NamespaceState &
50
+ NamespaceActions &
51
+ NamespaceSelectors;
52
+ type NamespaceStateCreator = StateCreator<State, [], [], NamespaceStore>;
53
+
54
+ const namespacesStore: NamespaceStateCreator = (set, get) => ({
55
+ list: {},
56
+ addNamespace: (id, info) => {
57
+ const item = {
58
+ data: {
59
+ accounts: null,
60
+ network: null,
61
+ connected: false,
62
+ connecting: false,
63
+ },
64
+ error: '',
65
+ info,
66
+ };
67
+
68
+ set(
69
+ produce((state: State) => {
70
+ state.namespaces.list[id] = item;
71
+ })
72
+ );
73
+ },
74
+ updateStatus: (id, key, value) => {
75
+ if (!get().namespaces.list[id]) {
76
+ throw new Error(`No namespace with '${id}' found.`);
77
+ }
78
+
79
+ set(
80
+ produce((state: State) => {
81
+ state.namespaces.list[id].data[key] = value;
82
+ })
83
+ );
84
+ },
85
+ getNamespaceData(storeId) {
86
+ return namespaceStateSelector(get(), storeId);
87
+ },
88
+ });
89
+
90
+ export { namespacesStore };