@konemono/nostr-login 1.10.16 → 1.11.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,12 +1,15 @@
1
1
  import { Info, RecentType } from 'nostr-login-components/dist/types/types';
2
- import NDK, { NDKSigner } from '@nostr-dev-kit/ndk';
2
+ import { RxNostr } from 'rx-nostr';
3
3
  import { NostrLoginOptions } from '../types';
4
+ import { PrivateKeySigner } from '../modules/Signer';
5
+ export declare function bytesToHex(bytes: Uint8Array): string;
6
+ export declare function hexToBytes(hex: string): Uint8Array;
4
7
  export declare const localStorageSetItem: (key: string, value: string) => void;
5
8
  export declare const localStorageGetItem: (key: string) => any;
6
9
  export declare const localStorageRemoveItem: (key: string) => void;
7
- export declare const fetchProfile: (info: Info, profileNdk: NDK) => Promise<import("@nostr-dev-kit/ndk").NDKUserProfile | null>;
10
+ export declare const fetchProfile: (info: Info, rxNostr: RxNostr) => Promise<any>;
8
11
  export declare const prepareSignupRelays: (signupRelays?: string) => string[];
9
- export declare const createProfile: (info: Info, profileNdk: NDK, signer: NDKSigner, signupRelays?: string, outboxRelays?: string[]) => Promise<void>;
12
+ export declare const createProfile: (info: Info, rxNostr: RxNostr, signer: PrivateKeySigner, signupRelays?: string, outboxRelays?: string[]) => Promise<void>;
10
13
  export declare const bunkerUrlToInfo: (bunkerUrl: string, sk?: string) => Info;
11
14
  export declare const isBunkerUrl: (value: string) => boolean;
12
15
  export declare const getBunkerUrl: (value: string, optionsModal: NostrLoginOptions) => Promise<string>;
@@ -2,8 +2,8 @@ export declare function encryptNip44(plaintext: string, conversationKey: Uint8Ar
2
2
  export declare function decryptNip44(payload: string, conversationKey: Uint8Array): string;
3
3
  export declare class Nip44 {
4
4
  private cache;
5
- createKey(privkey: string, pubkey: string): Uint8Array;
5
+ createKey(privkey: string | Uint8Array, pubkey: string): Uint8Array;
6
6
  private getKey;
7
- encrypt(privkey: string, pubkey: string, text: string): string;
8
- decrypt(privkey: string, pubkey: string, data: string): string;
7
+ encrypt(privkey: string | Uint8Array, pubkey: string, text: string): string;
8
+ decrypt(privkey: string | Uint8Array, pubkey: string, data: string): string;
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konemono/nostr-login",
3
- "version": "1.10.16",
3
+ "version": "1.11.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.esm.js",
6
6
  "types": "./dist/index.d.ts",
@@ -11,17 +11,17 @@
11
11
  },
12
12
  "author": "a-fralou",
13
13
  "dependencies": {
14
- "@nostr-dev-kit/ndk": "^2.3.1",
15
- "nostr-tools": "^1.17.0",
16
- "tseep": "^1.2.1"
14
+ "nostr-tools": "^2.19.4",
15
+ "rx-nostr": "^3.6.2",
16
+ "tseep": "^1.3.1"
17
17
  },
18
18
  "devDependencies": {
19
- "@rollup/plugin-commonjs": "^25.0.7",
20
- "@rollup/plugin-node-resolve": "^15.2.3",
19
+ "@rollup/plugin-commonjs": "^29.0.0",
20
+ "@rollup/plugin-node-resolve": "^16.0.3",
21
21
  "@rollup/plugin-terser": "^0.4.4",
22
22
  "nostr-login-components": "^1.0.3",
23
- "prettier": "^3.2.2",
24
- "rollup": "^4.9.6",
23
+ "prettier": "^3.7.4",
24
+ "rollup": "^4.55.1",
25
25
  "rollup-plugin-typescript2": "^0.36.0"
26
26
  },
27
27
  "license": "MIT"
@@ -1,8 +1,14 @@
1
- import { localStorageAddAccount, bunkerUrlToInfo, isBunkerUrl, fetchProfile, getBunkerUrl, localStorageRemoveCurrentAccount, createProfile, getIcon } from '../utils';
1
+ import { localStorageAddAccount, bunkerUrlToInfo, isBunkerUrl, fetchProfile, getBunkerUrl, localStorageRemoveCurrentAccount, createProfile, getIcon, bytesToHex, hexToBytes } from '../utils';
2
2
  import { ConnectionString, Info } from 'nostr-login-components/dist/types/types';
3
- import { generatePrivateKey, getEventHash, getPublicKey, nip19 } from 'nostr-tools';
3
+ import { createRxNostr, RxNostr } from 'rx-nostr';
4
+ import { generateSecretKey, getEventHash, getPublicKey, nip19 } from 'nostr-tools';
4
5
  import { NostrLoginAuthOptions, Response } from '../types';
5
- import NDK, { NDKEvent, NDKNip46Signer, NDKRpcResponse, NDKUser, NostrEvent } from '@nostr-dev-kit/ndk';
6
+
7
+
8
+
9
+ // Placeholder types for SimplePool transition
10
+ // private pool: SimplePool;
11
+ // private outboxPool: SimplePool;
6
12
  import { NostrParams } from './';
7
13
  import { EventEmitter } from 'tseep';
8
14
  import { Signer } from './Nostr';
@@ -33,8 +39,7 @@ const NOSTRCONNECT_APPS: ConnectionString[] = [
33
39
  ];
34
40
 
35
41
  class AuthNostrService extends EventEmitter implements Signer {
36
- private ndk: NDK;
37
- private profileNdk: NDK;
42
+ private rxNostr: RxNostr;
38
43
  private signer: Nip46Signer | null = null;
39
44
  private localSigner: PrivateKeySigner | null = null;
40
45
  private params: NostrParams;
@@ -61,15 +66,11 @@ class AuthNostrService extends EventEmitter implements Signer {
61
66
  constructor(params: NostrParams) {
62
67
  super();
63
68
  this.params = params;
64
- this.ndk = new NDK({
65
- enableOutboxModel: false,
66
- });
67
69
 
68
- this.profileNdk = new NDK({
69
- enableOutboxModel: true,
70
- explicitRelayUrls: OUTBOX_RELAYS,
71
- });
72
- this.profileNdk.connect();
70
+ this.rxNostr = createRxNostr({} as any);
71
+ // Default relays for initial connection if needed, though they are usually set per-action
72
+ // @ts-ignore
73
+ this.rxNostr.switchRelays(DEFAULT_NIP46_RELAYS);
73
74
 
74
75
  this.nip04 = {
75
76
  encrypt: this.encrypt04.bind(this),
@@ -81,30 +82,30 @@ class AuthNostrService extends EventEmitter implements Signer {
81
82
  };
82
83
  }
83
84
 
84
- public isIframe() {
85
+ public isIframe(): boolean {
85
86
  return !!this.iframe;
86
87
  }
87
88
 
88
- public async waitReady() {
89
+ public async waitReady(): Promise<void> {
89
90
  if (this.signerPromise) {
90
91
  try {
91
92
  await this.signerPromise;
92
- } catch {}
93
+ } catch { }
93
94
  }
94
95
 
95
96
  if (this.readyPromise) {
96
97
  try {
97
98
  await this.readyPromise;
98
- } catch {}
99
+ } catch { }
99
100
  }
100
101
  }
101
102
 
102
- public cancelNostrConnect() {
103
+ public cancelNostrConnect(): void {
103
104
  this.releaseSigner();
104
105
  this.resetAuth();
105
106
  }
106
107
 
107
- public cancelSignerInit() {
108
+ public cancelSignerInit(): void {
108
109
  if (this.signerAbortController) {
109
110
  this.signerAbortController.abort();
110
111
  this.signerAbortController = undefined;
@@ -133,7 +134,7 @@ class AuthNostrService extends EventEmitter implements Signer {
133
134
  iframeUrl?: string;
134
135
  customRelays?: string[];
135
136
  } = {},
136
- ) {
137
+ ): Promise<Info> {
137
138
  // カスタムリレーが指定されていれば使用、そうでなければ単一リレーまたはデフォルト
138
139
  const relays = customRelays && customRelays.length > 0 ? customRelays : relay ? [relay] : DEFAULT_NIP46_RELAYS;
139
140
 
@@ -168,11 +169,13 @@ class AuthNostrService extends EventEmitter implements Signer {
168
169
  return info;
169
170
  }
170
171
 
171
- public async createNostrConnect() {
172
- this.nostrConnectKey = generatePrivateKey();
172
+ public async createNostrConnect(): Promise<string> {
173
+ const skBytes = generateSecretKey();
174
+ // @ts-ignore
175
+ this.nostrConnectKey = bytesToHex(skBytes);
173
176
  this.nostrConnectSecret = Math.random().toString(36).substring(7);
174
177
 
175
- const pubkey = getPublicKey(this.nostrConnectKey);
178
+ const pubkey = getPublicKey(skBytes);
176
179
  const meta = {
177
180
  name: encodeURIComponent(document.location.host),
178
181
  url: encodeURIComponent(document.location.origin),
@@ -229,10 +232,14 @@ class AuthNostrService extends EventEmitter implements Signer {
229
232
  return [nostrconnect, apps];
230
233
  }
231
234
 
232
- public async localSignup(name: string, sk?: string) {
235
+ public async localSignup(name: string, sk?: string): Promise<void> {
233
236
  const signup = !sk;
234
- sk = sk || generatePrivateKey();
235
- const pubkey = getPublicKey(sk);
237
+ if (!sk) {
238
+ const skBytes = generateSecretKey();
239
+ sk = bytesToHex(skBytes);
240
+ }
241
+ // @ts-ignore
242
+ const pubkey = getPublicKey(hexToBytes(sk!));
236
243
  const info: Info = {
237
244
  pubkey,
238
245
  sk,
@@ -243,25 +250,118 @@ class AuthNostrService extends EventEmitter implements Signer {
243
250
  await this.setLocal(info, signup);
244
251
  }
245
252
 
246
- public async setLocal(info: Info, signup?: boolean) {
253
+ public async setLocal(info: Info, signup?: boolean): Promise<void> {
247
254
  this.releaseSigner();
248
- this.localSigner = new PrivateKeySigner(info.sk!);
255
+ this.localSigner = new PrivateKeySigner(hexToBytes(info.sk!));
249
256
 
250
- if (signup) await createProfile(info, this.profileNdk, this.localSigner, this.params.optionsModal.signupRelays, this.params.optionsModal.outboxRelays);
257
+ // TODO: nostr-toolsを使用するようにcreateProfileをリファクタリングする
258
+ if (signup) {
259
+ await createProfile(info, this.rxNostr, this.localSigner, this.params.optionsModal.signupRelays, this.params.optionsModal.outboxRelays);
260
+ }
251
261
 
252
262
  this.onAuth(signup ? 'signup' : 'login', info);
253
263
  }
254
264
 
255
- public prepareImportUrl(url: string) {
265
+ public prepareImportUrl(url: string): string {
256
266
  // for OTP we choose interactive import
257
267
  if (this.params.userInfo?.authMethod === 'otp') return url + '&import=true';
258
268
 
259
269
  // for local we export our existing key
260
270
  if (!this.localSigner || this.params.userInfo?.authMethod !== 'local') throw new Error('Most be local keys');
261
- return url + '#import=' + nip19.nsecEncode(this.localSigner.privateKey!);
271
+ // Ensure privateKey is Uint8Array for nsecEncode if needed, but nip19.nsecEncode usually takes Uint8Array
272
+ const skBytes = this.localSigner.privateKey!;
273
+ return url + '#import=' + nip19.nsecEncode(skBytes);
274
+ }
275
+
276
+ // リレー管理メソッド
277
+ public getRelayStatus(): Record<string, string> {
278
+ const status = this.rxNostr.getAllRelayStatus();
279
+ const result: Record<string, string> = {};
280
+ for (const [url, state] of Object.entries(status)) {
281
+ result[url] = String(state);
282
+ }
283
+ return result;
284
+ }
285
+
286
+ public getRelayStats(): {
287
+ total: number;
288
+ connected: number;
289
+ connecting: number;
290
+ disconnected: number;
291
+ error: number;
292
+ } {
293
+ const status = this.rxNostr.getAllRelayStatus();
294
+ const stats = {
295
+ total: 0,
296
+ connected: 0,
297
+ connecting: 0,
298
+ disconnected: 0,
299
+ error: 0,
300
+ };
301
+
302
+ for (const state of Object.values(status)) {
303
+ stats.total++;
304
+ const stateStr = String(state).toLowerCase();
305
+ if (stateStr === 'connected') stats.connected++;
306
+ else if (stateStr === 'connecting') stats.connecting++;
307
+ else if (stateStr === 'error') stats.error++;
308
+ else stats.disconnected++;
309
+ }
310
+
311
+ return stats;
312
+ }
313
+
314
+ public async connectToRelay(relayUrl: string): Promise<void> {
315
+ try {
316
+ this.rxNostr.reconnect(relayUrl);
317
+ console.log(`Connecting to relay: ${relayUrl}`);
318
+ } catch (error) {
319
+ console.error(`Failed to connect to relay ${relayUrl}:`, error);
320
+ throw error;
321
+ }
322
+ }
323
+
324
+ public async disconnectFromRelay(relayUrl: string): Promise<void> {
325
+ try {
326
+ // rx-nostrにはdisconnect APIがないため、リレーリストから除外する方法を使用
327
+ const currentRelays = Object.keys(this.rxNostr.getAllRelayStatus());
328
+ const newRelays = currentRelays.filter(url => url !== relayUrl);
329
+ if (newRelays.length > 0) {
330
+ // @ts-ignore
331
+ this.rxNostr.switchRelays(newRelays);
332
+ }
333
+ console.log(`Disconnected from relay: ${relayUrl}`);
334
+ } catch (error) {
335
+ console.error(`Failed to disconnect from relay ${relayUrl}:`, error);
336
+ throw error;
337
+ }
262
338
  }
263
339
 
264
- public async importAndConnect(cs: ConnectionString) {
340
+ public async reconnectAllRelays(): Promise<void> {
341
+ try {
342
+ const relays = Object.keys(this.rxNostr.getAllRelayStatus());
343
+ console.log(`Reconnecting to ${relays.length} relays...`);
344
+
345
+ for (const relay of relays) {
346
+ try {
347
+ this.rxNostr.reconnect(relay);
348
+ } catch (error) {
349
+ console.warn(`Failed to reconnect to ${relay}:`, error);
350
+ }
351
+ }
352
+ } catch (error) {
353
+ console.error('Failed to reconnect all relays:', error);
354
+ throw error;
355
+ }
356
+ }
357
+
358
+ public async checkRelayHealth(): Promise<boolean> {
359
+ const stats = this.getRelayStats();
360
+ // 少なくとも1つのリレーが接続されていればOK
361
+ return stats.connected > 0;
362
+ }
363
+
364
+ public async importAndConnect(cs: ConnectionString): Promise<void> {
265
365
  const { relay, domain, link, iframeUrl } = cs;
266
366
  if (!domain) throw new Error('Domain required');
267
367
 
@@ -278,22 +378,22 @@ class AuthNostrService extends EventEmitter implements Signer {
278
378
  this.onAuth('login', info);
279
379
  }
280
380
 
281
- public setReadOnly(pubkey: string) {
381
+ public setReadOnly(pubkey: string): void {
282
382
  const info: Info = { pubkey, authMethod: 'readOnly' };
283
383
  this.onAuth('login', info);
284
384
  }
285
385
 
286
- public setExtension(pubkey: string) {
386
+ public setExtension(pubkey: string): void {
287
387
  const info: Info = { pubkey, authMethod: 'extension' };
288
388
  this.onAuth('login', info);
289
389
  }
290
390
 
291
- public setOTP(pubkey: string, data: string) {
391
+ public setOTP(pubkey: string, data: string): void {
292
392
  const info: Info = { pubkey, authMethod: 'otp', otpData: data };
293
393
  this.onAuth('login', info);
294
394
  }
295
395
 
296
- public async setConnect(info: Info) {
396
+ public async setConnect(info: Info): Promise<void> {
297
397
  this.releaseSigner();
298
398
  await this.startAuth();
299
399
  await this.initSigner(info);
@@ -301,7 +401,7 @@ class AuthNostrService extends EventEmitter implements Signer {
301
401
  await this.endAuth();
302
402
  }
303
403
 
304
- public async createAccount(nip05: string) {
404
+ public async createAccount(nip05: string): Promise<{ bunkerUrl: string; sk: string | undefined }> {
305
405
  const [name, domain] = nip05.split('@');
306
406
 
307
407
  // bunker's own url
@@ -325,18 +425,19 @@ class AuthNostrService extends EventEmitter implements Signer {
325
425
  };
326
426
  }
327
427
 
328
- private releaseSigner() {
428
+ private releaseSigner(): void {
329
429
  this.signer = null;
330
430
  this.signerErrCallback?.('cancelled');
331
431
  this.localSigner = null;
332
432
 
333
433
  // disconnect from signer relays
334
- for (const r of this.ndk.pool.relays.keys()) {
335
- this.ndk.pool.removeRelay(r);
336
- }
434
+ // rx-nostr manages relays, we can switch to empty or default if needed
435
+ // or just leave them be as they might be reused?
436
+ // For now, let's just clear the signer instance.
437
+ // this.rxNostr.switchRelays([]); // Should we disconnect? Maybe better to keep connection for next signer?
337
438
  }
338
439
 
339
- public async logout(keepSigner = false) {
440
+ public async logout(keepSigner = false): Promise<void> {
340
441
  if (!keepSigner) this.releaseSigner();
341
442
 
342
443
  // move current to recent
@@ -348,7 +449,7 @@ class AuthNostrService extends EventEmitter implements Signer {
348
449
  this.emit('updateAccounts');
349
450
  }
350
451
 
351
- private setUserInfo(userInfo: Info | null) {
452
+ private setUserInfo(userInfo: Info | null): void {
352
453
  this.params.userInfo = userInfo;
353
454
  this.emit('onUserInfo', userInfo);
354
455
 
@@ -358,13 +459,14 @@ class AuthNostrService extends EventEmitter implements Signer {
358
459
  }
359
460
  }
360
461
 
361
- public exportKeys() {
462
+ public exportKeys(): string {
362
463
  if (!this.params.userInfo) return '';
363
464
  if (this.params.userInfo.authMethod !== 'local') return '';
364
- return nip19.nsecEncode(this.params.userInfo.sk!);
465
+ const skBytes = hexToBytes(this.params.userInfo.sk!);
466
+ return nip19.nsecEncode(skBytes);
365
467
  }
366
468
 
367
- private onAuth(type: 'login' | 'signup' | 'logout', info: Info | null = null) {
469
+ private onAuth(type: 'login' | 'signup' | 'logout', info: Info | null = null): void {
368
470
  if (type !== 'logout' && !info) throw new Error('No user info in onAuth');
369
471
 
370
472
  // make sure we emulate logout first
@@ -378,7 +480,8 @@ class AuthNostrService extends EventEmitter implements Signer {
378
480
 
379
481
  if (info) {
380
482
  // async profile fetch
381
- fetchProfile(info, this.profileNdk).then(p => {
483
+ // TODO: nostr-toolsを使用するようにfetchProfileをリファクタリングする
484
+ fetchProfile(info, this.rxNostr as any).then(p => {
382
485
  if (this.params.userInfo !== info) return;
383
486
 
384
487
  const userInfo = {
@@ -411,7 +514,7 @@ class AuthNostrService extends EventEmitter implements Signer {
411
514
  options.name = info!.name;
412
515
 
413
516
  if (info!.sk) {
414
- options.localNsec = nip19.nsecEncode(info!.sk);
517
+ options.localNsec = nip19.nsecEncode(hexToBytes(info!.sk));
415
518
  }
416
519
 
417
520
  if (info!.relays) {
@@ -437,7 +540,7 @@ class AuthNostrService extends EventEmitter implements Signer {
437
540
  }
438
541
  }
439
542
 
440
- private async createIframe(iframeUrl?: string) {
543
+ private async createIframe(iframeUrl?: string): Promise<{ iframe: HTMLIFrameElement; port: MessagePort } | undefined> {
441
544
  if (!iframeUrl) return undefined;
442
545
 
443
546
  // ensure iframe
@@ -496,18 +599,18 @@ class AuthNostrService extends EventEmitter implements Signer {
496
599
  // }
497
600
  // }
498
601
 
499
- public async sendNeedAuth() {
602
+ public async sendNeedAuth(): Promise<void> {
500
603
  const [nostrconnect] = await this.getNostrConnectServices();
501
604
  const event = new CustomEvent('nlNeedAuth', { detail: { nostrconnect } });
502
605
  console.log('nostr-login need auth', nostrconnect);
503
606
  document.dispatchEvent(event);
504
607
  }
505
608
 
506
- public isAuthing() {
609
+ public isAuthing(): boolean {
507
610
  return !!this.readyCallback;
508
611
  }
509
612
 
510
- public async startAuth() {
613
+ public async startAuth(): Promise<void> {
511
614
  console.log('startAuth');
512
615
  if (this.readyCallback) throw new Error('Already started');
513
616
 
@@ -515,7 +618,7 @@ class AuthNostrService extends EventEmitter implements Signer {
515
618
  this.readyPromise = new Promise<void>(ok => (this.readyCallback = ok));
516
619
  }
517
620
 
518
- public async endAuth() {
621
+ public async endAuth(): Promise<void> {
519
622
  console.log('endAuth', this.params.userInfo);
520
623
  if (this.params.userInfo && this.params.userInfo.iframeUrl) {
521
624
  // create iframe
@@ -531,28 +634,28 @@ class AuthNostrService extends EventEmitter implements Signer {
531
634
  this.readyCallback = undefined;
532
635
  }
533
636
 
534
- public resetAuth() {
637
+ public resetAuth(): void {
535
638
  if (this.readyCallback) this.readyCallback();
536
639
  this.readyCallback = undefined;
537
640
  }
538
641
 
539
- private async listen(info: Info) {
642
+ private async listen(info: Info): Promise<void> {
540
643
  if (!info.iframeUrl) return this.signer!.listen(this.nostrConnectSecret);
541
644
  const r = await this.starterReady!.wait();
542
645
  if (r[0] === 'starterError') throw new Error(r[1]);
543
646
  return this.signer!.setListenReply(r[1], this.nostrConnectSecret);
544
647
  }
545
648
 
546
- public async connect(info: Info, perms?: string) {
649
+ public async connect(info: Info, perms?: string): Promise<void> {
547
650
  return this.signer!.connect(info.token, perms);
548
651
  }
549
652
 
550
- public async initSigner(info: Info, { listen = false, connect = false, eventToAddAccount = false } = {}) {
653
+ public async initSigner(info: Info, { listen = false, connect = false, eventToAddAccount = false } = {}): Promise<void> {
551
654
  // mutex
552
655
  if (this.signerPromise) {
553
656
  try {
554
657
  await this.signerPromise;
555
- } catch {}
658
+ } catch { }
556
659
  }
557
660
 
558
661
  // we remove support for iframe from nip05 and bunker-url methods,
@@ -593,22 +696,28 @@ class AuthNostrService extends EventEmitter implements Signer {
593
696
  return this.signerPromise;
594
697
  }
595
698
 
596
- private async initSignerInternal(info: Info, listen: boolean, connect: boolean, eventToAddAccount: boolean, resolve: () => void) {
699
+ private async initSignerInternal(info: Info, listen: boolean, connect: boolean, eventToAddAccount: boolean, resolve: () => void): Promise<void> {
597
700
  // pre-connect if we're creating the connection (listen|connect) or
598
701
  // not iframe mode
599
702
  if (info.relays && !info.iframeUrl) {
600
- for (const r of info.relays) {
601
- this.ndk.addExplicitRelay(r, undefined);
602
- }
703
+ // @ts-ignore
704
+ this.rxNostr.switchRelays(info.relays);
603
705
  }
604
706
 
605
- // wait until we connect, otherwise
606
- // signer won't start properly
607
- await this.ndk.connect();
707
+ // rx-nostr connects automatically
608
708
 
609
709
  // create and prepare the signer
610
- const localSigner = new PrivateKeySigner(info.sk!);
611
- this.signer = new Nip46Signer(this.ndk, localSigner, info.signerPubkey!, info.iframeUrl ? new URL(info.iframeUrl!).origin : undefined);
710
+ const localSigner = new PrivateKeySigner(hexToBytes(info.sk!));
711
+
712
+ // TODO: 元のNDKロジック:
713
+ // This initialized the Nip46Signer with NDK instance.
714
+ //
715
+ // New Implementation Plan:
716
+ // 1. Pass the SimplePool instance or relay list to Nip46Signer.
717
+ // 2. Nip46Signer should manage its own connection or use the shared pool to publish/subscribe.
718
+
719
+ // TODO: ndk引数を削除する
720
+ this.signer = new Nip46Signer(this.rxNostr, localSigner, info.signerPubkey!, info.iframeUrl ? new URL(info.iframeUrl!).origin : undefined);
612
721
 
613
722
  // we should notify the banner the same way as
614
723
  // the onAuthUrl does
@@ -660,7 +769,7 @@ class AuthNostrService extends EventEmitter implements Signer {
660
769
  iframeUrl = '',
661
770
  customRelays,
662
771
  }: { name: string; bunkerUrl: string; sk?: string; domain?: string; iframeUrl?: string; customRelays?: string[] },
663
- ) {
772
+ ): Promise<void> {
664
773
  try {
665
774
  const info = bunkerUrlToInfo(bunkerUrl, sk);
666
775
  if (isBunkerUrl(name)) info.bunkerUrl = name;
@@ -697,8 +806,9 @@ class AuthNostrService extends EventEmitter implements Signer {
697
806
  }
698
807
  }
699
808
 
700
- public async signEvent(event: any) {
809
+ public async signEvent(event: any): Promise<any> {
701
810
  if (this.localSigner) {
811
+ // this.localSigner.privateKey is Uint8Array
702
812
  event.pubkey = getPublicKey(this.localSigner.privateKey!);
703
813
  event.id = getEventHash(event);
704
814
  event.sig = await this.localSigner.sign(event);
@@ -713,7 +823,7 @@ class AuthNostrService extends EventEmitter implements Signer {
713
823
  return event;
714
824
  }
715
825
 
716
- private async ensureSigner() {
826
+ private async ensureSigner(): Promise<void> {
717
827
  // signerがキャンセル等で破棄されている場合は再初期化
718
828
  if (!this.signer && this.params.userInfo) {
719
829
  console.log('Signer was destroyed, reinitializing...');
@@ -726,11 +836,23 @@ class AuthNostrService extends EventEmitter implements Signer {
726
836
  }
727
837
 
728
838
  // リレー接続を確認・再接続
729
- const stats = this.ndk.pool.stats();
730
- console.log('NDK pool stats:', stats);
731
-
732
- if (stats.connected === 0) {
733
- console.log('NDK relays disconnected, reinitializing signer...');
839
+ // TODO: 元のNDKロジック:
840
+ // Checks ndk.pool.stats() for connectivity.
841
+ //
842
+ // New Implementation Plan:
843
+ // 1. Iterate through SimplePool.relays or listConnectionStatus().
844
+ // 2. If no relays are connected, modify code to reconnect.
845
+
846
+ // TODO: rx-nostrの統計を確認する
847
+ // const stats = this.pool.listConnectionStatus();
848
+ // const stats = this.pool.listConnectionStatus();
849
+ // const stats = this.ndk.pool.stats();
850
+ // console.log('NDK pool stats:', stats);
851
+ const relayStates = this.rxNostr.getAllRelayStatus();
852
+ const connectedCount = Object.values(relayStates).filter(s => String(s) === 'connected').length;
853
+
854
+ if (connectedCount === 0) {
855
+ console.log('RxNostr relays disconnected, reinitializing signer...');
734
856
 
735
857
  // リレーが完全に切断されている場合、signerも再初期化する必要がある
736
858
  // (RPCサブスクリプションも切断されているため)
@@ -738,14 +860,8 @@ class AuthNostrService extends EventEmitter implements Signer {
738
860
  // 古いsignerを破棄
739
861
  this.signer = null;
740
862
 
741
- // 既存のリレーを一度切断
742
- for (const relay of this.ndk.pool.relays.values()) {
743
- try {
744
- relay.disconnect();
745
- } catch (e) {
746
- console.log('Error disconnecting relay:', e);
747
- }
748
- }
863
+ // 既存のリレーを一度切断 (rx-nostr reconnects automatically, but we might want to force it)
864
+ this.rxNostr.reconnect(Object.keys(relayStates)[0]);
749
865
 
750
866
  // signerを再初期化(リレー接続も含む)
751
867
  await this.initSigner(this.params.userInfo);
@@ -755,56 +871,41 @@ class AuthNostrService extends EventEmitter implements Signer {
755
871
  }
756
872
  }
757
873
 
758
- private async codec_call(method: string, pubkey: string, param: string) {
759
- return new Promise<string>((resolve, reject) => {
760
- this.signer!.rpc.sendRequest(this.signer!.remotePubkey!, method, [pubkey, param], 24133, (response: NDKRpcResponse) => {
761
- if (!response.error) {
762
- resolve(response.result);
763
- } else {
764
- reject(response.error);
765
- }
766
- });
767
- });
768
- }
769
874
 
770
- public async encrypt04(pubkey: string, plaintext: string) {
875
+
876
+ public async encrypt04(pubkey: string, plaintext: string): Promise<string> {
771
877
  if (this.localSigner) {
772
- return this.localSigner.encrypt(new NDKUser({ pubkey }), plaintext);
878
+ return this.localSigner.encrypt(pubkey as any, plaintext);
773
879
  } else {
774
880
  await this.ensureSigner();
775
- return this.signer!.encrypt(new NDKUser({ pubkey }), plaintext);
881
+ return this.signer!.encrypt(pubkey, plaintext);
776
882
  }
777
883
  }
778
884
 
779
- public async decrypt04(pubkey: string, ciphertext: string) {
885
+ public async decrypt04(pubkey: string, ciphertext: string): Promise<string> {
780
886
  if (this.localSigner) {
781
- return this.localSigner.decrypt(new NDKUser({ pubkey }), ciphertext);
887
+ return this.localSigner.decrypt(pubkey as any, ciphertext);
782
888
  } else {
783
- // decrypt is broken in ndk v2.3.1, and latest
784
- // ndk v2.8.1 doesn't allow to override connect easily,
785
- // so we reimplement and fix decrypt here as a temporary fix
786
889
  await this.ensureSigner();
787
- return this.codec_call('nip04_decrypt', pubkey, ciphertext);
890
+ return this.signer!.decrypt(pubkey, ciphertext);
788
891
  }
789
892
  }
790
893
 
791
- public async encrypt44(pubkey: string, plaintext: string) {
894
+ public async encrypt44(pubkey: string, plaintext: string): Promise<string> {
792
895
  if (this.localSigner) {
793
896
  return this.nip44Codec.encrypt(this.localSigner.privateKey!, pubkey, plaintext);
794
897
  } else {
795
- // no support of nip44 in ndk yet
796
898
  await this.ensureSigner();
797
- return this.codec_call('nip44_encrypt', pubkey, plaintext);
899
+ return this.signer!.encryptNip44(pubkey, plaintext);
798
900
  }
799
901
  }
800
902
 
801
- public async decrypt44(pubkey: string, ciphertext: string) {
903
+ public async decrypt44(pubkey: string, ciphertext: string): Promise<string> {
802
904
  if (this.localSigner) {
803
905
  return this.nip44Codec.decrypt(this.localSigner.privateKey!, pubkey, ciphertext);
804
906
  } else {
805
- // no support of nip44 in ndk yet
806
907
  await this.ensureSigner();
807
- return this.codec_call('nip44_decrypt', pubkey, ciphertext);
908
+ return this.signer!.decryptNip44(pubkey, ciphertext);
808
909
  }
809
910
  }
810
911
  }