onelobby 0.6.0 → 0.7.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.
Files changed (45) hide show
  1. package/README.md +2 -2
  2. package/dist/direct/hub.d.ts +2 -0
  3. package/dist/direct/hub.js +20 -1
  4. package/dist/direct/hub.js.map +1 -1
  5. package/dist/friendly.d.ts +1 -0
  6. package/dist/friendly.js +2 -0
  7. package/dist/friendly.js.map +1 -1
  8. package/dist/index.d.ts +0 -2
  9. package/dist/index.js +0 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/lobby.d.ts +29 -1
  12. package/dist/lobby.js +26 -6
  13. package/dist/lobby.js.map +1 -1
  14. package/dist/nostr/limits.d.ts +2 -0
  15. package/dist/nostr/limits.js +2 -0
  16. package/dist/nostr/limits.js.map +1 -1
  17. package/dist/nostr/relays.js +11 -1
  18. package/dist/nostr/relays.js.map +1 -1
  19. package/dist/onelobby.bundle.js +10 -10
  20. package/dist/onelobby.bundle.js.map +4 -4
  21. package/dist/onelobby.bundle.mjs +10 -10
  22. package/dist/onelobby.bundle.mjs.map +4 -4
  23. package/dist/onelobby.d.ts +1 -1
  24. package/dist/onelobby.global.js +79 -19
  25. package/dist/onelobby.global.js.map +3 -3
  26. package/dist/onelobby.global.min.js +10 -10
  27. package/dist/onelobby.global.min.js.map +4 -4
  28. package/dist/onelobby.js +10 -1
  29. package/dist/onelobby.js.map +1 -1
  30. package/dist/signaling.d.ts +2 -0
  31. package/dist/signaling.js.map +1 -1
  32. package/dist/socket.d.ts +15 -6
  33. package/dist/socket.js.map +1 -1
  34. package/dist/testing.d.ts +2 -0
  35. package/dist/testing.js +18 -2
  36. package/dist/testing.js.map +1 -1
  37. package/dist/transport.d.ts +2 -0
  38. package/dist/transport.js.map +1 -1
  39. package/dist/webrtc.d.ts +5 -0
  40. package/dist/webrtc.js +21 -2
  41. package/dist/webrtc.js.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/deprecated.d.ts +0 -18
  44. package/dist/deprecated.js +0 -11
  45. package/dist/deprecated.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"relays.js","sourceRoot":"","sources":["../../src/nostr/relays.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Nostr events and the relay pool (spec/nostr-signaling.md s.3 and s.6). Anonymous: every connection uses a throw-away\n * key and carries encrypted frames only.\n */\nimport type { Clock } from \"../clock.js\";\nimport type { SocketLike } from \"../transport.js\";\nimport { sha256, toHex, fromHex } from \"./crypto.js\";\nimport { schnorrPublicKey, schnorrSign } from \"./secp256k1.js\";\n\nexport const NOSTR_KIND = 25050;\n\nexport interface NostrEvent {\n id: string;\n pubkey: string;\n created_at: number;\n kind: number;\n tags: string[][];\n content: string;\n sig: string;\n}\n\n/** NIP-01 event id: SHA-256 of `[0, pubkey, created_at, kind, tags, content]` serialised without whitespace. */\nexport async function eventId(pubkey: string, createdAt: number, kind: number, tags: string[][], content: string): Promise<string> {\n return toHex(await sha256(new TextEncoder().encode(JSON.stringify([0, pubkey, createdAt, kind, tags, content]))));\n}\n\n/** A signed kind-25050 event (BIP340 Schnorr over the id). */\nexport async function makeEvent(secret: Uint8Array, topic: string, content: string, createdAt: number): Promise<NostrEvent> {\n const pubkey = toHex(schnorrPublicKey(secret));\n const tags = [[\"t\", topic]];\n const id = await eventId(pubkey, createdAt, NOSTR_KIND, tags, content);\n const sig = toHex(await schnorrSign(fromHex(id), secret));\n return { id, pubkey, created_at: createdAt, kind: NOSTR_KIND, tags, content, sig };\n}\n\n/** The WebSocket constructor to a relay; the browser's, or Node 22+'s global one. Tests pass their own. */\nexport type RelayConnect = (url: string) => SocketLike;\n\nexport const defaultRelayConnect: RelayConnect = (url) => {\n const WS = (globalThis as { WebSocket?: new (url: string) => unknown }).WebSocket;\n if (!WS) throw new Error(\"no WebSocket in this runtime (Node 22+ has one; older Node needs advanced.nostrConnect)\");\n return new WS(url) as SocketLike;\n};\n\nexport interface RelayPoolOptions {\n urls: readonly string[];\n topic: string;\n connect: RelayConnect;\n clock: Clock;\n /** Unix ms. */\n wall: () => number;\n onEvent: (ev: NostrEvent) => void;\n /** Called when the number of connected relays changes. */\n onChange?: () => void;\n}\n\ninterface Relay {\n url: string;\n ws: SocketLike | null;\n open: boolean;\n /** The first connect to this relay has succeeded or failed (a dead relay is known to be dead). */\n attempted: boolean;\n skipped: boolean;\n backoff: number;\n cancelRetry: (() => void) | null;\n}\n\nconst SEEN_MAX = 4096;\nconst SINCE_SLACK_S = 30;\n\n/** Every relay at once, each reconnected with backoff (1 s doubling to 30 s); events deduped by id. */\nexport class RelayPool {\n private readonly relays: Relay[];\n private readonly seen = new Set<string>();\n private readonly sub = \"ol\" + Math.random().toString(16).slice(2, 10);\n private closed = false;\n private waiters: (() => void)[] = [];\n\n constructor(private readonly o: RelayPoolOptions) {\n this.relays = o.urls.map((url) => ({ url, ws: null, open: false, attempted: false, skipped: false, backoff: 1000, cancelRetry: null }));\n }\n\n get total(): number {\n return this.relays.length;\n }\n\n /** Relays connected right now (and not skipped). */\n get connected(): number {\n return this.relays.filter((r) => r.open && !r.skipped).length;\n }\n\n /** Every relay has either connected, failed a connect, or been skipped: waiting longer for the rest is pointless. */\n get settled(): boolean {\n return this.relays.every((r) => r.attempted || r.skipped);\n }\n\n start(): void {\n for (const r of this.relays) this.dial(r);\n }\n\n /** Resolves true once one relay is connected, false after `timeoutMs` (or when closed). */\n whenUp(timeoutMs: number): Promise<boolean> {\n if (this.connected > 0) return Promise.resolve(true);\n return new Promise((resolve) => {\n const cancel = this.o.clock.setTimeout(() => done(false), timeoutMs);\n const done = (v: boolean) => {\n cancel();\n this.waiters = this.waiters.filter((w) => w !== check);\n resolve(v);\n };\n const check = () => {\n if (this.connected > 0) done(true);\n else if (this.closed) done(false);\n };\n this.waiters.push(check);\n });\n }\n\n publish(ev: NostrEvent): void {\n const msg = JSON.stringify([\"EVENT\", ev]);\n for (const r of this.relays) if (r.open && !r.skipped) this.trySend(r, msg);\n }\n\n close(): void {\n this.closed = true;\n for (const r of this.relays) {\n r.cancelRetry?.();\n r.cancelRetry = null;\n this.drop(r, false);\n }\n this.changed();\n }\n\n private changed(): void {\n for (const w of [...this.waiters]) w();\n this.o.onChange?.();\n }\n\n private trySend(r: Relay, msg: string): void {\n try {\n r.ws?.send(msg);\n } catch {\n /* a dying socket: its onclose reconnects */\n }\n }\n\n private dial(r: Relay): void {\n if (this.closed || r.skipped) return;\n let ws: SocketLike;\n try {\n ws = this.o.connect(r.url);\n } catch {\n r.attempted = true;\n this.retryLater(r);\n return;\n }\n r.ws = ws;\n ws.onopen = () => {\n if (r.ws !== ws) return;\n r.open = true;\n r.attempted = true;\n r.backoff = 1000;\n const since = Math.floor(this.o.wall() / 1000) - SINCE_SLACK_S;\n this.trySend(r, JSON.stringify([\"REQ\", this.sub, { kinds: [NOSTR_KIND], \"#t\": [this.o.topic], since }]));\n this.changed();\n };\n ws.onmessage = (e) => {\n if (r.ws === ws) this.onMessage(r, String(e.data));\n };\n const lost = () => {\n if (r.ws !== ws) return;\n const wasOpen = r.open;\n r.ws = null;\n r.open = false;\n r.attempted = true;\n if (wasOpen) this.changed();\n this.retryLater(r);\n };\n ws.onclose = lost;\n ws.onerror = () => {\n /* onclose follows; Node's WebSocket may not fire it for a failed connect, so retry from here too */\n lost();\n };\n }\n\n private drop(r: Relay, retry: boolean): void {\n const ws = r.ws;\n r.ws = null;\n r.open = false;\n try {\n ws?.close();\n } catch {\n /* ignore */\n }\n if (retry) this.retryLater(r);\n }\n\n private retryLater(r: Relay): void {\n if (this.closed || r.skipped || r.cancelRetry) return;\n const wait = r.backoff;\n r.backoff = Math.min(30_000, r.backoff * 2);\n r.cancelRetry = this.o.clock.setTimeout(() => {\n r.cancelRetry = null;\n this.dial(r);\n }, wait);\n }\n\n private skip(r: Relay): void {\n if (r.skipped) return;\n r.skipped = true;\n r.cancelRetry?.();\n r.cancelRetry = null;\n this.drop(r, false);\n this.changed();\n }\n\n private onMessage(r: Relay, text: string): void {\n let m: unknown;\n try {\n m = JSON.parse(text);\n } catch {\n return;\n }\n if (!Array.isArray(m)) return;\n switch (m[0]) {\n case \"EVENT\": {\n const ev = m[2] as NostrEvent | undefined;\n if (!ev || typeof ev.id !== \"string\" || typeof ev.pubkey !== \"string\" || typeof ev.content !== \"string\" || typeof ev.created_at !== \"number\") return;\n if (ev.kind !== NOSTR_KIND || !Array.isArray(ev.tags) || !ev.tags.some((t) => t[0] === \"t\" && t[1] === this.o.topic)) return;\n if (this.seen.has(ev.id)) return;\n this.seen.add(ev.id);\n if (this.seen.size > SEEN_MAX) this.seen.delete(this.seen.values().next().value as string);\n this.o.onEvent(ev);\n return;\n }\n case \"OK\":\n // refused (not a plain duplicate): this relay does not take our events, skip it for the session\n if (m[2] === false && !String(m[3] ?? \"\").startsWith(\"duplicate\")) this.skip(r);\n return;\n case \"CLOSED\":\n this.skip(r);\n return;\n }\n }\n}\n\n/** Default public relays (probed 2026-10-26, docs/design/no-server-fallback.md): all accept and echo ephemeral kind 25050. */\nexport const DEFAULT_NOSTR_RELAYS: readonly string[] = [\n \"wss://nos.lol\",\n \"wss://relay.primal.net\",\n \"wss://nostr-pub.wellorder.net\",\n \"wss://nostr.oxtr.dev\",\n \"wss://nostr.bitcoiner.social\",\n \"wss://relay.nostr.net\",\n \"wss://nostr.sathoarder.com\",\n];\n\n/** Public STUN servers for Nostr joiners (spec s.5). */\nexport const DEFAULT_NOSTR_STUN: readonly string[] = [\"stun:stun.l.google.com:19302\", \"stun:stun.cloudflare.com:3478\"];\n\nexport interface RelayCheck {\n url: string;\n ok: boolean;\n ms: number;\n error?: string;\n}\n\n/**\n * Probes each relay: connect, subscribe, publish one kind-25050 event to itself under a random topic with a random\n * key, and see it echoed. Anonymous (nothing about the player is sent). Use it to pick `hosting.nostrRelays`.\n */\nexport async function checkNostrRelays(\n urls: readonly string[],\n timeoutMs = 8000,\n opts: { connect?: RelayConnect; clock?: Clock } = {},\n): Promise<RelayCheck[]> {\n const connect = opts.connect ?? defaultRelayConnect;\n const setT = (fn: () => void, ms: number) => {\n const h = setTimeout(fn, ms);\n return () => clearTimeout(h);\n };\n return Promise.all(urls.map((url) => checkOne(url, timeoutMs, connect, opts.clock?.setTimeout.bind(opts.clock) ?? setT)));\n}\n\nasync function checkOne(url: string, timeoutMs: number, connect: RelayConnect, setT: (fn: () => void, ms: number) => () => void): Promise<RelayCheck> {\n const t0 = Date.now();\n const secret = new Uint8Array(32);\n globalThis.crypto.getRandomValues(secret);\n secret[0] &= 0x7f; // far below the curve order\n if (secret.every((b) => b === 0)) secret[31] = 1;\n const topic = toHex(globalThis.crypto.getRandomValues(new Uint8Array(32)));\n let ev: NostrEvent;\n try {\n ev = await makeEvent(secret, topic, \"probe\", Math.floor(Date.now() / 1000));\n } catch (e) {\n return { url, ok: false, ms: 0, error: String(e) };\n }\n return new Promise<RelayCheck>((resolve) => {\n let ws: SocketLike | null = null;\n let finished = false;\n let accepted = false;\n const finish = (ok: boolean, error?: string) => {\n if (finished) return;\n finished = true;\n cancel();\n try {\n ws?.close();\n } catch {\n /* ignore */\n }\n resolve({ url, ok, ms: Date.now() - t0, ...(error ? { error } : {}) });\n };\n const cancel = setT(() => finish(false, accepted ? \"accepted but not echoed\" : \"timeout\"), timeoutMs);\n try {\n ws = connect(url);\n } catch (e) {\n finish(false, String(e));\n return;\n }\n const sub = \"chk\" + topic.slice(0, 8);\n let published = false;\n const publish = () => {\n if (published) return;\n published = true;\n ws!.send(JSON.stringify([\"EVENT\", ev]));\n };\n ws.onopen = () => {\n ws!.send(JSON.stringify([\"REQ\", sub, { kinds: [NOSTR_KIND], \"#t\": [topic], since: Math.floor(Date.now() / 1000) - 30 }]));\n // some relays never send EOSE for a subscription with no stored events: publish shortly anyway\n setT(publish, 1500);\n };\n ws.onerror = () => finish(false, \"connection failed\");\n ws.onclose = () => finish(false, \"closed\");\n ws.onmessage = (e) => {\n let m: unknown;\n try {\n m = JSON.parse(String(e.data));\n } catch {\n return;\n }\n if (!Array.isArray(m)) return;\n if (m[0] === \"EOSE\") publish();\n else if (m[0] === \"OK\" && m[1] === ev.id) {\n if (m[2] === true) accepted = true;\n else finish(false, `refused: ${String(m[3] ?? \"\")}`.slice(0, 120));\n } else if (m[0] === \"CLOSED\") finish(false, `closed: ${String(m[2] ?? \"\")}`.slice(0, 120));\n else if (m[0] === \"EVENT\" && (m[2] as NostrEvent | undefined)?.id === ev.id) finish(true);\n };\n });\n}\n"]}
1
+ {"version":3,"file":"relays.js","sourceRoot":"","sources":["../../src/nostr/relays.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Nostr events and the relay pool (spec/nostr-signaling.md s.3 and s.6). Anonymous: every connection uses a throw-away\n * key and carries encrypted frames only.\n */\nimport type { Clock } from \"../clock.js\";\nimport type { SocketLike } from \"../transport.js\";\nimport { sha256, toHex, fromHex } from \"./crypto.js\";\nimport { schnorrPublicKey, schnorrSign } from \"./secp256k1.js\";\nimport { DEAD_RELAY_DIALS } from \"./limits.js\";\n\nexport const NOSTR_KIND = 25050;\n\nexport interface NostrEvent {\n id: string;\n pubkey: string;\n created_at: number;\n kind: number;\n tags: string[][];\n content: string;\n sig: string;\n}\n\n/** NIP-01 event id: SHA-256 of `[0, pubkey, created_at, kind, tags, content]` serialised without whitespace. */\nexport async function eventId(pubkey: string, createdAt: number, kind: number, tags: string[][], content: string): Promise<string> {\n return toHex(await sha256(new TextEncoder().encode(JSON.stringify([0, pubkey, createdAt, kind, tags, content]))));\n}\n\n/** A signed kind-25050 event (BIP340 Schnorr over the id). */\nexport async function makeEvent(secret: Uint8Array, topic: string, content: string, createdAt: number): Promise<NostrEvent> {\n const pubkey = toHex(schnorrPublicKey(secret));\n const tags = [[\"t\", topic]];\n const id = await eventId(pubkey, createdAt, NOSTR_KIND, tags, content);\n const sig = toHex(await schnorrSign(fromHex(id), secret));\n return { id, pubkey, created_at: createdAt, kind: NOSTR_KIND, tags, content, sig };\n}\n\n/** The WebSocket constructor to a relay; the browser's, or Node 22+'s global one. Tests pass their own. */\nexport type RelayConnect = (url: string) => SocketLike;\n\nexport const defaultRelayConnect: RelayConnect = (url) => {\n const WS = (globalThis as { WebSocket?: new (url: string) => unknown }).WebSocket;\n if (!WS) throw new Error(\"no WebSocket in this runtime (Node 22+ has one; older Node needs advanced.nostrConnect)\");\n return new WS(url) as SocketLike;\n};\n\nexport interface RelayPoolOptions {\n urls: readonly string[];\n topic: string;\n connect: RelayConnect;\n clock: Clock;\n /** Unix ms. */\n wall: () => number;\n onEvent: (ev: NostrEvent) => void;\n /** Called when the number of connected relays changes. */\n onChange?: () => void;\n}\n\ninterface Relay {\n url: string;\n ws: SocketLike | null;\n open: boolean;\n /** The first connect to this relay has succeeded or failed (a dead relay is known to be dead). */\n attempted: boolean;\n skipped: boolean;\n /** Has connected at least once this session. */\n everOpen: boolean;\n /** Failed dials in a row. */\n fails: number;\n backoff: number;\n cancelRetry: (() => void) | null;\n}\n\nconst SEEN_MAX = 4096;\nconst SINCE_SLACK_S = 30;\n\n/** Every relay at once, each reconnected with backoff (1 s doubling to 30 s); events deduped by id. */\nexport class RelayPool {\n private readonly relays: Relay[];\n private readonly seen = new Set<string>();\n private readonly sub = \"ol\" + Math.random().toString(16).slice(2, 10);\n private closed = false;\n private waiters: (() => void)[] = [];\n\n constructor(private readonly o: RelayPoolOptions) {\n this.relays = o.urls.map((url) => ({ url, ws: null, open: false, attempted: false, skipped: false, everOpen: false, fails: 0, backoff: 1000, cancelRetry: null }));\n }\n\n get total(): number {\n return this.relays.length;\n }\n\n /** Relays connected right now (and not skipped). */\n get connected(): number {\n return this.relays.filter((r) => r.open && !r.skipped).length;\n }\n\n /** Every relay has either connected, failed a connect, or been skipped: waiting longer for the rest is pointless. */\n get settled(): boolean {\n return this.relays.every((r) => r.attempted || r.skipped);\n }\n\n start(): void {\n for (const r of this.relays) this.dial(r);\n }\n\n /** Resolves true once one relay is connected, false after `timeoutMs` (or when closed). */\n whenUp(timeoutMs: number): Promise<boolean> {\n if (this.connected > 0) return Promise.resolve(true);\n return new Promise((resolve) => {\n const cancel = this.o.clock.setTimeout(() => done(false), timeoutMs);\n const done = (v: boolean) => {\n cancel();\n this.waiters = this.waiters.filter((w) => w !== check);\n resolve(v);\n };\n const check = () => {\n if (this.connected > 0) done(true);\n else if (this.closed) done(false);\n };\n this.waiters.push(check);\n });\n }\n\n publish(ev: NostrEvent): void {\n const msg = JSON.stringify([\"EVENT\", ev]);\n for (const r of this.relays) if (r.open && !r.skipped) this.trySend(r, msg);\n }\n\n close(): void {\n this.closed = true;\n for (const r of this.relays) {\n r.cancelRetry?.();\n r.cancelRetry = null;\n this.drop(r, false);\n }\n this.changed();\n }\n\n private changed(): void {\n for (const w of [...this.waiters]) w();\n this.o.onChange?.();\n }\n\n private trySend(r: Relay, msg: string): void {\n try {\n r.ws?.send(msg);\n } catch {\n /* a dying socket: its onclose reconnects */\n }\n }\n\n private dial(r: Relay): void {\n if (this.closed || r.skipped) return;\n let ws: SocketLike;\n try {\n ws = this.o.connect(r.url);\n } catch {\n r.attempted = true;\n this.retryLater(r);\n return;\n }\n r.ws = ws;\n ws.onopen = () => {\n if (r.ws !== ws) return;\n r.open = true;\n r.attempted = true;\n r.everOpen = true;\n r.fails = 0;\n r.backoff = 1000;\n const since = Math.floor(this.o.wall() / 1000) - SINCE_SLACK_S;\n this.trySend(r, JSON.stringify([\"REQ\", this.sub, { kinds: [NOSTR_KIND], \"#t\": [this.o.topic], since }]));\n this.changed();\n };\n ws.onmessage = (e) => {\n if (r.ws === ws) this.onMessage(r, String(e.data));\n };\n const lost = () => {\n if (r.ws !== ws) return;\n const wasOpen = r.open;\n r.ws = null;\n r.open = false;\n r.attempted = true;\n if (wasOpen) this.changed();\n this.retryLater(r);\n };\n ws.onclose = lost;\n ws.onerror = () => {\n /* onclose follows; Node's WebSocket may not fire it for a failed connect, so retry from here too */\n lost();\n };\n }\n\n private drop(r: Relay, retry: boolean): void {\n const ws = r.ws;\n r.ws = null;\n r.open = false;\n try {\n ws?.close();\n } catch {\n /* ignore */\n }\n if (retry) this.retryLater(r);\n }\n\n private retryLater(r: Relay): void {\n if (this.closed || r.skipped || r.cancelRetry) return;\n if (!r.everOpen) r.fails++;\n // a relay that is down (never connected, e.g. HTTP 503) is dropped once another relay carries the session\n if (!r.everOpen && r.fails >= DEAD_RELAY_DIALS && this.connected > 0) {\n this.skip(r);\n return;\n }\n const wait = r.backoff;\n r.backoff = Math.min(30_000, r.backoff * 2);\n r.cancelRetry = this.o.clock.setTimeout(() => {\n r.cancelRetry = null;\n this.dial(r);\n }, wait);\n }\n\n private skip(r: Relay): void {\n if (r.skipped) return;\n r.skipped = true;\n r.cancelRetry?.();\n r.cancelRetry = null;\n this.drop(r, false);\n this.changed();\n }\n\n private onMessage(r: Relay, text: string): void {\n let m: unknown;\n try {\n m = JSON.parse(text);\n } catch {\n return;\n }\n if (!Array.isArray(m)) return;\n switch (m[0]) {\n case \"EVENT\": {\n const ev = m[2] as NostrEvent | undefined;\n if (!ev || typeof ev.id !== \"string\" || typeof ev.pubkey !== \"string\" || typeof ev.content !== \"string\" || typeof ev.created_at !== \"number\") return;\n if (ev.kind !== NOSTR_KIND || !Array.isArray(ev.tags) || !ev.tags.some((t) => t[0] === \"t\" && t[1] === this.o.topic)) return;\n if (this.seen.has(ev.id)) return;\n this.seen.add(ev.id);\n if (this.seen.size > SEEN_MAX) this.seen.delete(this.seen.values().next().value as string);\n this.o.onEvent(ev);\n return;\n }\n case \"OK\":\n // refused (not a plain duplicate): this relay does not take our events, skip it for the session\n if (m[2] === false && !String(m[3] ?? \"\").startsWith(\"duplicate\")) this.skip(r);\n return;\n case \"CLOSED\":\n this.skip(r);\n return;\n }\n }\n}\n\n/** Default public relays (probed 2026-10-26, docs/design/no-server-fallback.md): all accept and echo ephemeral kind 25050. */\nexport const DEFAULT_NOSTR_RELAYS: readonly string[] = [\n \"wss://nos.lol\",\n \"wss://relay.primal.net\",\n \"wss://nostr-pub.wellorder.net\",\n \"wss://nostr.oxtr.dev\",\n \"wss://nostr.bitcoiner.social\",\n \"wss://relay.nostr.net\",\n \"wss://nostr.sathoarder.com\",\n];\n\n/** Public STUN servers for Nostr joiners (spec s.5). */\nexport const DEFAULT_NOSTR_STUN: readonly string[] = [\"stun:stun.l.google.com:19302\", \"stun:stun.cloudflare.com:3478\"];\n\nexport interface RelayCheck {\n url: string;\n ok: boolean;\n ms: number;\n error?: string;\n}\n\n/**\n * Probes each relay: connect, subscribe, publish one kind-25050 event to itself under a random topic with a random\n * key, and see it echoed. Anonymous (nothing about the player is sent). Use it to pick `hosting.nostrRelays`.\n */\nexport async function checkNostrRelays(\n urls: readonly string[],\n timeoutMs = 8000,\n opts: { connect?: RelayConnect; clock?: Clock } = {},\n): Promise<RelayCheck[]> {\n const connect = opts.connect ?? defaultRelayConnect;\n const setT = (fn: () => void, ms: number) => {\n const h = setTimeout(fn, ms);\n return () => clearTimeout(h);\n };\n return Promise.all(urls.map((url) => checkOne(url, timeoutMs, connect, opts.clock?.setTimeout.bind(opts.clock) ?? setT)));\n}\n\nasync function checkOne(url: string, timeoutMs: number, connect: RelayConnect, setT: (fn: () => void, ms: number) => () => void): Promise<RelayCheck> {\n const t0 = Date.now();\n const secret = new Uint8Array(32);\n globalThis.crypto.getRandomValues(secret);\n secret[0] &= 0x7f; // far below the curve order\n if (secret.every((b) => b === 0)) secret[31] = 1;\n const topic = toHex(globalThis.crypto.getRandomValues(new Uint8Array(32)));\n let ev: NostrEvent;\n try {\n ev = await makeEvent(secret, topic, \"probe\", Math.floor(Date.now() / 1000));\n } catch (e) {\n return { url, ok: false, ms: 0, error: String(e) };\n }\n return new Promise<RelayCheck>((resolve) => {\n let ws: SocketLike | null = null;\n let finished = false;\n let accepted = false;\n const finish = (ok: boolean, error?: string) => {\n if (finished) return;\n finished = true;\n cancel();\n try {\n ws?.close();\n } catch {\n /* ignore */\n }\n resolve({ url, ok, ms: Date.now() - t0, ...(error ? { error } : {}) });\n };\n const cancel = setT(() => finish(false, accepted ? \"accepted but not echoed\" : \"timeout\"), timeoutMs);\n try {\n ws = connect(url);\n } catch (e) {\n finish(false, String(e));\n return;\n }\n const sub = \"chk\" + topic.slice(0, 8);\n let published = false;\n const publish = () => {\n if (published) return;\n published = true;\n ws!.send(JSON.stringify([\"EVENT\", ev]));\n };\n ws.onopen = () => {\n ws!.send(JSON.stringify([\"REQ\", sub, { kinds: [NOSTR_KIND], \"#t\": [topic], since: Math.floor(Date.now() / 1000) - 30 }]));\n // some relays never send EOSE for a subscription with no stored events: publish shortly anyway\n setT(publish, 1500);\n };\n ws.onerror = () => finish(false, \"connection failed\");\n ws.onclose = () => finish(false, \"closed\");\n ws.onmessage = (e) => {\n let m: unknown;\n try {\n m = JSON.parse(String(e.data));\n } catch {\n return;\n }\n if (!Array.isArray(m)) return;\n if (m[0] === \"EOSE\") publish();\n else if (m[0] === \"OK\" && m[1] === ev.id) {\n if (m[2] === true) accepted = true;\n else finish(false, `refused: ${String(m[3] ?? \"\")}`.slice(0, 120));\n } else if (m[0] === \"CLOSED\") finish(false, `closed: ${String(m[2] ?? \"\")}`.slice(0, 120));\n else if (m[0] === \"EVENT\" && (m[2] as NostrEvent | undefined)?.id === ev.id) finish(true);\n };\n });\n}\n"]}