applesauce-wallet-connect 3.1.0 → 4.0.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.
@@ -1,10 +1,16 @@
1
- import { HiddenContentSigner } from "applesauce-core/helpers";
1
+ import { HiddenContentSigner, KnownEvent, UnlockedHiddenContent } from "applesauce-core/helpers";
2
2
  import { NostrEvent } from "nostr-tools";
3
3
  import { Transaction } from "./response.js";
4
4
  export declare const WALLET_NOTIFICATION_KIND = 23197;
5
5
  export declare const WALLET_LEGACY_NOTIFICATION_KIND = 23196;
6
+ /** A type for validated wallet notification events */
7
+ export type WalletNotificationEvent = KnownEvent<typeof WALLET_NOTIFICATION_KIND> | KnownEvent<typeof WALLET_LEGACY_NOTIFICATION_KIND>;
6
8
  /** A symbol used to cache the wallet notification on the event */
7
9
  export declare const WalletNotificationSymbol: unique symbol;
10
+ /** A type for unlocked notifications events */
11
+ export type UnlockedWalletNotification = UnlockedHiddenContent & {
12
+ [WalletNotificationSymbol]: WalletNotification;
13
+ };
8
14
  /** Supported notification types */
9
15
  export type NotificationType = "payment_received" | "payment_sent";
10
16
  /** Base notification structure */
@@ -21,8 +27,10 @@ export type PaymentSentNotification = BaseNotification<"payment_sent", Transacti
21
27
  /** Union type for all NIP-47 notification types */
22
28
  export type WalletNotification = PaymentReceivedNotification | PaymentSentNotification;
23
29
  /** Checks if a kind 23196 or 23197 event is locked */
24
- export declare function isWalletNotificationLocked(notification: NostrEvent): boolean;
30
+ export declare function isWalletNotificationUnlocked(notification: any): notification is UnlockedWalletNotification;
25
31
  /** Unlocks a kind 23196 or 23197 event */
26
- export declare function unlockWalletNotification(notification: NostrEvent, signer: HiddenContentSigner): Promise<WalletNotification | undefined | null>;
32
+ export declare function unlockWalletNotification(notification: NostrEvent, signer: HiddenContentSigner): Promise<WalletNotification | undefined>;
27
33
  /** Gets the wallet notification from a kind 23196 or 23197 event */
28
- export declare function getWalletNotification(notification: NostrEvent): WalletNotification | undefined | null;
34
+ export declare function getWalletNotification(notification: NostrEvent): WalletNotification | undefined;
35
+ /** Checks if an event is a valid wallet notification event */
36
+ export declare function isValidWalletNotification(notification: NostrEvent): notification is WalletNotificationEvent;
@@ -1,4 +1,4 @@
1
- import { getHiddenContent, getOrComputeCachedValue, isHiddenContentLocked, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "applesauce-core/helpers";
1
+ import { isHiddenContentUnlocked, notifyEventUpdate, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "applesauce-core/helpers";
2
2
  export const WALLET_NOTIFICATION_KIND = 23197;
3
3
  export const WALLET_LEGACY_NOTIFICATION_KIND = 23196;
4
4
  /** A symbol used to cache the wallet notification on the event */
@@ -7,22 +7,28 @@ export const WalletNotificationSymbol = Symbol("wallet-notification");
7
7
  setHiddenContentEncryptionMethod(WALLET_NOTIFICATION_KIND, "nip44");
8
8
  setHiddenContentEncryptionMethod(WALLET_LEGACY_NOTIFICATION_KIND, "nip04");
9
9
  /** Checks if a kind 23196 or 23197 event is locked */
10
- export function isWalletNotificationLocked(notification) {
11
- return isHiddenContentLocked(notification);
10
+ export function isWalletNotificationUnlocked(notification) {
11
+ return isHiddenContentUnlocked(notification) && Reflect.has(notification, WalletNotificationSymbol) === true;
12
12
  }
13
13
  /** Unlocks a kind 23196 or 23197 event */
14
14
  export async function unlockWalletNotification(notification, signer) {
15
- await unlockHiddenContent(notification, signer);
16
- return getWalletNotification(notification);
15
+ if (isWalletNotificationUnlocked(notification))
16
+ return notification[WalletNotificationSymbol];
17
+ const content = await unlockHiddenContent(notification, signer);
18
+ const parsed = JSON.parse(content);
19
+ // Save the parsed content
20
+ Reflect.set(notification, WalletNotificationSymbol, parsed);
21
+ notifyEventUpdate(notification);
22
+ return parsed;
17
23
  }
18
24
  /** Gets the wallet notification from a kind 23196 or 23197 event */
19
25
  export function getWalletNotification(notification) {
20
- if (isWalletNotificationLocked(notification))
26
+ if (isWalletNotificationUnlocked(notification))
27
+ return notification[WalletNotificationSymbol];
28
+ else
21
29
  return undefined;
22
- return getOrComputeCachedValue(notification, WalletNotificationSymbol, () => {
23
- const content = getHiddenContent(notification);
24
- if (!content)
25
- return null;
26
- return JSON.parse(content);
27
- });
30
+ }
31
+ /** Checks if an event is a valid wallet notification event */
32
+ export function isValidWalletNotification(notification) {
33
+ return notification.kind === WALLET_NOTIFICATION_KIND || notification.kind === WALLET_LEGACY_NOTIFICATION_KIND;
28
34
  }
@@ -1,10 +1,15 @@
1
- import { HiddenContentSigner } from "applesauce-core/helpers";
1
+ import { HiddenContentSigner, KnownEvent, UnlockedHiddenContent } from "applesauce-core/helpers";
2
2
  import { NostrEvent } from "nostr-tools";
3
3
  import { WalletConnectEncryptionMethod } from "./encryption.js";
4
4
  import { WalletMethod } from "./support.js";
5
5
  export declare const WALLET_REQUEST_KIND = 23194;
6
+ export type WalletRequestEvent = KnownEvent<typeof WALLET_REQUEST_KIND>;
6
7
  /** A symbol used to cache the wallet request on the event */
7
8
  export declare const WalletRequestSymbol: unique symbol;
9
+ /** Type for events with unlocked hidden content */
10
+ export type UnlockedWalletRequest = UnlockedHiddenContent & {
11
+ [WalletRequestSymbol]: WalletRequest;
12
+ };
8
13
  /** TLV record for keysend payments */
9
14
  export interface TLVRecord {
10
15
  /** TLV type */
@@ -116,12 +121,13 @@ export type GetInfoRequest = BaseWalletRequest<"get_info", GetInfoParams>;
116
121
  /** Union type for all NIP-47 request types */
117
122
  export type WalletRequest = PayInvoiceRequest | MultiPayInvoiceRequest | PayKeysendRequest | MultiPayKeysendRequest | MakeInvoiceRequest | LookupInvoiceRequest | ListTransactionsRequest | GetBalanceRequest | GetInfoRequest;
118
123
  /** Checks if a kind 23194 event is locked */
119
- export declare function isWalletRequestLocked(request: NostrEvent): boolean;
124
+ export declare function isWalletRequestUnlocked(request: any): request is UnlockedWalletRequest;
120
125
  /** Unlocks a kind 23194 event */
121
- export declare function unlockWalletRequest(request: NostrEvent, signer: HiddenContentSigner): Promise<WalletRequest | undefined | null>;
126
+ export declare function unlockWalletRequest(request: NostrEvent, signer: HiddenContentSigner): Promise<WalletRequest | undefined>;
122
127
  /** Gets the wallet request from a kind 23194 event */
123
- export declare function getWalletRequest(request: NostrEvent): WalletRequest | undefined | null;
128
+ export declare function getWalletRequest(request: NostrEvent): WalletRequest | undefined;
124
129
  /** Returns the wallet service pubkey from a request */
130
+ export declare function getWalletRequestServicePubkey(request: WalletRequestEvent): string;
125
131
  export declare function getWalletRequestServicePubkey(request: NostrEvent): string | undefined;
126
132
  /** Returns the expiration timestamp from a request */
127
133
  export declare function getWalletRequestExpiration(request: NostrEvent): number | undefined;
@@ -129,3 +135,5 @@ export declare function getWalletRequestExpiration(request: NostrEvent): number
129
135
  export declare function isWalletRequestExpired(request: NostrEvent): boolean;
130
136
  /** Gets the encryption method used for a request */
131
137
  export declare function getWalletRequestEncryption(request: NostrEvent): WalletConnectEncryptionMethod;
138
+ /** Checks if an event is a valid wallet request event */
139
+ export declare function isValidWalletRequest(request: NostrEvent): request is WalletRequestEvent;
@@ -1,30 +1,31 @@
1
- import { getHiddenContent, getOrComputeCachedValue, getTagValue, isHiddenContentLocked, isNIP04Encrypted, setHiddenContentEncryptionMethod, unixNow, unlockHiddenContent, } from "applesauce-core/helpers";
1
+ import { getTagValue, isHiddenContentUnlocked, isNIP04Encrypted, notifyEventUpdate, setHiddenContentEncryptionMethod, unixNow, unlockHiddenContent, } from "applesauce-core/helpers";
2
2
  export const WALLET_REQUEST_KIND = 23194;
3
3
  // Set the encryption method to use for request kind
4
4
  setHiddenContentEncryptionMethod(WALLET_REQUEST_KIND, "nip44");
5
5
  /** A symbol used to cache the wallet request on the event */
6
6
  export const WalletRequestSymbol = Symbol("wallet-request");
7
7
  /** Checks if a kind 23194 event is locked */
8
- export function isWalletRequestLocked(request) {
9
- return isHiddenContentLocked(request);
8
+ export function isWalletRequestUnlocked(request) {
9
+ return isHiddenContentUnlocked(request) && Reflect.has(request, WalletRequestSymbol) === true;
10
10
  }
11
11
  /** Unlocks a kind 23194 event */
12
12
  export async function unlockWalletRequest(request, signer) {
13
- await unlockHiddenContent(request, signer);
14
- return getWalletRequest(request);
13
+ if (isWalletRequestUnlocked(request))
14
+ return request[WalletRequestSymbol];
15
+ const content = await unlockHiddenContent(request, signer);
16
+ const parsed = JSON.parse(content);
17
+ // Save the parsed content
18
+ Reflect.set(request, WalletRequestSymbol, parsed);
19
+ notifyEventUpdate(request);
20
+ return parsed;
15
21
  }
16
22
  /** Gets the wallet request from a kind 23194 event */
17
23
  export function getWalletRequest(request) {
18
- if (isWalletRequestLocked(request))
24
+ if (isWalletRequestUnlocked(request))
25
+ return request[WalletRequestSymbol];
26
+ else
19
27
  return undefined;
20
- return getOrComputeCachedValue(request, WalletRequestSymbol, () => {
21
- const content = getHiddenContent(request);
22
- if (!content)
23
- return null;
24
- return JSON.parse(content);
25
- });
26
- }
27
- /** Returns the wallet service pubkey from a request */
28
+ }
28
29
  export function getWalletRequestServicePubkey(request) {
29
30
  return getTagValue(request, "p");
30
31
  }
@@ -49,3 +50,7 @@ export function getWalletRequestEncryption(request) {
49
50
  ? "nip04"
50
51
  : "nip44_v2";
51
52
  }
53
+ /** Checks if an event is a valid wallet request event */
54
+ export function isValidWalletRequest(request) {
55
+ return request.kind === WALLET_REQUEST_KIND && getWalletRequestServicePubkey(request) !== undefined;
56
+ }
@@ -1,11 +1,17 @@
1
- import { EncryptionMethod, HiddenContentSigner } from "applesauce-core/helpers";
1
+ import { EncryptionMethod, HiddenContentSigner, KnownEvent, UnlockedHiddenContent } from "applesauce-core/helpers";
2
2
  import { NostrEvent } from "nostr-tools";
3
3
  import { WalletErrorCode } from "./error.js";
4
- import { WalletMethod } from "./support.js";
5
4
  import { NotificationType } from "./notification.js";
5
+ import { WalletMethod } from "./support.js";
6
6
  export declare const WALLET_RESPONSE_KIND = 23195;
7
7
  /** A symbol used to cache the wallet response on the event */
8
8
  export declare const WalletResponseSymbol: unique symbol;
9
+ /** Type for events with unlocked hidden content */
10
+ export type UnlockedWalletResponse = UnlockedHiddenContent & {
11
+ [WalletResponseSymbol]: WalletResponse;
12
+ };
13
+ /** Type for validated wallet response events */
14
+ export type WalletResponseEvent = KnownEvent<typeof WALLET_RESPONSE_KIND>;
9
15
  /** Error object for wallet responses */
10
16
  export interface WalletResponseError {
11
17
  type: WalletErrorCode;
@@ -127,12 +133,16 @@ export type GetInfoResponse = BaseWalletResponse<"get_info", GetInfoResult>;
127
133
  /** Union type for all NIP-47 response types */
128
134
  export type WalletResponse = PayInvoiceResponse | MultiPayInvoiceResponse | PayKeysendResponse | MultiPayKeysendResponse | MakeInvoiceResponse | LookupInvoiceResponse | ListTransactionsResponse | GetBalanceResponse | GetInfoResponse;
129
135
  /** Checks if a kind 23195 event is locked */
130
- export declare function isWalletResponseLocked(response: NostrEvent): boolean;
136
+ export declare function isWalletResponseUnlocked(response: any): response is UnlockedWalletResponse;
131
137
  /** Unlocks a kind 23195 event */
132
- export declare function unlockWalletResponse(response: NostrEvent, signer: HiddenContentSigner, override?: EncryptionMethod): Promise<WalletResponse | undefined | null>;
138
+ export declare function unlockWalletResponse(response: NostrEvent, signer: HiddenContentSigner, override?: EncryptionMethod): Promise<WalletResponse | undefined>;
133
139
  /** Gets the wallet response from a kind 23195 event */
134
- export declare function getWalletResponse(response: NostrEvent): WalletResponse | undefined | null;
140
+ export declare function getWalletResponse(response: NostrEvent): WalletResponse | undefined;
135
141
  /** Returns the client pubkey of client this response is for */
142
+ export declare function getWalletResponseClientPubkey(response: WalletResponseEvent): string;
136
143
  export declare function getWalletResponseClientPubkey(response: NostrEvent): string | undefined;
137
144
  /** Returns the request id of the request this response is for */
145
+ export declare function getWalletResponseRequestId(response: WalletResponseEvent): string;
138
146
  export declare function getWalletResponseRequestId(response: NostrEvent): string | undefined;
147
+ /** Checks if event is a valid wallet response event */
148
+ export declare function isValidWalletResponse(response: NostrEvent): response is WalletResponseEvent;
@@ -1,35 +1,41 @@
1
- import { getHiddenContent, getOrComputeCachedValue, getTagValue, isHiddenContentLocked, isNIP04Encrypted, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "applesauce-core/helpers";
1
+ import { getTagValue, isHiddenContentUnlocked, isNIP04Encrypted, notifyEventUpdate, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "applesauce-core/helpers";
2
2
  export const WALLET_RESPONSE_KIND = 23195;
3
3
  // Set the encryption method to use for response kind
4
4
  setHiddenContentEncryptionMethod(WALLET_RESPONSE_KIND, "nip04");
5
5
  /** A symbol used to cache the wallet response on the event */
6
6
  export const WalletResponseSymbol = Symbol("wallet-response");
7
7
  /** Checks if a kind 23195 event is locked */
8
- export function isWalletResponseLocked(response) {
9
- return isHiddenContentLocked(response);
8
+ export function isWalletResponseUnlocked(response) {
9
+ return isHiddenContentUnlocked(response) && Reflect.has(response, WalletResponseSymbol) === true;
10
10
  }
11
11
  /** Unlocks a kind 23195 event */
12
12
  export async function unlockWalletResponse(response, signer, override) {
13
+ if (isWalletResponseUnlocked(response))
14
+ return response[WalletResponseSymbol];
13
15
  const encryption = override ?? (!isNIP04Encrypted(response.content) ? "nip44" : "nip04");
14
- await unlockHiddenContent(response, signer, encryption);
15
- return getWalletResponse(response);
16
+ const content = await unlockHiddenContent(response, signer, encryption);
17
+ const parsed = JSON.parse(content);
18
+ // Save the parsed content
19
+ Reflect.set(response, WalletResponseSymbol, parsed);
20
+ notifyEventUpdate(response);
21
+ return parsed;
16
22
  }
17
23
  /** Gets the wallet response from a kind 23195 event */
18
24
  export function getWalletResponse(response) {
19
- if (isWalletResponseLocked(response))
25
+ if (isWalletResponseUnlocked(response))
26
+ return response[WalletResponseSymbol];
27
+ else
20
28
  return undefined;
21
- return getOrComputeCachedValue(response, WalletResponseSymbol, () => {
22
- const content = getHiddenContent(response);
23
- if (!content)
24
- return null;
25
- return JSON.parse(content);
26
- });
27
29
  }
28
- /** Returns the client pubkey of client this response is for */
29
30
  export function getWalletResponseClientPubkey(response) {
30
31
  return getTagValue(response, "p");
31
32
  }
32
- /** Returns the request id of the request this response is for */
33
33
  export function getWalletResponseRequestId(response) {
34
34
  return getTagValue(response, "e");
35
35
  }
36
+ /** Checks if event is a valid wallet response event */
37
+ export function isValidWalletResponse(response) {
38
+ return (response.kind === WALLET_RESPONSE_KIND &&
39
+ getWalletResponseRequestId(response) !== undefined &&
40
+ getWalletResponseClientPubkey(response) !== undefined);
41
+ }
@@ -2,7 +2,7 @@ import { EncryptionMethod } from "applesauce-core/helpers";
2
2
  import { EventSigner } from "applesauce-factory";
3
3
  import { NostrEvent } from "nostr-tools";
4
4
  import { BehaviorSubject, Observable, Subscription } from "rxjs";
5
- import { GetBalanceResult, GetInfoResult, ListTransactionsResult, LookupInvoiceResult, MakeInvoiceParams, MakeInvoiceResult, NotificationType, PayInvoiceResult, PayKeysendResult, WalletAuthURI, WalletConnectEncryptionMethod, WalletConnectURI, WalletMethod, WalletNotification, WalletRequest, WalletResponse, WalletSupport } from "./helpers/index.js";
5
+ import { GetBalanceResult, GetInfoResult, ListTransactionsResult, LookupInvoiceResult, MakeInvoiceParams, MakeInvoiceResult, NotificationType, PayInvoiceResult, PayKeysendResult, WalletAuthURI, WalletConnectEncryptionMethod, WalletConnectURI, WalletMethod, WalletNotification, WalletNotificationEvent, WalletRequest, WalletResponse, WalletResponseEvent, WalletSupport } from "./helpers/index.js";
6
6
  import { NostrConnectionMethodsOptions, NostrPool, NostrPublishMethod, NostrSubscriptionMethod } from "./interop.js";
7
7
  export type SerializedWalletConnect = WalletConnectURI;
8
8
  export type WalletConnectOptions = NostrConnectionMethodsOptions & {
@@ -48,9 +48,9 @@ export declare class WalletConnect {
48
48
  protected waitForService$: Observable<string>;
49
49
  constructor(options: WalletConnectOptions);
50
50
  /** Process response events and return WalletResponse or throw error */
51
- protected handleResponseEvent(event: NostrEvent, encryption?: EncryptionMethod): Promise<WalletResponse>;
51
+ protected handleResponseEvent(event: WalletResponseEvent, encryption?: EncryptionMethod): Promise<WalletResponse>;
52
52
  /** Handle notification events */
53
- protected handleNotificationEvent(event: NostrEvent): Promise<WalletNotification>;
53
+ protected handleNotificationEvent(event: WalletNotificationEvent): Promise<WalletNotification>;
54
54
  /** Core RPC method that makes a request and returns the response */
55
55
  request(request: WalletRequest, options?: {
56
56
  timeout?: number;
@@ -2,10 +2,10 @@ import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
2
2
  import { simpleTimeout } from "applesauce-core";
3
3
  import { create } from "applesauce-factory";
4
4
  import { finalizeEvent, getPublicKey, nip04, nip44, verifyEvent } from "nostr-tools";
5
- import { BehaviorSubject, defer, filter, firstValueFrom, from, fromEvent, identity, ignoreElements, lastValueFrom, map, merge, mergeMap, repeat, ReplaySubject, retry, share, switchMap, takeUntil, tap, timer, toArray, } from "rxjs";
5
+ import { BehaviorSubject, defer, filter, firstValueFrom, from, fromEvent, identity, ignoreElements, lastValueFrom, map, merge, mergeMap, of, repeat, ReplaySubject, retry, share, switchMap, take, takeUntil, tap, timer, toArray, } from "rxjs";
6
6
  import { WalletRequestBlueprint } from "./blueprints/index.js";
7
7
  import { createWalletError } from "./helpers/error.js";
8
- import { createWalletAuthURI, 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";
8
+ import { createWalletAuthURI, getPreferredEncryption, getWalletRequestEncryption, getWalletResponseRequestId, getWalletSupport, isValidWalletNotification, isValidWalletResponse, parseWalletConnectURI, supportsMethod, supportsNotifications, supportsNotificationType, unlockWalletNotification, unlockWalletResponse, WALLET_INFO_KIND, WALLET_LEGACY_NOTIFICATION_KIND, WALLET_NOTIFICATION_KIND, WALLET_RESPONSE_KIND, } from "./helpers/index.js";
9
9
  import { getConnectionMethods, } from "./interop.js";
10
10
  export class WalletConnect {
11
11
  /** A fallback method to use for subscriptionMethod if none is passed in when creating the client */
@@ -103,19 +103,24 @@ export class WalletConnect {
103
103
  resetOnRefCountZero: () => timer(60000), // Keep info observable around for 1 minute after last unsubscribe
104
104
  }));
105
105
  this.encryption$ = this.support$.pipe(map((info) => (info ? getPreferredEncryption(info) : "nip04")));
106
- this.notifications$ = this.events$.pipe(filter((event) => event.kind === WALLET_NOTIFICATION_KIND), mergeMap((event) => this.handleNotificationEvent(event)));
107
- this.waitForService$ = this.events$.pipe(
108
- // Complete when the service is set
109
- takeUntil(this.service$),
110
- // Only listen for wallet info events
111
- filter((event) => event.kind === WALLET_INFO_KIND && !this.service),
112
- // Set the service to the pubkey of the wallet info event
113
- tap((event) => {
114
- // Set the service to the pubkey of the wallet info event
115
- this.service$.next(event.pubkey);
116
- }),
117
- // Get the service pubkey from the event
118
- map((event) => event.pubkey),
106
+ this.notifications$ = this.events$.pipe(filter((event) => isValidWalletNotification(event)), mergeMap((event) => this.handleNotificationEvent(event)));
107
+ this.waitForService$ = defer(() =>
108
+ // If service is already set, return it
109
+ this.service$.value
110
+ ? of(this.service$.value)
111
+ : // Otherwise listen for new wallet info events
112
+ this.events$.pipe(
113
+ // Only listen for wallet info events
114
+ filter((event) => event.kind === WALLET_INFO_KIND),
115
+ // Set the service to the pubkey of the wallet info event
116
+ tap((event) => {
117
+ // Set the service to the pubkey of the wallet info event
118
+ this.service$.next(event.pubkey);
119
+ }),
120
+ // Get the service pubkey from the event
121
+ map((event) => event.pubkey),
122
+ // Complete after the first value
123
+ take(1))).pipe(
119
124
  // Only create a single subscription to avoid multiple side effects
120
125
  share());
121
126
  }
@@ -126,11 +131,7 @@ export class WalletConnect {
126
131
  const requestId = getWalletResponseRequestId(event);
127
132
  if (!requestId)
128
133
  throw new Error("Response missing request ID");
129
- let response;
130
- if (isWalletResponseLocked(event))
131
- response = await unlockWalletResponse(event, this.signer, encryption);
132
- else
133
- response = getWalletResponse(event);
134
+ const response = await unlockWalletResponse(event, this.signer, encryption);
134
135
  if (!response)
135
136
  throw new Error("Failed to decrypt or parse response");
136
137
  return response;
@@ -139,11 +140,7 @@ export class WalletConnect {
139
140
  async handleNotificationEvent(event) {
140
141
  if (!verifyEvent(event))
141
142
  throw new Error("Invalid notification event signature");
142
- let notification;
143
- if (isWalletNotificationLocked(event))
144
- notification = await unlockWalletNotification(event, this.signer);
145
- else
146
- notification = getWalletNotification(event);
143
+ const notification = await unlockWalletNotification(event, this.signer);
147
144
  if (!notification)
148
145
  throw new Error("Failed to decrypt or parse notification");
149
146
  return notification;
@@ -167,7 +164,7 @@ export class WalletConnect {
167
164
  // Create an observable that publishes the request event when subscribed to
168
165
  const request$ = defer(() => from(this.publishMethod(this.relays, requestEvent))).pipe(ignoreElements());
169
166
  // Create an observable that listens for response events
170
- const responses$ = this.events$.pipe(filter((response) => response.kind === WALLET_RESPONSE_KIND && getWalletResponseRequestId(response) === requestEvent.id), mergeMap((response) => this.handleResponseEvent(response, encryption)),
167
+ const responses$ = this.events$.pipe(filter(isValidWalletResponse), filter((response) => getWalletResponseRequestId(response) === requestEvent.id), mergeMap((response) => this.handleResponseEvent(response, encryption)),
171
168
  // Set timeout for response events
172
169
  simpleTimeout(options.timeout || this.defaultTimeout));
173
170
  return merge(request$, responses$);
@@ -1,10 +1,9 @@
1
1
  import { EventSigner } from "applesauce-factory";
2
- import { NostrEvent } from "nostr-tools";
3
2
  import { Observable, Subscription } from "rxjs";
4
3
  import { WalletAuthURI } from "./helpers/auth-uri.js";
5
4
  import { WalletErrorCode } from "./helpers/error.js";
6
5
  import { NotificationType, WalletNotification } from "./helpers/notification.js";
7
- import { GetBalanceParams, GetInfoParams, ListTransactionsParams, LookupInvoiceParams, MakeInvoiceParams, MultiPayInvoiceParams, MultiPayKeysendParams, PayInvoiceParams, PayKeysendParams, WalletRequest } from "./helpers/request.js";
6
+ import { GetBalanceParams, GetInfoParams, ListTransactionsParams, LookupInvoiceParams, MakeInvoiceParams, MultiPayInvoiceParams, MultiPayKeysendParams, PayInvoiceParams, PayKeysendParams, WalletRequest, WalletRequestEvent } from "./helpers/request.js";
8
7
  import { GetBalanceResult, GetInfoResult, ListTransactionsResult, LookupInvoiceResult, MakeInvoiceResult, MultiPayInvoiceResult, MultiPayKeysendResult, PayInvoiceResult, PayKeysendResult, WalletResponse } from "./helpers/response.js";
9
8
  import { WalletSupport } from "./helpers/support.js";
10
9
  import { NostrConnectionMethodsOptions, NostrPool, NostrPublishMethod, NostrSubscriptionMethod } from "./interop.js";
@@ -83,11 +82,11 @@ export declare class WalletService {
83
82
  /** The service's public key */
84
83
  pubkey: string | null;
85
84
  /** The client's secret key */
86
- protected secret: Uint8Array;
85
+ protected secret?: Uint8Array;
87
86
  /** The client's public key */
88
87
  client: string;
89
88
  /** Shared observable for all wallet request events */
90
- protected events$: Observable<NostrEvent> | null;
89
+ protected events$: Observable<WalletRequestEvent> | null;
91
90
  /** Subscription to the events observable */
92
91
  protected subscription: Subscription | null;
93
92
  /** Whether the service is currently running */
@@ -106,15 +105,15 @@ export declare class WalletService {
106
105
  /** Publish the wallet support event */
107
106
  protected publishSupportEvent(): Promise<void>;
108
107
  /** Handle a wallet request event */
109
- protected handleRequestEvent(requestEvent: NostrEvent): Promise<void>;
108
+ protected handleRequestEvent(requestEvent: WalletRequestEvent): Promise<void>;
110
109
  /** Process a decrypted wallet request */
111
- protected processRequest(requestEvent: NostrEvent, request: WalletRequest): Promise<void>;
110
+ protected processRequest(requestEvent: WalletRequestEvent, request: WalletRequest): Promise<void>;
112
111
  /** Send a success response */
113
- protected sendSuccessResponse<T extends WalletResponse>(requestEvent: NostrEvent, method: T["result_type"], result: T["result"]): Promise<void>;
112
+ protected sendSuccessResponse<T extends WalletResponse>(requestEvent: WalletRequestEvent, method: T["result_type"], result: T["result"]): Promise<void>;
114
113
  /** Send an error response */
115
- protected sendErrorResponse(requestEvent: NostrEvent, errorType: WalletErrorCode, errorMessage: string): Promise<void>;
114
+ protected sendErrorResponse(requestEvent: WalletRequestEvent, errorType: WalletErrorCode, errorMessage: string): Promise<void>;
116
115
  /** Send a response event */
117
- protected sendResponse(requestEvent: NostrEvent, response: WalletResponse): Promise<void>;
116
+ protected sendResponse(requestEvent: WalletRequestEvent, response: WalletResponse): Promise<void>;
118
117
  /** Creates a service for a nostr+walletauth URI */
119
118
  static fromAuthURI(uri: string | WalletAuthURI, options: Omit<WalletServiceOptions, "relays">): WalletService;
120
119
  }
@@ -8,7 +8,7 @@ import { WalletResponseBlueprint } from "./blueprints/response.js";
8
8
  import { WalletSupportBlueprint } from "./blueprints/support.js";
9
9
  import { parseWalletAuthURI } from "./helpers/auth-uri.js";
10
10
  import { WalletBaseError } from "./helpers/error.js";
11
- import { getWalletRequest, isWalletRequestExpired, isWalletRequestLocked, unlockWalletRequest, WALLET_REQUEST_KIND, } from "./helpers/request.js";
11
+ import { getWalletRequest, isValidWalletRequest, isWalletRequestExpired, unlockWalletRequest, WALLET_REQUEST_KIND, } from "./helpers/request.js";
12
12
  import { getConnectionMethods, } from "./interop.js";
13
13
  /** NIP-47 Wallet Service implementation */
14
14
  export class WalletService {
@@ -49,10 +49,16 @@ export class WalletService {
49
49
  this.handlers = options.handlers;
50
50
  // Set the client's secret and public key
51
51
  if (options.secret) {
52
+ // Service was created with a custom secret
52
53
  this.secret = options.secret;
53
54
  this.client = getPublicKey(this.secret);
54
55
  }
56
+ else if (options.client) {
57
+ // Service was restored with only the clients pubkey
58
+ this.client = options.client;
59
+ }
55
60
  else {
61
+ // Generate secret and client pubkey
56
62
  this.secret = generateSecretKey();
57
63
  this.client = getPublicKey(this.secret);
58
64
  }
@@ -98,7 +104,9 @@ export class WalletService {
98
104
  // Ignore strings (support for applesauce-relay)
99
105
  filter((event) => typeof event !== "string"),
100
106
  // Only include valid wallet request events
101
- filter((event) => event.kind === WALLET_REQUEST_KIND && event.pubkey === this.client),
107
+ filter(isValidWalletRequest),
108
+ // Ensure they are to our pubkey
109
+ filter((event) => event.pubkey === this.client),
102
110
  // Verify event signature
103
111
  filter((event) => verifyEvent(event)),
104
112
  // Only create a single subscription to the relays
@@ -129,6 +137,8 @@ export class WalletService {
129
137
  }
130
138
  /** Get the connection URI for the service */
131
139
  getConnectURI() {
140
+ if (!this.secret)
141
+ throw new Error("Service was not created with a secret");
132
142
  if (!this.pubkey)
133
143
  throw new Error("Service is not running");
134
144
  if (!this.relays.length)
@@ -168,13 +178,7 @@ export class WalletService {
168
178
  if (isWalletRequestExpired(requestEvent))
169
179
  return await this.sendErrorResponse(requestEvent, "OTHER", "Request has expired");
170
180
  // Unlock the request if needed
171
- let request;
172
- if (isWalletRequestLocked(requestEvent)) {
173
- request = await unlockWalletRequest(requestEvent, this.signer);
174
- }
175
- else {
176
- request = getWalletRequest(requestEvent);
177
- }
181
+ const request = await unlockWalletRequest(requestEvent, this.signer);
178
182
  if (!request)
179
183
  return await this.sendErrorResponse(requestEvent, "OTHER", "Failed to decrypt or parse request");
180
184
  // Handle the request based on its method
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-wallet-connect",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -58,23 +58,25 @@
58
58
  }
59
59
  },
60
60
  "dependencies": {
61
- "applesauce-core": "^3.1.0",
62
- "applesauce-factory": "^3.1.0",
63
- "nostr-tools": "~2.15",
64
61
  "@noble/hashes": "^1.7.1",
62
+ "applesauce-core": "^4.0.0",
63
+ "applesauce-factory": "^4.0.0",
64
+ "nostr-tools": "~2.17",
65
65
  "rxjs": "^7.8.1"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@hirez_io/observer-spy": "^2.2.0",
69
69
  "@types/debug": "^4.1.12",
70
+ "rimraf": "^6.0.1",
70
71
  "typescript": "^5.8.3",
71
- "vitest": "^3.2.3"
72
+ "vitest": "^3.2.4"
72
73
  },
73
74
  "funding": {
74
75
  "type": "lightning",
75
76
  "url": "lightning:nostrudel@geyser.fund"
76
77
  },
77
78
  "scripts": {
79
+ "prebuild": "rimraf dist",
78
80
  "build": "tsc",
79
81
  "watch:build": "tsc --watch > /dev/null",
80
82
  "test": "vitest run --passWithNoTests",