@fedimint/core-web 0.1.0 → 0.1.2

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 (78) hide show
  1. package/README.md +20 -9
  2. package/index.d.ts +1 -0
  3. package/index.js +15 -0
  4. package/package.json +12 -35
  5. package/dist/dts/FedimintWallet.d.ts +0 -51
  6. package/dist/dts/FedimintWallet.d.ts.map +0 -1
  7. package/dist/dts/WalletDirector.d.ts +0 -78
  8. package/dist/dts/WalletDirector.d.ts.map +0 -1
  9. package/dist/dts/index.d.ts +0 -4
  10. package/dist/dts/index.d.ts.map +0 -1
  11. package/dist/dts/services/BalanceService.d.ts +0 -15
  12. package/dist/dts/services/BalanceService.d.ts.map +0 -1
  13. package/dist/dts/services/FederationService.d.ts +0 -13
  14. package/dist/dts/services/FederationService.d.ts.map +0 -1
  15. package/dist/dts/services/LightningService.d.ts +0 -48
  16. package/dist/dts/services/LightningService.d.ts.map +0 -1
  17. package/dist/dts/services/MintService.d.ts +0 -23
  18. package/dist/dts/services/MintService.d.ts.map +0 -1
  19. package/dist/dts/services/RecoveryService.d.ts +0 -13
  20. package/dist/dts/services/RecoveryService.d.ts.map +0 -1
  21. package/dist/dts/services/WalletService.d.ts +0 -13
  22. package/dist/dts/services/WalletService.d.ts.map +0 -1
  23. package/dist/dts/services/index.d.ts +0 -7
  24. package/dist/dts/services/index.d.ts.map +0 -1
  25. package/dist/dts/transport/TransportClient.d.ts +0 -55
  26. package/dist/dts/transport/TransportClient.d.ts.map +0 -1
  27. package/dist/dts/transport/index.d.ts +0 -3
  28. package/dist/dts/transport/index.d.ts.map +0 -1
  29. package/dist/dts/transport/wasmTransport/WasmWorkerTransport.d.ts +0 -12
  30. package/dist/dts/transport/wasmTransport/WasmWorkerTransport.d.ts.map +0 -1
  31. package/dist/dts/types/index.d.ts +0 -4
  32. package/dist/dts/types/index.d.ts.map +0 -1
  33. package/dist/dts/types/transport.d.ts +0 -35
  34. package/dist/dts/types/transport.d.ts.map +0 -1
  35. package/dist/dts/types/utils.d.ts +0 -23
  36. package/dist/dts/types/utils.d.ts.map +0 -1
  37. package/dist/dts/types/wallet.d.ts +0 -241
  38. package/dist/dts/types/wallet.d.ts.map +0 -1
  39. package/dist/dts/utils/logger.d.ts +0 -24
  40. package/dist/dts/utils/logger.d.ts.map +0 -1
  41. package/dist/index.d.ts +0 -609
  42. package/dist/index.js +0 -2
  43. package/dist/index.js.map +0 -1
  44. package/dist/worker.js +0 -2
  45. package/dist/worker.js.map +0 -1
  46. package/src/FedimintWallet.test.ts +0 -73
  47. package/src/FedimintWallet.ts +0 -119
  48. package/src/WalletDirector.ts +0 -118
  49. package/src/index.ts +0 -3
  50. package/src/services/BalanceService.test.ts +0 -26
  51. package/src/services/BalanceService.ts +0 -29
  52. package/src/services/FederationService.test.ts +0 -58
  53. package/src/services/FederationService.ts +0 -216
  54. package/src/services/LightningService.test.ts +0 -265
  55. package/src/services/LightningService.ts +0 -289
  56. package/src/services/MintService.test.ts +0 -74
  57. package/src/services/MintService.ts +0 -129
  58. package/src/services/RecoveryService.ts +0 -28
  59. package/src/services/WalletService.test.ts +0 -59
  60. package/src/services/WalletService.ts +0 -50
  61. package/src/services/index.ts +0 -6
  62. package/src/test/TestFedimintWallet.ts +0 -31
  63. package/src/test/TestWalletDirector.ts +0 -14
  64. package/src/test/TestingService.ts +0 -79
  65. package/src/test/crypto.ts +0 -44
  66. package/src/test/fixtures.test.ts +0 -18
  67. package/src/test/fixtures.ts +0 -88
  68. package/src/transport/TransportClient.test.ts +0 -6
  69. package/src/transport/TransportClient.ts +0 -251
  70. package/src/transport/index.ts +0 -2
  71. package/src/transport/wasmTransport/WasmWorkerTransport.ts +0 -39
  72. package/src/transport/wasmTransport/worker.js +0 -167
  73. package/src/transport/wasmTransport/worker.test.ts +0 -90
  74. package/src/types/index.ts +0 -3
  75. package/src/types/transport.ts +0 -54
  76. package/src/types/utils.ts +0 -29
  77. package/src/types/wallet.ts +0 -298
  78. package/src/utils/logger.ts +0 -69
@@ -1,79 +0,0 @@
1
- import { LightningService } from '../services'
2
- import { TransportClient } from '../transport'
3
-
4
- export const TESTING_INVITE =
5
- 'fed11qgqrsdnhwden5te0v9cxjtt4dekxzamxw4kz6mmjvvkhydted9ukg6r9xfsnx7th0fhn26tf093juamwv4u8gtnpwpcz7qqpyz0e327ua8geceutfrcaezwt22mk6s2rdy09kg72jrcmncng2gn0kp2m5sk'
6
-
7
- // This is a testing service that allows for inspecting the internals
8
- // of the TransportClient. It is not intended for use in production.
9
- export class TestingService {
10
- public TESTING_INVITE: string
11
- constructor(
12
- private client: TransportClient,
13
- private lightning: LightningService,
14
- ) {
15
- // Solo Mint on mutinynet
16
- this.TESTING_INVITE = TESTING_INVITE
17
- }
18
-
19
- getRequestCounter() {
20
- return this.client._getRequestCounter()
21
- }
22
-
23
- getRequestCallbackMap() {
24
- return this.client._getRequestCallbackMap()
25
- }
26
-
27
- async getInviteCode() {
28
- const res = await fetch(`${import.meta.env.FAUCET}/connect-string`)
29
- if (res.ok) {
30
- return await res.text()
31
- } else {
32
- throw new Error(`Failed to get invite code: ${await res.text()}`)
33
- }
34
- }
35
-
36
- private async getFaucetGatewayApi() {
37
- const res = await fetch(`${import.meta.env.FAUCET}/gateway-api`)
38
- if (res.ok) {
39
- return await res.text()
40
- } else {
41
- throw new Error(`Failed to get gateway: ${await res.text()}`)
42
- }
43
- }
44
-
45
- async getFaucetGatewayInfo() {
46
- await this.lightning.updateGatewayCache()
47
- const gateways = await this.lightning.listGateways()
48
- const api = await this.getFaucetGatewayApi()
49
- const gateway = gateways.find((g) => g.info.api === api)
50
- if (!gateway) {
51
- throw new Error(`Gateway not found: ${api}`)
52
- }
53
- return gateway.info
54
- }
55
-
56
- async payFaucetInvoice(invoice: string) {
57
- const res = await fetch(`${import.meta.env.FAUCET}/pay`, {
58
- method: 'POST',
59
- body: invoice,
60
- })
61
- if (res.ok) {
62
- return await res.text()
63
- } else {
64
- throw new Error(`Failed to pay faucet invoice: ${await res.text()}`)
65
- }
66
- }
67
-
68
- async createFaucetInvoice(amount: number) {
69
- const res = await fetch(`${import.meta.env.FAUCET}/invoice`, {
70
- method: 'POST',
71
- body: amount.toString(),
72
- })
73
- if (res.ok) {
74
- return await res.text()
75
- } else {
76
- throw new Error(`Failed to generate faucet invoice: ${await res.text()}`)
77
- }
78
- }
79
- }
@@ -1,44 +0,0 @@
1
- import * as secp256k1 from 'secp256k1'
2
-
3
- const randomBytes = (size: number): Uint8Array => {
4
- const array = new Uint8Array(size)
5
- window.crypto.getRandomValues(array)
6
- return array
7
- }
8
-
9
- interface KeyPair {
10
- secretKey: string
11
- publicKey: string
12
- }
13
-
14
- export const keyPair = (secretKey?: Uint8Array): KeyPair => {
15
- const privateKey: Uint8Array = secretKey
16
- ? validatePrivateKey(secretKey)
17
- : generatePrivateKey()
18
-
19
- const publicKey = secp256k1.publicKeyCreate(privateKey)
20
-
21
- return {
22
- secretKey: Array.from(privateKey)
23
- .map((b) => b.toString(16).padStart(2, '0'))
24
- .join(''), // Convert Uint8Array to hex string
25
- publicKey: Array.from(publicKey)
26
- .map((b) => b.toString(16).padStart(2, '0'))
27
- .join(''), // Convert Uint8Array to hex string
28
- }
29
- }
30
-
31
- const validatePrivateKey = (key: Uint8Array): Uint8Array => {
32
- if (!secp256k1.privateKeyVerify(key)) {
33
- throw new Error('Invalid private key provided')
34
- }
35
- return key
36
- }
37
-
38
- const generatePrivateKey = (): Uint8Array => {
39
- let key: Uint8Array
40
- do {
41
- key = randomBytes(32)
42
- } while (!secp256k1.privateKeyVerify(key))
43
- return key
44
- }
@@ -1,18 +0,0 @@
1
- import { expect } from 'vitest'
2
- import { walletTest } from './fixtures'
3
-
4
- walletTest('Fund wallet 1', async ({ fundedWallet }) => {
5
- expect(fundedWallet).toBeDefined()
6
- })
7
-
8
- walletTest('Fund wallet 2', async ({ fundedWallet }) => {
9
- expect(fundedWallet).toBeDefined()
10
- })
11
-
12
- walletTest('Fund wallet 3', async ({ fundedWallet }) => {
13
- expect(fundedWallet).toBeDefined()
14
- })
15
-
16
- walletTest('Fund wallet 4', async ({ fundedWallet }) => {
17
- expect(fundedWallet).toBeDefined()
18
- })
@@ -1,88 +0,0 @@
1
- import { expect, test } from 'vitest'
2
- import { TestFedimintWallet } from './TestFedimintWallet'
3
- import { TransportClient } from '../transport/TransportClient'
4
- import { WasmWorkerTransport } from '../transport/wasmTransport/WasmWorkerTransport'
5
- import { TestWalletDirector } from './TestWalletDirector'
6
-
7
- /**
8
- * Adds Fixtures for setting up and tearing down test FedimintWallet/WalletDirector instances
9
- */
10
- export const walletTest = test.extend<{
11
- walletDirector: TestWalletDirector
12
- wallet: TestFedimintWallet
13
- fundedWallet: TestFedimintWallet
14
- fundedWalletBeefy: TestFedimintWallet
15
- unopenedWallet: TestFedimintWallet
16
- }>({
17
- walletDirector: async ({}, use) => {
18
- const walletDirector = new TestWalletDirector()
19
- await use(walletDirector)
20
- },
21
- wallet: async ({ walletDirector }, use) => {
22
- const randomTestingId = Math.random().toString(36).substring(2, 15)
23
- const wallet = await walletDirector.createTestWallet()
24
- expect(wallet).toBeDefined()
25
- const inviteCode = await wallet.testing.getInviteCode()
26
- await expect(
27
- wallet.joinFederation(inviteCode, randomTestingId),
28
- ).resolves.toBe(true)
29
-
30
- await use(wallet)
31
-
32
- // clear up browser resources
33
- await wallet.cleanup()
34
-
35
- // remove the wallet db
36
- await new Promise((resolve) => {
37
- const request = indexedDB.deleteDatabase(randomTestingId)
38
- request.onsuccess = resolve
39
- request.onerror = resolve
40
- request.onblocked = resolve
41
- })
42
- },
43
-
44
- fundedWallet: async ({ wallet }, use) => {
45
- // 10K MSats
46
- await wallet.fundWallet(10_000)
47
- await use(wallet)
48
- },
49
- fundedWalletBeefy: async ({ wallet }, use) => {
50
- // 1M MSats
51
- await wallet.fundWallet(1_000_000)
52
- await use(wallet)
53
- },
54
- unopenedWallet: async ({ walletDirector }, use) => {
55
- const wallet = await walletDirector.createTestWallet()
56
- await use(wallet)
57
- },
58
- })
59
-
60
- /**
61
- * Adds Fixtures for setting up and tearing down a test Worker instance
62
- */
63
- export const workerTest = test.extend<{
64
- worker: Worker
65
- clientName: string
66
- transportClient: TransportClient
67
- }>({
68
- worker: async ({}, use) => {
69
- const worker = new Worker(
70
- new URL('../transport/wasmTransport/worker.js', import.meta.url),
71
- {
72
- type: 'module',
73
- },
74
- )
75
- await use(worker)
76
- worker.terminate()
77
- },
78
- clientName: async ({}, use) => {
79
- const randomTestingId = Math.random().toString(36).substring(2, 15)
80
- await use(randomTestingId)
81
- },
82
- transportClient: async ({}, use) => {
83
- // TODO: figure out how to use a different transport in runtime depending on the test
84
- // Ideally, we don't want to create separate fixtures for each transport
85
- const transportClient = new TransportClient(new WasmWorkerTransport())
86
- await use(transportClient)
87
- },
88
- })
@@ -1,6 +0,0 @@
1
- import { expect } from 'vitest'
2
- import { workerTest } from '../test/fixtures'
3
-
4
- workerTest('should initialize', async ({ transportClient }) => {
5
- expect(transportClient).toBeDefined()
6
- })
@@ -1,251 +0,0 @@
1
- import type {
2
- CancelFunction,
3
- JSONValue,
4
- ModuleKind,
5
- StreamError,
6
- StreamResult,
7
- TransportMessageType,
8
- } from '../types'
9
- import { Logger } from '../utils/logger'
10
- import type { Transport, TransportMessage } from '../types/transport'
11
-
12
- /**
13
- * Handles communication with a generic transport.
14
- * Must be instantiated with a platform-specific transport. (wasm for web, react native, etc.)
15
- */
16
- export class TransportClient {
17
- // Generic Transport. Can be wasm, react native, node, etc.
18
- private readonly transport: Transport
19
- private requestCounter = 0
20
- private requestCallbacks = new Map<number, (value: any) => void>()
21
- private initPromise: Promise<boolean> | undefined = undefined
22
- logger: Logger
23
-
24
- /**
25
- * @summary Constructor for the TransportClient
26
- * @param transport - The platform-specific transport to use. (wasm for web, react native, etc.)
27
- */
28
- constructor(transport: Transport) {
29
- this.transport = transport
30
- this.logger = new Logger(transport.logger)
31
- this.transport.setMessageHandler(this.handleTransportMessage)
32
- this.transport.setErrorHandler(this.handleTransportError)
33
- this.logger.info('TransportClient instantiated')
34
- this.logger.debug('TransportClient transport', transport)
35
- }
36
-
37
- // Idempotent setup - Loads the wasm module
38
- initialize() {
39
- if (this.initPromise) return this.initPromise
40
- this.initPromise = this.sendSingleMessage('init')
41
- return this.initPromise
42
- }
43
-
44
- private handleLogMessage(message: TransportMessage) {
45
- const { type, level, message: logMessage, ...data } = message
46
- this.logger.info(String(level), String(logMessage), data)
47
- }
48
-
49
- private handleTransportError = (error: unknown) => {
50
- this.logger.error('TransportClient error', error)
51
- }
52
-
53
- private handleTransportMessage = (message: TransportMessage) => {
54
- const { type, requestId, ...data } = message
55
- if (type === 'log') {
56
- this.handleLogMessage(message)
57
- }
58
- const streamCallback =
59
- requestId !== undefined ? this.requestCallbacks.get(requestId) : undefined
60
- // TODO: Handle errors... maybe have another callbacks list for errors?
61
- this.logger.debug('TransportClient - handleTransportMessage', message)
62
- if (streamCallback) {
63
- streamCallback(data) // {data: something} OR {error: something}
64
- } else if (requestId !== undefined) {
65
- this.logger.warn(
66
- 'TransportClient - handleTransportMessage - received message with no callback',
67
- requestId,
68
- message,
69
- )
70
- }
71
- }
72
-
73
- // TODO: Handle errors... maybe have another callbacks list for errors?
74
- // TODO: Handle timeouts
75
- // TODO: Handle multiple errors
76
-
77
- sendSingleMessage<
78
- Response extends JSONValue = JSONValue,
79
- Payload extends JSONValue = JSONValue,
80
- >(type: TransportMessageType, payload?: Payload) {
81
- return new Promise<Response>((resolve, reject) => {
82
- const requestId = ++this.requestCounter
83
- this.logger.debug(
84
- 'TransportClient - sendSingleMessage',
85
- requestId,
86
- type,
87
- payload,
88
- )
89
- this.requestCallbacks.set(
90
- requestId,
91
- (response: StreamResult<Response>) => {
92
- this.requestCallbacks.delete(requestId)
93
- this.logger.debug(
94
- 'TransportClient - sendSingleMessage - response',
95
- requestId,
96
- response,
97
- )
98
- if (response.data) resolve(response.data)
99
- else if (response.error) reject(response.error)
100
- else
101
- this.logger.warn(
102
- 'TransportClient - sendSingleMessage - malformed response',
103
- requestId,
104
- response,
105
- )
106
- },
107
- )
108
- this.transport.postMessage({ type, payload, requestId })
109
- })
110
- }
111
-
112
- /**
113
- * @summary Initiates an RPC stream with the specified module and method.
114
- *
115
- * @description
116
- * This function sets up an RPC stream by sending a request to a worker and
117
- * handling responses asynchronously. It ensures that unsubscription is handled
118
- * correctly, even if the unsubscribe function is called before the subscription
119
- * is fully established, by deferring the unsubscription attempt using `setTimeout`.
120
- *
121
- * The function operates in a non-blocking manner, leveraging Promises to manage
122
- * asynchronous operations and callbacks to handle responses.
123
- *
124
- *
125
- * @template Response - The expected type of the successful response.
126
- * @template Body - The type of the request body.
127
- * @param module - The module kind to interact with.
128
- * @param method - The method name to invoke on the module.
129
- * @param body - The request payload.
130
- * @param onSuccess - Callback invoked with the response data on success.
131
- * @param onError - Callback invoked with error information if an error occurs.
132
- * @param onEnd - Optional callback invoked when the stream ends.
133
- * @returns A function that can be called to cancel the subscription.
134
- *
135
- */
136
- rpcStream<
137
- Response extends JSONValue = JSONValue,
138
- Body extends JSONValue = JSONValue,
139
- >(
140
- module: ModuleKind,
141
- method: string,
142
- body: Body,
143
- onSuccess: (res: Response) => void,
144
- onError: (res: StreamError['error']) => void,
145
- onEnd: () => void = () => {},
146
- ): CancelFunction {
147
- const requestId = ++this.requestCounter
148
- this.logger.debug(
149
- 'TransportClient - rpcStream',
150
- requestId,
151
- module,
152
- method,
153
- body,
154
- )
155
- let unsubscribe: (value: void) => void = () => {}
156
- let isSubscribed = false
157
-
158
- const unsubscribePromise = new Promise<void>((resolve) => {
159
- unsubscribe = () => {
160
- if (isSubscribed) {
161
- // If already subscribed, resolve immediately to trigger unsubscription
162
- resolve()
163
- } else {
164
- // If not yet subscribed, defer the unsubscribe attempt to the next event loop tick
165
- // This ensures that subscription setup has time to complete
166
- setTimeout(() => unsubscribe(), 0)
167
- }
168
- }
169
- })
170
-
171
- // Initiate the inner RPC stream setup asynchronously
172
- this._rpcStreamInner(
173
- requestId,
174
- module,
175
- method,
176
- body,
177
- onSuccess,
178
- onError,
179
- onEnd,
180
- unsubscribePromise,
181
- ).then(() => {
182
- isSubscribed = true
183
- })
184
-
185
- return unsubscribe
186
- }
187
-
188
- private async _rpcStreamInner<
189
- Response extends JSONValue = JSONValue,
190
- Body extends JSONValue = JSONValue,
191
- >(
192
- requestId: number,
193
- module: ModuleKind,
194
- method: string,
195
- body: Body,
196
- onSuccess: (res: Response) => void,
197
- onError: (res: StreamError['error']) => void,
198
- onEnd: () => void = () => {},
199
- unsubscribePromise: Promise<void>,
200
- // Unsubscribe function
201
- ) {
202
- this.requestCallbacks.set(requestId, (response: StreamResult<Response>) => {
203
- if (response.error !== undefined) {
204
- onError(response.error)
205
- } else if (response.data !== undefined) {
206
- onSuccess(response.data)
207
- } else if (response.end !== undefined) {
208
- this.requestCallbacks.delete(requestId)
209
- onEnd()
210
- }
211
- })
212
- this.transport.postMessage({
213
- type: 'rpc',
214
- payload: { module, method, body },
215
- requestId,
216
- })
217
-
218
- unsubscribePromise.then(() => {
219
- this.transport.postMessage({
220
- type: 'unsubscribe',
221
- requestId,
222
- })
223
- this.requestCallbacks.delete(requestId)
224
- })
225
- }
226
-
227
- rpcSingle<
228
- Response extends JSONValue = JSONValue,
229
- Error extends string = string,
230
- >(module: ModuleKind, method: string, body: JSONValue) {
231
- this.logger.debug('TransportClient - rpcSingle', module, method, body)
232
- return new Promise<Response>((resolve, reject) => {
233
- this.rpcStream<Response>(module, method, body, resolve, reject)
234
- })
235
- }
236
-
237
- async cleanup() {
238
- await this.sendSingleMessage('cleanup')
239
- this.requestCounter = 0
240
- this.initPromise = undefined
241
- this.requestCallbacks.clear()
242
- }
243
-
244
- // For Testing
245
- _getRequestCounter() {
246
- return this.requestCounter
247
- }
248
- _getRequestCallbackMap() {
249
- return this.requestCallbacks
250
- }
251
- }
@@ -1,2 +0,0 @@
1
- export { TransportClient } from './TransportClient'
2
- export { WasmWorkerTransport } from './wasmTransport/WasmWorkerTransport'
@@ -1,39 +0,0 @@
1
- import type {
2
- Transport,
3
- TransportErrorHandler,
4
- TransportLogger,
5
- TransportMessageHandler,
6
- TransportRequest,
7
- } from '../../types/transport'
8
-
9
- export class WasmWorkerTransport implements Transport {
10
- private messageHandler: TransportMessageHandler = () => {}
11
- private errorHandler: TransportErrorHandler = () => {}
12
- private readonly worker: Worker
13
-
14
- logger: TransportLogger = console
15
-
16
- constructor() {
17
- this.worker = new Worker(new URL('./worker.js', import.meta.url), {
18
- type: 'module',
19
- })
20
- this.worker.onmessage = (event: MessageEvent) => {
21
- this.messageHandler(event.data)
22
- }
23
- this.worker.onerror = (event: ErrorEvent) => {
24
- this.errorHandler(event)
25
- }
26
- }
27
-
28
- postMessage(message: TransportRequest) {
29
- this.worker.postMessage(message)
30
- }
31
-
32
- setMessageHandler(handler: TransportMessageHandler) {
33
- this.messageHandler = handler
34
- }
35
-
36
- setErrorHandler(handler: TransportErrorHandler) {
37
- this.errorHandler = handler
38
- }
39
- }
@@ -1,167 +0,0 @@
1
- // Web Worker for fedimint-client-wasm to run in the browser
2
-
3
- // HACK: Fixes vitest browser runner
4
- // TODO: remove once https://github.com/vitest-dev/vitest/pull/6569 lands in a release
5
- globalThis.__vitest_browser_runner__ = { wrapDynamicImport: (foo) => foo() }
6
-
7
- // dynamically imported Constructor for WasmClient
8
- let WasmClient = null
9
- // client instance
10
- let client = null
11
-
12
- const streamCancelMap = new Map()
13
-
14
- const handleFree = (requestId) => {
15
- streamCancelMap.delete(requestId)
16
- }
17
-
18
- console.log('Worker - init')
19
-
20
- /**
21
- * Type definitions for the worker messages
22
- *
23
- * @typedef {import('../../types/transport').TransportMessageType} WorkerMessageType
24
- * @typedef {{
25
- * type: WorkerMessageType
26
- * payload: any
27
- * requestId: number
28
- * }} WorkerMessage
29
- * @param {{data: WorkerMessage}} event
30
- */
31
- self.onmessage = async (event) => {
32
- const { type, payload, requestId } = event.data
33
-
34
- try {
35
- if (type === 'init') {
36
- WasmClient = (await import('@fedimint/fedimint-client-wasm-bundler'))
37
- .WasmClient
38
- self.postMessage({ type: 'initialized', data: {}, requestId })
39
- } else if (type === 'open') {
40
- const { clientName } = payload
41
- client = (await WasmClient.open(clientName)) || null
42
- self.postMessage({
43
- type: 'open',
44
- data: { success: !!client },
45
- requestId,
46
- })
47
- } else if (type === 'join') {
48
- const { inviteCode, clientName: joinClientName } = payload
49
- try {
50
- client = await WasmClient.join_federation(joinClientName, inviteCode)
51
- self.postMessage({
52
- type: 'join',
53
- data: { success: !!client },
54
- requestId,
55
- })
56
- } catch (e) {
57
- self.postMessage({ type: 'error', error: e.message, requestId })
58
- }
59
- } else if (type === 'previewFederation') {
60
- const { inviteCode } = payload
61
- try {
62
- client = await WasmClient.preview_federation(inviteCode)
63
- const parsed = JSON.parse(client)
64
- self.postMessage({
65
- type: 'previewFederation',
66
- data: {
67
- success: !!client,
68
- config: parsed.config,
69
- federation_id: parsed.federation_id,
70
- },
71
- requestId,
72
- })
73
- } catch (e) {
74
- self.postMessage({ type: 'error', error: e.message, requestId })
75
- }
76
- } else if (type === 'rpc') {
77
- const { module, method, body } = payload
78
- console.log('RPC received', module, method, body)
79
- if (!client) {
80
- self.postMessage({
81
- type: 'error',
82
- error: 'WasmClient not initialized',
83
- requestId,
84
- })
85
- return
86
- }
87
- const rpcHandle = await client.rpc(
88
- module,
89
- method,
90
- JSON.stringify(body),
91
- (res) => {
92
- console.log('RPC response', requestId, res)
93
- const data = JSON.parse(res)
94
- self.postMessage({ type: 'rpcResponse', requestId, ...data })
95
-
96
- if (data.end !== undefined) {
97
- // Handle stream ending
98
- const handle = streamCancelMap.get(requestId)
99
- handle?.free()
100
- }
101
- },
102
- )
103
- streamCancelMap.set(requestId, rpcHandle)
104
- } else if (type === 'unsubscribe') {
105
- const rpcHandle = streamCancelMap.get(requestId)
106
- if (rpcHandle) {
107
- rpcHandle.cancel()
108
- rpcHandle.free()
109
- streamCancelMap.delete(requestId)
110
- }
111
- } else if (type === 'cleanup') {
112
- console.log('cleanup message received')
113
- client?.free()
114
- self.postMessage({
115
- type: 'cleanup',
116
- data: {},
117
- requestId,
118
- })
119
- close()
120
- } else if (type === 'parseInviteCode') {
121
- const { inviteCode } = payload
122
- try {
123
- const res = WasmClient.parse_invite_code(inviteCode)
124
- const parsedRes = JSON.parse(res)
125
- self.postMessage({
126
- type: 'parseInviteCode',
127
- data: parsedRes,
128
- requestId,
129
- })
130
- } catch (error) {
131
- self.postMessage({
132
- type: 'error',
133
- error: `Failed to parse invite code: ${error.message}`,
134
- requestId,
135
- })
136
- }
137
- } else if (type === 'parseBolt11Invoice') {
138
- const { invoiceStr } = payload
139
- try {
140
- const res = WasmClient.parse_bolt11_invoice(invoiceStr)
141
- const parsedRes = JSON.parse(res)
142
- self.postMessage({
143
- type: 'parseBolt11Invoice',
144
- data: parsedRes,
145
- requestId,
146
- })
147
- } catch (error) {
148
- self.postMessage({
149
- type: 'error',
150
- error: `Failed to parse invoice: ${error.message}`,
151
- requestId,
152
- })
153
- }
154
- } else {
155
- self.postMessage({
156
- type: 'error',
157
- error: 'Unknown message type',
158
- requestId,
159
- })
160
- }
161
- } catch (e) {
162
- console.error('ERROR', e)
163
- self.postMessage({ type: 'error', error: e, requestId })
164
- }
165
- }
166
-
167
- // self.postMessage({ type: 'init', data: {} })