@fedimint/core-web 0.0.2 → 0.0.4

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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -13
  3. package/dist/FedimintWallet.d.ts +40 -33
  4. package/dist/FedimintWallet.d.ts.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/services/BalanceService.d.ts +8 -0
  8. package/dist/services/BalanceService.d.ts.map +1 -0
  9. package/dist/services/FederationService.d.ts +12 -0
  10. package/dist/services/FederationService.d.ts.map +1 -0
  11. package/dist/services/LightningService.d.ts +17 -0
  12. package/dist/services/LightningService.d.ts.map +1 -0
  13. package/dist/services/MintService.d.ts +15 -0
  14. package/dist/services/MintService.d.ts.map +1 -0
  15. package/dist/services/RecoveryService.d.ts +13 -0
  16. package/dist/services/RecoveryService.d.ts.map +1 -0
  17. package/dist/services/index.d.ts +6 -0
  18. package/dist/services/index.d.ts.map +1 -0
  19. package/dist/types/wallet.d.ts +19 -3
  20. package/dist/types/wallet.d.ts.map +1 -1
  21. package/dist/worker/WorkerClient.d.ts +41 -0
  22. package/dist/worker/WorkerClient.d.ts.map +1 -0
  23. package/dist/worker/index.d.ts +2 -0
  24. package/dist/worker/index.d.ts.map +1 -0
  25. package/dist/worker.js +2 -0
  26. package/dist/worker.js.map +1 -0
  27. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm.d.ts +49 -0
  28. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm.js +4 -0
  29. package/node_modules/@fedimint/fedimint-client-wasm/fedimint_client_wasm_bg.js +1411 -0
  30. package/{wasm → node_modules/@fedimint/fedimint-client-wasm}/fedimint_client_wasm_bg.wasm +0 -0
  31. package/node_modules/@fedimint/fedimint-client-wasm/package.json +23 -0
  32. package/package.json +12 -5
  33. package/src/FedimintWallet.test.ts +74 -0
  34. package/src/FedimintWallet.ts +88 -342
  35. package/src/services/BalanceService.ts +24 -0
  36. package/src/services/FederationService.ts +32 -0
  37. package/src/services/LightningService.ts +128 -0
  38. package/src/services/MintService.ts +93 -0
  39. package/src/services/RecoveryService.ts +26 -0
  40. package/src/services/index.ts +5 -0
  41. package/src/types/wallet.ts +25 -2
  42. package/src/worker/WorkerClient.ts +190 -0
  43. package/src/worker/index.ts +1 -0
  44. package/src/worker/worker.js +85 -0
  45. package/dist/assets/fedimint_client_wasm_bg-DxOUItb-.wasm +0 -0
  46. package/dist/wasm.worker.d.ts +0 -1
  47. package/dist/wasm.worker.d.ts.map +0 -1
  48. package/src/vite-env.d.ts +0 -1
  49. package/src/wasm.worker.ts +0 -41
  50. package/wasm/fedimint_client_wasm.d.ts +0 -104
  51. package/wasm/fedimint_client_wasm.js +0 -1120
  52. package/wasm/fedimint_client_wasm_bg.js +0 -873
  53. package/wasm/fedimint_client_wasm_bg.wasm.d.ts +0 -34
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@fedimint/fedimint-client-wasm",
3
+ "private": true,
4
+ "type": "module",
5
+ "description": "Wasm-pack output for fedimint-client-wasm",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/fedimint/fedimint"
10
+ },
11
+ "files": [
12
+ "fedimint_client_wasm_bg.wasm",
13
+ "fedimint_client_wasm.js",
14
+ "fedimint_client_wasm_bg.js",
15
+ "fedimint_client_wasm.d.ts"
16
+ ],
17
+ "main": "fedimint_client_wasm.js",
18
+ "types": "fedimint_client_wasm.d.ts",
19
+ "sideEffects": [
20
+ "./fedimint_client_wasm.js",
21
+ "./snippets/*"
22
+ ]
23
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fedimint/core-web",
3
3
  "description": "Library for building web apps with a fedimint client",
4
- "version": "0.0.2",
4
+ "version": "0.0.4",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/fedimint/fedimint-web-sdk.git",
@@ -9,20 +9,27 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
- "wasm",
13
12
  "src"
14
13
  ],
15
- "sideEffects": false,
14
+ "sideEffects": [
15
+ "./dist/worker.js",
16
+ "./dist/index.js"
17
+ ],
16
18
  "type": "module",
17
19
  "main": "./dist/index.js",
18
20
  "types": "./dist/index.d.ts",
21
+ "dependencies": {
22
+ "@fedimint/fedimint-client-wasm": "file:./wasm"
23
+ },
24
+ "bundleDependencies": [
25
+ "@fedimint/fedimint-client-wasm"
26
+ ],
19
27
  "devDependencies": {
20
28
  "@rollup/plugin-terser": "^0.4.4",
21
29
  "@rollup/plugin-typescript": "^11.1.6",
22
- "@rollup/plugin-wasm": "^6.2.2",
23
30
  "@types/node": "^20.14.8",
24
- "@web/rollup-plugin-import-meta-assets": "^2.2.1",
25
31
  "rollup": "^4.21.2",
32
+ "rollup-plugin-typescript2": "^0.36.0",
26
33
  "tslib": "^2.7.0",
27
34
  "typescript": "^5.2.2"
28
35
  },
@@ -0,0 +1,74 @@
1
+ import { test, expect, vi } from 'vitest'
2
+ import { FedimintWallet } from './FedimintWallet'
3
+ import { beforeAll } from 'vitest'
4
+
5
+ let randomTestingId: string
6
+ let wallet: FedimintWallet
7
+ // Testnet
8
+ const TESTING_FEDERATION =
9
+ 'fed11qgqrgvnhwden5te0v9k8q6rp9ekh2arfdeukuet595cr2ttpd3jhq6rzve6zuer9wchxvetyd938gcewvdhk6tcqqysptkuvknc7erjgf4em3zfh90kffqf9srujn6q53d6r056e4apze5cw27h75'
10
+
11
+ beforeAll(() => {
12
+ randomTestingId = Math.random().toString(36).substring(2, 15)
13
+ wallet = new FedimintWallet()
14
+ expect(wallet).toBeDefined()
15
+
16
+ // Cleanup after all tests
17
+ return async () => {
18
+ // clear up browser resources
19
+ await wallet.cleanup()
20
+ // remove the wallet db
21
+ indexedDB.deleteDatabase(randomTestingId)
22
+ // swap out the randomTestingId for a new one, to avoid raciness
23
+ randomTestingId = Math.random().toString(36).substring(2, 15)
24
+ }
25
+ })
26
+
27
+ test('initial open & join', async () => {
28
+ expect(wallet).toBeDefined()
29
+ expect(wallet.isOpen()).toBe(false)
30
+ // On initial open, it should return false
31
+ // because no federations have been joined
32
+ await expect(wallet.open(randomTestingId)).resolves.toBe(false)
33
+ await expect(
34
+ wallet.joinFederation(TESTING_FEDERATION, randomTestingId),
35
+ ).resolves.toBeUndefined()
36
+ expect(wallet.isOpen()).toBe(true)
37
+ await expect(wallet.waitForOpen()).resolves.toBeUndefined()
38
+ })
39
+
40
+ test('Error on open & join if wallet is already open', async () => {
41
+ expect(wallet).toBeDefined()
42
+ expect(wallet.isOpen()).toBe(true)
43
+
44
+ // Test opening an already open wallet
45
+ try {
46
+ await wallet.open(randomTestingId)
47
+ } catch (error) {
48
+ expect(error).toBeInstanceOf(Error)
49
+ expect((error as Error).message).toBe('The FedimintWallet is already open.')
50
+ }
51
+
52
+ // Test joining federation on an already open wallet
53
+ try {
54
+ await wallet.joinFederation(TESTING_FEDERATION, randomTestingId)
55
+ } catch (error) {
56
+ expect(error).toBeInstanceOf(Error)
57
+ expect((error as Error).message).toBe(
58
+ 'The FedimintWallet is already open. You can only call `joinFederation` on closed clients.',
59
+ )
60
+ }
61
+ })
62
+ test('getConfig', async () => {
63
+ expect(wallet).toBeDefined()
64
+ expect(wallet.isOpen()).toBe(true)
65
+ const config = await wallet.federation.getConfig()
66
+ expect(config).toBeDefined()
67
+ })
68
+
69
+ test('empty getBalance', async () => {
70
+ expect(wallet).toBeDefined()
71
+ expect(wallet.isOpen()).toBe(true)
72
+ await expect(wallet.waitForOpen()).resolves.toBeUndefined()
73
+ await expect(wallet.balance.getBalance()).resolves.toEqual(0)
74
+ })
@@ -1,381 +1,127 @@
1
- import init, { RpcHandle, WasmClient } from '../wasm/fedimint_client_wasm.js'
1
+ import { WorkerClient } from './worker/WorkerClient'
2
2
  import {
3
- JSONValue,
4
- JSONObject,
5
- LightningGateway,
6
- OutgoingLightningPayment,
7
- LnPayState,
8
- LnReceiveState,
9
- StreamResult,
10
- StreamError,
11
- CreateBolt11Response,
12
- ModuleKind,
13
- } from './types/wallet.js'
3
+ BalanceService,
4
+ MintService,
5
+ LightningService,
6
+ FederationService,
7
+ RecoveryService,
8
+ } from './services'
14
9
 
15
10
  const DEFAULT_CLIENT_NAME = 'fm-default' as const
16
11
 
17
12
  export class FedimintWallet {
18
- private _fed: WasmClient | null = null
19
- private initPromise: Promise<void> | null = null
13
+ private client: WorkerClient
14
+
15
+ public balance: BalanceService
16
+ public mint: MintService
17
+ public lightning: LightningService
18
+ public federation: FederationService
19
+ public recovery: RecoveryService
20
+
20
21
  private openPromise: Promise<void> | null = null
21
22
  private resolveOpen: () => void = () => {}
23
+ private _isOpen: boolean = false
22
24
 
25
+ /**
26
+ * Creates a new instance of FedimintWallet.
27
+ *
28
+ * @description
29
+ * This constructor initializes a FedimintWallet instance, which manages communication
30
+ * with a Web Worker. The Web Worker is responsible for running WebAssembly code that
31
+ * handles the core Fedimint Client operations.
32
+ *
33
+ * (default) When not in lazy mode, the constructor immediately initializes the
34
+ * Web Worker and begins loading the WebAssembly module in the background. This
35
+ * allows for faster subsequent operations but may increase initial load time.
36
+ *
37
+ * In lazy mode, the Web Worker and WebAssembly initialization are deferred until
38
+ * the first operation that requires them, reducing initial overhead at the cost
39
+ * of a slight delay on the first operation.
40
+ *
41
+ * @param {boolean} lazy - If true, delays Web Worker and WebAssembly initialization
42
+ * until needed. Default is false.
43
+ *
44
+ * @example
45
+ * // Create a wallet with immediate initialization
46
+ * const wallet = new FedimintWallet();
47
+ * wallet.open();
48
+ *
49
+ * // Create a wallet with lazy initialization
50
+ * const lazyWallet = new FedimintWallet(true);
51
+ * // Some time later...
52
+ * lazyWallet.initialize();
53
+ * lazyWallet.open();
54
+ */
23
55
  constructor(lazy: boolean = false) {
24
- if (lazy) return
25
- this.initialize()
26
56
  this.openPromise = new Promise((resolve) => {
27
57
  this.resolveOpen = resolve
28
58
  })
59
+ this.client = new WorkerClient()
60
+ this.mint = new MintService(this.client)
61
+ this.lightning = new LightningService(this.client)
62
+ this.balance = new BalanceService(this.client)
63
+ this.federation = new FederationService(this.client)
64
+ this.recovery = new RecoveryService(this.client)
65
+
66
+ if (!lazy) {
67
+ this.initialize()
68
+ }
29
69
  }
30
70
 
31
- // Setup
32
71
  async initialize() {
33
- if (this.initPromise) return this.initPromise
34
- // this.worker = new Worker(new URL('./wasm.worker.ts', import.meta.url))
35
- this.initPromise = init().then(() => {
36
- console.trace('Fedimint Client Wasm Initialization complete')
37
- })
38
- return this.initPromise
72
+ await this.client.initialize()
39
73
  }
40
74
 
41
- async open(clientName: string = DEFAULT_CLIENT_NAME) {
42
- await this.initialize()
43
- const wasm = await WasmClient.open(clientName)
75
+ async waitForOpen() {
76
+ if (this._isOpen) return Promise.resolve()
77
+ return this.openPromise
78
+ }
44
79
 
45
- if (wasm === undefined) return false
46
- this._fed = wasm
47
- this.resolveOpen()
48
- return true
80
+ async open(clientName: string = DEFAULT_CLIENT_NAME) {
81
+ await this.client.initialize()
82
+ // TODO: Determine if this should be safe or throw
83
+ if (this._isOpen) throw new Error('The FedimintWallet is already open.')
84
+ const { success } = await this.client.sendSingleMessage('open', {
85
+ clientName,
86
+ })
87
+ if (success) {
88
+ this._isOpen = !!success
89
+ this.resolveOpen()
90
+ }
91
+ return success
49
92
  }
50
93
 
51
94
  async joinFederation(
52
95
  inviteCode: string,
53
96
  clientName: string = DEFAULT_CLIENT_NAME,
54
97
  ) {
55
- await this.initialize()
56
- this._fed = await WasmClient.join_federation(clientName, inviteCode)
57
- this.resolveOpen()
58
- }
59
-
60
- // RPC
61
- private async _rpcStream<
62
- Response extends JSONValue = JSONValue,
63
- Body extends JSONValue = JSONValue,
64
- >(
65
- module: ModuleKind,
66
- method: string,
67
- body: Body,
68
- onSuccess: (res: Response) => void,
69
- onError: (res: StreamError['error']) => void,
70
- ): Promise<RpcHandle> {
71
- await this.openPromise
72
- if (!this._fed) throw new Error('FedimintWallet is not open')
73
- const unsubscribe = await this._fed.rpc(
74
- module,
75
- method,
76
- JSON.stringify(body),
77
- (res: string) => {
78
- // TODO: Validate the response?
79
- const parsed = JSON.parse(res) as StreamResult<Response>
80
- if (parsed.error) {
81
- onError(parsed.error)
82
- } else {
83
- onSuccess(parsed.data)
84
- }
85
- },
86
- )
87
- return unsubscribe
88
- }
89
-
90
- private async _rpcSingle<Response extends JSONValue = JSONValue>(
91
- module: ModuleKind,
92
- method: string,
93
- body: JSONValue,
94
- ): Promise<Response> {
95
- return new Promise((resolve, reject) => {
96
- if (!this._fed) return reject('FedimintWallet is not open')
97
- this._fed.rpc(module, method, JSON.stringify(body), (res: string) => {
98
- // TODO: Validate the response?
99
- const parsed = JSON.parse(res) as StreamResult<Response>
100
- if (parsed.error) {
101
- reject(parsed.error)
102
- } else {
103
- resolve(parsed.data)
104
- }
105
- })
106
- })
107
- }
108
-
109
- async getBalance(): Promise<number> {
110
- return await this._rpcSingle('', 'get_balance', {})
111
- }
112
-
113
- // Mint module methods
114
-
115
- async redeemEcash(notes: string): Promise<void> {
116
- await this._rpcSingle('mint', 'reissue_external_notes', {
117
- oob_notes: notes, // "out of band notes"
118
- extra_meta: null,
119
- })
120
- }
121
-
122
- async reissueExternalNotes(
123
- oobNotes: string,
124
- extraMeta: JSONObject,
125
- ): Promise<string> {
126
- return await this._rpcSingle('mint', 'reissue_external_notes', {
127
- oob_notes: oobNotes,
128
- extra_meta: extraMeta,
98
+ await this.client.initialize()
99
+ // TODO: Determine if this should be safe or throw
100
+ if (this._isOpen)
101
+ throw new Error(
102
+ 'The FedimintWallet is already open. You can only call `joinFederation` on closed clients.',
103
+ )
104
+ const response = await this.client.sendSingleMessage('join', {
105
+ inviteCode,
106
+ clientName,
129
107
  })
130
- }
131
-
132
- subscribeReissueExternalNotes(
133
- operationId: string,
134
- onSuccess: (state: JSONValue) => void = () => {},
135
- onError: (error: string) => void = () => {},
136
- ) {
137
- type ReissueExternalNotesState =
138
- | 'Created'
139
- | 'Issuing'
140
- | 'Done'
141
- | { Failed: { error: string } }
142
-
143
- const unsubscribe = this._rpcStream<ReissueExternalNotesState>(
144
- 'mint',
145
- 'subscribe_reissue_external_notes',
146
- { operation_id: operationId },
147
- (res) => onSuccess(res),
148
- onError,
149
- )
150
-
151
- return () => {
152
- unsubscribe.then((unsub) => {
153
- unsub.cancel()
154
- unsub.free()
155
- })
108
+ if (response.success) {
109
+ this._isOpen = true
110
+ this.resolveOpen()
156
111
  }
157
112
  }
158
113
 
159
- async spendNotes(
160
- minAmount: number,
161
- tryCancelAfter: number,
162
- includeInvite: boolean,
163
- extraMeta: JSONValue,
164
- ): Promise<JSONValue> {
165
- return await this._rpcSingle('mint', 'spend_notes', {
166
- min_amount: minAmount,
167
- try_cancel_after: tryCancelAfter,
168
- include_invite: includeInvite,
169
- extra_meta: extraMeta,
170
- })
171
- }
172
-
173
- async validateNotes(oobNotes: string): Promise<number> {
174
- return await this._rpcSingle('mint', 'validate_notes', {
175
- oob_notes: oobNotes,
176
- })
177
- }
178
-
179
- async tryCancelSpendNotes(operationId: string): Promise<void> {
180
- await this._rpcSingle('mint', 'try_cancel_spend_notes', {
181
- operation_id: operationId,
182
- })
183
- }
184
-
185
- subscribeSpendNotes(
186
- operationId: string,
187
- onSuccess: (state: JSONValue) => void = () => {},
188
- onError: (error: string) => void = () => {},
189
- ) {
190
- const unsubscribe = this._rpcStream(
191
- 'mint',
192
- 'subscribe_spend_notes',
193
- { operation_id: operationId },
194
- (res) => onSuccess(res),
195
- onError,
196
- )
197
-
198
- return () => {
199
- unsubscribe.then((unsub) => {
200
- unsub.cancel()
201
- unsub.free()
202
- })
203
- }
204
- }
205
-
206
- async awaitSpendOobRefund(operationId: string): Promise<JSONValue> {
207
- return await this._rpcSingle('mint', 'await_spend_oob_refund', {
208
- operation_id: operationId,
209
- })
210
- }
211
-
212
114
  /**
213
115
  * This should ONLY be called when UNLOADING the wallet client.
214
116
  * After this call, the FedimintWallet instance should be discarded.
215
117
  */
216
118
  async cleanup() {
217
- await this._fed?.free()
218
- this._fed = null
219
119
  this.openPromise = null
120
+ this._isOpen = false
121
+ this.client.cleanup()
220
122
  }
221
123
 
222
124
  isOpen() {
223
- return this._fed !== null
224
- }
225
-
226
- async getConfig(): Promise<JSONValue> {
227
- return await this._rpcSingle('', 'get_config', {})
228
- }
229
-
230
- async getFederationId(): Promise<string> {
231
- return await this._rpcSingle('', 'get_federation_id', {})
232
- }
233
-
234
- async getInviteCode(peer: number): Promise<string | null> {
235
- return await this._rpcSingle('', 'get_invite_code', { peer })
236
- }
237
-
238
- async listOperations(): Promise<JSONValue[]> {
239
- return await this._rpcSingle('', 'list_operations', {})
240
- }
241
-
242
- async hasPendingRecoveries(): Promise<boolean> {
243
- return await this._rpcSingle('', 'has_pending_recoveries', {})
244
- }
245
-
246
- async waitForAllRecoveries(): Promise<void> {
247
- await this._rpcSingle('', 'wait_for_all_recoveries', {})
248
- }
249
-
250
- /// STREAMING RPCs --------------------
251
-
252
- subscribeBalance(
253
- onSuccess: (balance: number) => void = () => {},
254
- onError: (error: string) => void = () => {},
255
- ) {
256
- const unsubscribe = this._rpcStream<string>(
257
- '',
258
- 'subscribe_balance_changes',
259
- {},
260
- (res) => onSuccess(parseInt(res)),
261
- onError,
262
- )
263
-
264
- return () => {
265
- unsubscribe.then((unsub) => {
266
- unsub.cancel()
267
- unsub.free()
268
- })
269
- }
270
- }
271
-
272
- subscribeToRecoveryProgress(
273
- onSuccess: (progress: {
274
- module_id: number
275
- progress: JSONValue
276
- }) => void = () => {},
277
- onError: (error: string) => void = () => {},
278
- ) {
279
- const unsubscribe = this._rpcStream<{
280
- module_id: number
281
- progress: JSONValue
282
- }>('', 'subscribe_to_recovery_progress', {}, onSuccess, onError)
283
-
284
- return () => {
285
- unsubscribe.then((unsub) => {
286
- unsub.cancel()
287
- unsub.free()
288
- })
289
- }
290
- }
291
-
292
- // Lightning Network module methods
293
-
294
- async createBolt11Invoice(
295
- amount: number,
296
- description: string,
297
- expiryTime: number | null = null,
298
- extraMeta: JSONObject = {},
299
- gateway: LightningGateway | null = null,
300
- ): Promise<CreateBolt11Response> {
301
- return await this._rpcSingle('ln', 'create_bolt11_invoice', {
302
- amount,
303
- description,
304
- expiry_time: expiryTime,
305
- extra_meta: extraMeta,
306
- gateway,
307
- })
308
- }
309
-
310
- async payBolt11Invoice(
311
- invoice: string,
312
- maybeGateway: LightningGateway | null = null,
313
- extraMeta: JSONObject = {},
314
- ): Promise<OutgoingLightningPayment> {
315
- return await this._rpcSingle('ln', 'pay_bolt11_invoice', {
316
- maybe_gateway: maybeGateway,
317
- invoice,
318
- extra_meta: extraMeta,
319
- })
320
- }
321
-
322
- subscribeLnPay(
323
- operationId: string,
324
- onSuccess: (state: LnPayState) => void = () => {},
325
- onError: (error: string) => void = () => {},
326
- ) {
327
- const unsubscribe = this._rpcStream(
328
- 'ln',
329
- 'subscribe_ln_pay',
330
- { operation_id: operationId },
331
- onSuccess,
332
- onError,
333
- )
334
-
335
- return () => {
336
- unsubscribe.then((unsub) => {
337
- unsub.cancel()
338
- unsub.free()
339
- })
340
- }
341
- }
342
-
343
- subscribeLnReceive(
344
- operationId: string,
345
- onSuccess: (state: LnReceiveState) => void = () => {},
346
- onError: (error: string) => void = () => {},
347
- ) {
348
- const unsubscribe = this._rpcStream(
349
- 'ln',
350
- 'subscribe_ln_receive',
351
- { operation_id: operationId },
352
- onSuccess,
353
- onError,
354
- )
355
-
356
- return () => {
357
- unsubscribe.then((unsub) => {
358
- unsub.cancel()
359
- unsub.free()
360
- })
361
- }
362
- }
363
-
364
- async getGateway(
365
- gatewayId: string | null = null,
366
- forceInternal: boolean = false,
367
- ): Promise<LightningGateway | null> {
368
- return await this._rpcSingle('ln', 'get_gateway', {
369
- gateway_id: gatewayId,
370
- force_internal: forceInternal,
371
- })
372
- }
373
-
374
- async listGateways(): Promise<LightningGateway[]> {
375
- return await this._rpcSingle('ln', 'list_gateways', {})
376
- }
377
-
378
- async updateGatewayCache(): Promise<void> {
379
- await this._rpcSingle('ln', 'update_gateway_cache', {})
125
+ return this._isOpen
380
126
  }
381
127
  }
@@ -0,0 +1,24 @@
1
+ import { WorkerClient } from '../worker'
2
+
3
+ export class BalanceService {
4
+ constructor(private client: WorkerClient) {}
5
+
6
+ async getBalance(): Promise<number> {
7
+ return await this.client.rpcSingle('', 'get_balance', {})
8
+ }
9
+
10
+ subscribeBalance(
11
+ onSuccess: (balance: number) => void = () => {},
12
+ onError: (error: string) => void = () => {},
13
+ ) {
14
+ const unsubscribe = this.client.rpcStream<string>(
15
+ '',
16
+ 'subscribe_balance_changes',
17
+ {},
18
+ (res) => onSuccess(parseInt(res)),
19
+ onError,
20
+ )
21
+
22
+ return unsubscribe
23
+ }
24
+ }
@@ -0,0 +1,32 @@
1
+ import { JSONValue } from '../types/wallet'
2
+ import { WorkerClient } from '../worker'
3
+
4
+ export class FederationService {
5
+ constructor(private client: WorkerClient) {}
6
+
7
+ async getConfig(): Promise<JSONValue> {
8
+ return await this.client.rpcSingle('', 'get_config', {})
9
+ }
10
+
11
+ async getFederationId(): Promise<string> {
12
+ return await this.client.rpcSingle('', 'get_federation_id', {})
13
+ }
14
+
15
+ async getInviteCode(peer: number): Promise<string | null> {
16
+ return await this.client.rpcSingle('', 'get_invite_code', { peer })
17
+ }
18
+
19
+ async joinFederation(inviteCode: string, clientName: string): Promise<void> {
20
+ const response = await this.client.sendSingleMessage('join', {
21
+ inviteCode,
22
+ clientName,
23
+ })
24
+ if (!response.success) {
25
+ throw new Error('Failed to join federation')
26
+ }
27
+ }
28
+
29
+ async listOperations(): Promise<JSONValue[]> {
30
+ return await this.client.rpcSingle('', 'list_operations', {})
31
+ }
32
+ }