@welshman/signer 0.0.15 → 0.0.17

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,30 +1,19 @@
1
1
  import { Emitter } from "@welshman/lib";
2
2
  import { TrustedEvent, StampedEvent } from "@welshman/util";
3
+ import { Subscription } from "@welshman/net";
3
4
  import { ISigner } from '../util';
5
+ import { Nip01Signer } from './nip01';
4
6
  export type Nip46Algorithm = "nip04" | "nip44";
5
- export type Nip46Handler = {
6
- relays: string[];
7
- pubkey: string;
8
- domain?: string;
9
- };
10
- export type Nip46InitiateParams = {
11
- url: string;
12
- name: string;
13
- image: string;
14
- perms: string;
15
- relays: string[];
16
- abortController?: AbortController;
17
- };
7
+ export declare enum Nip46Event {
8
+ Send = "send",
9
+ Receive = "receive"
10
+ }
18
11
  export type Nip46BrokerParams = {
19
- secret: string;
20
- handler: Nip46Handler;
12
+ relays: string[];
13
+ clientSecret: string;
14
+ signerPubkey?: string;
21
15
  algorithm?: Nip46Algorithm;
22
16
  };
23
- export type Nip46Request = {
24
- method: string;
25
- params: string[];
26
- resolve: (result: Nip46ResponseWithResult) => void;
27
- };
28
17
  export type Nip46Response = {
29
18
  id: string;
30
19
  url: string;
@@ -44,39 +33,69 @@ export type Nip46ResponseWithError = {
44
33
  event: TrustedEvent;
45
34
  error: string;
46
35
  };
36
+ export declare class Nip46Receiver extends Emitter {
37
+ signer: ISigner;
38
+ params: Nip46BrokerParams;
39
+ sub?: Subscription;
40
+ constructor(signer: ISigner, params: Nip46BrokerParams);
41
+ start: () => Promise<void>;
42
+ stop: () => void;
43
+ }
44
+ export declare class Nip46Sender extends Emitter {
45
+ signer: ISigner;
46
+ params: Nip46BrokerParams;
47
+ processing: boolean;
48
+ queue: Nip46Request[];
49
+ constructor(signer: ISigner, params: Nip46BrokerParams);
50
+ send: (request: Nip46Request) => Promise<void>;
51
+ process: () => Promise<void>;
52
+ enqueue: (request: Nip46Request) => void;
53
+ stop: () => void;
54
+ }
55
+ export declare class Nip46Request {
56
+ readonly method: string;
57
+ readonly params: string[];
58
+ id: string;
59
+ promise: import("@welshman/lib").Deferred<Nip46ResponseWithResult, Nip46ResponseWithError>;
60
+ constructor(method: string, params: string[]);
61
+ listen: (receiver: Nip46Receiver) => Promise<void>;
62
+ send: (sender: Nip46Sender) => Promise<void>;
63
+ }
47
64
  export declare class Nip46Broker extends Emitter {
48
- #private;
49
- private params;
50
- static initiate({ url, name, image, perms, relays, abortController }: Nip46InitiateParams): {
51
- result: Promise<string | undefined>;
52
- params: URLSearchParams;
53
- nostrconnect: string;
54
- clientSecret: string;
55
- clientPubkey: string;
56
- };
57
- static parseBunkerLink(link: string): {
58
- token: string;
59
- pubkey: string;
60
- relays: string[];
61
- };
62
- static get(params: Nip46BrokerParams): Nip46Broker;
65
+ params: Nip46BrokerParams;
66
+ signer: ISigner;
67
+ sender: Nip46Sender;
68
+ receiver: Nip46Receiver;
63
69
  constructor(params: Nip46BrokerParams);
70
+ static get(params: Nip46BrokerParams): Nip46Broker;
64
71
  hasParams(params: Nip46BrokerParams): boolean;
65
- request: (method: string, params: string[]) => Promise<Nip46ResponseWithResult>;
66
- enqueue: (method: string, params: string[]) => Promise<Nip46ResponseWithResult>;
67
- createAccount: (username: string, perms?: string) => Promise<string>;
68
- connect: (token?: string, perms?: string, secret?: string) => Promise<boolean>;
72
+ makeSigner: () => Nip01Signer;
73
+ makeSender: () => Nip46Sender;
74
+ makeReceiver: () => Nip46Receiver;
75
+ setParams: (params: Partial<Nip46BrokerParams>) => void;
76
+ teardown: () => void;
77
+ enqueue: (method: string, params: string[]) => Promise<Nip46Request>;
78
+ send: (method: string, params: string[]) => Promise<string>;
79
+ parseBunkerUrl: (url: string) => {
80
+ signerPubkey: string;
81
+ connectSecret: string;
82
+ relays: string[];
83
+ };
84
+ makeNostrconnectUrl: (meta?: Record<string, string>) => Promise<string>;
85
+ waitForNostrconnect: (url: string, abort?: AbortController) => import("@welshman/lib").CustomPromise<Nip46ResponseWithResult, Nip46Response | undefined>;
86
+ ping: () => Promise<string>;
69
87
  getPublicKey: () => Promise<string>;
88
+ createAccount: (username: string, domain: string, perms?: string) => Promise<string>;
89
+ connect: (signerPubkey: string, connectSecret?: string, perms?: string) => Promise<string>;
70
90
  signEvent: (event: StampedEvent) => Promise<any>;
71
91
  nip04Encrypt: (pk: string, message: string) => Promise<string>;
72
92
  nip04Decrypt: (pk: string, message: string) => Promise<string>;
73
93
  nip44Encrypt: (pk: string, message: string) => Promise<string>;
74
94
  nip44Decrypt: (pk: string, message: string) => Promise<string>;
75
- teardown: () => void;
76
95
  }
77
96
  export declare class Nip46Signer implements ISigner {
78
- #private;
79
- private broker;
97
+ broker: Nip46Broker;
98
+ pubkey?: string;
80
99
  constructor(broker: Nip46Broker);
81
100
  getPubkey: () => Promise<string>;
82
101
  sign: (template: StampedEvent) => Promise<any>;
@@ -1,230 +1,293 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _Nip46Broker_signer, _Nip46Broker_handler, _Nip46Broker_algorithm, _Nip46Broker_closed, _Nip46Broker_processing, _Nip46Broker_connectResponse, _Nip46Broker_queue, _Nip46Broker_window, _Nip46Broker_sub, _Nip46Broker_subscribe, _Nip46Broker_processQueue, _Nip46Broker_getResult, _Nip46Signer_pubkey;
13
- import { Emitter, sleep, tryCatch, randomId, equals } from "@welshman/lib";
14
- import { createEvent, NOSTR_CONNECT } from "@welshman/util";
1
+ import { Emitter, throttle, makePromise, defer, sleep, tryCatch, randomId, equals } from "@welshman/lib";
2
+ import { createEvent, normalizeRelayUrl, NOSTR_CONNECT } from "@welshman/util";
15
3
  import { subscribe, publish, SubscriptionEvent } from "@welshman/net";
16
- import { decrypt, hash, own, makeSecret, getPubkey } from "../util.mjs";
4
+ import { decrypt, hash, own } from "../util.mjs";
17
5
  import { Nip01Signer } from "./nip01.mjs";
6
+ export var Nip46Event;
7
+ (function (Nip46Event) {
8
+ Nip46Event["Send"] = "send";
9
+ Nip46Event["Receive"] = "receive";
10
+ })(Nip46Event || (Nip46Event = {}));
18
11
  let singleton;
19
- export class Nip46Broker extends Emitter {
20
- static initiate({ url, name, image, perms, relays, abortController }) {
21
- const secret = Math.random().toString(36).substring(7);
22
- const clientSecret = makeSecret();
23
- const clientPubkey = getPubkey(clientSecret);
24
- const clientSigner = new Nip01Signer(clientSecret);
25
- const params = new URLSearchParams({ secret, url, name, image, perms });
26
- for (const relay of relays) {
27
- params.append('relay', relay);
12
+ const popupManager = (() => {
13
+ let pendingUrl = "";
14
+ let pendingSince = 0;
15
+ let currentWindow;
16
+ const openPending = throttle(1000, () => {
17
+ // If it's been a while since they asked for it, drop the request
18
+ if (Date.now() - pendingSince > 10000)
19
+ return;
20
+ // If we have an active, open window, continue to wait
21
+ if (currentWindow && !currentWindow.closed) {
22
+ setTimeout(() => openPending(), 100);
28
23
  }
29
- const nostrconnect = `nostrconnect://${clientPubkey}?${params.toString()}`;
30
- const result = new Promise(resolve => {
31
- const complete = (pubkey) => {
32
- sub.close();
33
- resolve(pubkey);
34
- };
35
- const sub = subscribe({
36
- relays,
37
- filters: [{ kinds: [NOSTR_CONNECT], "#p": [clientPubkey] }],
38
- onEvent: async ({ pubkey, content }) => {
39
- const response = await tryCatch(async () => JSON.parse(await decrypt(clientSigner, pubkey, content)));
40
- if ((response === null || response === void 0 ? void 0 : response.result) === secret) {
41
- complete(pubkey);
42
- }
43
- if ((response === null || response === void 0 ? void 0 : response.result) === 'ack') {
44
- console.warn("Bunker responded to nostrconnect with 'ack', which can lead to session hijacking");
45
- complete(pubkey);
46
- }
47
- },
48
- });
49
- abortController === null || abortController === void 0 ? void 0 : abortController.signal.addEventListener('abort', () => complete());
50
- });
51
- return { result, params, nostrconnect, clientSecret, clientPubkey };
52
- }
53
- static parseBunkerLink(link) {
54
- let token = "";
55
- let pubkey = "";
56
- let relays = [];
57
- try {
58
- const url = new URL(link);
59
- pubkey = url.hostname || url.pathname.replace(/\//g, '');
60
- relays = url.searchParams.getAll("relay") || [];
61
- token = url.searchParams.get("secret") || "";
62
- }
63
- catch (_a) {
64
- // pass
65
- }
66
- return { token, pubkey, relays };
67
- }
68
- static get(params) {
69
- if (!(singleton === null || singleton === void 0 ? void 0 : singleton.hasParams(params))) {
70
- singleton === null || singleton === void 0 ? void 0 : singleton.teardown();
71
- singleton = new Nip46Broker(params);
24
+ else {
25
+ // Attempt to open the window
26
+ const w = window.open(pendingUrl, "", "width=600,height=800,popup=yes");
27
+ // If open was successful, keep track of our window
28
+ if (w) {
29
+ currentWindow = w;
30
+ }
31
+ // In any case, this url has been handled
32
+ pendingUrl = "";
33
+ pendingSince = 0;
72
34
  }
73
- return singleton;
74
- }
75
- constructor(params) {
35
+ });
36
+ return {
37
+ open: (url) => {
38
+ pendingUrl = url;
39
+ pendingSince = Date.now();
40
+ openPending();
41
+ },
42
+ };
43
+ })();
44
+ export class Nip46Receiver extends Emitter {
45
+ constructor(signer, params) {
76
46
  super();
47
+ this.signer = signer;
77
48
  this.params = params;
78
- _Nip46Broker_signer.set(this, void 0);
79
- _Nip46Broker_handler.set(this, void 0);
80
- _Nip46Broker_algorithm.set(this, void 0);
81
- _Nip46Broker_closed.set(this, false);
82
- _Nip46Broker_processing.set(this, false);
83
- _Nip46Broker_connectResponse.set(this, void 0);
84
- _Nip46Broker_queue.set(this, []);
85
- _Nip46Broker_window.set(this, void 0);
86
- _Nip46Broker_sub.set(this, void 0);
87
- _Nip46Broker_subscribe.set(this, async () => {
88
- const pubkey = await __classPrivateFieldGet(this, _Nip46Broker_signer, "f").getPubkey();
49
+ this.start = async () => {
50
+ if (this.sub)
51
+ return;
52
+ const userPubkey = await this.signer.getPubkey();
53
+ const filters = [{ kinds: [NOSTR_CONNECT], "#p": [userPubkey] }];
54
+ this.sub = subscribe({ relays: this.params.relays, filters });
89
55
  return new Promise(resolve => {
90
- if (__classPrivateFieldGet(this, _Nip46Broker_sub, "f")) {
91
- __classPrivateFieldGet(this, _Nip46Broker_sub, "f").close();
92
- }
93
- __classPrivateFieldSet(this, _Nip46Broker_sub, subscribe({
94
- relays: __classPrivateFieldGet(this, _Nip46Broker_handler, "f").relays,
95
- filters: [{ kinds: [NOSTR_CONNECT], "#p": [pubkey] }],
96
- }), "f");
97
- __classPrivateFieldGet(this, _Nip46Broker_sub, "f").emitter.on(SubscriptionEvent.Send, resolve);
98
- __classPrivateFieldGet(this, _Nip46Broker_sub, "f").emitter.on(SubscriptionEvent.Event, async (url, event) => {
99
- const json = await decrypt(__classPrivateFieldGet(this, _Nip46Broker_signer, "f"), event.pubkey, event.content);
56
+ this.sub.emitter.on(SubscriptionEvent.Send, resolve);
57
+ this.sub.emitter.on(SubscriptionEvent.Event, async (url, event) => {
58
+ const json = await decrypt(this.signer, event.pubkey, event.content);
100
59
  const response = tryCatch(() => JSON.parse(json)) || {};
101
- if (!response.id) {
102
- console.error(`Invalid nostr-connect response: ${json}`);
103
- }
104
60
  // Delay errors in case there's a zombie signer out there clogging things up
105
61
  if (response.error) {
106
62
  await sleep(3000);
107
63
  }
108
- if (response.result === "auth_url") {
109
- this.emit(`auth-${response.id}`, response);
110
- }
111
- else {
112
- this.emit(`res-${response.id}`, response);
113
- }
64
+ this.emit(Nip46Event.Receive, { ...response, url, event });
114
65
  });
115
- __classPrivateFieldGet(this, _Nip46Broker_sub, "f").emitter.on("complete", () => {
116
- __classPrivateFieldSet(this, _Nip46Broker_sub, undefined, "f");
66
+ this.sub.emitter.on(SubscriptionEvent.Complete, () => {
67
+ this.sub = undefined;
117
68
  });
118
69
  });
119
- });
120
- _Nip46Broker_processQueue.set(this, async () => {
121
- if (__classPrivateFieldGet(this, _Nip46Broker_processing, "f")) {
70
+ };
71
+ this.stop = () => {
72
+ var _a;
73
+ (_a = this.sub) === null || _a === void 0 ? void 0 : _a.close();
74
+ this.removeAllListeners();
75
+ };
76
+ }
77
+ }
78
+ export class Nip46Sender extends Emitter {
79
+ constructor(signer, params) {
80
+ super();
81
+ this.signer = signer;
82
+ this.params = params;
83
+ this.processing = false;
84
+ this.queue = [];
85
+ this.send = async (request) => {
86
+ const { id, method, params } = request;
87
+ const { relays, signerPubkey, algorithm = "nip44" } = this.params;
88
+ if (!signerPubkey) {
89
+ throw new Error("Unable to send nip46 request without a signer pubkey");
90
+ }
91
+ const payload = JSON.stringify({ id, method, params });
92
+ const content = await this.signer[algorithm].encrypt(signerPubkey, payload);
93
+ const template = createEvent(NOSTR_CONNECT, { content, tags: [["p", signerPubkey]] });
94
+ const event = await this.signer.sign(template);
95
+ const pub = publish({ relays, event });
96
+ this.emit(Nip46Event.Send, { ...request, pub });
97
+ };
98
+ this.process = async () => {
99
+ if (this.processing) {
122
100
  return;
123
101
  }
124
- __classPrivateFieldSet(this, _Nip46Broker_processing, true, "f");
102
+ this.processing = true;
125
103
  try {
126
- while (__classPrivateFieldGet(this, _Nip46Broker_queue, "f").length > 0) {
127
- const [{ method, params, resolve }] = __classPrivateFieldGet(this, _Nip46Broker_queue, "f").splice(0, 1);
104
+ while (this.queue.length > 0) {
105
+ const [request] = this.queue.splice(0, 1);
128
106
  try {
129
- const response = await this.request(method, params);
130
- console.log('nip46 response:', { method, params, ...response });
131
- resolve(response);
107
+ await this.send(request);
132
108
  }
133
109
  catch (error) {
134
- console.error(`nip46 error:`, { method, params, ...error });
110
+ console.error(`nip46 error:`, error, request);
135
111
  }
136
112
  }
137
113
  }
138
114
  finally {
139
- __classPrivateFieldSet(this, _Nip46Broker_processing, false, "f");
140
- }
141
- });
142
- _Nip46Broker_getResult.set(this, async (promise) => {
143
- const { result } = await promise;
144
- return result;
145
- });
146
- this.request = async (method, params) => {
147
- if (__classPrivateFieldGet(this, _Nip46Broker_closed, "f")) {
148
- throw new Error("Attempted to make a nip46 request with a closed broker");
149
- }
150
- if (!__classPrivateFieldGet(this, _Nip46Broker_sub, "f")) {
151
- await __classPrivateFieldGet(this, _Nip46Broker_subscribe, "f").call(this);
115
+ this.processing = false;
152
116
  }
153
- const id = randomId();
154
- const recipient = __classPrivateFieldGet(this, _Nip46Broker_handler, "f").pubkey;
155
- const payload = JSON.stringify({ id, method, params });
156
- const content = await __classPrivateFieldGet(this, _Nip46Broker_signer, "f")[__classPrivateFieldGet(this, _Nip46Broker_algorithm, "f")].encrypt(recipient, payload);
157
- const template = createEvent(NOSTR_CONNECT, { content, tags: [["p", recipient]] });
158
- console.log('nip46 request:', { id, method, params });
159
- publish({
160
- relays: __classPrivateFieldGet(this, _Nip46Broker_handler, "f").relays,
161
- event: await __classPrivateFieldGet(this, _Nip46Broker_signer, "f").sign(template),
162
- });
163
- this.once(`auth-${id}`, response => {
164
- if (!__classPrivateFieldGet(this, _Nip46Broker_window, "f") || __classPrivateFieldGet(this, _Nip46Broker_window, "f").closed) {
165
- const w = window.open(response.error, "", "width=600,height=800,popup=yes");
166
- if (w) {
167
- __classPrivateFieldSet(this, _Nip46Broker_window, w, "f");
168
- }
117
+ };
118
+ this.enqueue = (request) => {
119
+ this.queue.push(request);
120
+ this.process();
121
+ };
122
+ this.stop = () => {
123
+ this.removeAllListeners();
124
+ };
125
+ }
126
+ }
127
+ export class Nip46Request {
128
+ constructor(method, params) {
129
+ this.method = method;
130
+ this.params = params;
131
+ this.id = randomId();
132
+ this.promise = defer();
133
+ this.listen = async (receiver) => {
134
+ await receiver.start();
135
+ const onReceive = (response) => {
136
+ if (response.id !== this.id) {
137
+ return;
169
138
  }
170
- });
171
- return new Promise((resolve, reject) => {
172
- this.once(`res-${id}`, (response) => {
139
+ if (response.result === "auth_url") {
140
+ popupManager.open(response.error);
141
+ }
142
+ else {
173
143
  if (response.error) {
174
- reject(response);
144
+ this.promise.reject(response);
175
145
  }
176
146
  else {
177
- resolve(response);
147
+ this.promise.resolve(response);
178
148
  }
179
- });
149
+ receiver.off(Nip46Event.Receive, onReceive);
150
+ }
151
+ };
152
+ receiver.on(Nip46Event.Receive, onReceive);
153
+ };
154
+ this.send = async (sender) => {
155
+ sender.enqueue(this);
156
+ };
157
+ }
158
+ }
159
+ export class Nip46Broker extends Emitter {
160
+ constructor(params) {
161
+ super();
162
+ this.params = params;
163
+ // Getters for helper objects
164
+ this.makeSigner = () => new Nip01Signer(this.params.clientSecret);
165
+ this.makeSender = () => {
166
+ const sender = new Nip46Sender(this.signer, this.params);
167
+ sender.on(Nip46Event.Send, (data) => {
168
+ console.log('nip46 send:', data);
180
169
  });
170
+ return sender;
171
+ };
172
+ this.makeReceiver = () => {
173
+ const receiver = new Nip46Receiver(this.signer, this.params);
174
+ receiver.on(Nip46Event.Receive, (data) => {
175
+ console.log('nip46 receive:', data);
176
+ });
177
+ return receiver;
178
+ };
179
+ // Lifecycle methods
180
+ this.setParams = (params) => {
181
+ this.params = { ...this.params, ...params };
182
+ // Stop everything that's stateful
183
+ this.teardown();
184
+ // Set it back up again
185
+ this.sender = this.makeSender();
186
+ this.receiver = this.makeReceiver();
187
+ };
188
+ this.teardown = () => {
189
+ this.sender.stop();
190
+ this.receiver.stop();
181
191
  };
182
- this.enqueue = (method, params) => new Promise(resolve => {
183
- __classPrivateFieldGet(this, _Nip46Broker_queue, "f").push({ method, params, resolve });
184
- __classPrivateFieldGet(this, _Nip46Broker_processQueue, "f").call(this);
185
- });
186
- this.createAccount = (username, perms = "") => {
187
- if (!__classPrivateFieldGet(this, _Nip46Broker_handler, "f").domain) {
188
- throw new Error("Unable to create an account without a handler domain");
192
+ // General purpose utility methods
193
+ this.enqueue = async (method, params) => {
194
+ const request = new Nip46Request(method, params);
195
+ await request.listen(this.receiver);
196
+ await request.send(this.sender);
197
+ return request;
198
+ };
199
+ this.send = async (method, params) => {
200
+ const request = await this.enqueue(method, params);
201
+ const response = await request.promise;
202
+ return response.result;
203
+ };
204
+ // Methods for initiating a connection
205
+ this.parseBunkerUrl = (url) => {
206
+ let connectSecret = "";
207
+ let signerPubkey = "";
208
+ let relays = [];
209
+ try {
210
+ const _url = new URL(url);
211
+ relays = _url.searchParams.getAll("relay") || [];
212
+ signerPubkey = _url.hostname || _url.pathname.replace(/\//g, '');
213
+ connectSecret = _url.searchParams.get("secret") || "";
189
214
  }
190
- return __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("create_account", [username, __classPrivateFieldGet(this, _Nip46Broker_handler, "f").domain, "", perms]));
215
+ catch (_a) {
216
+ // pass
217
+ }
218
+ return { signerPubkey, connectSecret, relays: relays.map(normalizeRelayUrl) };
191
219
  };
192
- this.connect = async (token = "", perms = "", secret = "") => {
193
- if (!__classPrivateFieldGet(this, _Nip46Broker_connectResponse, "f")) {
194
- const params = ["", token, perms];
195
- __classPrivateFieldSet(this, _Nip46Broker_connectResponse, await this.enqueue("connect", params), "f");
220
+ this.makeNostrconnectUrl = async (meta = {}) => {
221
+ const clientPubkey = await this.signer.getPubkey();
222
+ const secret = Math.random().toString(36).substring(7);
223
+ const params = new URLSearchParams({ ...meta, secret });
224
+ for (const relay of this.params.relays) {
225
+ params.append('relay', relay);
196
226
  }
197
- return __classPrivateFieldGet(this, _Nip46Broker_connectResponse, "f").result === 'ack';
198
- };
199
- this.getPublicKey = () => __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("get_public_key", []));
200
- this.signEvent = async (event) => JSON.parse(await __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("sign_event", [JSON.stringify(event)])));
201
- this.nip04Encrypt = (pk, message) => __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("nip04_encrypt", [pk, message]));
202
- this.nip04Decrypt = (pk, message) => __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("nip04_decrypt", [pk, message]));
203
- this.nip44Encrypt = (pk, message) => __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("nip44_encrypt", [pk, message]));
204
- this.nip44Decrypt = (pk, message) => __classPrivateFieldGet(this, _Nip46Broker_getResult, "f").call(this, this.enqueue("nip44_decrypt", [pk, message]));
205
- this.teardown = () => {
206
- var _a;
207
- __classPrivateFieldSet(this, _Nip46Broker_closed, true, "f");
208
- (_a = __classPrivateFieldGet(this, _Nip46Broker_sub, "f")) === null || _a === void 0 ? void 0 : _a.close();
227
+ return `nostrconnect://${clientPubkey}?${params.toString()}`;
209
228
  };
210
- __classPrivateFieldSet(this, _Nip46Broker_handler, params.handler, "f");
211
- __classPrivateFieldSet(this, _Nip46Broker_algorithm, params.algorithm || 'nip44', "f");
212
- __classPrivateFieldSet(this, _Nip46Broker_signer, new Nip01Signer(params.secret), "f");
229
+ this.waitForNostrconnect = (url, abort) => {
230
+ const secret = new URL(url).searchParams.get('secret');
231
+ return makePromise((resolve, reject) => {
232
+ const onReceive = (response) => {
233
+ if (["ack", secret].includes(response.result)) {
234
+ this.setParams({ signerPubkey: response.event.pubkey });
235
+ if (response.result === 'ack') {
236
+ console.warn("Bunker responded to nostrconnect with 'ack', which can lead to session hijacking");
237
+ }
238
+ resolve(response);
239
+ }
240
+ else {
241
+ reject(response);
242
+ }
243
+ cleanup();
244
+ };
245
+ const cleanup = () => {
246
+ this.receiver.off(Nip46Event.Receive, onReceive);
247
+ };
248
+ this.receiver.on(Nip46Event.Receive, onReceive);
249
+ this.receiver.start();
250
+ abort === null || abort === void 0 ? void 0 : abort.signal.addEventListener('abort', () => {
251
+ reject(undefined);
252
+ cleanup();
253
+ });
254
+ });
255
+ };
256
+ // Normal NIP 46 methods
257
+ this.ping = () => this.send("ping", []);
258
+ this.getPublicKey = () => this.send("get_public_key", []);
259
+ this.createAccount = (username, domain, perms = "") => this.send("create_account", [username, domain, "", perms]);
260
+ this.connect = async (signerPubkey, connectSecret = "", perms = "") => this.send("connect", [signerPubkey, connectSecret, perms]);
261
+ this.signEvent = async (event) => JSON.parse(await this.send("sign_event", [JSON.stringify(event)]));
262
+ this.nip04Encrypt = (pk, message) => this.send("nip04_encrypt", [pk, message]);
263
+ this.nip04Decrypt = (pk, message) => this.send("nip04_decrypt", [pk, message]);
264
+ this.nip44Encrypt = (pk, message) => this.send("nip44_encrypt", [pk, message]);
265
+ this.nip44Decrypt = (pk, message) => this.send("nip44_decrypt", [pk, message]);
266
+ this.signer = this.makeSigner();
267
+ this.sender = this.makeSender();
268
+ this.receiver = this.makeReceiver();
269
+ }
270
+ // Use a static getter to avoid duplicate connections
271
+ static get(params) {
272
+ if (!(singleton === null || singleton === void 0 ? void 0 : singleton.hasParams(params))) {
273
+ singleton === null || singleton === void 0 ? void 0 : singleton.teardown();
274
+ singleton = new Nip46Broker(params);
275
+ }
276
+ return singleton;
213
277
  }
278
+ // Expose params without exposing params
214
279
  hasParams(params) {
215
280
  return equals(this.params, params);
216
281
  }
217
282
  }
218
- _Nip46Broker_signer = new WeakMap(), _Nip46Broker_handler = new WeakMap(), _Nip46Broker_algorithm = new WeakMap(), _Nip46Broker_closed = new WeakMap(), _Nip46Broker_processing = new WeakMap(), _Nip46Broker_connectResponse = new WeakMap(), _Nip46Broker_queue = new WeakMap(), _Nip46Broker_window = new WeakMap(), _Nip46Broker_sub = new WeakMap(), _Nip46Broker_subscribe = new WeakMap(), _Nip46Broker_processQueue = new WeakMap(), _Nip46Broker_getResult = new WeakMap();
219
283
  export class Nip46Signer {
220
284
  constructor(broker) {
221
285
  this.broker = broker;
222
- _Nip46Signer_pubkey.set(this, void 0);
223
286
  this.getPubkey = async () => {
224
- if (!__classPrivateFieldGet(this, _Nip46Signer_pubkey, "f")) {
225
- __classPrivateFieldSet(this, _Nip46Signer_pubkey, await this.broker.getPublicKey(), "f");
287
+ if (!this.pubkey) {
288
+ this.pubkey = await this.broker.getPublicKey();
226
289
  }
227
- return __classPrivateFieldGet(this, _Nip46Signer_pubkey, "f");
290
+ return this.pubkey;
228
291
  };
229
292
  this.sign = async (template) => this.broker.signEvent(hash(own(template, await this.getPubkey())));
230
293
  this.nip04 = {
@@ -237,5 +300,4 @@ export class Nip46Signer {
237
300
  };
238
301
  }
239
302
  }
240
- _Nip46Signer_pubkey = new WeakMap();
241
303
  //# sourceMappingURL=nip46.mjs.map