applesauce-wallet-connect 0.0.0-next-20250808173123

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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/dist/actions/index.d.ts +1 -0
  4. package/dist/actions/index.js +1 -0
  5. package/dist/actions/tokens.d.ts +17 -0
  6. package/dist/actions/tokens.js +110 -0
  7. package/dist/actions/wallet.d.ts +13 -0
  8. package/dist/actions/wallet.js +64 -0
  9. package/dist/actions/zap-info.d.ts +22 -0
  10. package/dist/actions/zap-info.js +83 -0
  11. package/dist/actions/zaps.d.ts +8 -0
  12. package/dist/actions/zaps.js +30 -0
  13. package/dist/blueprints/history.d.ts +4 -0
  14. package/dist/blueprints/history.js +11 -0
  15. package/dist/blueprints/index.d.ts +4 -0
  16. package/dist/blueprints/index.js +4 -0
  17. package/dist/blueprints/info.d.ts +4 -0
  18. package/dist/blueprints/info.js +8 -0
  19. package/dist/blueprints/notification.d.ts +15 -0
  20. package/dist/blueprints/notification.js +21 -0
  21. package/dist/blueprints/request.d.ts +9 -0
  22. package/dist/blueprints/request.js +12 -0
  23. package/dist/blueprints/response.d.ts +5 -0
  24. package/dist/blueprints/response.js +10 -0
  25. package/dist/blueprints/support.d.ts +4 -0
  26. package/dist/blueprints/support.js +8 -0
  27. package/dist/blueprints/tokens.d.ts +7 -0
  28. package/dist/blueprints/tokens.js +11 -0
  29. package/dist/blueprints/wallet.d.ts +5 -0
  30. package/dist/blueprints/wallet.js +11 -0
  31. package/dist/blueprints/zaps.d.ts +8 -0
  32. package/dist/blueprints/zaps.js +12 -0
  33. package/dist/helpers/animated-qr.d.ts +30 -0
  34. package/dist/helpers/animated-qr.js +71 -0
  35. package/dist/helpers/connect-uri.d.ts +12 -0
  36. package/dist/helpers/connect-uri.js +23 -0
  37. package/dist/helpers/encryption.d.ts +2 -0
  38. package/dist/helpers/encryption.js +1 -0
  39. package/dist/helpers/error.d.ts +55 -0
  40. package/dist/helpers/error.js +81 -0
  41. package/dist/helpers/history.d.ts +26 -0
  42. package/dist/helpers/history.js +47 -0
  43. package/dist/helpers/index.d.ts +7 -0
  44. package/dist/helpers/index.js +7 -0
  45. package/dist/helpers/info.d.ts +34 -0
  46. package/dist/helpers/info.js +97 -0
  47. package/dist/helpers/methods.d.ts +1 -0
  48. package/dist/helpers/methods.js +1 -0
  49. package/dist/helpers/notification.d.ts +28 -0
  50. package/dist/helpers/notification.js +28 -0
  51. package/dist/helpers/nutzap.d.ts +27 -0
  52. package/dist/helpers/nutzap.js +66 -0
  53. package/dist/helpers/request.d.ts +131 -0
  54. package/dist/helpers/request.js +51 -0
  55. package/dist/helpers/response.d.ts +138 -0
  56. package/dist/helpers/response.js +35 -0
  57. package/dist/helpers/support.d.ts +34 -0
  58. package/dist/helpers/support.js +97 -0
  59. package/dist/helpers/tokens.d.ts +58 -0
  60. package/dist/helpers/tokens.js +162 -0
  61. package/dist/helpers/wallet.d.ts +15 -0
  62. package/dist/helpers/wallet.js +41 -0
  63. package/dist/helpers/zap-info.d.ts +19 -0
  64. package/dist/helpers/zap-info.js +42 -0
  65. package/dist/index.d.ts +5 -0
  66. package/dist/index.js +5 -0
  67. package/dist/interface.d.ts +6 -0
  68. package/dist/interface.js +1 -0
  69. package/dist/models/history.d.ts +6 -0
  70. package/dist/models/history.js +21 -0
  71. package/dist/models/index.d.ts +4 -0
  72. package/dist/models/index.js +4 -0
  73. package/dist/models/nutzap.d.ts +6 -0
  74. package/dist/models/nutzap.js +16 -0
  75. package/dist/models/tokens.d.ts +6 -0
  76. package/dist/models/tokens.js +58 -0
  77. package/dist/models/wallet.d.ts +13 -0
  78. package/dist/models/wallet.js +18 -0
  79. package/dist/operations/history.d.ts +7 -0
  80. package/dist/operations/history.js +34 -0
  81. package/dist/operations/index.d.ts +5 -0
  82. package/dist/operations/index.js +5 -0
  83. package/dist/operations/nutzap.d.ts +14 -0
  84. package/dist/operations/nutzap.js +33 -0
  85. package/dist/operations/tokens.d.ts +4 -0
  86. package/dist/operations/tokens.js +24 -0
  87. package/dist/operations/wallet.d.ts +8 -0
  88. package/dist/operations/wallet.js +30 -0
  89. package/dist/operations/zap-info.d.ts +10 -0
  90. package/dist/operations/zap-info.js +17 -0
  91. package/dist/types.d.ts +6 -0
  92. package/dist/types.js +1 -0
  93. package/dist/wallet-connect.d.ts +111 -0
  94. package/dist/wallet-connect.js +271 -0
  95. package/dist/wallet-service.d.ts +111 -0
  96. package/dist/wallet-service.js +270 -0
  97. package/package.json +83 -0
@@ -0,0 +1,30 @@
1
+ import { bytesToHex } from "@noble/hashes/utils";
2
+ import { modifyHiddenTags } from "applesauce-factory/operations";
3
+ import { setSingletonTag } from "applesauce-factory/operations/tag";
4
+ import { WALLET_KIND } from "../helpers/wallet.js";
5
+ /** Sets the content of a kind 375 wallet backup event */
6
+ export function setBackupContent(wallet) {
7
+ return async (draft, ctx) => {
8
+ if (wallet.kind !== WALLET_KIND)
9
+ throw new Error(`Cant create a wallet backup from kind ${wallet.kind}`);
10
+ if (!wallet.content)
11
+ throw new Error("Wallet missing content");
12
+ const pubkey = await ctx.signer?.getPublicKey();
13
+ if (wallet.pubkey !== pubkey)
14
+ throw new Error("Wallet pubkey dose not match signer pubkey");
15
+ return { ...draft, content: wallet.content };
16
+ };
17
+ }
18
+ /** Sets the "mint" tags in a wallet event */
19
+ export function setMints(mints) {
20
+ return modifyHiddenTags((tags) => [
21
+ // remove all existing mint tags
22
+ ...tags.filter((t) => t[0] !== "mint"),
23
+ // add new mint tags
24
+ ...mints.map((mint) => ["mint", mint]),
25
+ ]);
26
+ }
27
+ /** Sets the "privkey" tag on a wallet event */
28
+ export function setPrivateKey(privateKey) {
29
+ return modifyHiddenTags(setSingletonTag(["privkey", bytesToHex(privateKey)], true));
30
+ }
@@ -0,0 +1,10 @@
1
+ import { EventOperation } from "applesauce-factory";
2
+ /** Sets the relays for a nutzap info event */
3
+ export declare function setNutzapInfoRelays(relays: string[]): EventOperation;
4
+ /** Sets the mints for a nutzap info event */
5
+ export declare function setNutzapInfoMints(mints: Array<{
6
+ url: string;
7
+ units?: string[];
8
+ }>): EventOperation;
9
+ /** Sets the pubkey for a nutzap info event */
10
+ export declare function setNutzapInfoPubkey(pubkey: string): EventOperation;
@@ -0,0 +1,17 @@
1
+ import { modifyPublicTags } from "applesauce-factory/operations";
2
+ import { addNameValueTag, setSingletonTag } from "applesauce-factory/operations/tag";
3
+ /** Sets the relays for a nutzap info event */
4
+ export function setNutzapInfoRelays(relays) {
5
+ return modifyPublicTags(...relays.map((relay) => addNameValueTag(["relay", relay], false)));
6
+ }
7
+ /** Sets the mints for a nutzap info event */
8
+ export function setNutzapInfoMints(mints) {
9
+ return modifyPublicTags(...mints.map((mint) => {
10
+ const tag = mint.units ? ["mint", mint.url, ...mint.units] : ["mint", mint.url];
11
+ return addNameValueTag(tag, false);
12
+ }));
13
+ }
14
+ /** Sets the pubkey for a nutzap info event */
15
+ export function setNutzapInfoPubkey(pubkey) {
16
+ return modifyPublicTags(setSingletonTag(["pubkey", pubkey], true));
17
+ }
@@ -0,0 +1,6 @@
1
+ import { Filter, NostrEvent } from "nostr-tools";
2
+ import { Observable } from "rxjs";
3
+ /** A method used to subscribe to events on a set of relays */
4
+ export type NostrSubscriptionMethod = (relays: string[], filters: Filter[]) => Observable<NostrEvent | string>;
5
+ /** A method used for publishing an event, can return a Promise that completes when published or an Observable that completes when published*/
6
+ export type NostrPublishMethod = (relays: string[], event: NostrEvent) => Promise<any> | Observable<any>;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,111 @@
1
+ import { EventSigner } from "applesauce-factory";
2
+ import { NostrEvent } from "nostr-tools";
3
+ import { Observable, Subscription } from "rxjs";
4
+ import { EncryptionMethod } from "applesauce-core/helpers";
5
+ import { GetBalanceResult, GetInfoResult, ListTransactionsResult, LookupInvoiceResult, MakeInvoiceParams, MakeInvoiceResult, NotificationType, PayInvoiceResult, PayKeysendResult, WalletConnectEncryptionMethod, WalletConnectURI, WalletMethod, WalletNotification, WalletRequest, WalletResponse, WalletSupport } from "./helpers/index.js";
6
+ import { NostrPublishMethod, NostrSubscriptionMethod } from "./types.js";
7
+ export type SerializedWalletConnect = WalletConnectURI;
8
+ export type WalletConnectOptions = {
9
+ /** A method for subscribing to relays */
10
+ subscriptionMethod?: NostrSubscriptionMethod;
11
+ /** A method for publishing events */
12
+ publishMethod?: NostrPublishMethod;
13
+ /** Default timeout for RPC requests in milliseconds */
14
+ timeout?: number;
15
+ };
16
+ export declare class WalletConnect {
17
+ /** A fallback method to use for subscriptionMethod if none is passed in when creating the client */
18
+ static subscriptionMethod: NostrSubscriptionMethod | undefined;
19
+ /** A fallback method to use for publishMethod if none is passed in when creating the client */
20
+ static publishMethod: NostrPublishMethod | undefined;
21
+ /** A method that is called when an event needs to be published */
22
+ protected publishMethod: NostrPublishMethod;
23
+ /** The active nostr subscription method */
24
+ protected subscriptionMethod: NostrSubscriptionMethod;
25
+ /** The local client signer */
26
+ readonly secret: Uint8Array;
27
+ protected readonly signer: EventSigner;
28
+ /** The relays to use for the connection */
29
+ readonly relays: string[];
30
+ /** The wallet service public key */
31
+ readonly service: string;
32
+ /** Default timeout for requests */
33
+ defaultTimeout: number;
34
+ /** Observable for wallet info updates */
35
+ support$: Observable<WalletSupport | null>;
36
+ /** The preferred encryption method for the wallet */
37
+ encryption$: Observable<WalletConnectEncryptionMethod>;
38
+ /** Shared observable for all wallet response events and notifications */
39
+ protected events$: Observable<NostrEvent>;
40
+ /** Shared observable for all wallet notifications */
41
+ notifications$: Observable<WalletNotification>;
42
+ constructor(secret: Uint8Array, service: string, relays: string[], options?: WalletConnectOptions);
43
+ /** Process response events and return WalletResponse or throw error */
44
+ protected handleResponseEvent(event: NostrEvent, encryption?: EncryptionMethod): Promise<WalletResponse>;
45
+ /** Handle notification events */
46
+ protected handleNotificationEvent(event: NostrEvent): Promise<WalletNotification>;
47
+ /** Core RPC method that makes a request and returns the response */
48
+ request(request: WalletRequest, options?: {
49
+ timeout?: number;
50
+ }): Observable<WalletResponse>;
51
+ /**
52
+ * Listen for a type of notification
53
+ * @returns a method to unsubscribe the listener
54
+ */
55
+ notification<T extends WalletNotification>(type: T["notification_type"], listener: (notification: T["notification"]) => any): Subscription;
56
+ /** Get the wallet support info */
57
+ getSupport(): Promise<WalletSupport | null>;
58
+ /** Check if the wallet supports a method */
59
+ supportsMethod(method: WalletMethod): Promise<boolean>;
60
+ /** Check if the wallet supports notifications */
61
+ supportsNotifications(): Promise<boolean>;
62
+ /** Check if the wallet supports a notification type */
63
+ supportsNotificationType(type: NotificationType): Promise<boolean>;
64
+ /** Pay a lightning invoice */
65
+ payInvoice(invoice: string, amount?: number): Promise<PayInvoiceResult>;
66
+ /** Pay multiple lightning invoices */
67
+ payMultipleInvoices(invoices: Array<{
68
+ id?: string;
69
+ invoice: string;
70
+ amount?: number;
71
+ }>): Promise<PayInvoiceResult[]>;
72
+ /** Send a keysend payment */
73
+ payKeysend(pubkey: string, amount: number, preimage?: string, tlv_records?: Array<{
74
+ type: number;
75
+ value: string;
76
+ }>): Promise<PayKeysendResult>;
77
+ /** Send multiple keysend payments */
78
+ payMultipleKeysend(keysends: Array<{
79
+ id?: string;
80
+ pubkey: string;
81
+ amount: number;
82
+ preimage?: string;
83
+ tlv_records?: Array<{
84
+ type: number;
85
+ value: string;
86
+ }>;
87
+ }>): Promise<PayKeysendResult[]>;
88
+ /** Create a new invoice */
89
+ makeInvoice(amount: number, options?: Omit<MakeInvoiceParams, "amount">): Promise<MakeInvoiceResult>;
90
+ /** Look up an invoice by payment hash or invoice string */
91
+ lookupInvoice(payment_hash?: string, invoice?: string): Promise<LookupInvoiceResult>;
92
+ /** List transactions */
93
+ listTransactions(params?: {
94
+ from?: number;
95
+ until?: number;
96
+ limit?: number;
97
+ offset?: number;
98
+ unpaid?: boolean;
99
+ type?: "incoming" | "outgoing";
100
+ }): Promise<ListTransactionsResult>;
101
+ /** Get wallet balance */
102
+ getBalance(): Promise<GetBalanceResult>;
103
+ /** Get wallet info */
104
+ getInfo(): Promise<GetInfoResult>;
105
+ /** Serialize the WalletConnect instance */
106
+ toJSON(): SerializedWalletConnect;
107
+ /** Create a new WalletConnect instance from a serialized object */
108
+ static fromJSON(json: SerializedWalletConnect, options?: WalletConnectOptions): WalletConnect;
109
+ /** Create a new WalletConnect instance from a connection string */
110
+ static fromConnectionString(connectionString: string, options?: WalletConnectOptions): WalletConnect;
111
+ }
@@ -0,0 +1,271 @@
1
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
2
+ import { simpleTimeout } from "applesauce-core";
3
+ import { create } from "applesauce-factory";
4
+ import { finalizeEvent, getPublicKey, nip04, nip44, verifyEvent } from "nostr-tools";
5
+ import { defer, filter, firstValueFrom, from, ignoreElements, lastValueFrom, map, merge, mergeMap, ReplaySubject, share, switchMap, timer, toArray, } from "rxjs";
6
+ import { WalletRequestBlueprint } from "./blueprints/index.js";
7
+ import { createWalletError } from "./helpers/error.js";
8
+ import { getPreferredEncryption, getWalletNotification, getWalletRequestEncryption, getWalletResponse, getWalletResponseRequestId, getWalletSupport, isWalletNotificationLocked, isWalletResponseLocked, parseWalletConnectURI, supportsMethod, supportsNotifications, supportsNotificationType, unlockWalletNotification, unlockWalletResponse, WALLET_INFO_KIND, WALLET_LEGACY_NOTIFICATION_KIND, WALLET_NOTIFICATION_KIND, WALLET_RESPONSE_KIND, } from "./helpers/index.js";
9
+ export class WalletConnect {
10
+ /** A fallback method to use for subscriptionMethod if none is passed in when creating the client */
11
+ static subscriptionMethod = undefined;
12
+ /** A fallback method to use for publishMethod if none is passed in when creating the client */
13
+ static publishMethod = undefined;
14
+ /** A method that is called when an event needs to be published */
15
+ publishMethod;
16
+ /** The active nostr subscription method */
17
+ subscriptionMethod;
18
+ /** The local client signer */
19
+ secret;
20
+ signer;
21
+ /** The relays to use for the connection */
22
+ relays;
23
+ /** The wallet service public key */
24
+ service;
25
+ /** Default timeout for requests */
26
+ defaultTimeout;
27
+ /** Observable for wallet info updates */
28
+ support$;
29
+ /** The preferred encryption method for the wallet */
30
+ encryption$;
31
+ /** Shared observable for all wallet response events and notifications */
32
+ events$;
33
+ /** Shared observable for all wallet notifications */
34
+ notifications$;
35
+ constructor(secret, service, relays, options = {}) {
36
+ this.service = service;
37
+ this.secret = secret;
38
+ this.relays = relays;
39
+ this.defaultTimeout = options.timeout || 30000; // 30 second default timeout
40
+ // Create a signer for the factory
41
+ this.signer = {
42
+ getPublicKey: async () => getPublicKey(this.secret),
43
+ signEvent: async (draft) => finalizeEvent(draft, this.secret),
44
+ nip04: {
45
+ encrypt: async (pubkey, plaintext) => nip04.encrypt(this.secret, pubkey, plaintext),
46
+ decrypt: async (pubkey, ciphertext) => nip04.decrypt(this.secret, pubkey, ciphertext),
47
+ },
48
+ nip44: {
49
+ encrypt: async (pubkey, plaintext) => nip44.encrypt(plaintext, nip44.getConversationKey(this.secret, pubkey)),
50
+ decrypt: async (pubkey, ciphertext) => nip44.decrypt(ciphertext, nip44.getConversationKey(this.secret, pubkey)),
51
+ },
52
+ };
53
+ const subscriptionMethod = options.subscriptionMethod || WalletConnect.subscriptionMethod;
54
+ if (!subscriptionMethod)
55
+ throw new Error("Missing subscriptionMethod, either pass a method or set WalletConnect.subscriptionMethod");
56
+ const publishMethod = options.publishMethod || WalletConnect.publishMethod;
57
+ if (!publishMethod)
58
+ throw new Error("Missing publishMethod, either pass a method or set WalletConnect.publishMethod");
59
+ this.subscriptionMethod = subscriptionMethod;
60
+ this.publishMethod = publishMethod;
61
+ // Create shared response observable with ref counting and timer
62
+ this.events$ = defer(() => this.signer.getPublicKey()).pipe(switchMap((client) => this.subscriptionMethod(this.relays, [
63
+ // Subscribe to response events
64
+ {
65
+ kinds: [WALLET_RESPONSE_KIND, WALLET_NOTIFICATION_KIND, WALLET_LEGACY_NOTIFICATION_KIND],
66
+ "#p": [client],
67
+ authors: [this.service],
68
+ },
69
+ // Subscribe to wallet info events
70
+ { kinds: [WALLET_INFO_KIND], authors: [this.service] },
71
+ ])),
72
+ // Ingore strings (support for applesauce-relay)
73
+ filter((event) => typeof event !== "string"),
74
+ // Only include events from the wallet service
75
+ filter((event) => event.pubkey === this.service),
76
+ // Only create a single subscription to the relays
77
+ share({
78
+ resetOnRefCountZero: () => timer(60000), // Keep subscription open for 1 minute after last unsubscribe
79
+ }));
80
+ this.support$ = this.events$.pipe(filter((event) => event.kind === WALLET_INFO_KIND), map((event) => getWalletSupport(event)), share({
81
+ connector: () => new ReplaySubject(1),
82
+ resetOnRefCountZero: () => timer(60000), // Keep info observable around for 1 minute after last unsubscribe
83
+ }));
84
+ this.encryption$ = this.support$.pipe(map((info) => (info ? getPreferredEncryption(info) : "nip04")));
85
+ this.notifications$ = this.events$.pipe(filter((event) => event.kind === WALLET_NOTIFICATION_KIND), mergeMap((event) => this.handleNotificationEvent(event)));
86
+ }
87
+ /** Process response events and return WalletResponse or throw error */
88
+ async handleResponseEvent(event, encryption) {
89
+ if (!verifyEvent(event))
90
+ throw new Error("Invalid response event signature");
91
+ const requestId = getWalletResponseRequestId(event);
92
+ if (!requestId)
93
+ throw new Error("Response missing request ID");
94
+ let response;
95
+ if (isWalletResponseLocked(event))
96
+ response = await unlockWalletResponse(event, this.signer, encryption);
97
+ else
98
+ response = getWalletResponse(event);
99
+ if (!response)
100
+ throw new Error("Failed to decrypt or parse response");
101
+ return response;
102
+ }
103
+ /** Handle notification events */
104
+ async handleNotificationEvent(event) {
105
+ if (!verifyEvent(event))
106
+ throw new Error("Invalid notification event signature");
107
+ let notification;
108
+ if (isWalletNotificationLocked(event))
109
+ notification = await unlockWalletNotification(event, this.signer);
110
+ else
111
+ notification = getWalletNotification(event);
112
+ if (!notification)
113
+ throw new Error("Failed to decrypt or parse notification");
114
+ return notification;
115
+ }
116
+ /** Core RPC method that makes a request and returns the response */
117
+ request(request, options = {}) {
118
+ // Create the request evnet
119
+ return defer(async () => {
120
+ // Get the preferred encryption method for the wallet
121
+ const encryption = await firstValueFrom(this.encryption$);
122
+ // Create the request event
123
+ const draft = await create({ signer: this.signer }, WalletRequestBlueprint, this.service, request, encryption);
124
+ // Sign the request event
125
+ return await this.signer.signEvent(draft);
126
+ }).pipe(
127
+ // Then switch to the request observable
128
+ switchMap((requestEvent) => {
129
+ const encryption = getWalletRequestEncryption(requestEvent) === "nip44_v2" ? "nip44" : "nip04";
130
+ // Create an observable that publishes the request event when subscribed to
131
+ const request$ = defer(() => from(this.publishMethod(this.relays, requestEvent))).pipe(ignoreElements());
132
+ // Create an observable that listens for response events
133
+ const responses$ = this.events$.pipe(filter((response) => response.kind === WALLET_RESPONSE_KIND && getWalletResponseRequestId(response) === requestEvent.id), mergeMap((response) => this.handleResponseEvent(response, encryption)),
134
+ // Set timeout for response events
135
+ simpleTimeout(options.timeout || this.defaultTimeout));
136
+ return merge(request$, responses$);
137
+ }));
138
+ }
139
+ /**
140
+ * Listen for a type of notification
141
+ * @returns a method to unsubscribe the listener
142
+ */
143
+ notification(type, listener) {
144
+ return this.notifications$.subscribe((notification) => {
145
+ if (notification.notification_type === type)
146
+ listener(notification.notification);
147
+ });
148
+ }
149
+ // Convenience methods that return promises for easy API usage
150
+ /** Get the wallet support info */
151
+ getSupport() {
152
+ return firstValueFrom(this.support$);
153
+ }
154
+ /** Check if the wallet supports a method */
155
+ async supportsMethod(method) {
156
+ const support = await this.getSupport();
157
+ return support ? supportsMethod(support, method) : false;
158
+ }
159
+ /** Check if the wallet supports notifications */
160
+ async supportsNotifications() {
161
+ const support = await this.getSupport();
162
+ return support ? supportsNotifications(support) : false;
163
+ }
164
+ /** Check if the wallet supports a notification type */
165
+ async supportsNotificationType(type) {
166
+ const support = await this.getSupport();
167
+ return support ? supportsNotificationType(support, type) : false;
168
+ }
169
+ /** Pay a lightning invoice */
170
+ async payInvoice(invoice, amount) {
171
+ const response = await firstValueFrom(this.request({ method: "pay_invoice", params: { invoice, amount } }));
172
+ if (response.result_type !== "pay_invoice")
173
+ throw new Error(`Unexpected response type: ${response.result_type}`);
174
+ if (response.error)
175
+ throw createWalletError(response.error.type, response.error.message);
176
+ return response.result;
177
+ }
178
+ /** Pay multiple lightning invoices */
179
+ async payMultipleInvoices(invoices) {
180
+ return await lastValueFrom(this.request({ method: "multi_pay_invoice", params: { invoices } })
181
+ .pipe(map((response) => {
182
+ if (response.result_type !== "multi_pay_invoice")
183
+ throw new Error(`Unexpected response type: ${response.result_type}`);
184
+ if (response.error)
185
+ throw createWalletError(response.error.type, response.error.message);
186
+ return response.result;
187
+ }))
188
+ .pipe(toArray()));
189
+ }
190
+ /** Send a keysend payment */
191
+ async payKeysend(pubkey, amount, preimage, tlv_records) {
192
+ const response = await firstValueFrom(this.request({ method: "pay_keysend", params: { pubkey, amount, preimage, tlv_records } }));
193
+ if (response.result_type !== "pay_keysend")
194
+ throw new Error(`Unexpected response type: ${response.result_type}`);
195
+ if (response.error)
196
+ throw createWalletError(response.error.type, response.error.message);
197
+ return response.result;
198
+ }
199
+ /** Send multiple keysend payments */
200
+ async payMultipleKeysend(keysends) {
201
+ return lastValueFrom(this.request({ method: "multi_pay_keysend", params: { keysends } }).pipe(map((response) => {
202
+ if (response.result_type !== "multi_pay_keysend")
203
+ throw new Error(`Unexpected response type: ${response.result_type}`);
204
+ if (response.error)
205
+ throw createWalletError(response.error.type, response.error.message);
206
+ return response.result;
207
+ }), toArray()));
208
+ }
209
+ /** Create a new invoice */
210
+ async makeInvoice(amount, options) {
211
+ const response = await firstValueFrom(this.request({ method: "make_invoice", params: { amount, ...options } }));
212
+ if (response.result_type !== "make_invoice")
213
+ throw new Error(`Unexpected response type: ${response.result_type}`);
214
+ if (response.error)
215
+ throw createWalletError(response.error.type, response.error.message);
216
+ return response.result;
217
+ }
218
+ /** Look up an invoice by payment hash or invoice string */
219
+ async lookupInvoice(payment_hash, invoice) {
220
+ const response = await firstValueFrom(this.request({ method: "lookup_invoice", params: { payment_hash, invoice } }));
221
+ if (response.result_type !== "lookup_invoice")
222
+ throw new Error(`Unexpected response type: ${response.result_type}`);
223
+ if (response.error)
224
+ throw createWalletError(response.error.type, response.error.message);
225
+ return response.result;
226
+ }
227
+ /** List transactions */
228
+ async listTransactions(params) {
229
+ const response = await firstValueFrom(this.request({ method: "list_transactions", params: params || {} }));
230
+ if (response.result_type !== "list_transactions")
231
+ throw new Error(`Unexpected response type: ${response.result_type}`);
232
+ if (response.error)
233
+ throw createWalletError(response.error.type, response.error.message);
234
+ return response.result;
235
+ }
236
+ /** Get wallet balance */
237
+ async getBalance() {
238
+ const response = await firstValueFrom(this.request({ method: "get_balance", params: {} }));
239
+ if (response.result_type !== "get_balance")
240
+ throw new Error(`Unexpected response type: ${response.result_type}`);
241
+ if (response.error)
242
+ throw createWalletError(response.error.type, response.error.message);
243
+ return response.result;
244
+ }
245
+ /** Get wallet info */
246
+ async getInfo() {
247
+ const response = await firstValueFrom(this.request({ method: "get_info", params: {} }));
248
+ if (response.result_type !== "get_info")
249
+ throw new Error(`Unexpected response type: ${response.result_type}`);
250
+ if (response.error)
251
+ throw createWalletError(response.error.type, response.error.message);
252
+ return response.result;
253
+ }
254
+ /** Serialize the WalletConnect instance */
255
+ toJSON() {
256
+ return {
257
+ secret: bytesToHex(this.secret),
258
+ service: this.service,
259
+ relays: this.relays,
260
+ };
261
+ }
262
+ /** Create a new WalletConnect instance from a serialized object */
263
+ static fromJSON(json, options) {
264
+ return new WalletConnect(hexToBytes(json.secret), json.service, json.relays, options);
265
+ }
266
+ /** Create a new WalletConnect instance from a connection string */
267
+ static fromConnectionString(connectionString, options) {
268
+ const { secret, service, relays } = parseWalletConnectURI(connectionString);
269
+ return new WalletConnect(hexToBytes(secret), service, relays, options);
270
+ }
271
+ }
@@ -0,0 +1,111 @@
1
+ import { EventSigner } from "applesauce-factory";
2
+ import { NostrEvent } from "nostr-tools";
3
+ import { Observable, Subscription } from "rxjs";
4
+ import { WalletErrorCode } from "./helpers/error.js";
5
+ import { NotificationType, WalletNotification } from "./helpers/notification.js";
6
+ import { GetBalanceParams, GetInfoParams, ListTransactionsParams, LookupInvoiceParams, MakeInvoiceParams, MultiPayInvoiceParams, MultiPayKeysendParams, PayInvoiceParams, PayKeysendParams, WalletRequest } from "./helpers/request.js";
7
+ import { GetBalanceResult, GetInfoResult, ListTransactionsResult, LookupInvoiceResult, MakeInvoiceResult, MultiPayInvoiceResult, MultiPayKeysendResult, PayInvoiceResult, PayKeysendResult, WalletResponse } from "./helpers/response.js";
8
+ import { WalletSupport } from "./helpers/support.js";
9
+ import { NostrPublishMethod, NostrSubscriptionMethod } from "./types.js";
10
+ /** Handler function for pay_invoice method */
11
+ export type PayInvoiceHandler = (params: PayInvoiceParams) => Promise<PayInvoiceResult>;
12
+ /** Handler function for multi_pay_invoice method */
13
+ export type MultiPayInvoiceHandler = (params: MultiPayInvoiceParams) => Promise<MultiPayInvoiceResult[]>;
14
+ /** Handler function for pay_keysend method */
15
+ export type PayKeysendHandler = (params: PayKeysendParams) => Promise<PayKeysendResult>;
16
+ /** Handler function for multi_pay_keysend method */
17
+ export type MultiPayKeysendHandler = (params: MultiPayKeysendParams) => Promise<MultiPayKeysendResult[]>;
18
+ /** Handler function for make_invoice method */
19
+ export type MakeInvoiceHandler = (params: MakeInvoiceParams) => Promise<MakeInvoiceResult>;
20
+ /** Handler function for lookup_invoice method */
21
+ export type LookupInvoiceHandler = (params: LookupInvoiceParams) => Promise<LookupInvoiceResult>;
22
+ /** Handler function for list_transactions method */
23
+ export type ListTransactionsHandler = (params: ListTransactionsParams) => Promise<ListTransactionsResult>;
24
+ /** Handler function for get_balance method */
25
+ export type GetBalanceHandler = (params: GetBalanceParams) => Promise<GetBalanceResult>;
26
+ /** Handler function for get_info method */
27
+ export type GetInfoHandler = (params: GetInfoParams) => Promise<GetInfoResult>;
28
+ /** Map of method handlers for the wallet service */
29
+ export interface WalletServiceHandlers {
30
+ pay_invoice?: PayInvoiceHandler;
31
+ multi_pay_invoice?: MultiPayInvoiceHandler;
32
+ pay_keysend?: PayKeysendHandler;
33
+ multi_pay_keysend?: MultiPayKeysendHandler;
34
+ make_invoice?: MakeInvoiceHandler;
35
+ lookup_invoice?: LookupInvoiceHandler;
36
+ list_transactions?: ListTransactionsHandler;
37
+ get_balance?: GetBalanceHandler;
38
+ get_info?: GetInfoHandler;
39
+ }
40
+ /** Options for creating a WalletService */
41
+ export interface WalletServiceOptions {
42
+ /** The relays to use for the service */
43
+ relays: string[];
44
+ /** The signer to use for creating and unlocking events */
45
+ signer: EventSigner;
46
+ /** The client's secret key */
47
+ secret?: Uint8Array;
48
+ /** Map of method handlers */
49
+ handlers: WalletServiceHandlers;
50
+ /** An array of notifications this wallet supports */
51
+ notifications?: NotificationType[];
52
+ /** An optional method for subscribing to relays */
53
+ subscriptionMethod?: NostrSubscriptionMethod;
54
+ /** An optional method for publishing events */
55
+ publishMethod?: NostrPublishMethod;
56
+ }
57
+ /** NIP-47 Wallet Service implementation */
58
+ export declare class WalletService {
59
+ /** A fallback method to use for subscriptionMethod if none is passed in when creating the client */
60
+ static subscriptionMethod: NostrSubscriptionMethod | undefined;
61
+ /** A fallback method to use for publishMethod if none is passed in when creating the client */
62
+ static publishMethod: NostrPublishMethod | undefined;
63
+ /** A method for subscribing to relays */
64
+ protected readonly subscriptionMethod: NostrSubscriptionMethod;
65
+ /** A method for publishing events */
66
+ protected readonly publishMethod: NostrPublishMethod;
67
+ protected log: import("debug").Debugger;
68
+ /** The relays to use for the service */
69
+ readonly relays: string[];
70
+ /** The signer used for creating and unlocking events */
71
+ protected readonly signer: EventSigner;
72
+ /** Map of method handlers */
73
+ protected readonly handlers: WalletServiceHandlers;
74
+ /** Wallet support information */
75
+ protected readonly support: WalletSupport;
76
+ /** The service's public key */
77
+ pubkey: string | null;
78
+ /** The client's secret key */
79
+ protected secret: Uint8Array;
80
+ /** Shared observable for all wallet request events */
81
+ protected events$: Observable<NostrEvent> | null;
82
+ /** Subscription to the events observable */
83
+ protected subscription: Subscription | null;
84
+ /** Whether the service is currently running */
85
+ running: boolean;
86
+ /** Get the clients public key */
87
+ get client(): string;
88
+ constructor(options: WalletServiceOptions);
89
+ /** Start the wallet service */
90
+ start(): Promise<void>;
91
+ /** Stop the wallet service */
92
+ stop(): void;
93
+ /** Check if the service is running */
94
+ isRunning(): boolean;
95
+ /** Get the connection string for the service */
96
+ getConnectionString(): string;
97
+ /** Send a notification to the client */
98
+ notify<T extends WalletNotification>(type: T["notification_type"], notification: T["notification"], legacy?: boolean): Promise<void>;
99
+ /** Publish the wallet support event */
100
+ protected publishSupportEvent(): Promise<void>;
101
+ /** Handle a wallet request event */
102
+ protected handleRequestEvent(requestEvent: NostrEvent): Promise<void>;
103
+ /** Process a decrypted wallet request */
104
+ protected processRequest(requestEvent: NostrEvent, request: WalletRequest): Promise<void>;
105
+ /** Send a success response */
106
+ protected sendSuccessResponse<T extends WalletResponse>(requestEvent: NostrEvent, method: T["result_type"], result: T["result"]): Promise<void>;
107
+ /** Send an error response */
108
+ protected sendErrorResponse(requestEvent: NostrEvent, errorType: WalletErrorCode, errorMessage: string): Promise<void>;
109
+ /** Send a response event */
110
+ protected sendResponse(requestEvent: NostrEvent, response: WalletResponse): Promise<void>;
111
+ }