@konemono/nostr-login 1.15.4 → 1.15.5

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.15.4",
3
+ "version": "1.15.5",
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",
@@ -27,7 +27,7 @@
27
27
  "tseep": "^1.2.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@konemono/nostr-login-components": "^1.4.4",
30
+ "@konemono/nostr-login-components": "^1.4.5",
31
31
  "@rollup/plugin-commonjs": "^25.0.7",
32
32
  "@rollup/plugin-node-resolve": "^15.2.3",
33
33
  "@rollup/plugin-terser": "^0.4.4",
@@ -96,6 +96,7 @@ class AuthNostrService extends EventEmitter implements Signer {
96
96
  public cancelNostrConnect() {
97
97
  console.log('cancelNostrConnect called');
98
98
  this.releaseSigner();
99
+ this.resetNostrConnectKeys();
99
100
 
100
101
  // readyCallbackのみ解放
101
102
  this.resetAuth();
@@ -208,14 +209,35 @@ class AuthNostrService extends EventEmitter implements Signer {
208
209
  this.onAuth('login', info);
209
210
  }
210
211
 
212
+ // 接続成功後にkey/secretをリセット(次回のモーダル表示で新規生成される)
213
+ this.resetNostrConnectKeys();
214
+
211
215
  console.log('[nostrConnect] Completed successfully');
212
216
  return info;
213
217
  }
214
218
 
215
- public async createNostrConnect() {
216
- this.nostrConnectKey = generatePrivateKey();
217
- this.nostrConnectSecret = Array.from(crypto.getRandomValues(new Uint8Array(16)), b => b.toString(16).padStart(2, '0')).join('');
219
+ public async createNostrConnect(relays: string[]) {
220
+ this.ensureNostrConnectKeys();
221
+ return this.buildNostrConnectUrl(relays);
222
+ }
218
223
 
224
+ /**
225
+ * key/secret が未生成なら新規生成する。既存なら再利用。
226
+ * モーダル表示中にリレーが変更されても key/secret は維持される。
227
+ */
228
+ private ensureNostrConnectKeys() {
229
+ if (!this.nostrConnectKey) {
230
+ this.nostrConnectKey = generatePrivateKey();
231
+ }
232
+ if (!this.nostrConnectSecret) {
233
+ this.nostrConnectSecret = Array.from(crypto.getRandomValues(new Uint8Array(16)), b => b.toString(16).padStart(2, '0')).join('');
234
+ }
235
+ }
236
+
237
+ /**
238
+ * 現在の key/secret を使って nostrconnect:// URL を構築する。
239
+ */
240
+ private async buildNostrConnectUrl(relays: string[]): Promise<string> {
219
241
  const pubkey = getPublicKey(hexToBytes(this.nostrConnectKey));
220
242
  const meta = {
221
243
  name: encodeURIComponent(document.location.host),
@@ -224,27 +246,34 @@ class AuthNostrService extends EventEmitter implements Signer {
224
246
  perms: encodeURIComponent(this.params.optionsModal.perms || ''),
225
247
  };
226
248
 
227
- return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}`;
249
+ const relayParams = relays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
250
+ return `nostrconnect://${pubkey}?image=${meta.icon}&url=${meta.url}&name=${meta.name}&perms=${meta.perms}&secret=${this.nostrConnectSecret}${relayParams}`;
251
+ }
252
+
253
+ /**
254
+ * nostrconnect セッションをリセットし、key/secret を再生成可能にする。
255
+ */
256
+ public resetNostrConnectKeys() {
257
+ this.nostrConnectKey = '';
258
+ this.nostrConnectSecret = '';
228
259
  }
229
260
 
230
261
  public async getNostrConnectServices(customRelays?: string[], onUpdate?: (apps: ConnectionString[]) => void): Promise<[string, ConnectionString[]]> {
231
- const nostrconnect = await this.createNostrConnect();
262
+ const defaultRelays = customRelays && customRelays.length > 0 ? customRelays : DEFAULT_NIP46_RELAYS;
263
+ // ベースURLにリレーヒントを含める
264
+ const nostrconnect = await this.createNostrConnect(defaultRelays);
232
265
 
233
266
  const apps: ConnectionString[] = NOSTRCONNECT_APPS.map(a => ({ ...a }));
234
- const defaultRelays = customRelays && customRelays.length > 0 ? customRelays : DEFAULT_NIP46_RELAYS;
235
267
 
236
268
  // Build initial list: https services are 'loading', others are immediately available
237
269
  for (const a of apps) {
238
270
  if (a.link.startsWith('https://')) {
239
271
  a.available = 'loading';
240
- // Set link with default relays for now
241
- const relayParams = defaultRelays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
242
- a.link = nostrconnect + relayParams;
272
+ // nostrconnect URL にはすでにリレーヒントが含まれている
273
+ a.link = nostrconnect;
243
274
  } else {
244
275
  a.available = true;
245
- const relayParams = defaultRelays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
246
- const nc = nostrconnect + relayParams;
247
- a.link = a.link.replace('<nostrconnect>', nc);
276
+ a.link = a.link.replace('<nostrconnect>', nostrconnect);
248
277
  }
249
278
  }
250
279
 
@@ -259,15 +288,15 @@ class AuthNostrService extends EventEmitter implements Signer {
259
288
  try {
260
289
  const info = await fetchNostrJson(domain);
261
290
  const pubkey = info.names['_'];
262
- let relays = defaultRelays;
263
291
  const fetchedRelays = info.nip46[pubkey] as string[];
292
+ a.iframeUrl = info.nip46.iframe_url || '';
293
+ // サービス固有のリレーがあればURLを再構築
264
294
  if (fetchedRelays && fetchedRelays.length && (!customRelays || customRelays.length === 0)) {
265
- relays = fetchedRelays;
295
+ const serviceNostrconnect = this.replaceRelayHints(nostrconnect, fetchedRelays);
296
+ a.link = a.iframeUrl ? serviceNostrconnect : a.link;
297
+ } else {
298
+ a.link = a.iframeUrl ? nostrconnect : a.link;
266
299
  }
267
- a.iframeUrl = info.nip46.iframe_url || '';
268
- const relayParams = relays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
269
- const nc = nostrconnect + relayParams;
270
- a.link = a.iframeUrl ? nc : a.link;
271
300
  a.available = true;
272
301
  } catch (e) {
273
302
  console.log('Service unavailable', domain, e);
@@ -278,11 +307,17 @@ class AuthNostrService extends EventEmitter implements Signer {
278
307
 
279
308
  await Promise.all(fetchPromises);
280
309
 
281
- // QRコード用のnostrconnect URLにもリレーヒントを付与
282
- const relayParams = defaultRelays.map(r => `&relay=${encodeURIComponent(r)}`).join('');
283
- const nostrconnectWithRelays = nostrconnect + relayParams;
310
+ return [nostrconnect, apps];
311
+ }
284
312
 
285
- return [nostrconnectWithRelays, apps];
313
+ private replaceRelayHints(nostrconnectUrl: string, newRelays: string[]): string {
314
+ // 既存のrelay=パラメータを除去して新しいリレーに置換
315
+ const url = new URL(nostrconnectUrl);
316
+ url.searchParams.delete('relay');
317
+ for (const r of newRelays) {
318
+ url.searchParams.append('relay', r);
319
+ }
320
+ return url.toString();
286
321
  }
287
322
 
288
323
  public async localSignup(name: string, sk?: string) {