@konemono/nostr-login 1.13.2 → 1.13.3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konemono/nostr-login",
3
- "version": "1.13.2",
3
+ "version": "1.13.3",
4
4
  "description": "Extended fork of nostr-login with multi-relay support, QR scanner, and improved stability",
5
5
  "main": "./dist/index.esm.js",
6
6
  "types": "./dist/index.d.ts",
@@ -30,7 +30,7 @@
30
30
  "@rollup/plugin-commonjs": "^25.0.7",
31
31
  "@rollup/plugin-node-resolve": "^15.2.3",
32
32
  "@rollup/plugin-terser": "^0.4.4",
33
- "@konemono/nostr-login-components": "^1.2.2",
33
+ "@konemono/nostr-login-components": "^1.2.3",
34
34
  "prettier": "^3.2.2",
35
35
  "rollup": "^4.9.6",
36
36
  "rollup-plugin-typescript2": "^0.36.0"
@@ -653,7 +653,7 @@ class AuthNostrService extends EventEmitter implements Signer {
653
653
  }
654
654
  }
655
655
 
656
- await this.ndk.connect();
656
+ await this.ndk.connect(10000); // 10秒のタイムアウトでリレー接続
657
657
 
658
658
  const localSigner = new PrivateKeySigner(info.sk!);
659
659
  this.signer = new Nip46Signer(this.ndk, localSigner, info.signerPubkey!, iframeOrigin);
@@ -797,7 +797,7 @@ class AuthNostrService extends EventEmitter implements Signer {
797
797
  this.ensureRelaysInPool();
798
798
 
799
799
  try {
800
- await this.ndk.connect();
800
+ await this.ndk.connect(10000);
801
801
  } catch (e) {
802
802
  console.warn('forceReconnect: ndk.connect() threw, will poll for connection...', e);
803
803
  }
@@ -819,7 +819,7 @@ class AuthNostrService extends EventEmitter implements Signer {
819
819
  this.ensureRelaysInPool();
820
820
 
821
821
  try {
822
- await this.ndk.connect();
822
+ await this.ndk.connect(10000);
823
823
  } catch (e) {
824
824
  console.warn('ensureRelayConnection: ndk.connect() threw, will poll for connection...', e);
825
825
  }
@@ -42,28 +42,43 @@ class NostrRpc extends NDKNostrRpc {
42
42
  // リレーが不安定な状態ではEOSEが届かず無限にハングする。
43
43
  // NIP-46ではリアルタイムのレスポンスのみ必要なので、
44
44
  // EOSE待ちをスキップして直接subscribeする。
45
+ // cacheUsage: ONLY_RELAY で確実にリレーからのみ購読する。
46
+ // onEvent を使って race condition を回避(NDK推奨)。
45
47
  const sub = this._ndk.subscribe(filter, {
46
48
  closeOnEose: false,
47
49
  groupable: false,
48
- });
49
-
50
- sub.on('event', async (event: NDKEvent) => {
51
- try {
52
- const parsedEvent = await this.parseEvent(event);
53
- if ((parsedEvent as NDKRpcRequest).method) {
54
- this.emit('request', parsedEvent);
55
- } else {
56
- this.emit(`response-${parsedEvent.id}`, parsedEvent);
50
+ cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY,
51
+ onEvent: async (event: NDKEvent) => {
52
+ try {
53
+ const parsedEvent = await this.parseEvent(event);
54
+ if ((parsedEvent as NDKRpcRequest).method) {
55
+ this.emit('request', parsedEvent);
56
+ } else {
57
+ this.emit(`response-${parsedEvent.id}`, parsedEvent);
58
+ }
59
+ } catch (e) {
60
+ console.error('error parsing event in subscription', e);
57
61
  }
58
- } catch (e) {
59
- console.error('error parsing event in subscription', e);
60
- }
62
+ },
61
63
  });
62
64
 
63
65
  this.sub = sub;
64
66
  return sub;
65
67
  }
66
68
 
69
+ /**
70
+ * subscription が無ければ作る。localSigner の pubkey で kind:24133 を購読。
71
+ */
72
+ public async ensureSubscription(): Promise<void> {
73
+ if (this.sub) return;
74
+ const pubkey = this._signer.pubkey;
75
+ console.log('ensureSubscription: subscribing for', pubkey);
76
+ await this.subscribe({
77
+ 'kinds': [24133],
78
+ '#p': [pubkey],
79
+ });
80
+ }
81
+
67
82
  public stop() {
68
83
  if (this.sub) {
69
84
  this.sub.stop();
@@ -147,23 +162,27 @@ class NostrRpc extends NDKNostrRpc {
147
162
  }
148
163
  }
149
164
 
150
- // 修正: listen メソッドの改善
165
+ /**
166
+ * subscriptionを開始してから connect response を待つ。
167
+ * listen 後もsubscriptionは維持する(後続の get_public_key 等で必要)。
168
+ */
151
169
  public async listen(nostrConnectSecret: string): Promise<string> {
152
170
  const pubkey = this._signer.pubkey;
153
171
  console.log('nostr-login listening for conn to', pubkey, 'expecting secret:', nostrConnectSecret);
154
172
 
155
- const sub = await this.subscribe({
156
- 'kinds': [24133],
157
- '#p': [pubkey],
158
- });
173
+ await this.ensureSubscription();
159
174
 
160
175
  return new Promise<string>((ok, err) => {
161
176
  const timeout = setTimeout(() => {
162
- this.stop();
163
177
  err(new Error('Connection timeout: no response from signer'));
164
178
  }, 60000); // 60秒のタイムアウト
165
179
 
166
- sub.on('event', async (event: NDKEvent) => {
180
+ // subscribe onEvent ハンドラが response-${id} を emit するが、
181
+ // listen のレスポンスは request id が無い(unsolicited)ので
182
+ // 'request' イベントとして来る可能性がある。
183
+ // 代わりに subscribe 側でパースされたイベントを
184
+ // 直接 NDKSubscription の event で受け取る。
185
+ const handler = async (event: NDKEvent) => {
167
186
  try {
168
187
  const parsedEvent = await this.parseEvent(event);
169
188
  console.log('listen parsedEvent', parsedEvent);
@@ -180,36 +199,41 @@ class NostrRpc extends NDKNostrRpc {
180
199
  // secretの厳密な検証
181
200
  if (response.result === nostrConnectSecret) {
182
201
  clearTimeout(timeout);
183
- this.stop();
202
+ // subscriptionは維持する(後続リクエストで使うため stop しない)
184
203
  console.log('Connection established with signer:', event.pubkey);
185
204
  ok(event.pubkey);
186
205
  } else if (response.result === 'ack') {
187
206
  // ackは古い実装用の互換性のため警告のみ
188
207
  console.warn('Received "ack" instead of secret. This may indicate an older signer implementation.');
189
208
  clearTimeout(timeout);
190
- this.stop();
191
209
  ok(event.pubkey);
192
210
  } else {
193
211
  console.error('Invalid response:', response);
194
212
  clearTimeout(timeout);
195
- this.stop();
196
213
  err(new Error(response.error || 'Invalid connection response'));
197
214
  }
198
215
  }
199
216
  } catch (e) {
200
217
  console.error('Error parsing event in listen', e, event.rawEvent());
201
218
  }
202
- });
219
+ };
203
220
 
204
- sub.on('eose', () => {
205
- console.log('EOSE received in listen');
206
- });
221
+ if (this.sub) {
222
+ this.sub.on('event', handler);
223
+ }
207
224
  });
208
225
  }
209
226
 
227
+ /**
228
+ * subscriptionが無ければ開始してから connect リクエストを送る。
229
+ * レスポンスは subscription の event ハンドラ経由で受け取る。
230
+ */
210
231
  public async connect(pubkey: string, token?: string, perms?: string) {
211
232
  console.log('Sending connect request to', pubkey, 'with perms:', perms);
212
233
 
234
+ // connect のレスポンスを受け取るために subscription が必要
235
+ await this.ensureSubscription();
236
+
213
237
  return new Promise<void>((ok, err) => {
214
238
  const timeout = setTimeout(() => {
215
239
  err(new Error('Connect timeout: no response from signer'));