@wizardconnect/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/connection-manager.d.ts +45 -0
  2. package/dist/connection-manager.js +157 -0
  3. package/dist/connection-manager.js.map +1 -0
  4. package/dist/dapp-relay.d.ts +27 -0
  5. package/dist/dapp-relay.js +129 -0
  6. package/dist/dapp-relay.js.map +1 -0
  7. package/dist/index.d.ts +33 -0
  8. package/dist/index.js +21 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/key-exchange.d.ts +35 -0
  11. package/dist/key-exchange.js +154 -0
  12. package/dist/key-exchange.js.map +1 -0
  13. package/dist/log.d.ts +14 -0
  14. package/dist/log.js +23 -0
  15. package/dist/log.js.map +1 -0
  16. package/dist/message-queue.d.ts +15 -0
  17. package/dist/message-queue.js +61 -0
  18. package/dist/message-queue.js.map +1 -0
  19. package/dist/primitives.d.ts +5 -0
  20. package/dist/primitives.js +18 -0
  21. package/dist/primitives.js.map +1 -0
  22. package/dist/protocols/base.d.ts +37 -0
  23. package/dist/protocols/base.js +46 -0
  24. package/dist/protocols/base.js.map +1 -0
  25. package/dist/protocols/hdwalletv1.d.ts +56 -0
  26. package/dist/protocols/hdwalletv1.js +80 -0
  27. package/dist/protocols/hdwalletv1.js.map +1 -0
  28. package/dist/relay-client.d.ts +38 -0
  29. package/dist/relay-client.js +323 -0
  30. package/dist/relay-client.js.map +1 -0
  31. package/dist/relay-handler.d.ts +33 -0
  32. package/dist/relay-handler.js +125 -0
  33. package/dist/relay-handler.js.map +1 -0
  34. package/dist/utilnostr.d.ts +4 -0
  35. package/dist/utilnostr.js +16 -0
  36. package/dist/utilnostr.js.map +1 -0
  37. package/dist/wallet-relay.d.ts +20 -0
  38. package/dist/wallet-relay.js +71 -0
  39. package/dist/wallet-relay.js.map +1 -0
  40. package/package.json +34 -0
@@ -0,0 +1,323 @@
1
+ import { throwUnless, unwrap } from "./primitives.js";
2
+ import NDK, {
3
+ NDKPrivateKeySigner,
4
+ NDKUser,
5
+ NDKEvent,
6
+ NDKKind,
7
+ giftWrap,
8
+ giftUnwrap,
9
+ } from "@nostr-dev-kit/ndk";
10
+ import { binToHex, hash256, secp256k1 } from "@bitauth/libauth";
11
+ import { EventEmitter } from "eventemitter3";
12
+ import { isProtocolMessage, RelayMsgAction } from "./protocols/hdwalletv1.js";
13
+ import { deriveNostrPublicKey } from "./utilnostr.js";
14
+ import { MessageQueue } from "./message-queue.js";
15
+ import { debug, error as logError, Scope } from "./log.js";
16
+ export class RelayClient extends EventEmitter {
17
+ ndk;
18
+ paired;
19
+ config;
20
+ messageSubscription = null;
21
+ myPubkey;
22
+ myPubkeyHex;
23
+ lastProcessedTimestamp = 0;
24
+ messageQueue;
25
+ sequence = Math.floor(Math.random() * (Number.MAX_SAFE_INTEGER - 500_000));
26
+ pendingCalls = new Map();
27
+ pendingDeliveries = new Map();
28
+ constructor(config) {
29
+ super();
30
+ this.config = {
31
+ logNetworkActivity: true,
32
+ ...config,
33
+ };
34
+ this.ndk = new NDK({
35
+ explicitRelayUrls: this.config.explicitRelayUrls,
36
+ signer: new NDKPrivateKeySigner(this.config.signerPrivateKey),
37
+ enableOutboxModel: false,
38
+ autoConnectUserRelays: false,
39
+ });
40
+ this.messageQueue = new MessageQueue({
41
+ logActivity: this.config.logNetworkActivity,
42
+ });
43
+ this.myPubkey = unwrap(
44
+ secp256k1.derivePublicKeyCompressed(this.config.signerPrivateKey),
45
+ );
46
+ this.myPubkeyHex = deriveNostrPublicKey(this.config.signerPrivateKey);
47
+ if (this.config.pairedPublicKey) {
48
+ const pairedNostrPubkey =
49
+ this.config.pairedPublicKey.length === 33
50
+ ? this.config.pairedPublicKey.slice(1)
51
+ : this.config.pairedPublicKey;
52
+ this.paired = new NDKUser({ pubkey: binToHex(pairedNostrPubkey) });
53
+ } else {
54
+ this.paired = new NDKUser({ pubkey: "" });
55
+ }
56
+ }
57
+ setPairedPublicKey(pairedPublicKey) {
58
+ this.config.pairedPublicKey = pairedPublicKey;
59
+ const pairedNostrPubkey =
60
+ pairedPublicKey.length === 33
61
+ ? pairedPublicKey.slice(1)
62
+ : pairedPublicKey;
63
+ this.paired = new NDKUser({ pubkey: binToHex(pairedNostrPubkey) });
64
+ this.emit("paired");
65
+ }
66
+ getPublicKey() {
67
+ return this.myPubkey;
68
+ }
69
+ getPublicKeyHex() {
70
+ return this.myPubkeyHex;
71
+ }
72
+ isKeyExchangeComplete() {
73
+ if (!this.config.pairedPublicKey) {
74
+ return false;
75
+ }
76
+ return !this.config.pairedPublicKey.every((byte) => byte === 0);
77
+ }
78
+ async connect() {
79
+ if (this.config.logNetworkActivity) {
80
+ debug(Scope.Relay, `Connecting to relay...`);
81
+ }
82
+ if (this.lastProcessedTimestamp === 0) {
83
+ this.lastProcessedTimestamp = Math.floor(Date.now() / 1000) - 2;
84
+ }
85
+ try {
86
+ await this.ndk.connect();
87
+ if (this.config.logNetworkActivity) {
88
+ debug(Scope.Relay, `NDK connect() resolved`);
89
+ }
90
+ this.messageSubscription = this.ndk.subscribe(
91
+ {
92
+ kinds: [NDKKind.GiftWrap],
93
+ "#p": [this.myPubkeyHex],
94
+ },
95
+ { closeOnEose: false },
96
+ );
97
+ this.messageSubscription.on("event", async (wrappedEvent) => {
98
+ try {
99
+ const signer = this.ndk.signer;
100
+ if (!signer) {
101
+ throw new Error("No signer available");
102
+ }
103
+ const rumor = await giftUnwrap(wrappedEvent, undefined, signer);
104
+ if (rumor.kind === NDKKind.PrivateDirectMessage) {
105
+ let payload;
106
+ try {
107
+ payload = JSON.parse(rumor.content);
108
+ } catch (e) {
109
+ if (this.config.logNetworkActivity) {
110
+ logError(
111
+ Scope.Relay,
112
+ "Failed to parse message content as JSON:",
113
+ e,
114
+ );
115
+ }
116
+ return;
117
+ }
118
+ if (
119
+ !payload.time ||
120
+ (this.lastProcessedTimestamp > 0 &&
121
+ payload.time < this.lastProcessedTimestamp)
122
+ ) {
123
+ if (this.config.logNetworkActivity) {
124
+ debug(
125
+ Scope.Relay,
126
+ `Ignoring already-processed message (time: ${payload.time}, action: ${payload.action}, last processed: ${this.lastProcessedTimestamp})`,
127
+ );
128
+ }
129
+ return;
130
+ }
131
+ // wallet_ready carries the key exchange data (public_key + secret) so it
132
+ // must bypass the peer filter — the dapp doesn't know the wallet's pubkey yet.
133
+ const isKeyExchangeMessage =
134
+ payload.action === RelayMsgAction.WalletReady;
135
+ if (!isKeyExchangeMessage && this.config.pairedPublicKey) {
136
+ const pairedNostrPubkey =
137
+ this.config.pairedPublicKey.length === 33
138
+ ? binToHex(this.config.pairedPublicKey.slice(1))
139
+ : binToHex(this.config.pairedPublicKey);
140
+ if (rumor.pubkey !== pairedNostrPubkey) {
141
+ if (this.config.logNetworkActivity) {
142
+ debug(
143
+ Scope.Relay,
144
+ `Ignoring '${payload.action}' message from unknown peer: ${rumor.pubkey} (expected: ${pairedNostrPubkey})`,
145
+ );
146
+ }
147
+ return;
148
+ }
149
+ }
150
+ if (this.config.logNetworkActivity) {
151
+ debug(
152
+ Scope.Relay,
153
+ `Received message ${payload.action} from relay`,
154
+ );
155
+ }
156
+ this.handleRelayMessage(payload);
157
+ } else {
158
+ if (this.config.logNetworkActivity) {
159
+ debug(
160
+ Scope.Relay,
161
+ `Ignoring non-PrivateDirectMessage, kind: ${rumor.kind}`,
162
+ );
163
+ }
164
+ }
165
+ } catch (error) {
166
+ if (this.config.logNetworkActivity) {
167
+ logError(Scope.Relay, "Error handling incoming message:", error);
168
+ }
169
+ this.emitError(error);
170
+ }
171
+ });
172
+ this.messageSubscription.on("close", () => {
173
+ if (this.config.logNetworkActivity) {
174
+ debug(Scope.Relay, "Subscription closed, connection may be stale");
175
+ }
176
+ this.emit("disconnect", new Error("Subscription closed"));
177
+ });
178
+ this.waitForRelaysReady();
179
+ if (this.config.logNetworkActivity) {
180
+ debug(
181
+ Scope.Relay,
182
+ `Subscription created and handler set up, emitting connection event`,
183
+ );
184
+ }
185
+ this.emit("connection");
186
+ } catch (error) {
187
+ if (this.config.logNetworkActivity) {
188
+ logError(Scope.Relay, `Connection failed:`, error);
189
+ }
190
+ throw error;
191
+ }
192
+ }
193
+ async disconnect() {
194
+ this.lastProcessedTimestamp = Math.floor(Date.now() / 1000);
195
+ this.messageQueue.setNotReady();
196
+ if (this.messageSubscription) {
197
+ this.messageSubscription.stop();
198
+ this.messageSubscription = null;
199
+ }
200
+ }
201
+ getLastProcessedTimestamp() {
202
+ return this.lastProcessedTimestamp;
203
+ }
204
+ setLastProcessedTimestamp(timestamp) {
205
+ this.lastProcessedTimestamp = timestamp;
206
+ }
207
+ async relay(message) {
208
+ if (!this.config.pairedPublicKey) {
209
+ throw new Error(
210
+ "Cannot relay message: paired public key not set. Call setPairedPublicKey() first.",
211
+ );
212
+ }
213
+ if (!this.messageQueue.getReady()) {
214
+ return this.messageQueue.enqueue(message);
215
+ }
216
+ return this.publishMessage(message);
217
+ }
218
+ async publishMessage(message) {
219
+ this.netlog("send", message.action);
220
+ const signer = this.ndk.signer;
221
+ if (!signer) {
222
+ throw new Error("No signer available");
223
+ }
224
+ const rumor = new NDKEvent(this.ndk);
225
+ rumor.kind = NDKKind.PrivateDirectMessage;
226
+ rumor.content = JSON.stringify(message);
227
+ rumor.created_at = Math.floor(Date.now() / 1000);
228
+ rumor.tags = [["p", this.paired.pubkey]];
229
+ const wrappedEvent = await giftWrap(rumor, this.paired, signer);
230
+ try {
231
+ await wrappedEvent.publish();
232
+ if (this.config.logNetworkActivity) {
233
+ debug(Scope.Relay, `Published message ${message.action} to relay`);
234
+ }
235
+ } catch (error) {
236
+ if (this.config.logNetworkActivity) {
237
+ logError(
238
+ Scope.Relay,
239
+ `Failed to publish message ${message.action}:`,
240
+ error,
241
+ );
242
+ }
243
+ throw error;
244
+ }
245
+ }
246
+ async waitForRelaysReady() {
247
+ const maxWaitTime = 5000;
248
+ const checkInterval = 100;
249
+ const startTime = Date.now();
250
+ const checkRelays = async () => {
251
+ const pool = this.ndk.pool;
252
+ if (pool) {
253
+ const relays = pool.relays || [];
254
+ // NDKRelayStatus: DISCONNECTED=1, CONNECTED=5, AUTHENTICATED=8
255
+ const connectedRelays = Array.from(relays.values()).filter(
256
+ (relay) => relay.status >= 5,
257
+ );
258
+ if (connectedRelays.length > 0) {
259
+ if (this.config.logNetworkActivity) {
260
+ debug(
261
+ Scope.Relay,
262
+ `Relays ready (${connectedRelays.length} connected), processing queued messages`,
263
+ );
264
+ }
265
+ await this.messageQueue.setReady((msg) => this.publishMessage(msg));
266
+ return;
267
+ }
268
+ }
269
+ if (Date.now() - startTime < maxWaitTime) {
270
+ setTimeout(checkRelays, checkInterval);
271
+ } else {
272
+ if (this.config.logNetworkActivity) {
273
+ debug(
274
+ Scope.Relay,
275
+ "Relay ready check timeout, assuming ready and processing queued messages",
276
+ );
277
+ }
278
+ await this.messageQueue.setReady((msg) => this.publishMessage(msg));
279
+ }
280
+ };
281
+ setTimeout(checkRelays, 200);
282
+ }
283
+ isConnected() {
284
+ return true;
285
+ }
286
+ netlog(direction, what, sequence) {
287
+ if (!this.config.logNetworkActivity) {
288
+ return;
289
+ }
290
+ const us = binToHex(hash256(this.config.signerPrivateKey)).slice(-6);
291
+ const them = this.config.pairedPublicKey
292
+ ? binToHex(this.config.pairedPublicKey).slice(-6)
293
+ : "??????";
294
+ const pending = `c${this.pendingCalls.size} d${this.pendingDeliveries.size}`;
295
+ if (direction === "send") {
296
+ debug(
297
+ Scope.Relay,
298
+ `net [${sequence ?? "?"} ${pending}] ${us} -> ${them}: ${what}`,
299
+ );
300
+ } else {
301
+ debug(
302
+ Scope.Relay,
303
+ `net [${sequence ?? "?"} ${pending}] ${us} <- ${them}: ${what}`,
304
+ );
305
+ }
306
+ }
307
+ async handleRelayMessage(message) {
308
+ throwUnless(
309
+ isProtocolMessage(message),
310
+ `Invalid protocol message: ${message}`,
311
+ );
312
+ this.emit("message", message);
313
+ }
314
+ nextSequence() {
315
+ const current = this.sequence;
316
+ this.sequence += 2;
317
+ return current;
318
+ }
319
+ emitError(error) {
320
+ this.emit("error", error);
321
+ }
322
+ }
323
+ //# sourceMappingURL=relay-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-client.js","sourceRoot":"","sources":["../src/relay-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { RelayClient } from "./relay-client.js";
2
+ type RelayStatusCode =
3
+ | "connected"
4
+ | "reconnecting"
5
+ | "disconnected"
6
+ | "session_deleted";
7
+ export declare class RelayStatus {
8
+ status: RelayStatusCode;
9
+ error: string | null;
10
+ sessionId: string | null;
11
+ private constructor();
12
+ static connected(sessionId?: string): RelayStatus;
13
+ static reconnecting(reason: string | null, sessionId?: string): RelayStatus;
14
+ static disconnected(): RelayStatus;
15
+ static sessionDeleted(): RelayStatus;
16
+ }
17
+ export interface RelayUpdatePayload {
18
+ client: RelayClient;
19
+ status: RelayStatus;
20
+ }
21
+ export type RelayStatusCallback = (_payload: RelayUpdatePayload) => void;
22
+ export declare const initiateRelay: (
23
+ dispatchCallback: RelayStatusCallback,
24
+ signerPrivateKey: Uint8Array,
25
+ pairPublicKey: Uint8Array,
26
+ options?: {
27
+ explicitRelayUrls: string[];
28
+ reconnectInterval?: number;
29
+ maxReconnectAttempts?: number;
30
+ enableVisibilityHandling?: boolean;
31
+ },
32
+ ) => () => void;
33
+ export {};
@@ -0,0 +1,125 @@
1
+ import { RelayClient } from "./relay-client.js";
2
+ import { createConnectionManager } from "./connection-manager.js";
3
+ import { debug, error as logError, Scope } from "./log.js";
4
+ export class RelayStatus {
5
+ status;
6
+ error;
7
+ sessionId;
8
+ constructor(status, error, sessionId = null) {
9
+ this.status = status;
10
+ this.error = error;
11
+ this.sessionId = sessionId;
12
+ }
13
+ static connected(sessionId) {
14
+ return new RelayStatus("connected", null, sessionId || null);
15
+ }
16
+ static reconnecting(reason, sessionId) {
17
+ return new RelayStatus("reconnecting", reason, sessionId || null);
18
+ }
19
+ static disconnected() {
20
+ return new RelayStatus("disconnected", null, null);
21
+ }
22
+ static sessionDeleted() {
23
+ return new RelayStatus("session_deleted", null, null);
24
+ }
25
+ }
26
+ export const initiateRelay = (
27
+ dispatchCallback,
28
+ signerPrivateKey,
29
+ pairPublicKey,
30
+ options,
31
+ ) => {
32
+ const client = new RelayClient({
33
+ explicitRelayUrls: options?.explicitRelayUrls ?? [],
34
+ signerPrivateKey: signerPrivateKey,
35
+ pairedPublicKey: pairPublicKey,
36
+ });
37
+ let lastProcessedTimestamp = 0;
38
+ const connectionManager = createConnectionManager(
39
+ client,
40
+ {
41
+ onConnected: () => {
42
+ if (lastProcessedTimestamp > 0) {
43
+ client.setLastProcessedTimestamp(lastProcessedTimestamp);
44
+ } else {
45
+ lastProcessedTimestamp = client.getLastProcessedTimestamp();
46
+ }
47
+ dispatchCallback({
48
+ client,
49
+ status: RelayStatus.connected(),
50
+ });
51
+ },
52
+ onReconnecting: (_client, reason) => {
53
+ dispatchCallback({
54
+ client,
55
+ status: RelayStatus.reconnecting(reason),
56
+ });
57
+ },
58
+ onDisconnected: () => {
59
+ dispatchCallback({
60
+ client,
61
+ status: RelayStatus.disconnected(),
62
+ });
63
+ },
64
+ onError: (_client, _error) => {
65
+ // Error handling is already done in onReconnecting
66
+ },
67
+ },
68
+ {
69
+ connected: "connection",
70
+ disconnected: "disconnect",
71
+ error: "error",
72
+ },
73
+ {
74
+ reconnectInterval: options?.reconnectInterval,
75
+ maxReconnectAttempts: options?.maxReconnectAttempts,
76
+ enableVisibilityHandling: options?.enableVisibilityHandling ?? true,
77
+ scope: Scope.Relay,
78
+ onVisibilityChange: async (context) => {
79
+ if (context.state === "hidden") {
80
+ debug(Scope.Relay, "Page hidden, disconnecting relay");
81
+ context.setPaused(true);
82
+ try {
83
+ await client.disconnect();
84
+ lastProcessedTimestamp = client.getLastProcessedTimestamp();
85
+ debug(
86
+ Scope.Relay,
87
+ `Disconnected, last processed timestamp: ${lastProcessedTimestamp}`,
88
+ );
89
+ dispatchCallback({
90
+ client,
91
+ status: RelayStatus.disconnected(),
92
+ });
93
+ } catch (error) {
94
+ logError(
95
+ Scope.Relay,
96
+ "Error disconnecting on visibility change:",
97
+ error,
98
+ );
99
+ }
100
+ } else if (context.state === "visible") {
101
+ if (context.isPaused()) {
102
+ debug(Scope.Relay, "Page visible, reconnecting relay");
103
+ context.setPaused(false);
104
+ context.startConnectionLoop();
105
+ }
106
+ }
107
+ },
108
+ },
109
+ );
110
+ connectionManager.startConnectionLoop();
111
+ return () => {
112
+ dispatchCallback({
113
+ client,
114
+ status: RelayStatus.disconnected(),
115
+ });
116
+ (async () => {
117
+ try {
118
+ await connectionManager.cleanup();
119
+ } catch {
120
+ // Ignore disconnect errors during cleanup
121
+ }
122
+ })();
123
+ };
124
+ };
125
+ //# sourceMappingURL=relay-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-handler.js","sourceRoot":"","sources":["../src/relay-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function deriveNostrPublicKey(privateKey: Uint8Array): string;
2
+ export declare function deriveNostrPublicKeyBytes(
3
+ privateKey: Uint8Array,
4
+ ): Uint8Array;
@@ -0,0 +1,16 @@
1
+ import { binToHex, secp256k1 } from "@bitauth/libauth";
2
+ import { unwrap } from "./primitives.js";
3
+ export function deriveNostrPublicKey(privateKey) {
4
+ const publicKeyCompressed = unwrap(
5
+ secp256k1.derivePublicKeyCompressed(privateKey),
6
+ );
7
+ const publicKeyNostr = publicKeyCompressed.slice(1);
8
+ return binToHex(publicKeyNostr);
9
+ }
10
+ export function deriveNostrPublicKeyBytes(privateKey) {
11
+ const publicKeyCompressed = unwrap(
12
+ secp256k1.derivePublicKeyCompressed(privateKey),
13
+ );
14
+ return publicKeyCompressed.slice(1);
15
+ }
16
+ //# sourceMappingURL=utilnostr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilnostr.js","sourceRoot":"","sources":["../src/utilnostr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,UAAU,oBAAoB,CAAC,UAAsB;IACzD,MAAM,mBAAmB,GAAG,MAAM,CAChC,SAAS,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAChD,CAAC;IACF,MAAM,cAAc,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,QAAQ,CAAC,cAAc,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,UAAsB;IAC9D,MAAM,mBAAmB,GAAG,MAAM,CAChC,SAAS,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAChD,CAAC;IACF,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { RelayClient } from "./relay-client.js";
2
+ import { RelayStatusCallback } from "./relay-handler.js";
3
+ export interface WalletRelayOptions {
4
+ uri: string;
5
+ walletPrivateKey: Uint8Array;
6
+ explicitRelayUrls?: string[];
7
+ reconnectInterval?: number;
8
+ maxReconnectAttempts?: number;
9
+ }
10
+ export interface WalletRelayResult {
11
+ client: RelayClient;
12
+ dappPublicKey: Uint8Array;
13
+ walletPublicKey: Uint8Array;
14
+ secret: string;
15
+ cleanup: () => void;
16
+ }
17
+ export declare function initiateWalletRelay(
18
+ statusCallback: RelayStatusCallback,
19
+ options: WalletRelayOptions,
20
+ ): WalletRelayResult;
@@ -0,0 +1,71 @@
1
+ import { initiateRelay } from "./relay-handler.js";
2
+ import { decodeKeyExchangeURI, DEFAULT_RELAY_PORT } from "./key-exchange.js";
3
+ import { binToHex, hexToBin } from "@bitauth/libauth";
4
+ import { deriveNostrPublicKeyBytes } from "./utilnostr.js";
5
+ export function initiateWalletRelay(statusCallback, options) {
6
+ let decoded;
7
+ try {
8
+ decoded = decodeKeyExchangeURI(options.uri);
9
+ } catch (err) {
10
+ throw new Error(`Failed to decode connection URI: ${err.message}`, {
11
+ cause: err,
12
+ });
13
+ }
14
+ const dappPublicKeyHex = decoded.publicKey;
15
+ const secret = decoded.secret;
16
+ const dappPublicKeyNostr = hexToBin(dappPublicKeyHex);
17
+ const hostname = decoded.hostname;
18
+ const protocol = decoded.protocol;
19
+ const port = decoded.port;
20
+ const relayUrl = `${protocol}://${hostname}${port === (protocol === "wss" ? DEFAULT_RELAY_PORT : 80) ? "" : `:${port}`}`;
21
+ const walletPublicKeyNostr = deriveNostrPublicKeyBytes(
22
+ options.walletPrivateKey,
23
+ );
24
+ const walletPublicKeyHex = binToHex(walletPublicKeyNostr);
25
+ let relayClient = null;
26
+ const wrappedCallback = (payload) => {
27
+ if (!relayClient) {
28
+ relayClient = payload.client;
29
+ }
30
+ if (payload.status.status === "connected") {
31
+ // Set dapp's pubkey so outbound messages are addressed correctly.
32
+ // The wallet's own pubkey + secret are delivered via wallet_ready.
33
+ relayClient.setPairedPublicKey(dappPublicKeyNostr);
34
+ }
35
+ statusCallback(payload);
36
+ };
37
+ const relayUrls = [relayUrl];
38
+ if (options.explicitRelayUrls && options.explicitRelayUrls.length > 0) {
39
+ for (const explicitUrl of options.explicitRelayUrls) {
40
+ if (!relayUrls.includes(explicitUrl)) {
41
+ relayUrls.push(explicitUrl);
42
+ }
43
+ }
44
+ }
45
+ const cleanup = initiateRelay(
46
+ wrappedCallback,
47
+ options.walletPrivateKey,
48
+ dappPublicKeyNostr,
49
+ {
50
+ explicitRelayUrls: relayUrls,
51
+ reconnectInterval: options.reconnectInterval,
52
+ maxReconnectAttempts: options.maxReconnectAttempts,
53
+ },
54
+ );
55
+ const result = {
56
+ get client() {
57
+ if (!relayClient) {
58
+ throw new Error(
59
+ "Relay client not yet initialized. Wait for connection status callback.",
60
+ );
61
+ }
62
+ return relayClient;
63
+ },
64
+ dappPublicKey: dappPublicKeyNostr,
65
+ walletPublicKey: walletPublicKeyNostr,
66
+ secret,
67
+ cleanup,
68
+ };
69
+ return result;
70
+ }
71
+ //# sourceMappingURL=wallet-relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-relay.js","sourceRoot":"","sources":["../src/wallet-relay.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@wizardconnect/core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Transport and protocol primitives for WizardConnect",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist/"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "vitest --config vitest.config.ts --run --passWithNoTests",
14
+ "lint:prettier": "prettier . --list-different",
15
+ "lint:eslint": "eslint .",
16
+ "lint": "npm run lint:eslint && npm run lint:prettier",
17
+ "fix": "npm run fix:eslint && npm run fix:prettier",
18
+ "fix:prettier": "prettier . --write",
19
+ "fix:eslint": "npm run lint:eslint -- --fix"
20
+ },
21
+ "dependencies": {
22
+ "@bch-wc2/interfaces": "^0.0.8",
23
+ "@nostr-dev-kit/ndk": "^2.18.1",
24
+ "@bitauth/libauth": "^3.1.0-next.2",
25
+ "eventemitter3": "^5.0.1",
26
+ "isomorphic-ws": "^5.0.0",
27
+ "lossless-json": "^4.3.0",
28
+ "ws": "^8.18.0"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "^5.6.2",
32
+ "vitest": "^3.2.3"
33
+ }
34
+ }