@konemono/nostr-login 1.7.22 → 1.7.24

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,11 +1,13 @@
1
1
  import NDK, { NDKEvent, NDKFilter, NDKNip46Signer, NDKNostrRpc, NDKRpcRequest, NDKRpcResponse, NDKSubscription, NDKSubscriptionCacheUsage, NostrEvent } from '@nostr-dev-kit/ndk';
2
2
  import { validateEvent, verifySignature } from 'nostr-tools';
3
3
  import { PrivateKeySigner } from './Signer';
4
+ import { NIP46_TIMEOUT } from '../const';
4
5
 
5
6
  class NostrRpc extends NDKNostrRpc {
6
7
  protected _ndk: NDK;
7
8
  protected _signer: PrivateKeySigner;
8
9
  protected requests: Set<string> = new Set();
10
+ protected requestTimeouts: Map<string, NodeJS.Timeout> = new Map();
9
11
  private sub?: NDKSubscription;
10
12
  protected _useNip44: boolean = false;
11
13
 
@@ -16,19 +18,34 @@ class NostrRpc extends NDKNostrRpc {
16
18
  }
17
19
 
18
20
  public async subscribe(filter: NDKFilter): Promise<NDKSubscription> {
19
- // NOTE: fixing ndk
20
21
  filter.kinds = filter.kinds?.filter(k => k === 24133);
21
22
  this.sub = await super.subscribe(filter);
22
23
  return this.sub;
23
24
  }
24
25
 
25
26
  public stop() {
27
+ this.clearAllTimeouts();
26
28
  if (this.sub) {
27
29
  this.sub.stop();
28
30
  this.sub = undefined;
29
31
  }
30
32
  }
31
33
 
34
+ private clearAllTimeouts() {
35
+ for (const timeout of this.requestTimeouts.values()) {
36
+ clearTimeout(timeout);
37
+ }
38
+ this.requestTimeouts.clear();
39
+ }
40
+
41
+ private clearTimeout(id: string) {
42
+ const timeout = this.requestTimeouts.get(id);
43
+ if (timeout) {
44
+ clearTimeout(timeout);
45
+ this.requestTimeouts.delete(id);
46
+ }
47
+ }
48
+
32
49
  public setUseNip44(useNip44: boolean) {
33
50
  this._useNip44 = useNip44;
34
51
  }
@@ -39,7 +56,6 @@ class NostrRpc extends NDKNostrRpc {
39
56
  return ciphertext[l - 28] === '?' && ciphertext[l - 27] === 'i' && ciphertext[l - 26] === 'v' && ciphertext[l - 25] === '=';
40
57
  }
41
58
 
42
- // override to auto-decrypt nip04/nip44
43
59
  public async parseEvent(event: NDKEvent): Promise<NDKRpcRequest | NDKRpcResponse> {
44
60
  const remoteUser = this._ndk.getUser({ pubkey: event.pubkey });
45
61
  remoteUser.ndk = this._ndk;
@@ -68,9 +84,6 @@ class NostrRpc extends NDKNostrRpc {
68
84
  }
69
85
  }
70
86
 
71
- // ndk doesn't support nostrconnect:
72
- // we just listed to an unsolicited reply to
73
- // our pubkey and if it's ack/secret - we're fine
74
87
  public async listen(nostrConnectSecret: string): Promise<string> {
75
88
  const pubkey = this._signer.pubkey;
76
89
  console.log('nostr-login listening for conn to', pubkey);
@@ -78,61 +91,46 @@ class NostrRpc extends NDKNostrRpc {
78
91
  'kinds': [24133],
79
92
  '#p': [pubkey],
80
93
  });
81
-
82
94
  return new Promise<string>((ok, err) => {
83
- let finished = false;
84
-
85
- // 30 sec timeout
86
95
  const timeoutId = setTimeout(() => {
87
- if (!finished) {
88
- finished = true;
89
- this.stop();
90
- console.log('nostr-login: listen timeout, emitting timeout event');
91
- this.emit('timeout');
92
- err('Listen timed out');
93
- }
94
- }, 30000);
95
-
96
+ this.stop();
97
+ err(new Error('NIP46 listen timeout'));
98
+ }, NIP46_TIMEOUT);
99
+
96
100
  sub.on('event', async (event: NDKEvent) => {
97
- if (finished) return;
98
-
99
101
  try {
100
102
  const parsedEvent = await this.parseEvent(event);
101
- // console.log('ack parsedEvent', parsedEvent);
102
103
  if (!(parsedEvent as NDKRpcRequest).method) {
103
104
  const response = parsedEvent as NDKRpcResponse;
104
105
 
105
- // ignore
106
106
  if (response.result === 'auth_url') return;
107
107
 
108
- // FIXME for now accept 'ack' replies, later on only
109
- // accept secrets
110
108
  if (response.result === 'ack' || response.result === nostrConnectSecret) {
111
- finished = true;
112
109
  clearTimeout(timeoutId);
113
- this.stop();
114
110
  ok(event.pubkey);
115
111
  } else {
116
- finished = true;
117
112
  clearTimeout(timeoutId);
118
- this.stop();
119
113
  err(response.error);
120
114
  }
121
115
  }
122
116
  } catch (e) {
123
117
  console.log('error parsing event', e, event.rawEvent());
124
118
  }
119
+ this.stop();
125
120
  });
126
121
  });
127
122
  }
128
123
 
129
- // since ndk doesn't yet support perms param
130
- // we reimplement the 'connect' call here
131
- // instead of await signer.blockUntilReady();
132
124
  public async connect(pubkey: string, token?: string, perms?: string) {
133
125
  return new Promise<void>((ok, err) => {
134
126
  const connectParams = [pubkey!, token || '', perms || ''];
127
+
128
+ const timeoutId = setTimeout(() => {
129
+ err(new Error('NIP46 connect timeout'));
130
+ }, NIP46_TIMEOUT);
131
+
135
132
  this.sendRequest(pubkey!, 'connect', connectParams, 24133, (response: NDKRpcResponse) => {
133
+ clearTimeout(timeoutId);
136
134
  if (response.result === 'ack') {
137
135
  ok();
138
136
  } else {
@@ -146,25 +144,45 @@ class NostrRpc extends NDKNostrRpc {
146
144
  return Math.random().toString(36).substring(7);
147
145
  }
148
146
 
147
+ protected async ensureConnected(): Promise<void> {
148
+ const connectedRelays = Array.from(this._ndk.pool.relays.values()).filter(r => r.status === 1);
149
+
150
+ if (connectedRelays.length === 0) {
151
+ console.log('No connected relays, reconnecting...');
152
+ await this._ndk.connect();
153
+
154
+ await new Promise<void>((resolve, reject) => {
155
+ const timeout = setTimeout(() => {
156
+ reject(new Error('Failed to reconnect to relays'));
157
+ }, 5000);
158
+
159
+ const checkConnection = () => {
160
+ const connected = Array.from(this._ndk.pool.relays.values()).filter(r => r.status === 1);
161
+ if (connected.length > 0) {
162
+ clearTimeout(timeout);
163
+ console.log('Reconnected to', connected.length, 'relays');
164
+ resolve();
165
+ } else {
166
+ setTimeout(checkConnection, 100);
167
+ }
168
+ };
169
+ checkConnection();
170
+ });
171
+ }
172
+ }
173
+
149
174
  public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
175
+ await this.ensureConnected();
176
+
150
177
  const id = this.getId();
151
178
 
152
- // response handler will deduplicate auth urls and responses
153
179
  this.setResponseHandler(id, cb);
154
180
 
155
- // create and sign request
156
181
  const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
157
- console.log("sendRequest", { event, method, remotePubkey, params });
182
+ console.log('sendRequest', { event, method, remotePubkey, params });
158
183
 
159
- // send to relays
160
- const relays = await event.publish();
161
- if (relays.size === 0) throw new Error('Failed to publish to relays');
184
+ await event.publish();
162
185
 
163
- // NOTE: ndk returns a promise that never resolves and
164
- // in fact REQUIRES cb to be provided (otherwise no way
165
- // to consume the result), we've already stepped on the bug
166
- // of waiting for this unresolvable result, so now we return
167
- // undefined to make sure waiters fail, not hang.
168
186
  // @ts-ignore
169
187
  return undefined as NDKRpcResponse;
170
188
  }
@@ -172,7 +190,26 @@ class NostrRpc extends NDKNostrRpc {
172
190
  protected setResponseHandler(id: string, cb?: (res: NDKRpcResponse) => void) {
173
191
  let authUrlSent = false;
174
192
  const now = Date.now();
175
- return new Promise<NDKRpcResponse>((resolve, reject) => {
193
+
194
+ const timeoutId = setTimeout(() => {
195
+ if (this.requests.has(id)) {
196
+ this.requests.delete(id);
197
+ this.requestTimeouts.delete(id);
198
+ console.log('NIP46 request timeout for', id);
199
+ if (cb) {
200
+ cb({
201
+ id,
202
+ result: '',
203
+ error: 'NIP46 request timeout',
204
+ event: undefined as any,
205
+ });
206
+ }
207
+ }
208
+ }, NIP46_TIMEOUT);
209
+
210
+ this.requestTimeouts.set(id, timeoutId);
211
+
212
+ return new Promise<NDKRpcResponse>(() => {
176
213
  const responseHandler = (response: NDKRpcResponse) => {
177
214
  if (response.result === 'auth_url') {
178
215
  this.once(`response-${id}`, responseHandler);
@@ -182,30 +219,18 @@ class NostrRpc extends NDKNostrRpc {
182
219
  }
183
220
  } else if (cb) {
184
221
  if (this.requests.has(id)) {
222
+ this.clearTimeout(id);
185
223
  this.requests.delete(id);
186
224
  console.log('nostr-login processed nip46 request in', Date.now() - now, 'ms');
187
225
  cb(response);
188
- resolve(response);
189
226
  }
190
227
  }
191
228
  };
192
229
 
193
230
  this.once(`response-${id}`, responseHandler);
194
-
195
- // timeout
196
- setTimeout(() => {
197
- if (this.requests.has(id)) {
198
- this.requests.delete(id);
199
- this.removeListener(`response-${id}`, responseHandler);
200
- console.log('nostr-login: NIP-46 request timeout, emitting timeout event');
201
- this.emit('timeout');
202
- reject('[Nip46] Request timed out');
203
- }
204
- }, 30000);
205
231
  });
206
232
  }
207
233
 
208
-
209
234
  protected async createRequestEvent(id: string, remotePubkey: string, method: string, params: string[] = [], kind = 24133) {
210
235
  this.requests.add(id);
211
236
  const localUser = await this._signer.user();
@@ -232,7 +257,6 @@ export class IframeNostrRpc extends NostrRpc {
232
257
  private peerOrigin?: string;
233
258
  private iframePort?: MessagePort;
234
259
  private iframeRequests = new Map<string, { id: string; pubkey: string }>();
235
- private iframePingInterval?: NodeJS.Timeout;
236
260
 
237
261
  public constructor(ndk: NDK, localSigner: PrivateKeySigner, iframePeerOrigin?: string) {
238
262
  super(ndk, localSigner);
@@ -246,7 +270,6 @@ export class IframeNostrRpc extends NostrRpc {
246
270
  this._ndk,
247
271
  {},
248
272
  {
249
- // don't send to relay
250
273
  closeOnEose: true,
251
274
  cacheUsage: NDKSubscriptionCacheUsage.ONLY_CACHE,
252
275
  },
@@ -258,8 +281,7 @@ export class IframeNostrRpc extends NostrRpc {
258
281
 
259
282
  this.iframePort = port;
260
283
 
261
- // to make sure Chrome doesn't terminate the channel
262
- this.iframePingInterval = setInterval(() => {
284
+ setInterval(() => {
263
285
  console.log('iframe-nip46 ping');
264
286
  this.iframePort!.postMessage('ping');
265
287
  }, 5000);
@@ -273,7 +295,6 @@ export class IframeNostrRpc extends NostrRpc {
273
295
  return;
274
296
  }
275
297
 
276
- // a copy-paste from rpc.subscribe
277
298
  try {
278
299
  const event = ev.data;
279
300
 
@@ -281,7 +302,6 @@ export class IframeNostrRpc extends NostrRpc {
281
302
  if (!verifySignature(event)) throw new Error('Invalid event signature from iframe');
282
303
  const nevent = new NDKEvent(this._ndk, event);
283
304
  const parsedEvent = await this.parseEvent(nevent);
284
- // we're only implementing client-side rpc
285
305
  if (!(parsedEvent as NDKRpcRequest).method) {
286
306
  console.log('parsed response', parsedEvent);
287
307
  this.emit(`response-${parsedEvent.id}`, parsedEvent);
@@ -292,39 +312,26 @@ export class IframeNostrRpc extends NostrRpc {
292
312
  };
293
313
  }
294
314
 
295
- public cleanup() {
296
- if (this.iframePingInterval) {
297
- clearInterval(this.iframePingInterval);
298
- this.iframePingInterval = undefined;
315
+ public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
316
+ if (!this.iframePort) {
317
+ await this.ensureConnected();
299
318
  }
300
- }
301
319
 
302
- public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
303
320
  const id = this.getId();
304
321
 
305
- // create and sign request event
306
322
  const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
307
323
 
308
- // set response handler, it will dedup auth urls,
309
- // and also dedup response handlers - we're sending
310
- // to relays and to iframe
311
324
  this.setResponseHandler(id, cb);
312
325
 
313
326
  if (this.iframePort) {
314
- // map request event id to request id, if iframe
315
- // has no key it will reply with error:event_id (it can't
316
- // decrypt the request id without keys)
317
327
  this.iframeRequests.set(event.id, { id, pubkey: remotePubkey });
318
328
 
319
- // send to iframe
320
329
  console.log('iframe-nip46 sending request to', this.peerOrigin, event.rawEvent());
321
330
  this.iframePort.postMessage(event.rawEvent());
322
331
  } else {
323
- // send to relays
324
332
  await event.publish();
325
333
  }
326
334
 
327
- // see notes in 'super'
328
335
  // @ts-ignore
329
336
  return undefined as NDKRpcResponse;
330
337
  }
@@ -341,14 +348,11 @@ export class ReadyListener {
341
348
  this.promise = new Promise<any>(ok => {
342
349
  console.log(new Date(), 'started listener for', this.messages);
343
350
 
344
- // ready message handler
345
351
  const onReady = async (e: MessageEvent) => {
346
352
  const originHostname = new URL(origin!).hostname;
347
353
  const messageHostname = new URL(e.origin).hostname;
348
- // same host or subdomain
349
354
  const validHost = messageHostname === originHostname || messageHostname.endsWith('.' + originHostname);
350
355
  if (!validHost || !Array.isArray(e.data) || !e.data.length || !this.messages.includes(e.data[0])) {
351
- // console.log(new Date(), 'got invalid ready message', e.origin, e.data);
352
356
  return;
353
357
  }
354
358
 
@@ -362,14 +366,7 @@ export class ReadyListener {
362
366
 
363
367
  async wait(): Promise<any> {
364
368
  console.log(new Date(), 'waiting for', this.messages);
365
-
366
- const r = await new Promise<any>((ok, err) => {
367
- // 30 sec timeout for iframe ready
368
- setTimeout(() => err(new Date() + ' timeout for ' + this.messages), 30000);
369
-
370
- this.promise.then(ok).catch(err);
371
- });
372
-
369
+ const r = await this.promise;
373
370
  console.log(new Date(), 'finished waiting for', this.messages, r);
374
371
  return r;
375
372
  }
@@ -382,15 +379,11 @@ export class Nip46Signer extends NDKNip46Signer {
382
379
  constructor(ndk: NDK, localSigner: PrivateKeySigner, signerPubkey: string, iframeOrigin?: string) {
383
380
  super(ndk, signerPubkey, localSigner);
384
381
 
385
- // override with our own rpc implementation
386
382
  this._rpc = new IframeNostrRpc(ndk, localSigner, iframeOrigin);
387
- this._rpc.setUseNip44(true); // !!this.params.optionsModal.dev);
383
+ this._rpc.setUseNip44(true);
388
384
  this._rpc.on('authUrl', (url: string) => {
389
385
  this.emit('authUrl', url);
390
386
  });
391
- this._rpc.on('timeout', () => {
392
- this.emit('timeout');
393
- });
394
387
 
395
388
  this.rpc = this._rpc;
396
389
  }
@@ -400,17 +393,14 @@ export class Nip46Signer extends NDKNip46Signer {
400
393
  }
401
394
 
402
395
  private async setSignerPubkey(signerPubkey: string, sameAsUser: boolean = false) {
403
- console.log("setSignerPubkey", signerPubkey);
396
+ console.log('setSignerPubkey', signerPubkey);
404
397
 
405
- // ensure it's set
406
398
  this.remotePubkey = signerPubkey;
407
399
 
408
- // when we're sure it's known
409
400
  this._rpc.on(`iframeRestart-${signerPubkey}`, () => {
410
401
  this.emit('iframeRestart');
411
402
  });
412
403
 
413
- // now call getPublicKey and swap remotePubkey w/ that
414
404
  await this.initUserPubkey(sameAsUser ? signerPubkey : '');
415
405
  }
416
406
 
@@ -425,9 +415,19 @@ export class Nip46Signer extends NDKNip46Signer {
425
415
  this._userPubkey = await new Promise<string>((ok, err) => {
426
416
  if (!this.remotePubkey) throw new Error('Signer pubkey not set');
427
417
 
428
- console.log("get_public_key", this.remotePubkey);
418
+ console.log('get_public_key', this.remotePubkey);
419
+
420
+ const timeoutId = setTimeout(() => {
421
+ err(new Error('NIP46 get_public_key timeout'));
422
+ }, NIP46_TIMEOUT);
423
+
429
424
  this._rpc.sendRequest(this.remotePubkey, 'get_public_key', [], 24133, (response: NDKRpcResponse) => {
430
- ok(response.result);
425
+ clearTimeout(timeoutId);
426
+ if (response.error) {
427
+ err(new Error(response.error));
428
+ } else {
429
+ ok(response.result);
430
+ }
431
431
  });
432
432
  });
433
433
  }
@@ -449,15 +449,21 @@ export class Nip46Signer extends NDKNip46Signer {
449
449
  }
450
450
 
451
451
  public async createAccount2({ bunkerPubkey, name, domain, perms = '' }: { bunkerPubkey: string; name: string; domain: string; perms?: string }) {
452
- const params = [
453
- name,
454
- domain,
455
- '', // email
456
- perms,
457
- ];
458
-
459
- const r = await new Promise<NDKRpcResponse>(ok => {
460
- this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, ok);
452
+ const params = [name, domain, '', perms];
453
+
454
+ const r = await new Promise<NDKRpcResponse>((ok, err) => {
455
+ const timeoutId = setTimeout(() => {
456
+ err(new Error('NIP46 create_account timeout'));
457
+ }, NIP46_TIMEOUT);
458
+
459
+ this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, response => {
460
+ clearTimeout(timeoutId);
461
+ if (response.error) {
462
+ err(new Error(response.error));
463
+ } else {
464
+ ok(response);
465
+ }
466
+ });
461
467
  });
462
468
 
463
469
  console.log('create_account pubkey', r);
@@ -23,29 +23,9 @@ class ProcessManager extends EventEmitter {
23
23
 
24
24
  public async wait<T>(cb: () => Promise<T>): Promise<T> {
25
25
  // FIXME only allow 1 parallel req
26
- console.log('ProcessManager.wait called, callTimer exists:', !!this.callTimer, 'callCount:', this.callCount);
27
-
28
- let timeoutReject: ((reason?: any) => void) | undefined;
29
- let isTimedOut = false;
30
- let localTimer: NodeJS.Timeout | undefined;
31
-
32
- const timeoutPromise = new Promise<T>((_, reject) => {
33
- timeoutReject = reject;
34
- });
35
26
 
36
27
  if (!this.callTimer) {
37
- console.log('Setting up timeout timer for', CALL_TIMEOUT, 'ms');
38
- localTimer = setTimeout(() => {
39
- console.log('ProcessManager: timeout reached, emitting onCallTimeout');
40
- isTimedOut = true;
41
- this.emit('onCallTimeout');
42
- if (timeoutReject) {
43
- timeoutReject(new Error('[ProcessManager] Request timed out'));
44
- }
45
- }, CALL_TIMEOUT);
46
- this.callTimer = localTimer;
47
- } else {
48
- console.log('Timer already exists, not setting up new one');
28
+ this.callTimer = setTimeout(() => this.emit('onCallTimeout'), CALL_TIMEOUT);
49
29
  }
50
30
 
51
31
  if (!this.callCount) {
@@ -56,45 +36,23 @@ class ProcessManager extends EventEmitter {
56
36
 
57
37
  let error;
58
38
  let result;
59
- let raceFinished = false;
60
39
 
61
40
  try {
62
- result = await Promise.race([
63
- cb().then(r => {
64
- if (!raceFinished) {
65
- raceFinished = true;
66
- return r;
67
- }
68
- // Race already finished (timed out), ignore this result
69
- console.log('ProcessManager: ignoring late result after timeout');
70
- throw new Error('Already timed out');
71
- }),
72
- timeoutPromise.then(
73
- () => {
74
- raceFinished = true;
75
- throw new Error('Should not resolve');
76
- },
77
- (err) => {
78
- raceFinished = true;
79
- throw err;
80
- }
81
- )
82
- ]);
41
+ result = await cb();
83
42
  } catch (e) {
84
43
  error = e;
85
44
  }
86
45
 
87
46
  this.callCount--;
88
47
 
89
- // Always emit onCallEnd for cleanup
90
48
  this.emit('onCallEnd');
91
49
 
92
- // Clear the timer if it's the one we created
93
- if (this.callTimer === localTimer) {
50
+ if (this.callTimer) {
94
51
  clearTimeout(this.callTimer);
95
- this.callTimer = undefined;
96
52
  }
97
53
 
54
+ this.callTimer = undefined;
55
+
98
56
  if (error) {
99
57
  throw error;
100
58
  }
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Info, AuthMethod, ConnectionString, RecentType, BannerNotify } from 'nostr-login-components';
1
+ import { Info, AuthMethod, ConnectionString, RecentType, BannerNotify } from 'nostr-login-components/dist/types/types';
2
2
 
3
3
  export interface NostrLoginAuthOptions {
4
4
  localNsec?: string;
@@ -10,7 +10,6 @@ export interface NostrLoginAuthOptions {
10
10
  name?: string;
11
11
  }
12
12
 
13
- // NOTE: must be a subset of CURRENT_MODULE enum
14
13
  export type StartScreens =
15
14
  | 'welcome'
16
15
  | 'welcome-login'
@@ -27,56 +26,27 @@ export type StartScreens =
27
26
  | 'import';
28
27
 
29
28
  export interface NostrLoginOptions {
30
- // optional
31
29
  theme?: string;
32
30
  startScreen?: StartScreens;
33
31
  bunkers?: string;
34
32
  onAuth?: (npub: string, options: NostrLoginAuthOptions) => void;
35
33
  perms?: string;
36
34
  darkMode?: boolean;
37
-
38
- // do not show the banner, modals must be `launch`-ed
39
35
  noBanner?: boolean;
40
-
41
- // forward reqs to this bunker origin for testing
42
36
  devOverrideBunkerOrigin?: string;
43
-
44
- // deprecated, use methods=['local']
45
- // use local signup instead of nostr connect
46
37
  localSignup?: boolean;
47
-
48
- // allowed auth methods
49
38
  methods?: AuthMethod[];
50
-
51
- // otp endpoints
52
39
  otpRequestUrl?: string;
53
40
  otpReplyUrl?: string;
54
-
55
- // welcome screen's title/desc
56
41
  title?: string;
57
42
  description?: string;
58
-
59
- // comma-separated list of relays added
60
- // to relay list of new profiles created with local signup
61
43
  signupRelays?: string;
62
-
63
- // relay list to override hardcoded `OUTBOX_RELAYS` constant
64
44
  outboxRelays?: string[];
65
-
66
- // dev mode
67
45
  dev?: boolean;
68
-
69
- // use start.njump.me instead of local signup
70
46
  signupNstart?: boolean;
71
-
72
- // list of npubs to auto/suggest-follow on signup
73
47
  followNpubs?: string;
74
-
75
- // when method call auth needed, instead of showing
76
- // the modal, we start waiting for incoming nip46
77
- // connection and send the nostrconnect string using
78
- // nlNeedAuth event
79
48
  customNostrConnect?: boolean;
49
+ connectRelays?: string[];
80
50
  }
81
51
 
82
52
  export interface IBanner {
@@ -115,36 +115,22 @@ export const getBunkerUrl = async (value: string, optionsModal: NostrLoginOption
115
115
  const origin = optionsModal.devOverrideBunkerOrigin || `https://${domain}`;
116
116
  const bunkerUrl = `${origin}/.well-known/nostr.json?name=_`;
117
117
  const userUrl = `${origin}/.well-known/nostr.json?name=${name}`;
118
-
119
- // 10 sec timeout for fetch
120
- const controller = new AbortController();
121
- const timeoutId = setTimeout(() => controller.abort(), 10000);
122
-
123
- try {
124
- const bunker = await fetch(bunkerUrl, { signal: controller.signal });
125
- const bunkerData = await bunker.json();
126
- const bunkerPubkey = bunkerData.names['_'];
127
- const bunkerRelays = bunkerData.nip46[bunkerPubkey];
128
- const user = await fetch(userUrl, { signal: controller.signal });
129
- const userData = await user.json();
130
- const userPubkey = userData.names[name];
131
- // console.log({
132
- // bunkerData, userData, bunkerPubkey, bunkerRelays, userPubkey,
133
- // name, domain, origin
134
- // })
135
- if (!bunkerRelays.length) {
136
- throw new Error('Bunker relay not provided');
137
- }
138
-
139
- return `bunker://${userPubkey}?relay=${bunkerRelays[0]}`;
140
- } catch (e: any) {
141
- if (e.name === 'AbortError') {
142
- throw new Error('[getBunkerUrl] Request timed out');
143
- }
144
- throw e;
145
- } finally {
146
- clearTimeout(timeoutId);
118
+ const bunker = await fetch(bunkerUrl);
119
+ const bunkerData = await bunker.json();
120
+ const bunkerPubkey = bunkerData.names['_'];
121
+ const bunkerRelays = bunkerData.nip46[bunkerPubkey];
122
+ const user = await fetch(userUrl);
123
+ const userData = await user.json();
124
+ const userPubkey = userData.names[name];
125
+ // console.log({
126
+ // bunkerData, userData, bunkerPubkey, bunkerRelays, userPubkey,
127
+ // name, domain, origin
128
+ // })
129
+ if (!bunkerRelays.length) {
130
+ throw new Error('Bunker relay not provided');
147
131
  }
132
+
133
+ return `bunker://${userPubkey}?relay=${bunkerRelays[0]}`;
148
134
  }
149
135
 
150
136
  throw new Error('Invalid user name or bunker url');