@qntx/nostr 0.2.1 → 0.2.2

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 (57) hide show
  1. package/README.md +11 -11
  2. package/dist/{builder-CyrGKRVP.mjs → builder-8VQ_Xr6X.mjs} +2 -2
  3. package/dist/{builder-CyrGKRVP.mjs.map → builder-8VQ_Xr6X.mjs.map} +1 -1
  4. package/dist/{builder-BWn55Paf.d.mts → builder-C9VuhbfY.d.mts} +2 -2
  5. package/dist/{client-5DhgYV7P.mjs → client-BZMG37De.mjs} +3 -3
  6. package/dist/{client-5DhgYV7P.mjs.map → client-BZMG37De.mjs.map} +1 -1
  7. package/dist/client.d.mts +1 -1
  8. package/dist/client.mjs +1 -1
  9. package/dist/core.d.mts +4 -4
  10. package/dist/core.mjs +4 -3
  11. package/dist/{gossip-BRQwIM_q.d.mts → gossip-ZnGOJ1fo.d.mts} +2 -2
  12. package/dist/gossip.d.mts +1 -1
  13. package/dist/{index-Ba7bJ7DD.d.mts → index-23sRP0wl.d.mts} +2 -2
  14. package/dist/{index-BIhSADwK.d.mts → index-CLGInxR5.d.mts} +5 -5
  15. package/dist/{index-Boe8FshM.d.mts → index-CvkvqB16.d.mts} +20 -2
  16. package/dist/{index-B-CGNDPS.d.mts → index-Dj2TED7O.d.mts} +4 -4
  17. package/dist/index.d.mts +9 -9
  18. package/dist/index.mjs +7 -6
  19. package/dist/{key-Bbtys6o7.mjs → key-BZBap2p-.mjs} +3 -26
  20. package/dist/key-BZBap2p-.mjs.map +1 -0
  21. package/dist/{key-BlsYhN1V.d.mts → key-C6w9Fskk.d.mts} +2 -4
  22. package/dist/loaders.d.mts +1 -1
  23. package/dist/{nip17-DNEkz8rM.d.mts → nip17-jlcdeIQ8.d.mts} +2 -2
  24. package/dist/{nip65-DBfh2smt.d.mts → nip65-BlSAp_8P.d.mts} +2 -2
  25. package/dist/nips/blossom.d.mts +1 -1
  26. package/dist/nips/blossom.mjs +1 -1
  27. package/dist/nips/nip10.d.mts +1 -1
  28. package/dist/nips/nip10.mjs +1 -1
  29. package/dist/nips/nip17.d.mts +1 -1
  30. package/dist/nips/nip17.mjs +1 -1
  31. package/dist/nips/nip51.d.mts +1 -1
  32. package/dist/nips/nip51.mjs +1 -1
  33. package/dist/nips/nip57.mjs +1 -1
  34. package/dist/nips/nip57.mjs.map +1 -1
  35. package/dist/nips/nip59.mjs +2 -1
  36. package/dist/nips/nip59.mjs.map +1 -1
  37. package/dist/nips/nip65.d.mts +1 -1
  38. package/dist/nips/nip65.mjs +1 -1
  39. package/dist/nips/nip98.mjs +1 -1
  40. package/dist/nips/nip98.mjs.map +1 -1
  41. package/dist/{pool-C2xOcsun.mjs → pool-BGVx59yd.mjs} +2 -2
  42. package/dist/pool-BGVx59yd.mjs.map +1 -0
  43. package/dist/relay.mjs +1 -1
  44. package/dist/{signer-CKR9EHce.mjs → signer-BGSpLC7e.mjs} +3 -2
  45. package/dist/signer-BGSpLC7e.mjs.map +1 -0
  46. package/dist/signer.d.mts +1 -1
  47. package/dist/signer.mjs +1 -1
  48. package/dist/testing.mjs +3 -2
  49. package/dist/testing.mjs.map +1 -1
  50. package/dist/verifier-t5WoWbtY.mjs +38 -0
  51. package/dist/verifier-t5WoWbtY.mjs.map +1 -0
  52. package/dist/wasm.mjs +14 -21
  53. package/dist/wasm.mjs.map +1 -1
  54. package/package.json +1 -1
  55. package/dist/key-Bbtys6o7.mjs.map +0 -1
  56. package/dist/pool-C2xOcsun.mjs.map +0 -1
  57. package/dist/signer-CKR9EHce.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"nip98.mjs","names":[],"sources":["../../src/nips/nip98.ts"],"sourcesContent":["/**\n * NIP-98: HTTP Auth (kind 27235). Token is standard base64 of the signed event JSON, not base64url.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/98.md\n */\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { base64 } from \"@scure/base\";\n\nimport { NostrError } from \"../core/error.ts\";\nimport type { Event, EventTemplate } from \"../core/event.ts\";\nimport { validateSignedEvent } from \"../core/event.ts\";\nimport { verifyEvent } from \"../core/key.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { Tag } from \"../core/tag.ts\";\nimport { bytesToHex, utf8Decoder, utf8Encoder } from \"../core/util.ts\";\n\nconst AUTHORIZATION_SCHEME = \"Nostr \";\nconst DEFAULT_MAX_SKEW_SEC = 60;\n\nexport class Nip98Error extends NostrError {\n override name = \"Nip98Error\";\n}\n\n/** SHA-256 of the request body: raw bytes for string/Uint8Array, else JSON.stringify. */\nfunction hashPayload(payload: unknown): string {\n const bytes =\n typeof payload === \"string\"\n ? utf8Encoder.encode(payload)\n : payload instanceof Uint8Array\n ? payload\n : utf8Encoder.encode(JSON.stringify(payload));\n return bytesToHex(sha256(bytes));\n}\n\n/** RFC 4648 standard base64; accept missing `=` (NIP-98 spec example is unpadded). */\nfunction decodeStandardBase64(encoded: string): Uint8Array {\n const rem = encoded.length % 4;\n const padded = rem === 0 ? encoded : encoded + \"=\".repeat(4 - rem);\n return base64.decode(padded);\n}\n\nfunction stripAuthorizationScheme(token: string): string {\n const prefix = /^nostr\\s+/i.exec(token);\n return prefix ? token.slice(prefix[0].length) : token;\n}\n\n/**\n * Sign a kind 27235 auth event and encode it as a NIP-98 token. Uses standard base64\n * (`@scure/base`), not base64url.\n */\nexport async function getToken(\n url: string,\n method: string,\n sign: (template: EventTemplate) => Promise<Event> | Event,\n opts?: {\n includeAuthorizationScheme?: boolean;\n content?: string;\n payload?: unknown;\n now?: number;\n },\n): Promise<string> {\n const tags: Tag[] = [\n [\"u\", url],\n [\"method\", method],\n ];\n if (opts?.payload !== undefined) {\n tags.push([\"payload\", hashPayload(opts.payload)]);\n }\n\n const signed = await sign({\n kind: Kind.HttpAuth,\n created_at: opts?.now ?? Math.floor(Date.now() / 1000),\n tags,\n content: opts?.content ?? \"\",\n });\n\n const encoded = base64.encode(utf8Encoder.encode(JSON.stringify(signed)));\n return opts?.includeAuthorizationScheme === true ? AUTHORIZATION_SCHEME + encoded : encoded;\n}\n\n/** Decode a NIP-98 token (with or without the `Nostr ` scheme) into an event. */\nexport function unpackEventFromToken(token: string): Event {\n if (token === \"\") {\n throw new Nip98Error(\"missing token\");\n }\n\n const encoded = stripAuthorizationScheme(token);\n\n let json: string;\n try {\n json = utf8Decoder.decode(decodeStandardBase64(encoded));\n } catch (error) {\n throw new Nip98Error(\"invalid token encoding\", { cause: error });\n }\n if (!json.startsWith(\"{\")) {\n throw new Nip98Error(\"invalid token\");\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch (error) {\n throw new Nip98Error(\"invalid token JSON\", { cause: error });\n }\n if (!validateSignedEvent(parsed)) {\n throw new Nip98Error(\"token is not a signed event\");\n }\n return parsed;\n}\n\n/**\n * True when `event` is a valid NIP-98 auth event for `url` + `method`. Verifies signature, kind\n * 27235, timestamp window, `u`, `method`, and optional `payload` tag.\n */\nexport function validateAuthEvent(\n event: Event,\n url: string,\n method: string,\n opts?: { payload?: unknown; maxSkewSec?: number },\n): boolean {\n if (!verifyEvent(event)) {\n return false;\n }\n if (event.kind !== Kind.HttpAuth) {\n return false;\n }\n\n const maxSkewSec = opts?.maxSkewSec ?? DEFAULT_MAX_SKEW_SEC;\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - event.created_at) > maxSkewSec) {\n return false;\n }\n\n const u = event.tags.find((t) => t[0] === \"u\")?.[1];\n if (u !== url) {\n return false;\n }\n\n const m = event.tags.find((t) => t[0] === \"method\")?.[1];\n if (m === undefined || m.toLowerCase() !== method.toLowerCase()) {\n return false;\n }\n\n if (opts?.payload !== undefined) {\n const payloadTag = event.tags.find((t) => t[0] === \"payload\")?.[1];\n if (payloadTag !== hashPayload(opts.payload)) {\n return false;\n }\n }\n\n return true;\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAE7B,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAGA,SAAS,YAAY,SAA0B;CAC7C,MAAM,QACJ,OAAO,YAAY,WACf,YAAY,OAAO,OAAO,IAC1B,mBAAmB,aACjB,UACA,YAAY,OAAO,KAAK,UAAU,OAAO,CAAC;CAClD,OAAO,WAAW,OAAO,KAAK,CAAC;AACjC;;AAGA,SAAS,qBAAqB,SAA6B;CACzD,MAAM,MAAM,QAAQ,SAAS;CAC7B,MAAM,SAAS,QAAQ,IAAI,UAAU,UAAU,IAAI,OAAO,IAAI,GAAG;CACjE,OAAO,OAAO,OAAO,MAAM;AAC7B;AAEA,SAAS,yBAAyB,OAAuB;CACvD,MAAM,SAAS,aAAa,KAAK,KAAK;CACtC,OAAO,SAAS,MAAM,MAAM,OAAO,EAAE,CAAC,MAAM,IAAI;AAClD;;;;;AAMA,eAAsB,SACpB,KACA,QACA,MACA,MAMiB;CACjB,MAAM,OAAc,CAClB,CAAC,KAAK,GAAG,GACT,CAAC,UAAU,MAAM,CACnB;CACA,IAAI,MAAM,YAAY,KAAA,GACpB,KAAK,KAAK,CAAC,WAAW,YAAY,KAAK,OAAO,CAAC,CAAC;CAGlD,MAAM,SAAS,MAAM,KAAK;EACxB,MAAM,KAAK;EACX,YAAY,MAAM,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;EACrD;EACA,SAAS,MAAM,WAAW;CAC5B,CAAC;CAED,MAAM,UAAU,OAAO,OAAO,YAAY,OAAO,KAAK,UAAU,MAAM,CAAC,CAAC;CACxE,OAAO,MAAM,+BAA+B,OAAO,uBAAuB,UAAU;AACtF;;AAGA,SAAgB,qBAAqB,OAAsB;CACzD,IAAI,UAAU,IACZ,MAAM,IAAI,WAAW,eAAe;CAGtC,MAAM,UAAU,yBAAyB,KAAK;CAE9C,IAAI;CACJ,IAAI;EACF,OAAO,YAAY,OAAO,qBAAqB,OAAO,CAAC;CACzD,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,0BAA0B,EAAE,OAAO,MAAM,CAAC;CACjE;CACA,IAAI,CAAC,KAAK,WAAW,GAAG,GACtB,MAAM,IAAI,WAAW,eAAe;CAGtC,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;CAC1B,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,EAAE,OAAO,MAAM,CAAC;CAC7D;CACA,IAAI,CAAC,oBAAoB,MAAM,GAC7B,MAAM,IAAI,WAAW,6BAA6B;CAEpD,OAAO;AACT;;;;;AAMA,SAAgB,kBACd,OACA,KACA,QACA,MACS;CACT,IAAI,CAAC,YAAY,KAAK,GACpB,OAAO;CAET,IAAI,MAAM,SAAS,KAAK,UACtB,OAAO;CAGT,MAAM,aAAa,MAAM,cAAc;CACvC,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;CACxC,IAAI,KAAK,IAAI,MAAM,MAAM,UAAU,IAAI,YACrC,OAAO;CAIT,IADU,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,OACvC,KACR,OAAO;CAGT,MAAM,IAAI,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,QAAQ,CAAC,GAAG;CACtD,IAAI,MAAM,KAAA,KAAa,EAAE,YAAY,MAAM,OAAO,YAAY,GAC5D,OAAO;CAGT,IAAI,MAAM,YAAY,KAAA,GACD;MAAA,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,SAAS,CAAC,GAAG,OAC7C,YAAY,KAAK,OAAO,GACzC,OAAO;CAAA;CAIX,OAAO;AACT"}
1
+ {"version":3,"file":"nip98.mjs","names":[],"sources":["../../src/nips/nip98.ts"],"sourcesContent":["/**\n * NIP-98: HTTP Auth (kind 27235). Token is standard base64 of the signed event JSON, not base64url.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/98.md\n */\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { base64 } from \"@scure/base\";\n\nimport { NostrError } from \"../core/error.ts\";\nimport type { Event, EventTemplate } from \"../core/event.ts\";\nimport { validateSignedEvent } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { Tag } from \"../core/tag.ts\";\nimport { bytesToHex, utf8Decoder, utf8Encoder } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\n\nconst AUTHORIZATION_SCHEME = \"Nostr \";\nconst DEFAULT_MAX_SKEW_SEC = 60;\n\nexport class Nip98Error extends NostrError {\n override name = \"Nip98Error\";\n}\n\n/** SHA-256 of the request body: raw bytes for string/Uint8Array, else JSON.stringify. */\nfunction hashPayload(payload: unknown): string {\n const bytes =\n typeof payload === \"string\"\n ? utf8Encoder.encode(payload)\n : payload instanceof Uint8Array\n ? payload\n : utf8Encoder.encode(JSON.stringify(payload));\n return bytesToHex(sha256(bytes));\n}\n\n/** RFC 4648 standard base64; accept missing `=` (NIP-98 spec example is unpadded). */\nfunction decodeStandardBase64(encoded: string): Uint8Array {\n const rem = encoded.length % 4;\n const padded = rem === 0 ? encoded : encoded + \"=\".repeat(4 - rem);\n return base64.decode(padded);\n}\n\nfunction stripAuthorizationScheme(token: string): string {\n const prefix = /^nostr\\s+/i.exec(token);\n return prefix ? token.slice(prefix[0].length) : token;\n}\n\n/**\n * Sign a kind 27235 auth event and encode it as a NIP-98 token. Uses standard base64\n * (`@scure/base`), not base64url.\n */\nexport async function getToken(\n url: string,\n method: string,\n sign: (template: EventTemplate) => Promise<Event> | Event,\n opts?: {\n includeAuthorizationScheme?: boolean;\n content?: string;\n payload?: unknown;\n now?: number;\n },\n): Promise<string> {\n const tags: Tag[] = [\n [\"u\", url],\n [\"method\", method],\n ];\n if (opts?.payload !== undefined) {\n tags.push([\"payload\", hashPayload(opts.payload)]);\n }\n\n const signed = await sign({\n kind: Kind.HttpAuth,\n created_at: opts?.now ?? Math.floor(Date.now() / 1000),\n tags,\n content: opts?.content ?? \"\",\n });\n\n const encoded = base64.encode(utf8Encoder.encode(JSON.stringify(signed)));\n return opts?.includeAuthorizationScheme === true ? AUTHORIZATION_SCHEME + encoded : encoded;\n}\n\n/** Decode a NIP-98 token (with or without the `Nostr ` scheme) into an event. */\nexport function unpackEventFromToken(token: string): Event {\n if (token === \"\") {\n throw new Nip98Error(\"missing token\");\n }\n\n const encoded = stripAuthorizationScheme(token);\n\n let json: string;\n try {\n json = utf8Decoder.decode(decodeStandardBase64(encoded));\n } catch (error) {\n throw new Nip98Error(\"invalid token encoding\", { cause: error });\n }\n if (!json.startsWith(\"{\")) {\n throw new Nip98Error(\"invalid token\");\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch (error) {\n throw new Nip98Error(\"invalid token JSON\", { cause: error });\n }\n if (!validateSignedEvent(parsed)) {\n throw new Nip98Error(\"token is not a signed event\");\n }\n return parsed;\n}\n\n/**\n * True when `event` is a valid NIP-98 auth event for `url` + `method`. Verifies signature, kind\n * 27235, timestamp window, `u`, `method`, and optional `payload` tag.\n */\nexport function validateAuthEvent(\n event: Event,\n url: string,\n method: string,\n opts?: { payload?: unknown; maxSkewSec?: number },\n): boolean {\n if (!verifyEvent(event)) {\n return false;\n }\n if (event.kind !== Kind.HttpAuth) {\n return false;\n }\n\n const maxSkewSec = opts?.maxSkewSec ?? DEFAULT_MAX_SKEW_SEC;\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - event.created_at) > maxSkewSec) {\n return false;\n }\n\n const u = event.tags.find((t) => t[0] === \"u\")?.[1];\n if (u !== url) {\n return false;\n }\n\n const m = event.tags.find((t) => t[0] === \"method\")?.[1];\n if (m === undefined || m.toLowerCase() !== method.toLowerCase()) {\n return false;\n }\n\n if (opts?.payload !== undefined) {\n const payloadTag = event.tags.find((t) => t[0] === \"payload\")?.[1];\n if (payloadTag !== hashPayload(opts.payload)) {\n return false;\n }\n }\n\n return true;\n}\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAE7B,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAGA,SAAS,YAAY,SAA0B;CAC7C,MAAM,QACJ,OAAO,YAAY,WACf,YAAY,OAAO,OAAO,IAC1B,mBAAmB,aACjB,UACA,YAAY,OAAO,KAAK,UAAU,OAAO,CAAC;CAClD,OAAO,WAAW,OAAO,KAAK,CAAC;AACjC;;AAGA,SAAS,qBAAqB,SAA6B;CACzD,MAAM,MAAM,QAAQ,SAAS;CAC7B,MAAM,SAAS,QAAQ,IAAI,UAAU,UAAU,IAAI,OAAO,IAAI,GAAG;CACjE,OAAO,OAAO,OAAO,MAAM;AAC7B;AAEA,SAAS,yBAAyB,OAAuB;CACvD,MAAM,SAAS,aAAa,KAAK,KAAK;CACtC,OAAO,SAAS,MAAM,MAAM,OAAO,EAAE,CAAC,MAAM,IAAI;AAClD;;;;;AAMA,eAAsB,SACpB,KACA,QACA,MACA,MAMiB;CACjB,MAAM,OAAc,CAClB,CAAC,KAAK,GAAG,GACT,CAAC,UAAU,MAAM,CACnB;CACA,IAAI,MAAM,YAAY,KAAA,GACpB,KAAK,KAAK,CAAC,WAAW,YAAY,KAAK,OAAO,CAAC,CAAC;CAGlD,MAAM,SAAS,MAAM,KAAK;EACxB,MAAM,KAAK;EACX,YAAY,MAAM,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;EACrD;EACA,SAAS,MAAM,WAAW;CAC5B,CAAC;CAED,MAAM,UAAU,OAAO,OAAO,YAAY,OAAO,KAAK,UAAU,MAAM,CAAC,CAAC;CACxE,OAAO,MAAM,+BAA+B,OAAO,uBAAuB,UAAU;AACtF;;AAGA,SAAgB,qBAAqB,OAAsB;CACzD,IAAI,UAAU,IACZ,MAAM,IAAI,WAAW,eAAe;CAGtC,MAAM,UAAU,yBAAyB,KAAK;CAE9C,IAAI;CACJ,IAAI;EACF,OAAO,YAAY,OAAO,qBAAqB,OAAO,CAAC;CACzD,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,0BAA0B,EAAE,OAAO,MAAM,CAAC;CACjE;CACA,IAAI,CAAC,KAAK,WAAW,GAAG,GACtB,MAAM,IAAI,WAAW,eAAe;CAGtC,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;CAC1B,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,EAAE,OAAO,MAAM,CAAC;CAC7D;CACA,IAAI,CAAC,oBAAoB,MAAM,GAC7B,MAAM,IAAI,WAAW,6BAA6B;CAEpD,OAAO;AACT;;;;;AAMA,SAAgB,kBACd,OACA,KACA,QACA,MACS;CACT,IAAI,CAAC,YAAY,KAAK,GACpB,OAAO;CAET,IAAI,MAAM,SAAS,KAAK,UACtB,OAAO;CAGT,MAAM,aAAa,MAAM,cAAc;CACvC,MAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;CACxC,IAAI,KAAK,IAAI,MAAM,MAAM,UAAU,IAAI,YACrC,OAAO;CAIT,IADU,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,OACvC,KACR,OAAO;CAGT,MAAM,IAAI,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,QAAQ,CAAC,GAAG;CACtD,IAAI,MAAM,KAAA,KAAa,EAAE,YAAY,MAAM,OAAO,YAAY,GAC5D,OAAO;CAGT,IAAI,MAAM,YAAY,KAAA,GACD;MAAA,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,SAAS,CAAC,GAAG,OAC7C,YAAY,KAAK,OAAO,GACzC,OAAO;CAAA;CAIX,OAAO;AACT"}
@@ -1,5 +1,5 @@
1
1
  import { g as NostrError, h as MessageError, l as normalizeURL, v as WasmVerifyPoisonedError } from "./util-LfQirgDk.mjs";
2
- import { s as verifyEvent } from "./key-Bbtys6o7.mjs";
2
+ import { n as verifyEvent } from "./verifier-t5WoWbtY.mjs";
3
3
  import { n as canonicalizeFilters, r as filterFingerprint, t as canonicalizeFilter } from "./filter-BQl3GlHt.mjs";
4
4
  import { n as createSubscriptionId, r as encodeClientMessage, s as parseRelayMessage, t as assertSubscriptionId } from "./message-DcY6Fi9o.mjs";
5
5
  import { t as NoSignerError } from "./error-B__OMBRY.mjs";
@@ -2102,4 +2102,4 @@ var Pool = class {
2102
2102
  //#endregion
2103
2103
  export { RelayStatus as a, isInsecureRelayUrl as c, RelayClosedError as d, RelayConnectionError as f, RelayTimeoutError as g, RelaySuspendedError as h, Relay as i, getWebSocketImplementation as l, RelayPublishError as m, fanIn as n, Subscription as o, RelayError as p, fetchRouted as r, subscriptionToAsyncIterable as s, Pool as t, useWebSocketImplementation as u };
2104
2104
 
2105
- //# sourceMappingURL=pool-C2xOcsun.mjs.map
2105
+ //# sourceMappingURL=pool-BGVx59yd.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool-BGVx59yd.mjs","names":[],"sources":["../src/relay/error.ts","../src/relay/websocket.ts","../src/relay/url.ts","../src/relay/neg-session.ts","../src/relay/ping.ts","../src/relay/subscription.ts","../src/relay/subscribe.ts","../src/relay/relay.ts","../src/relay/fan-in.ts","../src/relay/pool.ts"],"sourcesContent":["import { NostrError } from \"../core/error.ts\";\n\n/** Base class for relay errors; carries the relay URL when known. */\nexport class RelayError extends NostrError {\n override name = \"RelayError\";\n readonly url: string | undefined;\n\n constructor(message: string, url?: string, options?: ErrorOptions) {\n super(url !== undefined && url !== \"\" ? `${message} (${url})` : message, options);\n this.url = url;\n }\n}\n\n/** A relay connection attempt or socket failed. */\nexport class RelayConnectionError extends RelayError {\n override name = \"RelayConnectionError\";\n}\n/** A relay answered an EVENT with `ok: false`. */\nexport class RelayPublishError extends RelayError {\n override name = \"RelayPublishError\";\n}\n/** A subscription was closed by the relay (`CLOSED`) or the socket dropped. */\nexport class RelayClosedError extends RelayError {\n override name = \"RelayClosedError\";\n}\n/** A relay operation exceeded its deadline. */\nexport class RelayTimeoutError extends RelayError {\n override name = \"RelayTimeoutError\";\n}\n/**\n * A relay was suspended for delivering more events that fail id/signature verification than its\n * {@link PoolOptions.invalidEventPolicy} allows. Carries `until`, the epoch-ms time when the relay\n * may connect again.\n */\nexport class RelaySuspendedError extends RelayError {\n override name = \"RelaySuspendedError\";\n /** Epoch milliseconds when the suspension lifts. */\n readonly until: number;\n\n constructor(url: string, until: number) {\n super(\"relay suspended for delivering invalid events\", url);\n this.until = until;\n }\n}\n","import { RelayConnectionError } from \"./error.ts\";\n\n/** Minimal WebSocket surface used by Relay (browser or `ws`). */\nexport type WebSocketLike = {\n readyState: number;\n send: (data: string) => void;\n close: (code?: number, reason?: string) => void;\n addEventListener: (type: string, listener: (ev: unknown) => void) => void;\n removeEventListener: (type: string, listener: (ev: unknown) => void) => void;\n ping?: () => void;\n /** Node `ws` emits `pong` on the EventEmitter; `addEventListener(\"pong\")` is a no-op. */\n once?: (event: string, listener: (...args: unknown[]) => void) => void;\n on?: (event: string, listener: (...args: unknown[]) => void) => void;\n off?: (event: string, listener: (...args: unknown[]) => void) => void;\n};\n\nexport type WebSocketConstructor = {\n new (url: string): WebSocketLike;\n readonly OPEN: number;\n readonly CONNECTING: number;\n readonly CLOSING: number;\n readonly CLOSED: number;\n};\n\nlet impl: WebSocketConstructor | undefined;\n\ntry {\n if (globalThis.WebSocket !== undefined) {\n impl = globalThis.WebSocket;\n }\n} catch {\n // no global WebSocket\n}\n\n/** Inject a WebSocket implementation (required on Node unless undici/global is present). */\nexport function useWebSocketImplementation(websocketImplementation: WebSocketConstructor): void {\n impl = websocketImplementation;\n}\n\nexport function getWebSocketImplementation(): WebSocketConstructor {\n if (!impl) {\n throw new RelayConnectionError(\n \"No WebSocket implementation available; call useWebSocketImplementation() or run in a browser\",\n );\n }\n return impl;\n}\n","/**\n * True for `ws:` / `http:` URLs that are not `.onion`. Local-network `ws://` is still insecure;\n * allow those via a trusted set.\n */\nexport function isInsecureRelayUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n if (parsed.hostname.endsWith(\".onion\")) {\n return false;\n }\n return parsed.protocol === \"ws:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n","import { abortReason } from \"../core/abort.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport type { ClientMessage } from \"../core/message.ts\";\nimport { Nip77Error, runNegSession } from \"../nips/nip77.ts\";\nimport type { NegentropyStorageVector } from \"../nips/nip77.ts\";\nimport { RelayTimeoutError } from \"./error.ts\";\n\nexport type NegSession = {\n queue: string[];\n waiter:\n | {\n resolve: (hex: string) => void;\n reject: (err: unknown) => void;\n }\n | undefined;\n error: Error | undefined;\n};\n\nexport function createNegSession(): NegSession {\n return { queue: [], waiter: undefined, error: undefined };\n}\n\nexport function pushNegMsg(session: NegSession, hex: string): void {\n if (session.waiter) {\n const { waiter } = session;\n session.waiter = undefined;\n waiter.resolve(hex);\n } else {\n session.queue.push(hex);\n }\n}\n\nexport function failNegSession(session: NegSession, err: Error): void {\n session.error = err;\n if (session.waiter) {\n const { waiter } = session;\n session.waiter = undefined;\n waiter.reject(err);\n }\n}\n\nexport function failNegErr(session: NegSession, reason: string): void {\n failNegSession(session, new Nip77Error(reason));\n}\n\n/** Wire queue/timeout/abort around `runNegSession`. Not a second session class. */\nexport async function runWiredNegSession(opts: {\n session: NegSession;\n storage: NegentropyStorageVector;\n filter: Filter;\n id: string;\n timeoutMs: number;\n signal?: AbortSignal | undefined;\n send: (message: ClientMessage) => void;\n url: string;\n}): Promise<{ have: string[]; need: string[] }> {\n const { session, storage, filter, id, timeoutMs, signal, send, url } = opts;\n const deadline = Date.now() + timeoutMs;\n\n const timedOut = (): RelayTimeoutError => new RelayTimeoutError(\"negentropy timed out\", url);\n\n const remainingMs = (): number => deadline - Date.now();\n\n const next = async (): Promise<string> => {\n if (session.error !== undefined) {\n throw session.error;\n }\n if (remainingMs() <= 0) {\n throw timedOut();\n }\n const queued = session.queue.shift();\n if (queued !== undefined) {\n return queued;\n }\n return new Promise<string>((resolve, reject) => {\n const timer = setTimeout(() => {\n session.waiter = undefined;\n reject(timedOut());\n }, remainingMs());\n const fail = (err: unknown): void => {\n clearTimeout(timer);\n session.waiter = undefined;\n // oxlint-disable-next-line typescript/prefer-promise-reject-errors -- forwards abort/signal reasons verbatim\n reject(err);\n };\n const onAbort = (): void => {\n if (signal) {\n fail(abortReason(signal));\n }\n };\n session.waiter = {\n resolve: (hex) => {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n resolve(hex);\n },\n reject: (err) => fail(err),\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n };\n\n return runNegSession({\n storage,\n openingSend: (hex) => {\n send([\"NEG-OPEN\", id, filter, hex]);\n },\n msgSend: (hex) => {\n send([\"NEG-MSG\", id, hex]);\n },\n next,\n });\n}\n","import type { Filter } from \"../core/filter.ts\";\nimport type { ClientMessage, SubscriptionId } from \"../core/message.ts\";\nimport type { WebSocketLike } from \"./websocket.ts\";\n\nexport const DEFAULT_PING_INTERVAL_MS = 29_000;\nexport const DEFAULT_PING_TIMEOUT_MS = 20_000;\n\nconst PING_DUMMY_ID = \"a\".repeat(64);\nconst PING_DUMMY_FILTER: Filter = { ids: [PING_DUMMY_ID], limit: 0 };\n/** Browser WebSocket and `ws` both use 1 for OPEN. */\nconst WS_OPEN = 1;\n\ntype PingWaiter = {\n resolve: (alive: boolean) => void;\n};\n\nexport type PingLoopOpts = {\n send: (message: ClientMessage) => void;\n nextSubId: (prefix: string) => string;\n getWs: () => WebSocketLike | undefined;\n closeWs: () => void;\n pingIntervalMs: number;\n pingTimeoutMs: number;\n};\n\n/** Node `ws` delivers `pong` on the EventEmitter, not via addEventListener. */\nexport function canNativePing(ws: WebSocketLike): boolean {\n return (\n typeof ws.ping === \"function\" && (typeof ws.once === \"function\" || typeof ws.on === \"function\")\n );\n}\n\n/** REQ-dummy or native ping/pong keepalive. Does not import class Relay. */\nexport class PingLoop {\n readonly #opts: PingLoopOpts;\n #timer: ReturnType<typeof setInterval> | undefined;\n readonly #waiters = new Map<SubscriptionId, PingWaiter>();\n #gen = 0;\n #nativePing: { abort: () => void } | undefined;\n\n constructor(opts: PingLoopOpts) {\n this.#opts = opts;\n }\n\n start(): void {\n this.stop();\n this.#timer = setInterval(() => {\n void this.#pingpong();\n }, this.#opts.pingIntervalMs);\n }\n\n stop(): void {\n if (this.#timer !== undefined) {\n clearInterval(this.#timer);\n this.#timer = undefined;\n }\n this.#abortCurrentPing();\n }\n\n hasWaiter(id: string): boolean {\n return this.#waiters.has(id);\n }\n\n finishDummyPing(id: string): boolean {\n const waiter = this.#waiters.get(id);\n if (!waiter) {\n return false;\n }\n this.#waiters.delete(id);\n waiter.resolve(true);\n try {\n this.#opts.send([\"CLOSE\", id]);\n } catch {\n // socket already gone\n }\n return true;\n }\n\n #abortCurrentPing(): void {\n this.#gen += 1;\n const native = this.#nativePing;\n this.#nativePing = undefined;\n native?.abort();\n for (const waiter of this.#waiters.values()) {\n waiter.resolve(false);\n }\n this.#waiters.clear();\n }\n\n async #pingpong(): Promise<void> {\n const ws = this.#opts.getWs();\n if (!ws || ws.readyState !== WS_OPEN) {\n return;\n }\n if (this.#nativePing !== undefined || this.#waiters.size > 0) {\n return;\n }\n\n const gen = this.#gen;\n const ping = canNativePing(ws) ? this.#waitForNativePing(ws) : this.#waitForDummyPing();\n const ok = await new Promise<boolean>((resolve) => {\n let settled = false;\n const done = (alive: boolean) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n resolve(alive);\n };\n const timer = setTimeout(() => {\n if (this.#nativePing !== undefined || this.#waiters.size > 0) {\n done(false);\n }\n }, this.#opts.pingTimeoutMs);\n void (async (): Promise<void> => {\n done(await ping);\n })();\n });\n\n if (gen !== this.#gen) {\n return;\n }\n\n if (!ok) {\n this.#abortCurrentPing();\n this.#opts.closeWs();\n }\n }\n\n async #waitForNativePing(ws: WebSocketLike): Promise<boolean> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = (alive: boolean) => {\n if (settled) {\n return;\n }\n settled = true;\n this.#nativePing = undefined;\n ws.off?.(\"pong\", onPong);\n resolve(alive);\n };\n const onPong = () => finish(true);\n this.#nativePing = { abort: () => finish(false) };\n\n // node `ws` once() wraps the listener; off(fn) would miss it.\n if (typeof ws.on === \"function\" && typeof ws.off === \"function\") {\n ws.on(\"pong\", onPong);\n } else if (typeof ws.once === \"function\") {\n ws.once(\"pong\", onPong);\n } else {\n ws.on?.(\"pong\", onPong);\n }\n try {\n if (typeof ws.ping === \"function\") {\n ws.ping();\n } else {\n finish(false);\n }\n } catch {\n finish(false);\n }\n });\n }\n\n async #waitForDummyPing(): Promise<boolean> {\n return new Promise((resolve) => {\n const id = this.#opts.nextSubId(\"__ping__\");\n this.#waiters.set(id, { resolve });\n try {\n this.#opts.send([\"REQ\", id, PING_DUMMY_FILTER]);\n } catch {\n this.#waiters.delete(id);\n resolve(false);\n }\n });\n }\n}\n","import type { Event } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { createSubscriptionId } from \"../core/message.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { RelayClosedError } from \"./error.ts\";\n\nexport type SubscriptionHandlers = {\n onevent?: ((event: Event) => void) | undefined;\n oneose?: (() => void) | undefined;\n onclose?: ((reason: string) => void) | undefined;\n /** Skip verify + onevent when true. Evaluated after parse, before verify. */\n alreadyHaveEvent?: ((id: string) => boolean) | undefined;\n /**\n * Fired for every EVENT id this sub sees, including duplicates and alreadyHaveEvent hits, after\n * parse and before the verify skip.\n */\n receivedEvent?: ((id: string) => void) | undefined;\n};\n\n/** Options for {@link Relay.subscribe}: event handlers plus REQ behavior. */\nexport type SubscribeOptions = SubscriptionHandlers & {\n id?: string | undefined;\n /**\n * If set, fire `oneose` once after this many ms if EOSE has not arrived. Does not close the REQ.\n * `Relay.fetch` is the one-shot closer.\n */\n eoseTimeoutMs?: number | undefined;\n /**\n * One-shot REQ: do not join a live coalescing group, and close on EOSE. Default false (live).\n * `Relay.fetch` passes true.\n */\n closeOnEose?: boolean | undefined;\n signal?: AbortSignal | undefined;\n};\n\nexport class Subscription {\n readonly id: string;\n readonly filters: Filter[];\n readonly handlers: SubscriptionHandlers;\n readonly closeOnEose: boolean;\n eosed = false;\n closed = false;\n /** True after one CLOSED `auth-required:` retry. */\n authRetried = false;\n /** Inclusive NIP-01 `since` watermark from verified EVENTs. */\n lastCreatedAt: number | undefined;\n /** Event ids at `lastCreatedAt` (same-second reconnect dedup). Not all seen ids. */\n readonly idsAtWatermark: Set<string> = new Set<string>();\n readonly #sendClose: (id: string) => void;\n readonly #abort: (() => void) | undefined;\n\n constructor(filters: Filter[], opts: SubscribeOptions, sendClose: (id: string) => void) {\n this.#sendClose = sendClose;\n this.id = createSubscriptionId(opts.id);\n this.filters = filters;\n this.closeOnEose = opts.closeOnEose === true;\n this.handlers = {\n onevent: opts.onevent,\n oneose: opts.oneose,\n onclose: opts.onclose,\n alreadyHaveEvent: opts.alreadyHaveEvent,\n receivedEvent: opts.receivedEvent,\n };\n\n if (opts.signal) {\n if (opts.signal.aborted) {\n this.close(\"aborted\");\n } else {\n const onAbort = () => this.close(\"aborted\");\n opts.signal.addEventListener(\"abort\", onAbort, { once: true });\n this.#abort = () => opts.signal?.removeEventListener(\"abort\", onAbort);\n }\n }\n }\n\n close(reason = \"closed by client\"): void {\n if (this.closed) {\n return;\n }\n this.closed = true;\n this.#abort?.();\n this.#sendClose(this.id);\n invokeSafely(() => this.handlers.onclose?.(reason));\n }\n\n /** Advance the reconnect watermark after a verified EVENT. */\n noteVerified(event: Event): void {\n if (this.lastCreatedAt === undefined || event.created_at > this.lastCreatedAt) {\n this.lastCreatedAt = event.created_at;\n this.idsAtWatermark.clear();\n this.idsAtWatermark.add(event.id);\n return;\n }\n if (event.created_at === this.lastCreatedAt) {\n this.idsAtWatermark.add(event.id);\n }\n }\n\n /**\n * Filters for re-REQ. Original `filters` stay unchanged. NIP-01 `since` is inclusive — never\n * `lastCreatedAt + 1`.\n */\n replayFilters(): Filter[] {\n const since = this.lastCreatedAt;\n if (since === undefined) {\n return this.filters;\n }\n return this.filters.map((f) => ({\n ...f,\n since: f.since === undefined ? since : Math.max(f.since, since),\n }));\n }\n}\n\n/** AsyncIterable wrapper over a subscription's events until EOSE or close. */\nexport function subscriptionToAsyncIterable(\n start: (handlers: SubscriptionHandlers) => { close: (reason?: string) => void },\n opts?: { signal?: AbortSignal | undefined; includeEose?: boolean | undefined },\n): AsyncIterable<Event> & { close: (reason?: string) => void } {\n const queue: Event[] = [];\n let done = false;\n let error: Error | undefined;\n let wake: (() => void) | undefined;\n // `let` is required: onclose can fire synchronously while start() is still assigning closer.\n // oxlint-disable-next-line prefer-const\n let closer: { close: (reason?: string) => void } | undefined;\n // Set before every locally initiated close so onclose can distinguish it\n // from a remote/transport close without comparing reason strings.\n let localClose = false;\n\n const notify = () => {\n wake?.();\n wake = undefined;\n };\n\n const waitForWake = async (): Promise<void> =>\n new Promise<void>((resolve) => {\n wake = resolve;\n });\n\n const closeLocal = (reason: string): void => {\n localClose = true;\n closer?.close(reason);\n done = true;\n notify();\n };\n\n closer = start({\n onevent(event) {\n queue.push(event);\n notify();\n },\n oneose() {\n if (opts?.includeEose === false) {\n closeLocal(\"eose\");\n }\n },\n onclose(reason) {\n // The Subscription's own abort listener fires before this wrapper's,\n // so a signal-driven close can surface here while localClose is still\n // false — it is still a local close, not a remote one.\n if (opts?.signal?.aborted === true) {\n localClose = true;\n }\n if (!localClose && reason) {\n error = new RelayClosedError(reason);\n }\n done = true;\n notify();\n },\n });\n\n if (opts?.signal) {\n if (opts.signal.aborted) {\n closeLocal(\"aborted\");\n } else {\n opts.signal.addEventListener(\"abort\", () => closeLocal(\"aborted\"), { once: true });\n }\n }\n\n return {\n close(reason?: string) {\n closeLocal(reason ?? \"closed by client\");\n },\n [Symbol.asyncIterator]() {\n return {\n async next(): Promise<IteratorResult<Event>> {\n while (true) {\n const value = queue.shift();\n if (value !== undefined) {\n return { value, done: false };\n }\n if (error !== undefined) {\n throw error;\n }\n if (done) {\n return { value: undefined, done: true };\n }\n // oxlint-disable-next-line no-await-in-loop -- the async iterator waits for each EVENT serially\n await waitForWake();\n }\n },\n // oxlint-disable-next-line typescript/require-await -- AsyncIterator.return must be async-shaped though cleanup is synchronous\n async return(): Promise<IteratorResult<Event>> {\n closeLocal(\"iterator returned\");\n return { value: undefined, done: true };\n },\n };\n },\n };\n}\n","import { abortReason, throwIfAborted } from \"../core/abort.ts\";\n/** REQ subscription runtime: exclusive one-shot, live coalescing, dispatch, reconnect replay. */\nimport type { Event } from \"../core/event.ts\";\nimport { filterFingerprint } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport type { ClientMessage, SubscriptionId } from \"../core/message.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { Subscription, subscriptionToAsyncIterable } from \"./subscription.ts\";\nimport type { SubscribeOptions } from \"./subscription.ts\";\n\nexport type LiveGroup = {\n fp: string;\n sub: Subscription;\n attachments: Set<Subscription>;\n};\n\nexport type LiveCtx = {\n liveByFp: Map<string, LiveGroup>;\n liveBySubId: Map<SubscriptionId, LiveGroup>;\n subs: Map<SubscriptionId, Subscription>;\n connected: () => boolean;\n enableReconnect: () => boolean;\n send: (message: ClientMessage) => void;\n scheduleReconnect: () => void;\n acceptEvent: (event: Event) => boolean;\n armEoseTimeout: (sub: Subscription, ms: number) => void;\n};\n\nexport function openExclusive(\n ctx: LiveCtx,\n filters: Filter[],\n opts: SubscribeOptions,\n): Subscription {\n const sub = new Subscription(filters, opts, (id) => {\n ctx.subs.delete(id);\n try {\n if (ctx.connected()) {\n ctx.send([\"CLOSE\", id]);\n }\n } catch {\n // ignore\n }\n });\n\n ctx.subs.set(sub.id, sub);\n if (ctx.connected()) {\n ctx.send([\"REQ\", sub.id, ...filters]);\n } else if (ctx.enableReconnect()) {\n ctx.scheduleReconnect();\n }\n\n if (opts.eoseTimeoutMs !== undefined) {\n ctx.armEoseTimeout(sub, opts.eoseTimeoutMs);\n }\n return sub;\n}\n\nexport function subscribeLive(\n ctx: LiveCtx,\n filters: Filter[],\n opts: SubscribeOptions,\n): Subscription {\n const fp = filterFingerprint(filters);\n let group = ctx.liveByFp.get(fp);\n let created = false;\n if (!group) {\n created = true;\n const wire = new Subscription(filters, { id: opts.id }, () => {\n endLiveGroup(ctx, fp, { sendClose: true, reason: \"closed by client\" });\n });\n group = { fp, sub: wire, attachments: new Set() };\n ctx.liveByFp.set(fp, group);\n ctx.liveBySubId.set(wire.id, group);\n ctx.subs.set(wire.id, wire);\n }\n\n const slot: { handle: Subscription | undefined } = { handle: undefined };\n const handle = new Subscription(filters, { ...opts, id: group.sub.id }, () => {\n // constructor may close on an already-aborted signal before `handle` is assigned\n const current = slot.handle;\n if (!current) {\n return;\n }\n detachLive(ctx, fp, current);\n });\n slot.handle = handle;\n\n if (handle.closed) {\n if (created && group.attachments.size === 0) {\n forgetLiveGroup(ctx, group);\n }\n return handle;\n }\n\n group.attachments.add(handle);\n\n if (created) {\n if (ctx.connected()) {\n ctx.send([\"REQ\", group.sub.id, ...filters]);\n } else if (ctx.enableReconnect()) {\n ctx.scheduleReconnect();\n }\n }\n\n if (opts.eoseTimeoutMs !== undefined) {\n ctx.armEoseTimeout(handle, opts.eoseTimeoutMs);\n }\n\n if (group.sub.eosed) {\n queueMicrotask(() => {\n if (handle.closed || handle.eosed) {\n return;\n }\n handle.eosed = true;\n invokeSafely(() => handle.handlers.oneose?.());\n });\n }\n\n return handle;\n}\n\nexport function forgetLiveGroup(ctx: LiveCtx, group: LiveGroup): void {\n ctx.liveByFp.delete(group.fp);\n ctx.liveBySubId.delete(group.sub.id);\n ctx.subs.delete(group.sub.id);\n group.sub.closed = true;\n}\n\nexport function detachLive(ctx: LiveCtx, fp: string, handle: Subscription): void {\n const group = ctx.liveByFp.get(fp);\n if (!group) {\n return;\n }\n if (!group.attachments.delete(handle)) {\n return;\n }\n if (group.attachments.size > 0) {\n return;\n }\n endLiveGroup(ctx, fp, { sendClose: true, reason: \"closed by client\" });\n}\n\nexport function endLiveGroup(\n ctx: LiveCtx,\n fp: string,\n opts: { sendClose: boolean; reason: string },\n): void {\n const group = ctx.liveByFp.get(fp);\n if (!group) {\n return;\n }\n const { id } = group.sub;\n const remaining = [...group.attachments];\n group.attachments.clear();\n forgetLiveGroup(ctx, group);\n if (opts.sendClose) {\n try {\n if (ctx.connected()) {\n ctx.send([\"CLOSE\", id]);\n }\n } catch {\n // ignore\n }\n }\n for (const att of remaining) {\n invokeSafely(() => {\n att.close(opts.reason);\n });\n }\n}\n\nexport function deliverLiveEvent(ctx: LiveCtx, group: LiveGroup, event: Event): void {\n const { sub } = group;\n const attachments = [...group.attachments];\n for (const att of attachments) {\n invokeSafely(() => {\n att.handlers.receivedEvent?.(event.id);\n });\n }\n if (sub.idsAtWatermark.has(event.id)) {\n return;\n }\n\n const recipients: Subscription[] = [];\n for (const att of attachments) {\n if (att.closed) {\n continue;\n }\n let skip = false;\n invokeSafely(() => {\n skip = Boolean(att.handlers.alreadyHaveEvent?.(event.id));\n });\n if (!skip) {\n recipients.push(att);\n }\n }\n if (recipients.length === 0) {\n return;\n }\n if (!ctx.acceptEvent(event)) {\n return;\n }\n\n sub.noteVerified(event);\n for (const att of recipients) {\n att.noteVerified(event);\n }\n for (const att of recipients) {\n invokeSafely(() => {\n att.handlers.onevent?.(event);\n });\n }\n}\n\nexport function deliverLiveEose(group: LiveGroup): void {\n const attachments = [...group.attachments];\n for (const att of attachments) {\n if (att.closed || att.eosed) {\n continue;\n }\n att.eosed = true;\n invokeSafely(() => {\n att.handlers.oneose?.();\n });\n }\n}\n\nexport function closeAllSubscriptions(ctx: LiveCtx, reason: string): void {\n const fps = [...ctx.liveByFp.keys()];\n for (const fp of fps) {\n invokeSafely(() => {\n endLiveGroup(ctx, fp, { sendClose: false, reason });\n });\n }\n for (const sub of ctx.subs.values()) {\n if (!sub.closed) {\n sub.closed = true;\n invokeSafely(() => {\n sub.handlers.onclose?.(reason);\n });\n }\n }\n ctx.subs.clear();\n ctx.liveByFp.clear();\n ctx.liveBySubId.clear();\n}\n\nexport function dropSubscription(ctx: LiveCtx, sub: Subscription, reason: string): void {\n const group = ctx.liveBySubId.get(sub.id);\n if (group) {\n endLiveGroup(ctx, group.fp, { sendClose: false, reason });\n return;\n }\n ctx.subs.delete(sub.id);\n sub.closed = true;\n invokeSafely(() => {\n sub.handlers.onclose?.(reason);\n });\n}\n\nexport function onSubEvent(ctx: LiveCtx, subId: string, event: Event): void {\n const sub = ctx.subs.get(subId);\n if (!sub || sub.closed) {\n return;\n }\n const group = ctx.liveBySubId.get(subId);\n if (group) {\n deliverLiveEvent(ctx, group, event);\n return;\n }\n invokeSafely(() => {\n sub.handlers.receivedEvent?.(event.id);\n });\n if (sub.idsAtWatermark.has(event.id)) {\n return;\n }\n let have = false;\n invokeSafely(() => {\n have = Boolean(sub.handlers.alreadyHaveEvent?.(event.id));\n });\n if (have) {\n return;\n }\n if (!ctx.acceptEvent(event)) {\n return;\n }\n sub.noteVerified(event);\n invokeSafely(() => {\n sub.handlers.onevent?.(event);\n });\n}\n\nexport function onSubEose(ctx: LiveCtx, subId: string): void {\n const sub = ctx.subs.get(subId);\n if (!sub || sub.closed) {\n return;\n }\n if (sub.eosed) {\n return;\n }\n sub.eosed = true;\n const group = ctx.liveBySubId.get(subId);\n if (group) {\n deliverLiveEose(group);\n } else {\n invokeSafely(() => {\n sub.handlers.oneose?.();\n });\n if (sub.closeOnEose) {\n sub.close(\"eose\");\n }\n }\n}\n\nexport function resubscribeAll(ctx: LiveCtx): boolean {\n for (const sub of ctx.subs.values()) {\n if (sub.closed) {\n continue;\n }\n sub.eosed = false;\n sub.authRetried = false;\n const group = ctx.liveBySubId.get(sub.id);\n if (group) {\n for (const att of group.attachments) {\n att.eosed = false;\n }\n }\n try {\n ctx.send([\"REQ\", sub.id, ...sub.replayFilters()]);\n } catch {\n return false;\n }\n }\n return true;\n}\n\nexport function streamFilters(\n subscribe: (filters: Filter[], opts: SubscribeOptions) => Subscription,\n filters: Filter[],\n opts?: { signal?: AbortSignal | undefined; id?: string | undefined },\n): AsyncIterable<Event> & { close: (reason?: string) => void } {\n return subscriptionToAsyncIterable(\n (handlers) => subscribe(filters, { ...handlers, id: opts?.id, signal: opts?.signal }),\n { signal: opts?.signal },\n );\n}\n\nexport async function fetchFilters(\n subscribe: (filters: Filter[], opts: SubscribeOptions) => Subscription,\n filters: Filter[],\n opts: {\n timeoutMs: number;\n signal?: AbortSignal | undefined;\n id?: string | undefined;\n url: string;\n },\n): Promise<Event[]> {\n throwIfAborted(opts.signal);\n const events: Event[] = [];\n const seen = new Set<string>();\n\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n const done = (err?: unknown) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n let reason = \"aborted\";\n if (err instanceof Error) {\n reason = err.message;\n } else if (err === undefined) {\n reason = \"fetch complete\";\n }\n sub.close(reason);\n if (err === undefined) {\n resolve();\n } else {\n // oxlint-disable-next-line typescript/prefer-promise-reject-errors -- forwards abort/signal reasons verbatim\n reject(err);\n }\n };\n\n const timer = setTimeout(() => done(), opts.timeoutMs);\n\n const sub = subscribe(filters, {\n id: opts.id,\n signal: opts.signal,\n closeOnEose: true,\n onevent(event) {\n if (seen.has(event.id)) {\n return;\n }\n seen.add(event.id);\n events.push(event);\n },\n oneose() {\n done();\n },\n onclose() {\n // The Subscription's own abort listener may close it before ours runs;\n // an aborted signal still rejects the fetch with the signal's reason.\n if (!settled) {\n done(opts.signal?.aborted === true ? abortReason(opts.signal) : undefined);\n }\n },\n });\n\n opts.signal?.addEventListener(\n \"abort\",\n () => done(opts.signal ? abortReason(opts.signal) : undefined),\n { once: true },\n );\n });\n\n return events;\n}\n\nexport function armEoseTimeout(sub: Subscription, eoseTimeoutMs: number): void {\n const timer = setTimeout(() => {\n if (sub.eosed || sub.closed) {\n return;\n }\n sub.eosed = true;\n invokeSafely(() => {\n sub.handlers.oneose?.();\n });\n }, eoseTimeoutMs);\n const prevClose = sub.handlers.onclose;\n // oxlint-disable-next-line unicorn/prefer-add-event-listener -- SubscriptionHandlers is a callback record, not an EventTarget\n sub.handlers.onclose = (reason) => {\n clearTimeout(timer);\n prevClose?.(reason);\n };\n const prevEose = sub.handlers.oneose;\n sub.handlers.oneose = () => {\n clearTimeout(timer);\n prevEose?.();\n };\n}\n","import { abortReason, raceSignal, throwIfAborted } from \"../core/abort.ts\";\nimport { MessageError, WasmVerifyPoisonedError } from \"../core/error.ts\";\nimport type { Event, EventTemplate } from \"../core/event.ts\";\nimport { canonicalizeFilter, canonicalizeFilters } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport {\n assertSubscriptionId,\n createSubscriptionId,\n encodeClientMessage,\n parseRelayMessage,\n} from \"../core/message.ts\";\nimport type { ClientMessage, CountResult, SubscriptionId } from \"../core/message.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport { isAuthRequired, makeAuthEvent } from \"../nips/nip42.ts\";\nimport { Nip77Error } from \"../nips/nip77.ts\";\nimport type { NegentropyStorageVector } from \"../nips/nip77.ts\";\nimport { NoSignerError } from \"../signer/error.ts\";\nimport {\n RelayClosedError,\n RelayConnectionError,\n RelayError,\n RelayPublishError,\n RelayTimeoutError,\n} from \"./error.ts\";\nimport {\n createNegSession,\n failNegErr,\n failNegSession,\n pushNegMsg,\n runWiredNegSession,\n} from \"./neg-session.ts\";\nimport type { NegSession } from \"./neg-session.ts\";\nimport { DEFAULT_PING_INTERVAL_MS, DEFAULT_PING_TIMEOUT_MS, PingLoop } from \"./ping.ts\";\nimport {\n armEoseTimeout,\n closeAllSubscriptions,\n dropSubscription,\n fetchFilters,\n onSubEose,\n onSubEvent,\n openExclusive,\n resubscribeAll,\n streamFilters,\n subscribeLive,\n} from \"./subscribe.ts\";\nimport type { LiveCtx, LiveGroup } from \"./subscribe.ts\";\nimport type { SubscribeOptions, Subscription } from \"./subscription.ts\";\nimport { getWebSocketImplementation } from \"./websocket.ts\";\nimport type { WebSocketConstructor, WebSocketLike } from \"./websocket.ts\";\n\n/** Relay lifecycle states. */\nexport const RelayStatus = {\n Initialized: \"initialized\",\n Connecting: \"connecting\",\n Connected: \"connected\",\n Disconnected: \"disconnected\",\n Closed: \"closed\",\n} as const;\n/** Union of the {@link RelayStatus} values. */\nexport type RelayStatusName = (typeof RelayStatus)[keyof typeof RelayStatus];\n\n/** Per-relay options: socket override, verification, timeouts, reconnect, ping, NIP-42 auth. */\nexport type RelayOptions = {\n websocketImplementation?: WebSocketConstructor | undefined;\n verifyEvent?: ((event: Event) => boolean) | undefined;\n publishTimeoutMs?: number | undefined;\n connectTimeoutMs?: number | undefined;\n /**\n * When true, unexpected disconnects schedule reconnect with backoff and re-fire open\n * subscriptions. Default false.\n */\n enableReconnect?: boolean | undefined;\n /** Backoff delays in ms between reconnect attempts. */\n reconnectBackoffMs?: number[] | undefined;\n enablePing?: boolean | undefined;\n pingIntervalMs?: number | undefined;\n pingTimeoutMs?: number | undefined;\n /** When set, CLOSED/OK `auth-required:` triggers AUTH then retries the REQ/EVENT/COUNT. */\n authSigner?: ((template: EventTemplate) => Promise<Event>) | undefined;\n};\n\n/** A relay's NIP-01 OK reply to a published event. */\nexport type PublishResult = {\n ok: boolean;\n message: string;\n};\n\ntype PublishWaiter = {\n resolve: (result: PublishResult) => void;\n reject: (err: Error) => void;\n timer: ReturnType<typeof setTimeout> | undefined;\n event?: Event;\n authRetried?: boolean;\n timeoutMs: number;\n};\n\ntype CountWaiter = {\n resolve: (result: CountResult) => void;\n reject: (err: unknown) => void;\n timer: ReturnType<typeof setTimeout> | undefined;\n filters: Filter[];\n authRetried: boolean;\n timeoutMs: number;\n};\n\ntype SocketHandlers = {\n onOpen: () => void;\n onError: () => void;\n onClose: () => void;\n onMessage: (ev: unknown) => void;\n ws: WebSocketLike;\n};\n\nconst DEFAULT_BACKOFF = [1000, 2000, 5000, 10_000, 20_000, 30_000, 60_000];\n\nconst noop = (): void => {\n // placeholder until the Promise executor captures resolve/reject\n};\n\n/**\n * Single-relay NIP-01 client. Connection lifecycle, REQ/CLOSE, EVENT publish ACK, AUTH, COUNT,\n * NIP-77, optional reconnect.\n */\nexport class Relay {\n readonly url: string;\n #ws: WebSocketLike | undefined;\n #connected = false;\n #gen = 0;\n #status: RelayStatusName = RelayStatus.Initialized;\n #connecting: Promise<void> | undefined;\n #connectFinish: ((err?: unknown) => void) | undefined;\n #connectTimer: ReturnType<typeof setTimeout> | undefined;\n #socketHandlers: SocketHandlers | undefined;\n readonly #subs = new Map<SubscriptionId, Subscription>();\n readonly #liveByFp = new Map<string, LiveGroup>();\n readonly #liveBySubId = new Map<SubscriptionId, LiveGroup>();\n readonly #live: LiveCtx;\n readonly #publishes = new Map<string, PublishWaiter>();\n readonly #counts = new Map<string, CountWaiter>();\n readonly #neg = new Map<SubscriptionId, NegSession>();\n readonly #WS: WebSocketConstructor;\n readonly #verify: (event: Event) => boolean;\n #verifyDead = false;\n readonly #publishTimeoutMs: number;\n readonly #connectTimeoutMs: number;\n readonly #enableReconnect: boolean;\n readonly #backoff: number[];\n #serial = 0;\n #challenge: string | undefined;\n #authedChallenge: string | undefined;\n /** Challenge value already answered on this connection; duplicates are not re-signed. */\n #answeredChallenge: string | undefined;\n /** Settled OK verdict for `#answeredChallenge`; set only once the relay replies. */\n #answeredResult: PublishResult | undefined;\n #authPromise: Promise<PublishResult> | undefined;\n readonly #authSigner: ((template: EventTemplate) => Promise<Event>) | undefined;\n #intentionalClose = false;\n #reconnectAttempts = 0;\n #reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n #skipReconnect = false;\n /** Collapses error+close pairs into a single terminal/reconnect action. */\n #deathHandled = false;\n readonly #enablePing: boolean;\n readonly #ping: PingLoop;\n\n onnotice: ((msg: string) => void) | undefined;\n onclose: (() => void) | undefined;\n /** Fired when the relay sends a NIP-42 AUTH challenge. */\n onauth: ((challenge: string) => void) | undefined;\n /** Fired after a successful reconnect (not the initial connect). */\n onreconnect: (() => void) | undefined;\n /**\n * Fired when a delivered EVENT fails id/signature verification, just before the event is dropped.\n * A poisoned verifier dropping events does not fire it.\n */\n oninvalidevent: (() => void) | undefined;\n\n constructor(url: string, opts: RelayOptions = {}) {\n this.url = normalizeURL(url);\n this.#WS = opts.websocketImplementation ?? getWebSocketImplementation();\n this.#verify = opts.verifyEvent ?? verifyEvent;\n this.#publishTimeoutMs = opts.publishTimeoutMs ?? 4400;\n this.#connectTimeoutMs = opts.connectTimeoutMs ?? 5000;\n this.#enableReconnect = opts.enableReconnect ?? false;\n this.#backoff = opts.reconnectBackoffMs ?? DEFAULT_BACKOFF;\n this.#enablePing = opts.enablePing ?? false;\n this.#authSigner = opts.authSigner;\n this.#ping = new PingLoop({\n send: (message) => this.#send(message),\n nextSubId: (prefix) => this.nextSubId(prefix),\n getWs: () => this.#ws,\n closeWs: () => {\n const ws = this.#ws;\n if (ws && ws.readyState === this.#WS.OPEN) {\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n },\n pingIntervalMs: opts.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS,\n pingTimeoutMs: opts.pingTimeoutMs ?? DEFAULT_PING_TIMEOUT_MS,\n });\n this.#live = {\n liveByFp: this.#liveByFp,\n liveBySubId: this.#liveBySubId,\n subs: this.#subs,\n connected: () => this.#connected,\n enableReconnect: () => this.#enableReconnect,\n send: (message) => this.#send(message),\n scheduleReconnect: () => this.#scheduleReconnect(),\n acceptEvent: (event) => this.#acceptEvent(event),\n armEoseTimeout,\n };\n }\n\n /** Latest NIP-42 challenge, if any. */\n get challenge(): string | undefined {\n return this.#challenge;\n }\n\n get connected(): boolean {\n return this.#connected;\n }\n\n get status(): RelayStatusName {\n return this.#status;\n }\n\n get generation(): number {\n return this.#gen;\n }\n\n get reconnectEnabled(): boolean {\n return this.#enableReconnect;\n }\n\n /** User subscriptions only; dummy ping REQs are not counted. */\n get subscriptionCount(): number {\n return this.#subs.size;\n }\n\n /** One-shot requests still awaiting a relay reply (EVENT ACK, COUNT, NEG). */\n get inFlightCount(): number {\n return this.#publishes.size + this.#counts.size + this.#neg.size;\n }\n\n static async connect(\n url: string,\n opts?: RelayOptions & { signal?: AbortSignal },\n ): Promise<Relay> {\n const relay = new Relay(url, opts);\n await relay.connect({ signal: opts?.signal });\n return relay;\n }\n\n async connect(opts?: {\n signal?: AbortSignal | undefined;\n timeoutMs?: number | undefined;\n }): Promise<void> {\n if (this.#connected) {\n return;\n }\n // A connect attempt is never owned by a caller's signal: joiners race\n // their own signal against the shared attempt; only close() cancels it.\n if (this.#connecting) {\n await raceSignal(this.#connecting, opts?.signal);\n return;\n }\n throwIfAborted(opts?.signal);\n\n const gen = ++this.#gen;\n this.#intentionalClose = false;\n this.#skipReconnect = false;\n this.#deathHandled = false;\n this.#clearReconnectTimer();\n this.#status = RelayStatus.Connecting;\n\n const timeoutMs = opts?.timeoutMs ?? this.#connectTimeoutMs;\n const isReconnect = this.#reconnectAttempts > 0;\n\n let resolveConnect: () => void = noop;\n let rejectConnect: (err: unknown) => void = noop;\n let settled = false;\n let ws: WebSocketLike | undefined;\n\n const connecting = new Promise<void>((resolve, reject) => {\n resolveConnect = resolve;\n rejectConnect = reject;\n });\n\n const release = (): void => {\n if (ws === undefined) {\n return;\n }\n try {\n ws.removeEventListener(\"open\", handlers.onOpen);\n ws.removeEventListener(\"error\", handlers.onError);\n ws.removeEventListener(\"close\", handlers.onClose);\n ws.removeEventListener(\"message\", handlers.onMessage);\n } catch {\n // ignore\n }\n if (this.#socketHandlers === handlers) {\n this.#socketHandlers = undefined;\n }\n try {\n if (ws.readyState !== this.#WS.CLOSED && ws.readyState !== this.#WS.CLOSING) {\n ws.close();\n }\n } catch {\n // ignore\n }\n if (this.#ws === ws) {\n this.#ws = undefined;\n }\n };\n\n const finish = (err?: unknown): void => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n if (this.#connectTimer === timer) {\n this.#connectTimer = undefined;\n }\n if (this.#connectFinish === finish) {\n this.#connectFinish = undefined;\n }\n if (this.#connecting === connecting) {\n this.#connecting = undefined;\n }\n if (err === undefined) {\n resolveConnect();\n } else {\n rejectConnect(err);\n }\n };\n\n this.#connecting = connecting;\n this.#connectFinish = finish;\n\n const timer = setTimeout(() => {\n if (gen !== this.#gen) {\n release();\n return;\n }\n if (!isReconnect && !this.#enableReconnect) {\n this.#skipReconnect = true;\n }\n release();\n finish(new RelayTimeoutError(\"connection timed out\", this.url));\n if (gen === this.#gen) {\n this.#handleSocketDeath(\"connection timed out\", { fromConnectAttempt: true, gen });\n }\n }, timeoutMs);\n this.#connectTimer = timer;\n\n try {\n ws = new this.#WS(this.url);\n } catch (error) {\n if (!isReconnect && !this.#enableReconnect) {\n this.#skipReconnect = true;\n }\n finish(error);\n if (gen === this.#gen) {\n this.#handleSocketDeath(\"connection failed\", { fromConnectAttempt: true, gen });\n }\n await raceSignal(connecting, opts?.signal);\n return;\n }\n this.#ws = ws;\n\n const onOpen = (): void => {\n if (gen !== this.#gen) {\n release();\n return;\n }\n this.#connected = true;\n this.#status = RelayStatus.Connected;\n this.#deathHandled = false;\n const wasReconnect = this.#reconnectAttempts > 0;\n this.#challenge = undefined;\n this.#authPromise = undefined;\n this.#authedChallenge = undefined;\n this.#answeredChallenge = undefined;\n this.#answeredResult = undefined;\n if (!resubscribeAll(this.#live)) {\n this.#connected = false;\n this.#status = RelayStatus.Disconnected;\n if (!isReconnect && !this.#enableReconnect) {\n this.#skipReconnect = true;\n }\n release();\n finish(new RelayConnectionError(\"connection failed\", this.url));\n if (\n this.#enableReconnect &&\n !this.#intentionalClose &&\n !this.#skipReconnect &&\n this.#subs.size > 0\n ) {\n this.#scheduleReconnect();\n }\n return;\n }\n this.#reconnectAttempts = 0;\n if (this.#enablePing) {\n this.#ping.start();\n } else {\n this.#ping.stop();\n }\n if (wasReconnect) {\n invokeSafely(() => this.onreconnect?.());\n }\n finish();\n };\n const onError = (): void => {\n if (gen !== this.#gen) {\n release();\n return;\n }\n this.#connected = false;\n const fromConnectAttempt = !settled;\n if (!settled && !isReconnect && !this.#enableReconnect) {\n this.#skipReconnect = true;\n }\n release();\n finish(new RelayConnectionError(\"connection failed\", this.url));\n if (gen === this.#gen) {\n this.#handleSocketDeath(\"connection failed\", { fromConnectAttempt, gen });\n }\n };\n const onClose = (): void => {\n if (gen !== this.#gen) {\n release();\n return;\n }\n this.#connected = false;\n const fromConnectAttempt = !settled;\n if (!settled && !isReconnect && !this.#enableReconnect) {\n this.#skipReconnect = true;\n }\n release();\n if (fromConnectAttempt) {\n finish(new RelayConnectionError(\"websocket closed\", this.url));\n }\n if (gen === this.#gen) {\n this.#handleSocketDeath(\"websocket closed\", { fromConnectAttempt, gen });\n }\n };\n const onMessage = (ev: unknown): void => {\n if (gen !== this.#gen) {\n return;\n }\n const data = typeof ev === \"object\" && ev !== null && \"data\" in ev ? ev.data : ev;\n this.#onMessage(String(data));\n };\n\n const handlers: SocketHandlers = { onOpen, onError, onClose, onMessage, ws };\n this.#socketHandlers = handlers;\n ws.addEventListener(\"open\", onOpen);\n ws.addEventListener(\"error\", onError);\n ws.addEventListener(\"close\", onClose);\n ws.addEventListener(\"message\", onMessage);\n\n await raceSignal(connecting, opts?.signal);\n }\n\n #detachSocketHandlers(): void {\n const h = this.#socketHandlers;\n if (!h) {\n return;\n }\n try {\n h.ws.removeEventListener(\"open\", h.onOpen);\n h.ws.removeEventListener(\"error\", h.onError);\n h.ws.removeEventListener(\"close\", h.onClose);\n h.ws.removeEventListener(\"message\", h.onMessage);\n } catch {\n // ignore\n }\n this.#socketHandlers = undefined;\n }\n\n /** Graceful shutdown: disables reconnect and closes all subscriptions. */\n close(): void {\n this.#gen += 1;\n this.#status = RelayStatus.Closed;\n this.#intentionalClose = true;\n this.#skipReconnect = true;\n this.#clearReconnectTimer();\n if (this.#connectTimer !== undefined) {\n clearTimeout(this.#connectTimer);\n this.#connectTimer = undefined;\n }\n this.#ping.stop();\n this.#connectFinish?.(new RelayClosedError(\"relay closed\", this.url));\n try {\n closeAllSubscriptions(this.#live, \"relay closed\");\n } finally {\n this.#rejectPublishes(new RelayClosedError(\"relay closed\", this.url));\n this.#rejectCounts(new RelayClosedError(\"relay closed\", this.url));\n this.#rejectNeg(new RelayClosedError(\"relay closed\", this.url));\n this.#detachSocketHandlers();\n this.#teardownSocket();\n this.#connected = false;\n invokeSafely(() => this.onclose?.());\n }\n }\n\n /**\n * Sever the socket while keeping every subscription: unlike {@link close}, open REQ state is\n * preserved and reconnect stays suppressed — the next {@link connect} re-subscribes all of them.\n * {@link Pool} uses this to suspend a relay without tearing down its live subscriptions.\n */\n disconnect(): void {\n this.#gen += 1;\n this.#status = RelayStatus.Disconnected;\n this.#intentionalClose = true;\n this.#skipReconnect = true;\n this.#clearReconnectTimer();\n if (this.#connectTimer !== undefined) {\n clearTimeout(this.#connectTimer);\n this.#connectTimer = undefined;\n }\n this.#ping.stop();\n this.#connectFinish?.(new RelayClosedError(\"relay disconnected\", this.url));\n this.#rejectPublishes(new RelayClosedError(\"relay disconnected\", this.url));\n this.#rejectCounts(new RelayClosedError(\"relay disconnected\", this.url));\n this.#rejectNeg(new RelayClosedError(\"relay disconnected\", this.url));\n this.#detachSocketHandlers();\n this.#teardownSocket();\n this.#connected = false;\n }\n\n #teardownSocket(): void {\n try {\n this.#ws?.close();\n } catch {\n // ignore\n }\n this.#ws = undefined;\n }\n\n #clearReconnectTimer(): void {\n if (this.#reconnectTimer !== undefined) {\n clearTimeout(this.#reconnectTimer);\n this.#reconnectTimer = undefined;\n }\n }\n\n #rejectPublishes(err: Error): void {\n for (const [, waiter] of this.#publishes) {\n clearTimeout(waiter.timer);\n waiter.reject(err);\n }\n this.#publishes.clear();\n }\n\n #rejectCounts(err: Error): void {\n for (const [, waiter] of this.#counts) {\n clearTimeout(waiter.timer);\n waiter.reject(err);\n }\n this.#counts.clear();\n }\n\n #rejectNeg(err: Error): void {\n for (const session of this.#neg.values()) {\n failNegSession(session, err);\n }\n this.#neg.clear();\n }\n\n /** Unexpected socket death. Keep subscriptions if reconnecting. */\n #handleSocketDeath(reason: string, opts: { fromConnectAttempt?: boolean; gen: number }): void {\n if (opts.gen !== this.#gen) {\n return;\n }\n if (this.#deathHandled) {\n return;\n }\n this.#deathHandled = true;\n this.#ping.stop();\n this.#detachSocketHandlers();\n this.#connected = false;\n this.#ws = undefined;\n this.#rejectPublishes(new RelayClosedError(reason, this.url));\n this.#rejectCounts(new RelayClosedError(reason, this.url));\n this.#rejectNeg(new RelayClosedError(reason, this.url));\n\n const canReconnect =\n this.#enableReconnect &&\n !this.#intentionalClose &&\n !this.#skipReconnect &&\n this.#subs.size > 0;\n\n if (canReconnect) {\n this.#status = RelayStatus.Disconnected;\n this.#scheduleReconnect();\n return;\n }\n\n if (!this.#intentionalClose) {\n this.#status = RelayStatus.Disconnected;\n }\n\n if (opts.fromConnectAttempt !== true || this.#subs.size > 0) {\n closeAllSubscriptions(this.#live, reason);\n if (!this.#intentionalClose) {\n invokeSafely(() => this.onclose?.());\n }\n }\n\n this.#status = RelayStatus.Closed;\n }\n\n #scheduleReconnect(): void {\n if (this.#reconnectTimer !== undefined) {\n return;\n }\n if (this.#connected) {\n return;\n }\n const delay =\n this.#backoff[Math.min(this.#reconnectAttempts, this.#backoff.length - 1)] ?? 60_000;\n this.#reconnectAttempts += 1;\n this.#reconnectTimer = setTimeout(() => {\n this.#reconnectTimer = undefined;\n if (this.#intentionalClose || this.#connected) {\n return;\n }\n void (async (): Promise<void> => {\n try {\n await this.connect();\n } catch {\n if (\n this.#enableReconnect &&\n !this.#intentionalClose &&\n !this.#skipReconnect &&\n this.#subs.size > 0 &&\n !this.#connected\n ) {\n this.#scheduleReconnect();\n }\n }\n })();\n }, delay);\n }\n\n #send(message: ClientMessage | string): void {\n if (!this.#ws || !this.#connected) {\n throw new RelayClosedError(\"not connected\", this.url);\n }\n const raw = typeof message === \"string\" ? message : encodeClientMessage(message);\n this.#ws.send(raw);\n }\n\n #onMessage(raw: string): void {\n let msg;\n try {\n msg = parseRelayMessage(raw);\n } catch {\n return;\n }\n\n switch (msg[0]) {\n case \"EVENT\": {\n const [, subId, event] = msg;\n if (this.#ping.hasWaiter(subId)) {\n return;\n }\n onSubEvent(this.#live, subId, event);\n break;\n }\n case \"EOSE\": {\n const [, subId] = msg;\n if (this.#ping.finishDummyPing(subId)) {\n return;\n }\n onSubEose(this.#live, subId);\n break;\n }\n case \"CLOSED\": {\n const [, subId, reason] = msg;\n if (this.#ping.finishDummyPing(subId)) {\n return;\n }\n const countWaiter = this.#counts.get(subId);\n if (countWaiter) {\n if (isAuthRequired(reason) && this.#authSigner && !countWaiter.authRetried) {\n countWaiter.authRetried = true;\n void this.#authThenRecount(subId, countWaiter, reason);\n return;\n }\n countWaiter.reject(new RelayClosedError(reason || \"COUNT closed\", this.url));\n return;\n }\n const sub = this.#subs.get(subId);\n if (!sub) {\n return;\n }\n if (isAuthRequired(reason) && this.#authSigner && !sub.authRetried) {\n sub.authRetried = true;\n void this.#authThenResubscribe(sub, reason);\n return;\n }\n dropSubscription(this.#live, sub, reason);\n break;\n }\n case \"OK\": {\n const [, eventId, ok, message] = msg;\n const waiter = this.#publishes.get(eventId);\n if (!waiter) {\n return;\n }\n if (\n !ok &&\n isAuthRequired(message) &&\n waiter.event !== undefined &&\n waiter.authRetried !== true &&\n this.#authSigner\n ) {\n waiter.authRetried = true;\n void this.#authThenRepublish(waiter, eventId, message);\n return;\n }\n clearTimeout(waiter.timer);\n this.#publishes.delete(eventId);\n waiter.resolve({ ok, message });\n break;\n }\n case \"COUNT\": {\n const [, countId, payload] = msg;\n const waiter = this.#counts.get(countId);\n if (!waiter) {\n return;\n }\n waiter.resolve(payload);\n break;\n }\n case \"NEG-MSG\": {\n const [, negId, hex] = msg;\n const session = this.#neg.get(negId);\n if (!session) {\n return;\n }\n pushNegMsg(session, hex);\n break;\n }\n case \"NEG-ERR\": {\n const [, negId, reason] = msg;\n const session = this.#neg.get(negId);\n if (!session) {\n return;\n }\n failNegErr(session, reason);\n break;\n }\n case \"NOTICE\": {\n const [, notice] = msg;\n invokeSafely(() => this.onnotice?.(notice));\n break;\n }\n case \"AUTH\": {\n const [, authChallenge] = msg;\n // A re-sent identical challenge keeps the in-flight/settled dedupe;\n // only a new challenge value resets the answer state.\n if (authChallenge !== this.#challenge) {\n this.#authPromise = undefined;\n this.#authedChallenge = undefined;\n this.#answeredChallenge = undefined;\n this.#answeredResult = undefined;\n }\n this.#challenge = authChallenge;\n invokeSafely(() => this.onauth?.(authChallenge));\n break;\n }\n }\n }\n\n /** Low-level REQ with callbacks. Survives reconnect when enableReconnect is on. */\n subscribe(filters: Filter[], opts: SubscribeOptions = {}): Subscription {\n if (filters.length === 0) {\n throw new MessageError(\"REQ requires at least one filter\");\n }\n if (!this.#connected && !this.#enableReconnect) {\n throw new RelayClosedError(\"not connected\", this.url);\n }\n const canonical = canonicalizeFilters(filters);\n if (opts.closeOnEose === true) {\n return openExclusive(this.#live, canonical, opts);\n }\n return subscribeLive(this.#live, canonical, opts);\n }\n\n #acceptEvent(event: Event): boolean {\n if (this.#verifyDead) {\n return false;\n }\n try {\n const ok = this.#verify(event);\n if (!ok) {\n invokeSafely(() => this.oninvalidevent?.());\n }\n return ok;\n } catch (error) {\n if (error instanceof WasmVerifyPoisonedError || error instanceof WebAssembly.RuntimeError) {\n this.#verifyDead = true;\n invokeSafely(() => this.onnotice?.(\"verify-poisoned: wasm instance aborted\"));\n return false;\n }\n throw error;\n }\n }\n\n /** AsyncIterable of events for filters until the subscription is closed. */\n stream(\n filters: Filter[],\n opts?: { signal?: AbortSignal; id?: string },\n ): AsyncIterable<Event> & {\n close: (reason?: string) => void;\n } {\n return streamFilters((f, o) => this.subscribe(f, o), filters, opts);\n }\n\n /** One-shot query: collect events until EOSE or timeout, then close. */\n async fetch(\n filters: Filter[],\n opts?: {\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n id?: string | undefined;\n },\n ): Promise<Event[]> {\n if (filters.length === 0) {\n throw new MessageError(\"REQ requires at least one filter\");\n }\n const canonical = canonicalizeFilters(filters);\n if (!this.#connected) {\n await this.connect({ signal: opts?.signal });\n }\n return fetchFilters((f, o) => this.subscribe(f, o), canonical, {\n timeoutMs: opts?.timeoutMs ?? 4400,\n signal: opts?.signal,\n id: opts?.id,\n url: this.url,\n });\n }\n\n /** Publish an event and wait for OK. */\n async publish(event: Event, opts?: { timeoutMs?: number | undefined }): Promise<PublishResult> {\n if (!this.#connected) {\n throw new RelayClosedError(\"not connected\", this.url);\n }\n const timeoutMs = opts?.timeoutMs ?? this.#publishTimeoutMs;\n\n const result = await new Promise<PublishResult>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#publishes.delete(event.id);\n reject(new RelayTimeoutError(\"publish timed out\", this.url));\n }, timeoutMs);\n this.#publishes.set(event.id, { resolve, reject, timer, event, timeoutMs });\n try {\n this.#send([\"EVENT\", event]);\n } catch (error) {\n clearTimeout(timer);\n this.#publishes.delete(event.id);\n reject(error instanceof Error ? error : new RelayPublishError(\"publish failed\", this.url));\n }\n });\n\n return result;\n }\n\n /**\n * NIP-45 COUNT: ask the relay how many events match `filters`. Resolves with the COUNT payload\n * (count / optional approximate / optional hll).\n */\n async count(\n filters: Filter[],\n opts?: {\n id?: string | undefined;\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n },\n ): Promise<CountResult> {\n if (!this.#connected) {\n throw new RelayClosedError(\"not connected\", this.url);\n }\n if (filters.length === 0) {\n throw new RelayError(\"COUNT requires at least one filter\", this.url);\n }\n throwIfAborted(opts?.signal);\n const canonical = canonicalizeFilters(filters);\n\n const id = opts?.id === undefined ? this.nextSubId(\"count\") : createSubscriptionId(opts.id);\n const timeoutMs = opts?.timeoutMs ?? this.#publishTimeoutMs;\n\n return new Promise<CountResult>((resolve, reject) => {\n const cleanup = () => {\n opts?.signal?.removeEventListener(\"abort\", onAbort);\n };\n const waiter: CountWaiter = {\n resolve: (result) => {\n if (waiter.timer !== undefined) {\n clearTimeout(waiter.timer);\n }\n waiter.timer = undefined;\n this.#counts.delete(id);\n cleanup();\n resolve(result);\n },\n reject: (err) => {\n if (waiter.timer !== undefined) {\n clearTimeout(waiter.timer);\n }\n waiter.timer = undefined;\n this.#counts.delete(id);\n cleanup();\n // oxlint-disable-next-line typescript/prefer-promise-reject-errors -- forwards abort/signal reasons verbatim\n reject(err);\n },\n timer: undefined,\n filters: [...canonical],\n authRetried: false,\n timeoutMs,\n };\n const onAbort = () => {\n if (opts?.signal) {\n waiter.reject(abortReason(opts.signal));\n }\n };\n waiter.timer = setTimeout(() => {\n waiter.reject(new RelayTimeoutError(\"count timed out\", this.url));\n }, timeoutMs);\n this.#counts.set(id, waiter);\n\n opts?.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n try {\n this.#send([\"COUNT\", id, ...canonical]);\n } catch (error) {\n waiter.reject(\n error instanceof Error ? error : new RelayPublishError(\"count failed\", this.url),\n );\n }\n });\n }\n\n /** NIP-42 AUTH: sign the current challenge and wait for OK. */\n async auth(\n sign: (template: EventTemplate) => Promise<Event>,\n opts?: { timeoutMs?: number | undefined },\n ): Promise<PublishResult> {\n const challenge = this.#challenge;\n if (challenge === undefined || challenge === \"\") {\n throw new RelayError(\"no AUTH challenge received from relay\", this.url);\n }\n if (this.#authPromise) {\n return this.#authPromise;\n }\n if (this.#answeredChallenge === challenge && this.#answeredResult !== undefined) {\n return this.#answeredResult;\n }\n\n const pending = (async () => {\n const template = makeAuthEvent(this.url, challenge);\n let event: Event;\n try {\n event = await sign(template);\n } catch (error) {\n // A lazy signer may legitimately have nothing to sign with; ignore the\n // challenge quietly — the connection stays open without an AUTH frame.\n if (error instanceof NoSignerError) {\n return { ok: false, message: \"auth: no signer\" };\n }\n throw error;\n }\n if (!this.#connected) {\n throw new RelayClosedError(\"not connected\", this.url);\n }\n const timeoutMs = opts?.timeoutMs ?? this.#publishTimeoutMs;\n\n return new Promise<PublishResult>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#publishes.delete(event.id);\n reject(new RelayTimeoutError(\"auth timed out\", this.url));\n }, timeoutMs);\n this.#publishes.set(event.id, {\n resolve: (result) => {\n // Cache the relay's settled verdict: a repeated challenge replays\n // it without re-signing. Timeouts and send failures never reach\n // here, so a later auth() signs again.\n if (this.#challenge === challenge) {\n this.#answeredChallenge = challenge;\n this.#answeredResult = result;\n }\n resolve(result);\n },\n reject,\n timer,\n timeoutMs,\n });\n try {\n this.#send([\"AUTH\", event]);\n } catch (error) {\n clearTimeout(timer);\n this.#publishes.delete(event.id);\n reject(\n error instanceof Error ? error : new RelayPublishError(\"auth send failed\", this.url),\n );\n }\n });\n })();\n this.#authPromise = pending;\n try {\n const result = await pending;\n if (result.ok && this.#challenge === challenge) {\n this.#authedChallenge = challenge;\n }\n return result;\n } finally {\n if (this.#authPromise === pending) {\n this.#authPromise = undefined;\n }\n }\n }\n\n /**\n * Clear a cached AUTH rejection for the current challenge so a later `auth()` signs again. A\n * successful auth and in-flight answers are kept. When a challenge is pending and unanswered,\n * `onauth` is re-fired so the pool's automatic auth can run once more.\n */\n resetAuth(): void {\n if (this.#answeredResult !== undefined && !this.#answeredResult.ok) {\n this.#answeredChallenge = undefined;\n this.#answeredResult = undefined;\n }\n if (this.#challenge !== undefined && this.#challenge !== this.#authedChallenge) {\n const challenge = this.#challenge;\n invokeSafely(() => this.onauth?.(challenge));\n }\n }\n\n async #ensureAuthed(): Promise<boolean> {\n const signer = this.#authSigner;\n if (!signer) {\n return false;\n }\n for (let i = 0; i < 3; i++) {\n if (this.#challenge === undefined || this.#challenge === \"\") {\n return false;\n }\n if (this.#authedChallenge === this.#challenge) {\n return true;\n }\n const signed = this.#challenge;\n // oxlint-disable-next-line no-await-in-loop -- auth retries are sequential: each round waits for the new AUTH challenge\n const result = await this.auth(signer);\n if (this.#authedChallenge === this.#challenge) {\n return true;\n }\n if (!result.ok) {\n if (this.#challenge === undefined || this.#challenge === \"\" || this.#challenge === signed) {\n return false;\n }\n continue;\n }\n }\n return this.#authedChallenge === this.#challenge;\n }\n\n async #authThenResubscribe(sub: Subscription, reason: string): Promise<void> {\n try {\n if (!(await this.#ensureAuthed())) {\n dropSubscription(this.#live, sub, reason);\n return;\n }\n if (sub.closed || !this.#connected) {\n dropSubscription(this.#live, sub, reason);\n return;\n }\n sub.eosed = false;\n const group = this.#liveBySubId.get(sub.id);\n if (group) {\n for (const att of group.attachments) {\n att.eosed = false;\n }\n }\n this.#send([\"REQ\", sub.id, ...sub.replayFilters()]);\n } catch {\n dropSubscription(this.#live, sub, reason);\n }\n }\n\n async #authThenRecount(id: string, waiter: CountWaiter, reason: string): Promise<void> {\n if (waiter.timer !== undefined) {\n clearTimeout(waiter.timer);\n waiter.timer = undefined;\n }\n const fail = () => {\n waiter.reject(new RelayClosedError(reason || \"COUNT closed\", this.url));\n };\n try {\n const ok = await this.#ensureAuthed();\n if (this.#counts.get(id) !== waiter) {\n return;\n }\n if (!ok) {\n fail();\n return;\n }\n if (!this.#connected) {\n fail();\n return;\n }\n waiter.timer = setTimeout(() => {\n waiter.reject(new RelayTimeoutError(\"count timed out\", this.url));\n }, waiter.timeoutMs);\n this.#send([\"COUNT\", id, ...waiter.filters]);\n } catch (error) {\n if (!this.#counts.has(id)) {\n return;\n }\n waiter.reject(\n error instanceof Error ? error : new RelayClosedError(reason || \"COUNT closed\", this.url),\n );\n }\n }\n\n async #authThenRepublish(waiter: PublishWaiter, eventId: string, message: string): Promise<void> {\n if (waiter.timer !== undefined) {\n clearTimeout(waiter.timer);\n waiter.timer = undefined;\n }\n const finish = (result: PublishResult) => {\n if (waiter.timer !== undefined) {\n clearTimeout(waiter.timer);\n }\n this.#publishes.delete(eventId);\n waiter.resolve(result);\n };\n try {\n if (!waiter.event) {\n finish({ ok: false, message });\n return;\n }\n const ok = await this.#ensureAuthed();\n if (this.#publishes.get(eventId) !== waiter) {\n return;\n }\n if (!ok) {\n finish({ ok: false, message });\n return;\n }\n if (!this.#connected) {\n finish({ ok: false, message });\n return;\n }\n waiter.timer = setTimeout(() => {\n this.#publishes.delete(eventId);\n waiter.reject(new RelayTimeoutError(\"publish timed out\", this.url));\n }, waiter.timeoutMs);\n this.#send([\"EVENT\", waiter.event]);\n } catch {\n if (!this.#publishes.has(eventId)) {\n return;\n }\n finish({ ok: false, message });\n }\n }\n\n /**\n * NIP-77: run Negentropy reconciliation against this relay. Returns the local-only (`have`) and\n * remote-only (`need`) event ids. Does not upload or download events.\n *\n * `timeoutMs` is a single wall-clock deadline for the whole session (`NEG-OPEN` through the last\n * `NEG-MSG`), not a per-message budget. Default: {@link RelayOptions.publishTimeoutMs}.\n */\n async negReconcile(\n filter: Filter,\n storage: NegentropyStorageVector,\n opts?: {\n id?: string | undefined;\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n },\n ): Promise<{ have: string[]; need: string[] }> {\n if (!this.#connected) {\n throw new RelayClosedError(\"not connected\", this.url);\n }\n throwIfAborted(opts?.signal);\n const canonical = canonicalizeFilter(filter);\n\n const id = opts?.id === undefined ? this.nextSubId(\"neg\") : assertSubscriptionId(opts.id);\n const timeoutMs = opts?.timeoutMs ?? this.#publishTimeoutMs;\n const prev = this.#neg.get(id);\n if (prev) {\n failNegSession(prev, new Nip77Error(\"closed: replaced by new NEG-OPEN\"));\n }\n const session = createNegSession();\n this.#neg.set(id, session);\n\n try {\n return await runWiredNegSession({\n session,\n storage,\n filter: canonical,\n id,\n timeoutMs,\n signal: opts?.signal,\n send: (message) => this.#send(message),\n url: this.url,\n });\n } finally {\n if (this.#neg.get(id) === session) {\n this.#neg.delete(id);\n try {\n this.#send([\"NEG-CLOSE\", id]);\n } catch {\n // connection already gone\n }\n }\n }\n }\n\n /** Generate a unique subscription id for this relay instance. */\n nextSubId(prefix = \"sub\"): string {\n this.#serial += 1;\n return `${prefix}:${this.#serial}`;\n }\n}\n\nexport type { CountResult } from \"../core/message.ts\";\nexport type { SubscribeOptions, SubscriptionHandlers } from \"./subscription.ts\";\n","import { abortReason, throwIfAborted } from \"../core/abort.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { RelayClosedError } from \"./error.ts\";\nimport type { Pool } from \"./pool.ts\";\nimport type { Relay } from \"./relay.ts\";\n\nexport type RoutedJob = {\n urls: ReadonlyArray<string>;\n filters: ReadonlyArray<Filter>;\n id?: string | undefined;\n};\n\nexport type FanInOptions = {\n /** First receipt only (deduped across jobs). `relayUrl` is the normalized relay URL. */\n onevent?: ((event: Event, relayUrl: string) => void) | undefined;\n oneose?: (() => void) | undefined;\n onclose?: ((reason: string) => void) | undefined;\n signal?: AbortSignal | undefined;\n /** Armed at fan-in only. Never forwarded to relay.subscribe. */\n eoseTimeoutMs?: number | undefined;\n alreadyHaveEvent?: ((id: string) => boolean) | undefined;\n /** Every receipt from every relay, including skipped duplicates. */\n receivedEvent?: ((id: string, relayUrl: string) => void) | undefined;\n closeOnEose?: boolean | undefined;\n /** Optional. ensureRelay uses Pool.#opts.connectTimeoutMs when omitted. */\n connectTimeoutMs?: number | undefined;\n};\n\n/**\n * Aggregate EOSE/close across routed jobs. One `seen` set. `pending` counts URL list entries\n * (duplicates included). `pendingEose` counts unique `jobIndex:url` keys.\n */\nexport function fanIn(\n pool: Pool,\n jobs: ReadonlyArray<RoutedJob>,\n opts: FanInOptions = {},\n): { close: (reason?: string) => void } {\n const seen = new Set<string>();\n const closers: Array<{ close: (reason?: string) => void }> = [];\n let closed = false;\n let eoseFired = false;\n let eoseTimer: ReturnType<typeof setTimeout> | undefined;\n const eoseDone = new Set<string>();\n const eoseAttempted = new Set<string>();\n let pendingEose = 0;\n let pending = 0;\n\n const fireEose = () => {\n if (closed || eoseFired) {\n return;\n }\n eoseFired = true;\n if (eoseTimer !== undefined) {\n clearTimeout(eoseTimer);\n eoseTimer = undefined;\n }\n invokeSafely(() => opts.oneose?.());\n };\n\n const markEose = (jobIndex: number, url: string) => {\n const key = `${jobIndex}:${url}`;\n if (eoseDone.has(key)) {\n return;\n }\n eoseDone.add(key);\n pendingEose -= 1;\n if (pendingEose === 0) {\n fireEose();\n }\n };\n\n const settleClose = () => {\n closed = true;\n if (eoseTimer !== undefined) {\n clearTimeout(eoseTimer);\n eoseTimer = undefined;\n }\n };\n\n const closeAll = (reason?: string) => {\n if (closed) {\n return;\n }\n settleClose();\n for (const c of closers) {\n c.close(reason);\n }\n invokeSafely(() => opts.onclose?.(reason ?? \"closed by client\"));\n };\n\n if (opts.signal?.aborted === true) {\n closed = true;\n invokeSafely(() => opts.onclose?.(\"aborted\"));\n return { close: closeAll };\n }\n\n opts.signal?.addEventListener(\"abort\", () => closeAll(\"aborted\"), { once: true });\n\n const failUrl = (jobIndex: number, key: string): void => {\n markEose(jobIndex, key);\n pending -= 1;\n if (pending <= 0 && closers.length === 0 && !closed) {\n settleClose();\n invokeSafely(() => opts.onclose?.(\"all relays failed\"));\n }\n };\n\n const attach = (relay: Relay, job: RoutedJob, jobIndex: number): void => {\n if (closed) {\n return;\n }\n const received = opts.receivedEvent;\n const sub = relay.subscribe([...job.filters], {\n id: jobs.length === 1 ? job.id : undefined,\n closeOnEose: opts.closeOnEose,\n alreadyHaveEvent: (id) => {\n let have = seen.has(id);\n invokeSafely(() => {\n have = have || Boolean(opts.alreadyHaveEvent?.(id));\n });\n return have;\n },\n receivedEvent:\n received === undefined ? undefined : (id) => invokeSafely(() => received(id, relay.url)),\n onevent: (event) => {\n seen.add(event.id);\n invokeSafely(() => opts.onevent?.(event, relay.url));\n },\n oneose: () => markEose(jobIndex, relay.url),\n onclose: (reason) => {\n markEose(jobIndex, relay.url);\n pending -= 1;\n if (pending <= 0 && !closed) {\n settleClose();\n invokeSafely(() => opts.onclose?.(reason));\n }\n },\n });\n closers.push(sub);\n };\n\n for (const [jobIndex, job] of jobs.entries()) {\n // Equivalent spellings of one relay URL attach exactly once per job.\n const jobUrls = new Set<string>();\n for (const url of job.urls) {\n let key: string;\n try {\n key = normalizeURL(url);\n } catch {\n key = url; // invalid URL: ensureRelay fails it like a dead relay\n }\n if (jobUrls.has(key)) {\n continue;\n }\n jobUrls.add(key);\n pending += 1;\n const eoseKey = `${jobIndex}:${key}`;\n if (!eoseAttempted.has(eoseKey)) {\n eoseAttempted.add(eoseKey);\n pendingEose += 1;\n }\n\n const tryAttach = (relay: Relay): void => {\n try {\n attach(relay, job, jobIndex);\n } catch (error) {\n if (error instanceof RelayClosedError) {\n failUrl(jobIndex, key);\n return;\n }\n throw error;\n }\n };\n\n void (async (): Promise<void> => {\n let relay: Relay;\n try {\n relay = await pool.ensureRelay(key, {\n signal: opts.signal,\n timeoutMs: opts.connectTimeoutMs,\n });\n } catch {\n // ensureRelay rejected only — not tryAttach throws (those must not look like connect failure).\n const existing = pool.getRelay(key);\n if (existing !== undefined) {\n tryAttach(existing);\n return;\n }\n failUrl(jobIndex, key);\n return;\n }\n tryAttach(relay);\n })();\n }\n }\n\n if (opts.eoseTimeoutMs !== undefined && pending > 0) {\n eoseTimer = setTimeout(() => {\n eoseTimer = undefined;\n fireEose();\n }, opts.eoseTimeoutMs);\n }\n\n if (pending === 0) {\n queueMicrotask(() => {\n if (closed) {\n return;\n }\n settleClose();\n invokeSafely(() => opts.onclose?.(\"no relays\"));\n });\n }\n\n return { close: closeAll };\n}\n\nexport async function fetchRouted(\n pool: Pool,\n jobs: ReadonlyArray<RoutedJob>,\n opts: {\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n connectTimeoutMs?: number | undefined;\n /** Every event of every relay batch, including cross-relay duplicates. */\n onevent?: ((event: Event, relayUrl: string) => void) | undefined;\n } = {},\n): Promise<Event[]> {\n throwIfAborted(opts.signal);\n const byId = new Map<string, Event>();\n await Promise.all(\n jobs.flatMap((job) => {\n const urls: string[] = [];\n for (const raw of job.urls) {\n let key: string;\n try {\n key = normalizeURL(raw);\n } catch {\n key = raw; // invalid URL: ensureRelay fails it like a dead relay\n }\n if (!urls.includes(key)) {\n urls.push(key);\n }\n }\n return urls.map(async (url) => {\n let batch: Event[];\n let relayUrl: string;\n try {\n const relay = await pool.ensureRelay(url, {\n signal: opts.signal,\n timeoutMs: opts.connectTimeoutMs,\n });\n relayUrl = relay.url;\n batch = await relay.fetch([...job.filters], {\n timeoutMs: opts.timeoutMs,\n signal: opts.signal,\n });\n } catch {\n // An abort rejects the whole call; per-relay failures are skipped.\n if (opts.signal?.aborted === true) {\n throw abortReason(opts.signal);\n }\n return;\n }\n // The whole batch lands before callbacks so a throwing onevent cannot\n // drop events; listener errors are reported, never propagated.\n for (const event of batch) {\n if (!byId.has(event.id)) {\n byId.set(event.id, event);\n }\n }\n for (const event of batch) {\n invokeSafely(() => opts.onevent?.(event, relayUrl));\n }\n });\n }),\n );\n return [...byId.values()];\n}\n","import { abortReason, throwIfAborted } from \"../core/abort.ts\";\nimport { MessageError } from \"../core/error.ts\";\nimport type { Event, EventTemplate } from \"../core/event.ts\";\nimport { canonicalizeFilters } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { assertSubscriptionId } from \"../core/message.ts\";\nimport type { CountResult } from \"../core/message.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { RelayConnectionError, RelayPublishError, RelaySuspendedError } from \"./error.ts\";\nimport { fanIn, fetchRouted } from \"./fan-in.ts\";\nimport { Relay, RelayStatus } from \"./relay.ts\";\nimport type { PublishResult, RelayOptions, SubscribeOptions } from \"./relay.ts\";\nimport { isInsecureRelayUrl } from \"./url.ts\";\nimport type { WebSocketConstructor } from \"./websocket.ts\";\n\n/** Per-relay tolerance for events that fail id/signature verification. */\nexport type InvalidEventPolicy = {\n /** Invalid events tolerated within `windowMs`; exceeding it suspends the relay. */\n limit: number;\n windowMs: number;\n /** How long a suspended relay stays closed before it may reconnect. */\n cooldownMs: number;\n};\n\n/** Pool-wide options applied to every managed relay. */\nexport type PoolOptions = {\n websocketImplementation?: WebSocketConstructor | undefined;\n verifyEvent?: RelayOptions[\"verifyEvent\"];\n publishTimeoutMs?: number | undefined;\n connectTimeoutMs?: number | undefined;\n enableReconnect?: boolean | undefined;\n reconnectBackoffMs?: number[] | undefined;\n enablePing?: boolean | undefined;\n pingIntervalMs?: number | undefined;\n pingTimeoutMs?: number | undefined;\n /**\n * When set, automatically answer NIP-42 AUTH challenges for relays that send them. Return\n * undefined to skip a given relay URL.\n */\n automaticallyAuth?:\n | ((relayURL: string) => ((event: EventTemplate) => Promise<Event>) | undefined)\n | undefined;\n /** When false (default), ensureRelay rejects isInsecureRelayUrl unless trusted. */\n allowInsecure?: boolean | undefined;\n trustedInsecureUrls?: ReadonlyArray<string> | undefined;\n /** Close unused relays. Unset/0 = disabled. */\n idleTimeoutMs?: number | undefined;\n idleCleanupIntervalMs?: number | undefined;\n onIdleRelaysClosed?: ((urls: string[]) => void) | undefined;\n /**\n * Soft cap on connected non-pinned relays. When `ensureRelay` would create a new non-pinned relay\n * at the cap, the least-recently-used idle one is closed first (idle = no subscriptions and no\n * in-flight requests). If none is idle the connect proceeds anyway — the cap never fails a\n * request.\n */\n maxRelays?: number | undefined;\n /** Normalized URLs never closed by idle cleanup or `maxRelays` eviction. */\n pinnedUrls?: ReadonlyArray<string> | undefined;\n /**\n * When set, a relay whose `limit`-th-plus-one EVENT fails id/signature verification inside a\n * `windowMs` sliding window is disconnected and suspended for `cooldownMs`. During suspension\n * `ensureRelay` rejects with {@link RelaySuspendedError}; once it lifts, live subscriptions resume\n * through the normal reconnect path. Unset = events are dropped without counting, as before.\n */\n invalidEventPolicy?: InvalidEventPolicy | undefined;\n /**\n * Fired once when a relay is suspended for exceeding `invalidEventPolicy`: `url` is the\n * normalized relay URL and `until` the epoch-ms time the suspension lifts.\n */\n onRelaySuspended?: ((url: string, until: number) => void) | undefined;\n};\n\n/** Per-relay publish outcome: the relay's OK reply or an error string. */\nexport type PoolPublishResult = {\n url: string;\n result?: PublishResult;\n error?: string;\n};\n\n/** Multi-relay subscribe options: callbacks also receive the normalized relay URL. */\nexport type PoolSubscribeOptions = Omit<SubscribeOptions, \"onevent\" | \"receivedEvent\"> & {\n onevent?: ((event: Event, relayUrl: string) => void) | undefined;\n receivedEvent?: ((id: string, relayUrl: string) => void) | undefined;\n};\n\n/** Per-relay NIP-45 COUNT result (or its error). */\nexport type PoolCountResult = {\n url: string;\n count?: number;\n approximate?: boolean;\n hll?: string;\n error?: string;\n};\n\nfunction isIdle(relay: Relay): boolean {\n return (\n relay.status !== RelayStatus.Connecting &&\n relay.subscriptionCount === 0 &&\n relay.inFlightCount === 0\n );\n}\n\n/** Multi-relay coordinator: connection reuse, cross-relay event dedup, fan-out publish. */\nexport class Pool {\n readonly #relays = new Map<string, Relay>();\n readonly #opts: PoolOptions;\n readonly #lastActivity = new Map<string, number>();\n readonly #idleTimeoutMs: number;\n #idleTimer: ReturnType<typeof setInterval> | undefined;\n #allowInsecure: boolean;\n #trustedInsecure: Set<string>;\n #pinned: Set<string>;\n /** Per-relay timestamps of verification failures inside the sliding window. */\n readonly #invalidEvents = new Map<string, number[]>();\n /** Normalized URL → epoch ms when its suspension lifts. */\n readonly #suspendedUntil = new Map<string, number>();\n readonly #resumeTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n constructor(opts: PoolOptions = {}) {\n this.#opts = opts;\n this.#allowInsecure = opts.allowInsecure ?? false;\n this.#trustedInsecure = new Set((opts.trustedInsecureUrls ?? []).map(normalizeURL));\n this.#pinned = new Set((opts.pinnedUrls ?? []).map(normalizeURL));\n this.#idleTimeoutMs = opts.idleTimeoutMs ?? 0;\n if (this.#idleTimeoutMs > 0) {\n this.#idleTimer = setInterval(\n () => this.cleanIdleRelays(),\n opts.idleCleanupIntervalMs ?? 30_000,\n );\n }\n }\n\n setAllowInsecure(allow: boolean): void {\n this.#allowInsecure = allow;\n }\n\n setTrustedInsecureUrls(urls: ReadonlyArray<string>): void {\n this.#trustedInsecure = new Set(urls.map(normalizeURL));\n }\n\n setPinnedUrls(urls: ReadonlyArray<string>): void {\n this.#pinned = new Set(urls.map(normalizeURL));\n }\n\n /**\n * Drop cached AUTH rejections and re-fire pending challenges on every pooled relay, so a later\n * `setSigner` takes effect without reconnect.\n */\n resetAuth(): void {\n for (const relay of this.#relays.values()) {\n relay.resetAuth();\n }\n }\n\n cleanIdleRelays(): void {\n if (this.#idleTimeoutMs <= 0) {\n return;\n }\n const now = Date.now();\n const idle: string[] = [];\n for (const [url, relay] of this.#relays) {\n if (this.#pinned.has(url) || !isIdle(relay)) {\n continue;\n }\n const last = this.#lastActivity.get(url) ?? 0;\n if (!relay.connected || now - last >= this.#idleTimeoutMs) {\n idle.push(url);\n }\n }\n for (const url of this.#lastActivity.keys()) {\n if (!this.#relays.has(url)) {\n this.#lastActivity.delete(url);\n }\n }\n if (idle.length === 0) {\n return;\n }\n this.close(idle);\n invokeSafely(() => this.#opts.onIdleRelaysClosed?.(idle));\n }\n\n #touch(url: string): void {\n this.#lastActivity.set(url, Date.now());\n }\n\n /**\n * Count one verification failure for `norm`; on the `limit + 1`-th inside `windowMs` suspend the\n * relay: drop its connection (subscriptions kept), record `until`, and fire `onRelaySuspended`.\n */\n #noteInvalidEvent(norm: string): void {\n const policy = this.#opts.invalidEventPolicy;\n if (policy === undefined) {\n return;\n }\n const now = Date.now();\n const window = (this.#invalidEvents.get(norm) ?? []).filter((at) => now - at < policy.windowMs);\n window.push(now);\n if (window.length <= policy.limit) {\n this.#invalidEvents.set(norm, window);\n return;\n }\n this.#invalidEvents.delete(norm);\n if (this.#suspendedUntil.has(norm)) {\n return;\n }\n const until = now + policy.cooldownMs;\n this.#suspendedUntil.set(norm, until);\n this.#relays.get(norm)?.disconnect();\n const resume = setTimeout(() => {\n this.#resumeTimers.delete(norm);\n this.#suspendedUntil.delete(norm);\n const relay = this.#relays.get(norm);\n if (relay === undefined || relay.connected || relay.subscriptionCount === 0) {\n return;\n }\n void (async (): Promise<void> => {\n try {\n await relay.connect();\n } catch {\n // With enableReconnect the relay's own backoff retries; otherwise the\n // next ensureRelay attempt reconnects on demand.\n }\n })();\n }, policy.cooldownMs);\n this.#resumeTimers.set(norm, resume);\n invokeSafely(() => this.#opts.onRelaySuspended?.(norm, until));\n }\n\n #rejectInsecure(url: string, norm: string): void {\n if (this.#allowInsecure) {\n return;\n }\n if (!isInsecureRelayUrl(url)) {\n return;\n }\n if (this.#trustedInsecure.has(norm)) {\n return;\n }\n throw new RelayConnectionError(\"insecure relay connection blocked\", norm);\n }\n\n #stopIdleCleanup(): void {\n if (this.#idleTimer === undefined) {\n return;\n }\n clearInterval(this.#idleTimer);\n this.#idleTimer = undefined;\n }\n\n /**\n * Soft cap: closing the least-recently-used idle non-pinned relay when a new non-pinned relay\n * would push the count past `maxRelays`. Busy relays are never evicted; with none idle the cap is\n * exceeded rather than failing.\n */\n #enforceMaxRelays(incoming: string): void {\n const cap = this.#opts.maxRelays;\n if (cap === undefined || this.#pinned.has(incoming)) {\n return;\n }\n let count = 0;\n let oldestUrl: string | undefined;\n let oldestAt = Number.POSITIVE_INFINITY;\n for (const [url, relay] of this.#relays) {\n if (this.#pinned.has(url)) {\n continue;\n }\n count += 1;\n if (!isIdle(relay)) {\n continue;\n }\n const at = this.#lastActivity.get(url) ?? 0;\n if (at < oldestAt) {\n oldestAt = at;\n oldestUrl = url;\n }\n }\n if (count >= cap && oldestUrl !== undefined) {\n this.close([oldestUrl]);\n }\n }\n\n async ensureRelay(\n url: string,\n opts?: { signal?: AbortSignal | undefined; timeoutMs?: number | undefined },\n ): Promise<Relay> {\n const norm = normalizeURL(url);\n this.#rejectInsecure(url, norm);\n const suspendedUntil = this.#suspendedUntil.get(norm);\n if (suspendedUntil !== undefined) {\n if (Date.now() < suspendedUntil) {\n throw new RelaySuspendedError(norm, suspendedUntil);\n }\n this.#suspendedUntil.delete(norm);\n }\n let relay = this.#relays.get(norm);\n if (!relay) {\n this.#enforceMaxRelays(norm);\n const signFn = this.#opts.automaticallyAuth?.(norm) ?? undefined;\n const created = new Relay(norm, {\n websocketImplementation: this.#opts.websocketImplementation,\n verifyEvent: this.#opts.verifyEvent,\n publishTimeoutMs: this.#opts.publishTimeoutMs,\n connectTimeoutMs: this.#opts.connectTimeoutMs,\n enableReconnect: this.#opts.enableReconnect,\n reconnectBackoffMs: this.#opts.reconnectBackoffMs,\n enablePing: this.#opts.enablePing,\n pingIntervalMs: this.#opts.pingIntervalMs,\n pingTimeoutMs: this.#opts.pingTimeoutMs,\n authSigner: signFn,\n });\n // Only drop from the pool on terminal close (reconnect keeps the entry).\n // oxlint-disable-next-line unicorn/prefer-add-event-listener -- Relay.onclose is a property callback, not an EventTarget\n created.onclose = () => {\n this.#relays.delete(norm);\n this.#lastActivity.delete(norm);\n };\n created.oninvalidevent = () => {\n this.#noteInvalidEvent(norm);\n };\n if (signFn) {\n created.onauth = () => {\n void (async (): Promise<void> => {\n try {\n await created.auth(signFn);\n } catch {\n // auth failure surfaces on subsequent CLOSED/OK; avoid unhandled rejection\n }\n })();\n };\n }\n this.#relays.set(norm, created);\n relay = created;\n }\n this.#touch(norm);\n if (!relay.connected) {\n try {\n await relay.connect({\n signal: opts?.signal,\n timeoutMs: opts?.timeoutMs ?? this.#opts.connectTimeoutMs,\n });\n } catch (error) {\n // Keep the entry when reconnect is enabled so open subscriptions can recover.\n if (this.#opts.enableReconnect !== true) {\n this.#relays.delete(norm);\n this.#lastActivity.delete(norm);\n }\n throw error;\n }\n }\n return relay;\n }\n\n close(urls?: string[]): void {\n if (!urls) {\n this.#stopIdleCleanup();\n for (const timer of this.#resumeTimers.values()) {\n clearTimeout(timer);\n }\n this.#resumeTimers.clear();\n this.#suspendedUntil.clear();\n this.#invalidEvents.clear();\n for (const relay of this.#relays.values()) {\n relay.close();\n }\n this.#relays.clear();\n this.#lastActivity.clear();\n return;\n }\n for (const url of urls) {\n const norm = normalizeURL(url);\n const timer = this.#resumeTimers.get(norm);\n if (timer !== undefined) {\n clearTimeout(timer);\n this.#resumeTimers.delete(norm);\n }\n this.#relays.get(norm)?.close();\n this.#relays.delete(norm);\n this.#lastActivity.delete(norm);\n }\n }\n\n /**\n * Subscribe across relays. Deduplicates by event id. Returns a closer; callbacks receive every\n * new event once.\n */\n subscribe(\n relays: string[],\n filters: Filter[],\n opts: PoolSubscribeOptions = {},\n ): { close: (reason?: string) => void } {\n if (filters.length === 0) {\n throw new MessageError(\"REQ requires at least one filter\");\n }\n if (opts.id !== undefined) {\n assertSubscriptionId(opts.id);\n }\n const canonical = canonicalizeFilters(filters);\n return fanIn(this, [{ urls: relays, filters: canonical, id: opts.id }], {\n onevent: opts.onevent,\n oneose: opts.oneose,\n onclose: opts.onclose,\n signal: opts.signal,\n eoseTimeoutMs: opts.eoseTimeoutMs,\n alreadyHaveEvent: opts.alreadyHaveEvent,\n receivedEvent: opts.receivedEvent,\n closeOnEose: opts.closeOnEose,\n connectTimeoutMs: this.#opts.connectTimeoutMs,\n });\n }\n\n /** Fetch events until each connected relay EOSE or timeout; dedupe by id. */\n async fetch(\n relays: string[],\n filters: Filter[],\n opts?: {\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n /** Every event of every relay batch, including cross-relay duplicates. */\n onevent?: ((event: Event, relayUrl: string) => void) | undefined;\n },\n ): Promise<Event[]> {\n if (filters.length === 0) {\n throw new MessageError(\"REQ requires at least one filter\");\n }\n return fetchRouted(this, [{ urls: relays, filters: canonicalizeFilters(filters) }], {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n connectTimeoutMs: this.#opts.connectTimeoutMs,\n onevent: opts?.onevent,\n });\n }\n\n /** Publish to all listed relays; returns per-relay outcomes. */\n async publish(\n relays: string[],\n event: Event,\n opts?: { timeoutMs?: number | undefined },\n ): Promise<PoolPublishResult[]> {\n const results = await Promise.all(\n relays.map(async (url): Promise<PoolPublishResult> => {\n try {\n const relay = await this.ensureRelay(url, {\n timeoutMs: this.#opts.connectTimeoutMs,\n });\n this.#touch(relay.url);\n const result = await relay.publish(event, { timeoutMs: opts?.timeoutMs });\n return { url: relay.url, result };\n } catch (error) {\n return { url, error: error instanceof Error ? error.message : String(error) };\n }\n }),\n );\n return results;\n }\n\n /** First successful publish (Promise.any semantics). */\n async publishAny(\n relays: string[],\n event: Event,\n opts?: { timeoutMs?: number | undefined },\n ): Promise<PoolPublishResult> {\n return Promise.any(\n relays.map(async (url) => {\n const relay = await this.ensureRelay(url, {\n timeoutMs: this.#opts.connectTimeoutMs,\n });\n this.#touch(relay.url);\n const result = await relay.publish(event, { timeoutMs: opts?.timeoutMs });\n if (!result.ok) {\n throw new RelayPublishError(result.message || \"rejected\", relay.url);\n }\n return { url: relay.url, result };\n }),\n );\n }\n\n /**\n * NIP-45 COUNT across relays. Per-relay outcomes; failures do not throw. Counts are not summed —\n * each relay reports independently (may overlap).\n */\n async count(\n relays: string[],\n filters: Filter[],\n opts?: { timeoutMs?: number | undefined; signal?: AbortSignal | undefined },\n ): Promise<PoolCountResult[]> {\n throwIfAborted(opts?.signal);\n const canonical = canonicalizeFilters(filters);\n const results = await Promise.all(\n relays.map(async (url): Promise<PoolCountResult> => {\n try {\n const relay = await this.ensureRelay(url, {\n signal: opts?.signal,\n timeoutMs: this.#opts.connectTimeoutMs,\n });\n this.#touch(relay.url);\n const payload: CountResult = await relay.count(canonical, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n const out: PoolCountResult = { url: relay.url, count: payload.count };\n if (payload.approximate !== undefined) {\n out.approximate = payload.approximate;\n }\n if (payload.hll !== undefined) {\n out.hll = payload.hll;\n }\n return out;\n } catch (error) {\n // An abort rejects the whole call; per-relay failures are reported.\n if (opts?.signal?.aborted === true) {\n throw abortReason(opts.signal);\n }\n return { url, error: error instanceof Error ? error.message : String(error) };\n }\n }),\n );\n return results;\n }\n\n listRelays(): string[] {\n return [...this.#relays.keys()];\n }\n\n /** Lookup a pooled relay, including disconnected reconnecting entries. */\n getRelay(url: string): Relay | undefined {\n try {\n return this.#relays.get(normalizeURL(url));\n } catch {\n return this.#relays.get(url);\n }\n }\n\n /** Currently connected URLs. Unlike listRelays(), excludes reconnecting/disconnected entries. */\n connectedUrls(): string[] {\n const urls: string[] = [];\n for (const [url, relay] of this.#relays) {\n if (relay.connected) {\n urls.push(url);\n }\n }\n return urls;\n }\n}\n"],"mappings":"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"}
package/dist/relay.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as RelayStatus, c as isInsecureRelayUrl, d as RelayClosedError, f as RelayConnectionError, g as RelayTimeoutError, h as RelaySuspendedError, i as Relay, l as getWebSocketImplementation, m as RelayPublishError, n as fanIn, o as Subscription, p as RelayError, r as fetchRouted, s as subscriptionToAsyncIterable, t as Pool, u as useWebSocketImplementation } from "./pool-C2xOcsun.mjs";
1
+ import { a as RelayStatus, c as isInsecureRelayUrl, d as RelayClosedError, f as RelayConnectionError, g as RelayTimeoutError, h as RelaySuspendedError, i as Relay, l as getWebSocketImplementation, m as RelayPublishError, n as fanIn, o as Subscription, p as RelayError, r as fetchRouted, s as subscriptionToAsyncIterable, t as Pool, u as useWebSocketImplementation } from "./pool-BGVx59yd.mjs";
2
2
  export { Pool, Relay, RelayClosedError, RelayConnectionError, RelayError, RelayPublishError, RelayStatus, RelaySuspendedError, RelayTimeoutError, Subscription, fanIn, fetchRouted, getWebSocketImplementation, isInsecureRelayUrl, subscriptionToAsyncIterable, useWebSocketImplementation };
@@ -1,7 +1,8 @@
1
1
  import { f as CryptoError, i as bytesToHex$1, n as assertHex32, o as isHex32 } from "./util-LfQirgDk.mjs";
2
2
  import { t as Kind } from "./kind-Cxwhhkx8.mjs";
3
3
  import { h as Tag, m as validateSignedEvent, u as signedMatchesUnsigned } from "./event-D8Nfoh4K.mjs";
4
- import { i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as verifyEvent, t as Keys } from "./key-Bbtys6o7.mjs";
4
+ import { i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, t as Keys } from "./key-BZBap2p-.mjs";
5
+ import { n as verifyEvent } from "./verifier-t5WoWbtY.mjs";
5
6
  import { decrypt, encrypt } from "./nips/nip04.mjs";
6
7
  import { decrypt as decrypt$1, encrypt as encrypt$1, getConversationKey } from "./nips/nip44.mjs";
7
8
  import { t as invokeSafely } from "./report-CHld4uWj.mjs";
@@ -505,4 +506,4 @@ var Nip46Signer = class Nip46Signer {
505
506
  //#endregion
506
507
  export { KeysSigner as a, isNip07Available as i, Nip07Signer as n, getWindowNostr as r, Nip46Signer as t };
507
508
 
508
- //# sourceMappingURL=signer-CKR9EHce.mjs.map
509
+ //# sourceMappingURL=signer-BGSpLC7e.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer-BGSpLC7e.mjs","names":["nip04.encrypt","nip04.decrypt","nip44.getConversationKey","nip44.encrypt","nip44.decrypt","decrypt","bytesToHex","encrypt"],"sources":["../src/signer/keys.ts","../src/signer/nip07.ts","../src/signer/nip46.ts"],"sourcesContent":["import type { Event, UnsignedEvent } from \"../core/event.ts\";\nimport type { SecretKey } from \"../core/key.ts\";\nimport { Keys, signEvent } from \"../core/key.ts\";\nimport * as nip04 from \"../nips/nip04.ts\";\nimport * as nip44 from \"../nips/nip44.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Local secret-key signer with NIP-04 (legacy) and NIP-44 support. */\nexport class KeysSigner implements NostrSigner {\n readonly #keys: Keys;\n readonly #convKeys = new Map<string, Uint8Array>();\n\n constructor(secretKey: SecretKey | Uint8Array | string | Keys) {\n this.#keys = secretKey instanceof Keys ? secretKey : Keys.fromSecretKey(secretKey);\n }\n\n get keys(): Keys {\n return this.#keys;\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; KeysSigner signs synchronously\n async getPublicKey(): Promise<string> {\n return this.#keys.publicKey;\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; KeysSigner signs synchronously\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n return signEvent(unsigned, this.#keys);\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; KeysSigner signs synchronously\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip04.encrypt(this.#keys.secretKey.bytes, peer, plaintext);\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; KeysSigner signs synchronously\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return nip04.decrypt(this.#keys.secretKey.bytes, peer, ciphertext);\n }\n\n #conversationKey(peer: string): Uint8Array {\n const pk = peer.toLowerCase();\n let key = this.#convKeys.get(pk);\n if (!key) {\n key = nip44.getConversationKey(this.#keys.secretKey.bytes, pk);\n this.#convKeys.set(pk, key);\n }\n return key;\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; KeysSigner signs synchronously\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip44.encrypt(plaintext, this.#conversationKey(peer));\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; KeysSigner signs synchronously\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return nip44.decrypt(payload, this.#conversationKey(peer));\n }\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport { assertHex32 } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/**\n * Minimal NIP-07 provider surface (browser extension `window.nostr`).\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/07.md\n */\nexport type WindowNostr = {\n getPublicKey: () => Promise<string>;\n signEvent: (event: EventTemplate) => Promise<Event>;\n nip04?: {\n encrypt: (pubkey: string, plaintext: string) => Promise<string>;\n decrypt: (pubkey: string, ciphertext: string) => Promise<string>;\n };\n nip44?: {\n encrypt: (pubkey: string, plaintext: string) => Promise<string>;\n decrypt: (pubkey: string, ciphertext: string) => Promise<string>;\n };\n};\n\ntype GlobalWithNostr = typeof globalThis & {\n nostr?: WindowNostr;\n window?: { nostr?: WindowNostr };\n};\n\n/** Resolve `window.nostr` / `globalThis.nostr` when present. */\nexport function getWindowNostr(): WindowNostr | undefined {\n const g = globalThis as GlobalWithNostr;\n return g.nostr ?? g.window?.nostr;\n}\n\n/** True when a NIP-07 provider is injected in the current environment. */\nexport function isNip07Available(): boolean {\n const n = getWindowNostr();\n return Boolean(n && typeof n.getPublicKey === \"function\" && typeof n.signEvent === \"function\");\n}\n\n/**\n * Signer backed by a NIP-07 browser extension (or any injected provider). Never holds secret keys\n * in-process.\n */\nexport class Nip07Signer implements NostrSigner {\n readonly #provider: WindowNostr | undefined;\n\n constructor(provider?: WindowNostr) {\n this.#provider = provider;\n }\n\n #resolve(): WindowNostr {\n const provider = this.#provider ?? getWindowNostr();\n if (!provider) {\n throw new CryptoError(\"NIP-07 provider not available (window.nostr missing)\");\n }\n return provider;\n }\n\n async getPublicKey(): Promise<string> {\n const pk = await this.#resolve().getPublicKey();\n try {\n return assertHex32(pk, \"pubkey\");\n } catch (error) {\n throw new CryptoError(\"NIP-07 getPublicKey returned an invalid pubkey\", {\n cause: error instanceof Error ? error : undefined,\n });\n }\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const provider = this.#resolve();\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags.map((t) => {\n const [name, ...rest] = t;\n if (name === undefined) {\n throw new CryptoError(\"unsigned event has an empty tag\");\n }\n return [name, ...rest];\n }),\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n\n const signed = await provider.signEvent(template);\n if (!validateSignedEvent(signed)) {\n throw new CryptoError(\"NIP-07 signEvent returned an invalid event\");\n }\n if (!verifyEvent(signed)) {\n throw new CryptoError(\"NIP-07 signed event failed signature verification\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new CryptoError(\"NIP-07 signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n const { nip04 } = this.#resolve();\n if (!nip04?.encrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip04.encrypt\");\n }\n return nip04.encrypt(peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n const { nip04 } = this.#resolve();\n if (!nip04?.decrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip04.decrypt\");\n }\n return nip04.decrypt(peer, ciphertext);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n const { nip44 } = this.#resolve();\n if (!nip44?.encrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip44.encrypt\");\n }\n return nip44.encrypt(peer, plaintext);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n const { nip44 } = this.#resolve();\n if (!nip44?.decrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip44.decrypt\");\n }\n return nip44.decrypt(peer, payload);\n }\n}\n","import { randomBytes } from \"@noble/hashes/utils.js\";\n\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { SecretKey, finalizeEvent, getPublicKey } from \"../core/key.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { Tag } from \"../core/tag.ts\";\nimport { bytesToHex, isHex32 } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport { decrypt, encrypt, getConversationKey } from \"../nips/nip44.ts\";\nimport {\n Nip46Error,\n decodeNip46Response,\n encodeNip46Request,\n parseBunkerURL,\n parseNostrConnectURI,\n} from \"../nips/nip46.ts\";\nimport type { BunkerPointer, ClientMetadata, Nip46Request } from \"../nips/nip46.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Subscribe options used by NIP-46 transport (structural subset of Pool). */\nexport type Nip46SubscribeOptions = {\n signal?: AbortSignal | undefined;\n onevent?: ((event: Event) => void) | undefined;\n onclose?: ((reason: string) => void) | undefined;\n};\n\n/**\n * Structural relay transport for NIP-46 RPC. Satisfied by {@link import(\"../relay/pool.ts\").Pool};\n * constructed above the signer layer so `signer` never imports `relay` (ADR-0001).\n */\nexport type Nip46Transport = {\n subscribe: (\n relays: string[],\n filters: Filter[],\n opts?: Nip46SubscribeOptions,\n ) => { close: (reason?: string) => void };\n publish: (\n relays: string[],\n event: Event,\n ) => Promise<ReadonlyArray<{ result?: { ok: boolean; message: string }; error?: string }>>;\n close: (urls?: string[]) => void;\n};\n\n/** Options for {@link Nip46Signer}: transport, timeouts, and relay hints. */\nexport type Nip46SignerOptions = {\n /** Shared transport. When set, the signer does not close it on {@link Nip46Signer.close}. */\n pool?: Nip46Transport;\n /**\n * Factory for a private transport when `pool` is omitted. Typical: `() => new Pool({\n * websocketImplementation, enableReconnect: true })`.\n */\n createPool?: () => Nip46Transport;\n /**\n * Relays used when the bunker pointer has none, and merged uniquely onto a nonempty pointer\n * (pointer first).\n */\n relays?: string[];\n /** Bunker connection secret when the pointer or bunker:// URL has none. */\n secret?: string | undefined;\n /** Local client key used to encrypt RPC (not the remote user key). */\n clientSecretKey?: SecretKey | Uint8Array | string;\n /** Called when bunker returns `auth_url` for a pending request. */\n onAuthUrl?: (url: string) => void;\n /** Per-request timeout in ms. Default 30s. */\n timeoutMs?: number;\n /**\n * Timeout in ms applied after the bunker replies `auth_url`: the request keeps waiting for the\n * real response until this elapses. Default 300s.\n */\n authTimeoutMs?: number;\n /** Requested permissions sent with `connect` (`method[:kind]` list). */\n perms?: string[];\n /** Client metadata sent with bunker-initiated `connect`. */\n metadata?: ClientMetadata;\n};\n\nfunction resolveClientSecret(key?: SecretKey | Uint8Array | string): SecretKey {\n if (key === undefined) {\n return SecretKey.generate();\n }\n if (key instanceof SecretKey) {\n return key;\n }\n if (typeof key === \"string\") {\n return SecretKey.fromHex(key);\n }\n return SecretKey.fromBytes(key);\n}\n\nfunction resolveTransport(opts: Nip46SignerOptions): { pool: Nip46Transport; ownsPool: boolean } {\n if (opts.pool) {\n return { pool: opts.pool, ownsPool: false };\n }\n if (opts.createPool) {\n return { pool: opts.createPool(), ownsPool: true };\n }\n throw new Nip46Error(\n \"Nip46Signer requires pool or createPool (inject Pool from @qntx/nostr/relay)\",\n );\n}\n\nfunction applyPointerOpts(pointer: BunkerPointer, opts: Nip46SignerOptions): BunkerPointer {\n let next: BunkerPointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n if (opts.secret !== undefined && next.secret === undefined) {\n next = { ...next, secret: opts.secret };\n }\n\n const relays = next.relays.length > 0 ? next.relays : [...(opts.relays ?? [])];\n if (relays.length === 0) {\n throw new Nip46Error(\"no relays for bunker connection\");\n }\n if (next.relays.length > 0 && opts.relays !== undefined && opts.relays.length > 0) {\n const merged = [...next.relays];\n for (const r of opts.relays) {\n if (!merged.includes(r)) {\n merged.push(r);\n }\n }\n return { ...next, relays: merged };\n }\n return { ...next, relays };\n}\n\nfunction resolveBunkerPointer(input: string | BunkerPointer): BunkerPointer {\n if (typeof input !== \"string\") {\n return {\n pubkey: input.pubkey.toLowerCase(),\n relays: [...input.relays],\n secret: input.secret,\n };\n }\n\n const bunker = parseBunkerURL(input);\n if (bunker) {\n return bunker;\n }\n\n throw new Nip46Error(\"invalid bunker input (expected bunker:// URL or BunkerPointer)\");\n}\n\ntype PendingRequest = {\n resolve: (v: string) => void;\n reject: (e: Error) => void;\n method: string;\n timer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * NIP-46 remote signer (bunker / nostrconnect). Implements {@link NostrSigner}; never holds the\n * remote user's secret key. Network I/O is injected via {@link Nip46Transport} (no relay import).\n */\nexport class Nip46Signer implements NostrSigner {\n readonly #pool: Nip46Transport;\n readonly #ownsPool: boolean;\n readonly #clientSecret: SecretKey;\n readonly #clientPubkey: string;\n readonly #pointer: BunkerPointer;\n readonly #conversationKey: Uint8Array;\n readonly #onAuthUrl: ((url: string) => void) | undefined;\n readonly #timeoutMs: number;\n readonly #authTimeoutMs: number;\n readonly #perms: string[] | undefined;\n readonly #metadata: ClientMetadata | undefined;\n #relays: string[];\n readonly #listeners = new Map<string, PendingRequest>();\n #sub: { close: (reason?: string) => void } | undefined;\n #open = false;\n #cachedRemotePubkey: string | undefined;\n\n private constructor(\n clientSecret: SecretKey,\n pointer: BunkerPointer,\n pool: Nip46Transport,\n ownsPool: boolean,\n opts: Nip46SignerOptions,\n ) {\n if (pointer.relays.length === 0) {\n throw new Nip46Error(\"bunker pointer has no relays\");\n }\n this.#clientSecret = clientSecret;\n this.#clientPubkey = getPublicKey(clientSecret);\n this.#pointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n this.#relays = [...pointer.relays];\n this.#pool = pool;\n this.#ownsPool = ownsPool;\n this.#conversationKey = getConversationKey(clientSecret.bytes, this.#pointer.pubkey);\n this.#onAuthUrl = opts.onAuthUrl;\n this.#timeoutMs = opts.timeoutMs ?? 30_000;\n this.#authTimeoutMs = opts.authTimeoutMs ?? 300_000;\n this.#perms = opts.perms;\n this.#metadata = opts.metadata;\n }\n\n get bunker(): Readonly<BunkerPointer> {\n return {\n pubkey: this.#pointer.pubkey,\n relays: [...this.#relays],\n secret: this.#pointer.secret,\n };\n }\n\n get clientPublicKey(): string {\n return this.#clientPubkey;\n }\n\n /**\n * Subscribe to an already-known bunker pointer. Does not send the `connect` RPC (reconnect\n * without a new handshake). Requires `clientSecretKey` — reconnect must reuse the original client\n * identity.\n */\n static fromBunker(\n pointer: BunkerPointer,\n opts: Nip46SignerOptions & { clientSecretKey: SecretKey | Uint8Array | string },\n ): Nip46Signer {\n if (opts.clientSecretKey === undefined) {\n throw new Nip46Error(\"fromBunker requires clientSecretKey\");\n }\n const resolved = applyPointerOpts(pointer, opts);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const { pool, ownsPool } = resolveTransport(opts);\n const signer = new Nip46Signer(sk, resolved, pool, ownsPool, opts);\n signer.#startSubscription();\n return signer;\n }\n\n /**\n * Connect using a `bunker://` URL or pre-parsed pointer. Invalid strings throw. A NIP-05\n * identifier is not a bunker pointer. When both pointer and `opts.relays` are nonempty, unique\n * `opts.relays` are appended.\n */\n static async connect(\n input: string | BunkerPointer,\n opts: Nip46SignerOptions = {},\n ): Promise<Nip46Signer> {\n const pointer = resolveBunkerPointer(input);\n const signer = Nip46Signer.fromBunker(pointer, {\n ...opts,\n clientSecretKey: resolveClientSecret(opts.clientSecretKey),\n });\n try {\n await signer.connectRemote();\n try {\n await signer.switchRelays();\n } catch {\n // Bunker may not implement switch_relays.\n }\n await signer.getPublicKey();\n return signer;\n } catch (error) {\n await signer.close();\n throw error;\n }\n }\n\n /**\n * Wait for a bunker to complete a client-initiated `nostrconnect://` handshake. Requires\n * `clientSecretKey` whose pubkey matches the URI client pubkey (build the URI with\n * {@link createNostrConnectURI} after generating keys).\n */\n static async fromNostrConnectURI(\n connectionURI: string,\n opts: Nip46SignerOptions & {\n clientSecretKey: SecretKey | Uint8Array | string;\n signal?: AbortSignal;\n handshakeTimeoutMs?: number;\n },\n ): Promise<Nip46Signer> {\n const params = parseNostrConnectURI(connectionURI);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const clientPubkey = getPublicKey(sk);\n\n if (clientPubkey !== params.clientPubkey) {\n throw new Nip46Error(\"client secret key does not match nostrconnect client pubkey\");\n }\n\n const { pool, ownsPool } = resolveTransport(opts);\n const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 300_000;\n\n return new Promise((resolve, reject) => {\n let settled = false;\n const finish = (err?: Error, signer?: Nip46Signer) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n sub.close(err ? \"failed\" : \"connected\");\n if (err) {\n if (ownsPool) {\n pool.close();\n }\n reject(err);\n } else if (signer) {\n resolve(signer);\n }\n };\n\n const timer = setTimeout(() => {\n finish(new Nip46Error(\"nostrconnect handshake timed out\"));\n }, handshakeTimeoutMs);\n\n const sub = pool.subscribe(\n params.relays,\n [{ kinds: [Kind.NostrConnect], \"#p\": [clientPubkey], limit: 0 }],\n {\n signal: opts.signal,\n onevent: (event) => {\n try {\n const convKey = getConversationKey(sk.bytes, event.pubkey);\n const payload = decrypt(event.content, convKey);\n const response = decodeNip46Response(payload);\n if (response.result !== params.secret) {\n return;\n }\n\n const pointer: BunkerPointer = {\n pubkey: event.pubkey.toLowerCase(),\n relays: params.relays,\n secret: params.secret,\n };\n const signer = new Nip46Signer(sk, pointer, pool, ownsPool, opts);\n signer.#startSubscription();\n void (async () => {\n try {\n await signer.switchRelays();\n } catch {\n // Relay switch at connect time is best-effort.\n }\n try {\n await signer.getPublicKey();\n finish(undefined, signer);\n } catch (error: unknown) {\n finish(error instanceof Error ? error : new Nip46Error(String(error)));\n }\n })();\n } catch {\n // ignore non-matching events\n }\n },\n onclose: (reason) => {\n if (reason !== \"connected\" && reason !== \"failed\") {\n finish(new Nip46Error(`nostrconnect subscription closed: ${reason}`));\n }\n },\n },\n );\n });\n }\n\n #startSubscription(): void {\n this.#sub?.close();\n this.#sub = this.#pool.subscribe(\n this.#relays,\n [\n {\n kinds: [Kind.NostrConnect],\n authors: [this.#pointer.pubkey],\n \"#p\": [this.#clientPubkey],\n limit: 0,\n },\n ],\n {\n onevent: (event) => {\n try {\n const payload = decrypt(event.content, this.#conversationKey);\n const { id, result, error } = decodeNip46Response(payload);\n\n if (result === \"auth_url\" && this.#listeners.has(id)) {\n const listener = this.#listeners.get(id);\n if (!listener) {\n return;\n }\n if (error !== undefined && error !== \"\") {\n invokeSafely(() => this.#onAuthUrl?.(error));\n }\n clearTimeout(listener.timer);\n listener.timer = this.#requestTimer(id, listener, this.#authTimeoutMs);\n return;\n }\n\n const listener = this.#dropRequest(id);\n if (!listener) {\n return;\n }\n if (error !== undefined && error !== \"\") {\n listener.reject(new Nip46Error(error));\n } else if (result === undefined) {\n listener.reject(new Nip46Error(\"empty NIP-46 response\"));\n } else {\n listener.resolve(result);\n }\n } catch {\n // ignore decrypt failures from unrelated events\n }\n },\n onclose: () => {\n this.#sub = undefined;\n },\n },\n );\n this.#open = true;\n }\n\n async connectRemote(overrides?: { metadata?: ClientMetadata; perms?: string[] }): Promise<void> {\n const metadata = overrides?.metadata ?? this.#metadata;\n const perms = overrides?.perms ?? this.#perms;\n const params = [this.#pointer.pubkey, this.#pointer.secret ?? \"\"];\n const hasPerms = perms !== undefined && perms.length > 0;\n if (hasPerms || metadata !== undefined) {\n params.push(hasPerms ? perms.join(\",\") : \"\");\n }\n if (metadata !== undefined) {\n params.push(JSON.stringify(metadata));\n }\n const result = await this.#sendRequest(\"connect\", params);\n if (result === \"ack\") {\n return;\n }\n const { secret } = this.#pointer;\n if (secret !== undefined && secret !== \"\" && result === secret) {\n return;\n }\n throw new Nip46Error(`connect result is not ack or secret: ${result}`);\n }\n\n /**\n * Ask the bunker for its preferred relay list and resubscribe when it changes. Spec result is a\n * JSON array of URLs, or `null` when nothing changes.\n */\n async switchRelays(): Promise<string[] | undefined> {\n const resp = await this.#sendRequest(\"switch_relays\", []);\n if (resp === \"null\") {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(resp);\n } catch (error) {\n throw new Nip46Error(\"invalid switch_relays JSON\", {\n cause: error instanceof Error ? error : undefined,\n });\n }\n if (\n !Array.isArray(parsed) ||\n parsed.length === 0 ||\n !parsed.every((x) => typeof x === \"string\")\n ) {\n throw new Nip46Error(\"invalid switch_relays result\");\n }\n this.#relays = parsed;\n this.#startSubscription();\n return parsed;\n }\n\n /** Courtesy session teardown. Always closes the local signer afterwards. */\n async logout(): Promise<void> {\n try {\n const resp = await this.#sendRequest(\"logout\", []);\n if (resp !== \"ack\") {\n throw new Nip46Error(`logout result is not ack: ${resp}`);\n }\n } finally {\n await this.close();\n }\n }\n\n async ping(): Promise<void> {\n const resp = await this.#sendRequest(\"ping\", []);\n if (resp !== \"pong\") {\n throw new Nip46Error(`ping result is not pong: ${resp}`);\n }\n }\n\n async getPublicKey(): Promise<string> {\n if (this.#cachedRemotePubkey === undefined) {\n const pk = await this.#sendRequest(\"get_public_key\", []);\n if (!isHex32(pk.toLowerCase())) {\n throw new Nip46Error(\"bunker returned invalid pubkey\");\n }\n this.#cachedRemotePubkey = pk.toLowerCase();\n }\n return this.#cachedRemotePubkey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags,\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n const resp = await this.#sendRequest(\"sign_event\", [JSON.stringify(template)]);\n let signed: unknown;\n try {\n signed = JSON.parse(resp);\n } catch (error) {\n throw new Nip46Error(\"bunker returned invalid sign_event JSON\", {\n cause: error instanceof Error ? error : undefined,\n });\n }\n if (!validateSignedEvent(signed) || !verifyEvent(signed)) {\n throw new Nip46Error(\"bunker returned improperly signed event\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new Nip46Error(\"signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip04_encrypt\", [peer, plaintext]);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return this.#sendRequest(\"nip04_decrypt\", [peer, ciphertext]);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip44_encrypt\", [peer, plaintext]);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return this.#sendRequest(\"nip44_decrypt\", [peer, payload]);\n }\n\n // oxlint-disable-next-line typescript/require-await -- NostrSigner is async; teardown is synchronous\n async close(): Promise<void> {\n this.#open = false;\n for (const [, listener] of this.#listeners) {\n clearTimeout(listener.timer);\n listener.reject(new Nip46Error(\"signer closed\"));\n }\n this.#listeners.clear();\n this.#sub?.close(\"signer closed\");\n this.#sub = undefined;\n if (this.#ownsPool) {\n this.#pool.close();\n }\n }\n\n async #sendRequest(method: string, params: string[]): Promise<string> {\n if (!this.#open) {\n throw new Nip46Error(\"signer is closed\");\n }\n if (!this.#sub) {\n this.#startSubscription();\n }\n\n const id = bytesToHex(randomBytes(16));\n const req: Nip46Request = { id, method, params };\n const encrypted = encrypt(encodeNip46Request(req), this.#conversationKey);\n\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [Tag.p(this.#pointer.pubkey)],\n content: encrypted,\n created_at: Math.floor(Date.now() / 1000),\n },\n this.#clientSecret,\n );\n\n const resultPromise = new Promise<string>((resolve, reject) => {\n const listener: PendingRequest = { resolve, reject, method };\n listener.timer = this.#requestTimer(id, listener, this.#timeoutMs);\n this.#listeners.set(id, listener);\n });\n\n let replies;\n try {\n replies = await this.#pool.publish(this.#relays, event);\n } catch (error) {\n this.#dropRequest(id);\n throw error;\n }\n if (!replies.some((reply) => reply.result?.ok === true)) {\n const listener = this.#dropRequest(id);\n const detail = replies\n .map((reply) => reply.error ?? reply.result?.message)\n .filter((message): message is string => Boolean(message))\n .join(\"; \");\n listener?.reject(new Nip46Error(`request not accepted by any relay: ${detail}`));\n }\n return resultPromise;\n }\n\n #dropRequest(id: string): PendingRequest | undefined {\n const listener = this.#listeners.get(id);\n if (!listener) {\n return undefined;\n }\n clearTimeout(listener.timer);\n this.#listeners.delete(id);\n return listener;\n }\n\n #requestTimer(id: string, listener: PendingRequest, ms: number): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n this.#dropRequest(id);\n listener.reject(new Nip46Error(`NIP-46 request timed out: ${listener.method}`));\n }, ms);\n }\n}\n"],"mappings":"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"}
package/dist/signer.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { t as NostrSigner } from "./types-CRQEk0Oi.mjs";
2
- import { a as Nip07Signer, c as isNip07Available, i as Nip46Transport, l as KeysSigner, n as Nip46SignerOptions, o as WindowNostr, r as Nip46SubscribeOptions, s as getWindowNostr, t as Nip46Signer, u as NoSignerError } from "./index-Ba7bJ7DD.mjs";
2
+ import { a as Nip07Signer, c as isNip07Available, i as Nip46Transport, l as KeysSigner, n as Nip46SignerOptions, o as WindowNostr, r as Nip46SubscribeOptions, s as getWindowNostr, t as Nip46Signer, u as NoSignerError } from "./index-23sRP0wl.mjs";
3
3
  export { KeysSigner, Nip07Signer, Nip46Signer, type Nip46SignerOptions, type Nip46SubscribeOptions, type Nip46Transport, NoSignerError, type NostrSigner, type WindowNostr, getWindowNostr, isNip07Available };
package/dist/signer.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { t as NoSignerError } from "./error-B__OMBRY.mjs";
2
- import { a as KeysSigner, i as isNip07Available, n as Nip07Signer, r as getWindowNostr, t as Nip46Signer } from "./signer-CKR9EHce.mjs";
2
+ import { a as KeysSigner, i as isNip07Available, n as Nip07Signer, r as getWindowNostr, t as Nip46Signer } from "./signer-BGSpLC7e.mjs";
3
3
  export { KeysSigner, Nip07Signer, Nip46Signer, NoSignerError, getWindowNostr, isNip07Available };
package/dist/testing.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import { c as isRecord, i as bytesToHex, l as normalizeURL } from "./util-LfQirgDk.mjs";
2
2
  import { t as Kind } from "./kind-Cxwhhkx8.mjs";
3
3
  import { m as validateSignedEvent, t as compareEventsDesc, y as isTag } from "./event-D8Nfoh4K.mjs";
4
- import { r as finalizeEvent, s as verifyEvent, t as Keys } from "./key-Bbtys6o7.mjs";
5
- import { t as EventBuilder } from "./builder-CyrGKRVP.mjs";
4
+ import { r as finalizeEvent, t as Keys } from "./key-BZBap2p-.mjs";
5
+ import { n as verifyEvent } from "./verifier-t5WoWbtY.mjs";
6
+ import { t as EventBuilder } from "./builder-8VQ_Xr6X.mjs";
6
7
  import { a as matchFilter } from "./filter-BQl3GlHt.mjs";
7
8
  import { decrypt, encrypt, getConversationKey } from "./nips/nip44.mjs";
8
9
  import { decodeNip46Request, encodeNip46Response } from "./nips/nip46.mjs";