@qntx/nostr 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/dist/abort-Ba8tDrOI.mjs +38 -0
  2. package/dist/abort-Ba8tDrOI.mjs.map +1 -0
  3. package/dist/{builder-BphJa-Y-.d.mts → builder-BWn55Paf.d.mts} +20 -14
  4. package/dist/{builder-q0VsvnYE.mjs → builder-CyrGKRVP.mjs} +32 -16
  5. package/dist/builder-CyrGKRVP.mjs.map +1 -0
  6. package/dist/{client-Bd8B1mYm.mjs → client-BWsX9Cv1.mjs} +354 -195
  7. package/dist/client-BWsX9Cv1.mjs.map +1 -0
  8. package/dist/client.d.mts +1 -1
  9. package/dist/client.mjs +1 -1
  10. package/dist/core.d.mts +8 -8
  11. package/dist/core.mjs +8 -9
  12. package/dist/error-BW7re1UN.d.mts +9 -0
  13. package/dist/error-B__OMBRY.mjs +14 -0
  14. package/dist/error-B__OMBRY.mjs.map +1 -0
  15. package/dist/{error-WEFS-R-4.d.mts → error-CR8Urc84.d.mts} +20 -8
  16. package/dist/{error-CwBxle6N.mjs → error-DrEIM7FO.mjs} +5 -3
  17. package/dist/error-DrEIM7FO.mjs.map +1 -0
  18. package/dist/{event-CzoQEFMF.mjs → event-D8Nfoh4K.mjs} +40 -32
  19. package/dist/event-D8Nfoh4K.mjs.map +1 -0
  20. package/dist/{event-B5D2jxt_.d.mts → event-fU3Y01PR.d.mts} +23 -20
  21. package/dist/{filter-BxwjEkZp.mjs → filter-BQl3GlHt.mjs} +42 -35
  22. package/dist/filter-BQl3GlHt.mjs.map +1 -0
  23. package/dist/filter-C0IMByE3.d.mts +37 -0
  24. package/dist/{gossip-C5RVB1UB.d.mts → gossip-BRQwIM_q.d.mts} +25 -23
  25. package/dist/{gossip-3xkRRCm_.mjs → gossip-oloDMWEj.mjs} +52 -34
  26. package/dist/gossip-oloDMWEj.mjs.map +1 -0
  27. package/dist/gossip.d.mts +1 -1
  28. package/dist/gossip.mjs +1 -1
  29. package/dist/{http-6vevbBlu.d.mts → http-C4HwIu4B.d.mts} +7 -7
  30. package/dist/{http-D2rhokZo.mjs → http-CuazNRIP.mjs} +10 -6
  31. package/dist/http-CuazNRIP.mjs.map +1 -0
  32. package/dist/index-B425CAcQ.d.mts +328 -0
  33. package/dist/index-BVyfUBuG.d.mts +181 -0
  34. package/dist/{index-BYMnhRIC.d.mts → index-Ba7bJ7DD.d.mts} +68 -50
  35. package/dist/{index-DaRyjo7O.d.mts → index-Boe8FshM.d.mts} +13 -7
  36. package/dist/index-CUIvFQdE.d.mts +73 -0
  37. package/dist/index-JdaS_uce.d.mts +207 -0
  38. package/dist/index.d.mts +22 -20
  39. package/dist/index.mjs +19 -18
  40. package/dist/{key-Dn-aX4x4.mjs → key-Bbtys6o7.mjs} +22 -14
  41. package/dist/key-Bbtys6o7.mjs.map +1 -0
  42. package/dist/{key-BiGxGLhg.d.mts → key-BlsYhN1V.d.mts} +9 -6
  43. package/dist/{kind-BLl4cLOc.mjs → kind-Cxwhhkx8.mjs} +2 -1
  44. package/dist/kind-Cxwhhkx8.mjs.map +1 -0
  45. package/dist/{loaders-BNQszDAn.mjs → loaders-o6YXB_Ri.mjs} +329 -305
  46. package/dist/loaders-o6YXB_Ri.mjs.map +1 -0
  47. package/dist/loaders.d.mts +3 -3
  48. package/dist/loaders.mjs +2 -2
  49. package/dist/memory-C2EVx0_O.mjs +46 -0
  50. package/dist/memory-C2EVx0_O.mjs.map +1 -0
  51. package/dist/{memory-BCmhZPek.mjs → memory-index-Do1mz0WF.mjs} +212 -82
  52. package/dist/memory-index-Do1mz0WF.mjs.map +1 -0
  53. package/dist/{message-C_Uj-Y-c.mjs → message-DcY6Fi9o.mjs} +38 -24
  54. package/dist/message-DcY6Fi9o.mjs.map +1 -0
  55. package/dist/{message-DJC-Jz6T.d.mts → message-iGPIqnn0.d.mts} +15 -8
  56. package/dist/{nip17-BWq-Kfq5.d.mts → nip17-DNEkz8rM.d.mts} +18 -17
  57. package/dist/{nip19-D7905oIv.d.mts → nip19-BevCJZsp.d.mts} +23 -3
  58. package/dist/{nip46-C_DoxiS_.d.mts → nip46-DDV4dC56.d.mts} +13 -12
  59. package/dist/{nip59-DljW_sYh.d.mts → nip59-zQgdLcEr.d.mts} +28 -25
  60. package/dist/{nip65-Di5hZRuV.d.mts → nip65-DBfh2smt.d.mts} +8 -3
  61. package/dist/{nip77-ByxlgoQO.d.mts → nip77-DH4RhS5r.d.mts} +9 -8
  62. package/dist/nips/blossom.d.mts +37 -37
  63. package/dist/nips/blossom.mjs +67 -52
  64. package/dist/nips/blossom.mjs.map +1 -1
  65. package/dist/nips/nip04.d.mts +2 -3
  66. package/dist/nips/nip04.mjs +6 -10
  67. package/dist/nips/nip04.mjs.map +1 -1
  68. package/dist/nips/nip05.d.mts +37 -43
  69. package/dist/nips/nip05.mjs +57 -57
  70. package/dist/nips/nip05.mjs.map +1 -1
  71. package/dist/nips/nip10.d.mts +18 -19
  72. package/dist/nips/nip10.mjs +76 -61
  73. package/dist/nips/nip10.mjs.map +1 -1
  74. package/dist/nips/nip11.d.mts +9 -8
  75. package/dist/nips/nip11.mjs +14 -11
  76. package/dist/nips/nip11.mjs.map +1 -1
  77. package/dist/nips/nip13.d.mts +9 -9
  78. package/dist/nips/nip13.mjs +15 -17
  79. package/dist/nips/nip13.mjs.map +1 -1
  80. package/dist/nips/nip17.d.mts +1 -1
  81. package/dist/nips/nip17.mjs +17 -12
  82. package/dist/nips/nip17.mjs.map +1 -1
  83. package/dist/nips/nip19.d.mts +1 -1
  84. package/dist/nips/nip19.mjs +52 -29
  85. package/dist/nips/nip19.mjs.map +1 -1
  86. package/dist/nips/nip21.d.mts +5 -6
  87. package/dist/nips/nip21.mjs +8 -7
  88. package/dist/nips/nip21.mjs.map +1 -1
  89. package/dist/nips/nip27.d.mts +7 -8
  90. package/dist/nips/nip27.mjs +26 -25
  91. package/dist/nips/nip27.mjs.map +1 -1
  92. package/dist/nips/nip42.d.mts +5 -6
  93. package/dist/nips/nip42.mjs +3 -3
  94. package/dist/nips/nip42.mjs.map +1 -1
  95. package/dist/nips/nip44.d.mts +24 -7
  96. package/dist/nips/nip44.mjs +25 -15
  97. package/dist/nips/nip44.mjs.map +1 -1
  98. package/dist/nips/nip46.d.mts +1 -1
  99. package/dist/nips/nip46.mjs +52 -49
  100. package/dist/nips/nip46.mjs.map +1 -1
  101. package/dist/nips/nip49.d.mts +8 -7
  102. package/dist/nips/nip49.mjs +16 -12
  103. package/dist/nips/nip49.mjs.map +1 -1
  104. package/dist/nips/nip51.d.mts +25 -27
  105. package/dist/nips/nip51.mjs +47 -36
  106. package/dist/nips/nip51.mjs.map +1 -1
  107. package/dist/nips/nip57.d.mts +12 -13
  108. package/dist/nips/nip57.mjs +35 -38
  109. package/dist/nips/nip57.mjs.map +1 -1
  110. package/dist/nips/nip59.d.mts +1 -1
  111. package/dist/nips/nip59.mjs +14 -18
  112. package/dist/nips/nip59.mjs.map +1 -1
  113. package/dist/nips/nip65.d.mts +1 -1
  114. package/dist/nips/nip65.mjs +11 -8
  115. package/dist/nips/nip65.mjs.map +1 -1
  116. package/dist/nips/nip77.d.mts +1 -1
  117. package/dist/nips/nip77.mjs +56 -34
  118. package/dist/nips/nip77.mjs.map +1 -1
  119. package/dist/nips/nip96.d.mts +21 -12
  120. package/dist/nips/nip96.mjs +59 -36
  121. package/dist/nips/nip96.mjs.map +1 -1
  122. package/dist/nips/nip98.d.mts +12 -12
  123. package/dist/nips/nip98.mjs +18 -19
  124. package/dist/nips/nip98.mjs.map +1 -1
  125. package/dist/{nostr_crypto_wasm_bg-hi5aXi5P.mjs → nostr_crypto_wasm_bg-Czrdty7Q.mjs} +1 -1
  126. package/dist/nostr_crypto_wasm_bg.wasm +0 -0
  127. package/dist/{pool-C_j1OmBB.mjs → pool-XmAGaufS.mjs} +611 -487
  128. package/dist/pool-XmAGaufS.mjs.map +1 -0
  129. package/dist/pool-tEr7c5bG.d.mts +302 -0
  130. package/dist/reactive-DDlThDSZ.mjs +324 -0
  131. package/dist/reactive-DDlThDSZ.mjs.map +1 -0
  132. package/dist/reactive-DFpqtIf_.d.mts +66 -0
  133. package/dist/relay.d.mts +5 -4
  134. package/dist/relay.mjs +2 -2
  135. package/dist/report-CHld4uWj.mjs +32 -0
  136. package/dist/report-CHld4uWj.mjs.map +1 -0
  137. package/dist/{signer-CZ6K6FUc.mjs → signer-CKR9EHce.mjs} +107 -72
  138. package/dist/signer-CKR9EHce.mjs.map +1 -0
  139. package/dist/signer.d.mts +3 -3
  140. package/dist/signer.mjs +3 -2
  141. package/dist/storage-xXxLGCVb.mjs +1376 -0
  142. package/dist/storage-xXxLGCVb.mjs.map +1 -0
  143. package/dist/storage.d.mts +4 -4
  144. package/dist/storage.mjs +5 -4
  145. package/dist/store.d.mts +2 -0
  146. package/dist/store.mjs +2 -0
  147. package/dist/testing.d.mts +125 -0
  148. package/dist/testing.mjs +957 -0
  149. package/dist/testing.mjs.map +1 -0
  150. package/dist/types-2pCUprRU.d.mts +47 -0
  151. package/dist/types-CRQEk0Oi.d.mts +19 -0
  152. package/dist/util-LfQirgDk.mjs +113 -0
  153. package/dist/util-LfQirgDk.mjs.map +1 -0
  154. package/dist/wasm.d.mts +4 -4
  155. package/dist/wasm.mjs +55 -56
  156. package/dist/wasm.mjs.map +1 -1
  157. package/dist/websocket-CmeqvAkp.d.mts +27 -0
  158. package/package.json +31 -9
  159. package/dist/builder-q0VsvnYE.mjs.map +0 -1
  160. package/dist/client-Bd8B1mYm.mjs.map +0 -1
  161. package/dist/error-B49rbDzT.d.mts +0 -7
  162. package/dist/error-CwBxle6N.mjs.map +0 -1
  163. package/dist/error-DZEs5OuZ.mjs +0 -24
  164. package/dist/error-DZEs5OuZ.mjs.map +0 -1
  165. package/dist/event-CzoQEFMF.mjs.map +0 -1
  166. package/dist/filter-BxwjEkZp.mjs.map +0 -1
  167. package/dist/filter-DUEKP3q1.d.mts +0 -40
  168. package/dist/gossip-3xkRRCm_.mjs.map +0 -1
  169. package/dist/http-D2rhokZo.mjs.map +0 -1
  170. package/dist/index-C0C4e-Gn.d.mts +0 -55
  171. package/dist/index-DgOugrpF.d.mts +0 -275
  172. package/dist/index-EwL6fHLo.d.mts +0 -267
  173. package/dist/index-k2YhCgsh.d.mts +0 -57
  174. package/dist/key-Dn-aX4x4.mjs.map +0 -1
  175. package/dist/kind-BLl4cLOc.mjs.map +0 -1
  176. package/dist/loaders-BNQszDAn.mjs.map +0 -1
  177. package/dist/memory-BCmhZPek.mjs.map +0 -1
  178. package/dist/message-C_Uj-Y-c.mjs.map +0 -1
  179. package/dist/pool-C_j1OmBB.mjs.map +0 -1
  180. package/dist/pool-DhRi7l-b.d.mts +0 -297
  181. package/dist/signer-CZ6K6FUc.mjs.map +0 -1
  182. package/dist/storage-DOy0iLRE.mjs +0 -870
  183. package/dist/storage-DOy0iLRE.mjs.map +0 -1
  184. package/dist/types-BzyADqnw.d.mts +0 -19
  185. package/dist/types-Dn24TPFs.d.mts +0 -43
  186. package/dist/util-6tfLQ9JF.mjs +0 -73
  187. package/dist/util-6tfLQ9JF.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.mjs","names":["parts","nip44Decrypt","nip44Encrypt"],"sources":["../src/testing/relay-core.ts","../src/testing/network.ts","../src/testing/serve.ts","../src/testing/conformance.ts","../src/testing/nip46.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport { compareEventsDesc, validateSignedEvent } from \"../core/event.ts\";\nimport { matchFilter } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { verifyEvent } from \"../core/key.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { bytesToHex, isRecord, normalizeURL } from \"../core/util.ts\";\nimport { Negentropy, PROTOCOL_VERSION, storageFromEvents } from \"../nips/nip77.ts\";\nimport { MemoryEventStore } from \"../storage/memory.ts\";\nimport type { PutResult } from \"../storage/types.ts\";\n\nexport type FakeRelayOptions = {\n /** Delay before every relay→client message. */\n latencyMs?: number;\n auth?: {\n /** Sent as `[\"AUTH\", challenge]` right after the socket opens. */\n challenge: string;\n /** REQ whose filters can match these kinds is CLOSED `auth-required:` until AUTH succeeds. */\n readKinds?: ReadonlyArray<number>;\n /** EVENT → `[\"OK\", id, false, \"auth-required: ...\"]` until AUTH succeeds. */\n writes?: boolean;\n };\n /** EVENT → `[\"OK\", id, false, \"rate-limited: ...\"]`; nothing is stored. */\n rateLimited?: boolean;\n /** Out-of-order reply: send EOSE first, then the stored events. */\n eoseBeforeEvents?: boolean;\n};\n\nexport type FakeRelay = {\n readonly url: string;\n seed: (events: ReadonlyArray<Event>) => void;\n events: () => ReadonlyArray<Event>;\n inject: (event: Event) => void;\n disconnect: () => void;\n closeSubscriptions: (reason: string) => void;\n configure: (opts: Partial<FakeRelayOptions>) => void;\n /** Every parsed client→relay message received, in arrival order. */\n clientMessages: () => ReadonlyArray<unknown>;\n};\n\n/** One relay→client transport (an in-process socket or a `ws` connection). */\nexport type RelayTransport = {\n send: (data: string) => void;\n close: () => void;\n};\n\nexport type FakeRelaySession = {\n transport: RelayTransport;\n subs: Map<string, Filter[]>;\n negs: Map<string, Negentropy>;\n authed: boolean;\n queue: Promise<void>;\n};\n\n/** Wire filters are trusted as NIP-01 filters once they are records. */\nfunction isFilter(value: unknown): value is Filter {\n return isRecord(value);\n}\n\nfunction searchMatch(filter: Filter, event: Event): boolean {\n if (filter.search === undefined) {\n return true;\n }\n return event.content.toLowerCase().includes(filter.search.toLowerCase());\n}\n\nfunction subMatches(filters: ReadonlyArray<Filter>, event: Event): boolean {\n return filters.some((f) => matchFilter(f, event) && searchMatch(f, event));\n}\n\n/** Put outcomes that made the event part of the relay's live stream. */\nfunction isLivePut(result: PutResult): boolean {\n return (\n result === \"accepted\" || result === \"replaced\" || result === \"deleted\" || result === \"ephemeral\"\n );\n}\n\nfunction mayReadKinds(filters: ReadonlyArray<Filter>, readKinds: ReadonlyArray<number>): boolean {\n return filters.some((f) => f.kinds === undefined || f.kinds.some((k) => readKinds.includes(k)));\n}\n\n/**\n * Transport-agnostic fake relay: one NIP-01/42/45/50/77 session state machine per connection,\n * storage via {@link MemoryEventStore}. No timers except `latencyMs`; no global state.\n */\nexport class FakeRelayCore implements FakeRelay {\n readonly url: string;\n #opts: FakeRelayOptions;\n readonly #store = new MemoryEventStore();\n readonly #sessions = new Set<FakeRelaySession>();\n #mirror = new Map<string, Event>();\n readonly #inbox: unknown[] = [];\n #pending: Promise<void> = Promise.resolve();\n\n constructor(url: string, opts: FakeRelayOptions = {}) {\n this.url = normalizeURL(url);\n this.#opts = opts;\n }\n\n configure(opts: Partial<FakeRelayOptions>): void {\n this.#opts = { ...this.#opts, ...opts };\n }\n\n seed(events: ReadonlyArray<Event>): void {\n for (const event of events) {\n this.#mirror.set(event.id, event);\n }\n this.#pending = (async (): Promise<void> => {\n await this.#pending;\n for (const event of events) {\n // Sequential puts keep per-event store ordering for replaceables.\n // oxlint-disable-next-line eslint/no-await-in-loop\n await this.#store.put(event);\n }\n await this.#refreshMirror();\n })();\n }\n\n events(): ReadonlyArray<Event> {\n return [...this.#mirror.values()];\n }\n\n inject(event: Event): void {\n this.#pending = (async (): Promise<void> => {\n await this.#pending;\n const result = await this.#store.put(event);\n await this.#refreshMirror();\n if (isLivePut(result)) {\n this.#deliver(event);\n }\n })();\n }\n\n disconnect(): void {\n const sessions: FakeRelaySession[] = [...this.#sessions];\n this.#sessions.clear();\n for (const session of sessions) {\n session.transport.close();\n }\n }\n\n closeSubscriptions(reason: string): void {\n for (const session of this.#sessions) {\n for (const id of session.subs.keys()) {\n this.#send(session, [\"CLOSED\", id, reason]);\n }\n session.subs.clear();\n session.negs.clear();\n }\n }\n\n clientMessages(): ReadonlyArray<unknown> {\n return this.#inbox;\n }\n\n /** Attach a transport; returns a handle for {@link handleMessage}/detach. */\n connect(transport: RelayTransport): FakeRelaySession {\n const session: FakeRelaySession = {\n transport,\n subs: new Map(),\n negs: new Map(),\n authed: false,\n queue: Promise.resolve(),\n };\n this.#sessions.add(session);\n if (this.#opts.auth) {\n this.#send(session, [\"AUTH\", this.#opts.auth.challenge]);\n }\n return session;\n }\n\n detach(session: FakeRelaySession): void {\n this.#sessions.delete(session);\n }\n\n /** Feed a raw client→relay frame. Messages of one session are handled in order. */\n handleMessage(session: FakeRelaySession, raw: string): void {\n // A handler throw must not poison the session queue: NOTICE and continue.\n session.queue = (async (): Promise<void> => {\n try {\n await session.queue;\n await this.#handle(session, raw);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n try {\n this.#send(session, [\"NOTICE\", `error: ${message}`]);\n } catch {\n // transport gone\n }\n }\n })();\n }\n\n async #refreshMirror(): Promise<void> {\n const all = await this.#store.query([{}]);\n this.#mirror = new Map(all.map((e) => [e.id, e]));\n }\n\n #send(session: FakeRelaySession, message: unknown[]): void {\n const payload = JSON.stringify(message);\n const { latencyMs } = this.#opts;\n if (latencyMs !== undefined && latencyMs > 0) {\n setTimeout(() => session.transport.send(payload), latencyMs);\n return;\n }\n session.transport.send(payload);\n }\n\n #deliver(event: Event): void {\n for (const session of this.#sessions) {\n for (const [id, filters] of session.subs) {\n if (subMatches(filters, event)) {\n this.#send(session, [\"EVENT\", id, event]);\n }\n }\n }\n }\n\n async #matched(filters: Filter[]): Promise<Event[]> {\n // Per-filter NIP-01 limit: query unbounded, apply search, keep that\n // filter's newest — never a cross-filter minimum.\n const keptPerFilter = await Promise.all(\n filters.map(async (filter): Promise<Event[]> => {\n const unbounded = { ...filter };\n delete unbounded.limit;\n const queried = await this.#store.query([unbounded]);\n const rows = queried.filter((event) => searchMatch(filter, event));\n rows.sort(compareEventsDesc);\n return filter.limit === undefined ? rows : rows.slice(0, filter.limit);\n }),\n );\n const seen = new Map<string, Event>();\n for (const kept of keptPerFilter) {\n for (const event of kept) {\n if (!seen.has(event.id)) {\n seen.set(event.id, event);\n }\n }\n }\n const matched = [...seen.values()];\n matched.sort(compareEventsDesc);\n return matched;\n }\n\n async #handle(session: FakeRelaySession, raw: string): Promise<void> {\n await this.#pending;\n let msg: unknown;\n try {\n msg = JSON.parse(raw);\n } catch {\n this.#send(session, [\"NOTICE\", \"error: invalid message\"]);\n return;\n }\n if (!Array.isArray(msg)) {\n this.#send(session, [\"NOTICE\", \"error: invalid message\"]);\n return;\n }\n const items: unknown[] = msg;\n const [type] = items;\n if (typeof type !== \"string\") {\n this.#send(session, [\"NOTICE\", \"error: invalid message\"]);\n return;\n }\n this.#inbox.push(msg);\n\n switch (type) {\n case \"EVENT\": {\n const [, rawEvent] = items;\n if (!isRecord(rawEvent) || typeof rawEvent[\"id\"] !== \"string\") {\n this.#send(session, [\"NOTICE\", \"invalid: malformed event\"]);\n return;\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- wire record trusted as Event; verifyEvent below is the authoritative check\n const event = rawEvent as Event;\n if (this.#opts.rateLimited === true) {\n this.#send(session, [\"OK\", event.id, false, \"rate-limited: slow down\"]);\n return;\n }\n if (this.#opts.auth?.writes === true && !session.authed) {\n this.#send(session, [\"OK\", event.id, false, \"auth-required: login first\"]);\n return;\n }\n if (!verifyEvent(event)) {\n this.#send(session, [\"OK\", event.id, false, \"invalid: signature or id\"]);\n return;\n }\n const result = await this.#store.put(event);\n await this.#refreshMirror();\n if (result === \"rejected\") {\n this.#send(session, [\n \"OK\",\n event.id,\n false,\n \"invalid: a newer version of this event exists\",\n ]);\n return;\n }\n if (result === \"invalid\") {\n this.#send(session, [\"OK\", event.id, false, \"invalid: malformed event\"]);\n return;\n }\n if (result === \"duplicate\") {\n this.#send(session, [\"OK\", event.id, true, \"duplicate: already have this event\"]);\n return;\n }\n this.#send(session, [\"OK\", event.id, true, \"\"]);\n this.#deliver(event);\n return;\n }\n case \"REQ\": {\n const [, id] = items;\n const filters = items.slice(2);\n if (typeof id !== \"string\" || filters.length === 0 || !filters.every(isFilter)) {\n this.#send(session, [\"NOTICE\", \"error: invalid REQ\"]);\n return;\n }\n const readKinds = this.#opts.auth?.readKinds;\n if (readKinds !== undefined && !session.authed && mayReadKinds(filters, readKinds)) {\n this.#send(session, [\"CLOSED\", id, \"auth-required: we only serve to authed users\"]);\n return;\n }\n session.subs.set(id, filters);\n const matched = await this.#matched(filters);\n if (this.#opts.eoseBeforeEvents === true) {\n this.#send(session, [\"EOSE\", id]);\n }\n for (const event of matched) {\n this.#send(session, [\"EVENT\", id, event]);\n }\n if (this.#opts.eoseBeforeEvents !== true) {\n this.#send(session, [\"EOSE\", id]);\n }\n return;\n }\n case \"CLOSE\": {\n const [, id] = items;\n if (typeof id === \"string\") {\n session.subs.delete(id);\n }\n return;\n }\n case \"COUNT\": {\n const [, id] = items;\n const filters = items.slice(2);\n if (typeof id !== \"string\" || !filters.every(isFilter)) {\n this.#send(session, [\"NOTICE\", \"error: invalid COUNT\"]);\n return;\n }\n const matched = await this.#matched(filters);\n this.#send(session, [\"COUNT\", id, { count: matched.length }]);\n return;\n }\n case \"AUTH\": {\n const { auth } = this.#opts;\n const [, rawAuth] = items;\n if (!validateSignedEvent(rawAuth)) {\n this.#send(session, [\"OK\", \"0\".repeat(64), false, \"error: invalid auth event\"]);\n return;\n }\n const challengeTag = rawAuth.tags.find((t) => t[0] === \"challenge\")?.[1];\n const relayTag = rawAuth.tags.find((t) => t[0] === \"relay\")?.[1];\n let relayOk = false;\n if (relayTag !== undefined) {\n try {\n relayOk = normalizeURL(relayTag) === this.url;\n } catch {\n // unparseable relay tag\n }\n }\n if (\n auth !== undefined &&\n rawAuth.kind === Kind.ClientAuth &&\n verifyEvent(rawAuth) &&\n challengeTag === auth.challenge &&\n relayOk\n ) {\n session.authed = true;\n this.#send(session, [\"OK\", rawAuth.id, true, \"\"]);\n return;\n }\n this.#send(session, [\"OK\", rawAuth.id, false, \"error: invalid auth event\"]);\n return;\n }\n case \"NEG-OPEN\": {\n if (items.length === 5) {\n this.#send(session, [\"NEG-ERR\", items[1], \"error: obsolete 5-element NEG-OPEN\"]);\n return;\n }\n const [, id, rawFilter, negMessage] = items;\n if (\n items.length !== 4 ||\n typeof id !== \"string\" ||\n !isFilter(rawFilter) ||\n typeof negMessage !== \"string\"\n ) {\n const badId = typeof id === \"string\" ? id : \"\";\n this.#send(session, [\"NEG-ERR\", badId, \"error: invalid NEG-OPEN\"]);\n return;\n }\n // The NIP-77 filter is a plain NIP-01 filter — `limit` applies.\n const matched = await this.#matched([rawFilter]);\n const neg = new Negentropy(storageFromEvents(matched));\n let opened: string | undefined;\n try {\n opened = neg.reconcile(negMessage).nextMessage ?? undefined;\n } catch {\n this.#send(session, [\"NEG-ERR\", id, \"error: invalid negentropy message\"]);\n return;\n }\n session.negs.set(id, neg);\n this.#send(session, [\n \"NEG-MSG\",\n id,\n opened ?? bytesToHex(new Uint8Array([PROTOCOL_VERSION])),\n ]);\n return;\n }\n case \"NEG-MSG\": {\n const [, id, negMessage] = items;\n if (items.length !== 3 || typeof id !== \"string\" || typeof negMessage !== \"string\") {\n return;\n }\n const handle = session.negs.get(id);\n if (handle === undefined) {\n this.#send(session, [\"NEG-ERR\", id, \"closed: unknown subscription\"]);\n return;\n }\n let next: string | undefined;\n try {\n next = handle.reconcile(negMessage).nextMessage ?? undefined;\n } catch {\n session.negs.delete(id);\n this.#send(session, [\"NEG-ERR\", id, \"error: invalid negentropy message\"]);\n return;\n }\n this.#send(session, [\n \"NEG-MSG\",\n id,\n next ?? bytesToHex(new Uint8Array([PROTOCOL_VERSION])),\n ]);\n return;\n }\n case \"NEG-CLOSE\": {\n const [, id] = items;\n if (typeof id === \"string\") {\n session.negs.delete(id);\n }\n return;\n }\n default:\n this.#send(session, [\"NOTICE\", `error: unsupported ${type}`]);\n }\n }\n}\n","import { normalizeURL } from \"../core/util.ts\";\nimport type { WebSocketConstructor } from \"../relay/websocket.ts\";\nimport { FakeRelayCore } from \"./relay-core.ts\";\nimport type { FakeRelay, FakeRelayOptions, RelayTransport } from \"./relay-core.ts\";\n\nexport { type FakeRelay, type FakeRelayOptions } from \"./relay-core.ts\";\nexport type FakeRelayNetwork = {\n /** Pass to `Client` / `Pool` / `useWebSocketImplementation`. */\n readonly websocketImplementation: WebSocketConstructor;\n /** Get-or-create a relay handle by normalized URL. */\n relay: (url: string, opts?: FakeRelayOptions) => FakeRelay;\n close: () => void;\n};\n\ntype Listener = (ev: unknown) => void;\n\n/**\n * In-process fake relay network. `new websocketImplementation(url)` opens a socket bound to the\n * network's relay for that URL; `send` is dispatched to the relay session directly (no polling).\n */\nexport function createFakeRelayNetwork(defaults: FakeRelayOptions = {}): FakeRelayNetwork {\n const cores = new Map<string, FakeRelayCore>();\n\n const coreFor = (url: string, opts?: FakeRelayOptions): FakeRelayCore => {\n const key = normalizeURL(url);\n let core = cores.get(key);\n if (!core) {\n core = new FakeRelayCore(key, { ...defaults, ...opts });\n cores.set(key, core);\n } else if (opts) {\n core.configure(opts);\n }\n return core;\n };\n\n class FakeSocket {\n static readonly OPEN = 1;\n static readonly CONNECTING = 0;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n\n readonly url: string;\n /** Client→relay frames, for tests that inspect wire traffic. */\n readonly sent: string[] = [];\n readyState = FakeSocket.CONNECTING;\n readonly #listeners = new Map<string, Set<Listener>>();\n #session: ReturnType<FakeRelayCore[\"connect\"]> | undefined;\n #queuedSends: string[] = [];\n readonly #core: FakeRelayCore;\n\n constructor(url: string) {\n this.url = url;\n this.#core = coreFor(url);\n queueMicrotask(() => this.#open());\n }\n\n #open(): void {\n if (this.readyState !== FakeSocket.CONNECTING) {\n return;\n }\n this.readyState = FakeSocket.OPEN;\n const transport: RelayTransport = {\n send: (data) => this.#emit(\"message\", { data }),\n close: () => this.#terminate(),\n };\n // \"open\" listeners may send immediately; relay frames (e.g. the AUTH\n // challenge) must follow \"open\", so connect afterwards and flush.\n this.#emit(\"open\", {});\n this.#session = this.#core.connect(transport);\n const queued = this.#queuedSends;\n this.#queuedSends = [];\n for (const data of queued) {\n this.#core.handleMessage(this.#session, data);\n }\n }\n\n send(data: string): void {\n if (this.readyState !== FakeSocket.OPEN) {\n return;\n }\n this.sent.push(data);\n if (this.#session) {\n this.#core.handleMessage(this.#session, data);\n } else {\n this.#queuedSends.push(data);\n }\n }\n\n close(): void {\n this.#terminate();\n }\n\n #terminate(): void {\n if (this.readyState === FakeSocket.CLOSING || this.readyState === FakeSocket.CLOSED) {\n this.readyState = FakeSocket.CLOSED;\n return;\n }\n this.readyState = FakeSocket.CLOSED;\n const session = this.#session;\n this.#session = undefined;\n if (session) {\n this.#core.detach(session);\n }\n this.#emit(\"close\", {});\n }\n\n addEventListener(type: string, listener: Listener): void {\n let set = this.#listeners.get(type);\n if (!set) {\n set = new Set();\n this.#listeners.set(type, set);\n }\n set.add(listener);\n }\n\n removeEventListener(type: string, listener: Listener): void {\n this.#listeners.get(type)?.delete(listener);\n }\n\n #emit(type: string, ev: unknown): void {\n for (const listener of this.#listeners.get(type) ?? []) {\n listener(ev);\n }\n }\n }\n\n return {\n websocketImplementation: FakeSocket,\n relay: coreFor,\n close() {\n for (const core of cores.values()) {\n core.disconnect();\n }\n cores.clear();\n },\n };\n}\n","import { FakeRelayCore } from \"./relay-core.ts\";\nimport type { FakeRelay, FakeRelayOptions, RelayTransport } from \"./relay-core.ts\";\n\nexport type ServedFakeRelay = {\n url: string;\n relay: FakeRelay;\n close: () => Promise<void>;\n};\n\n/**\n * Serve the fake relay on a real WebSocket port via the optional `ws` peer dependency (dynamic\n * import — `@qntx/nostr/testing` never requires `ws` unless you serve). `port: 0` picks an\n * ephemeral port.\n */\nexport async function serveFakeRelay(\n opts: FakeRelayOptions & { port?: number; host?: string } = {},\n): Promise<ServedFakeRelay> {\n const { port = 0, host = \"127.0.0.1\", ...relayOpts } = opts;\n const { WebSocketServer } = await import(\"ws\");\n const wss = new WebSocketServer({ port, host });\n await new Promise<void>((resolve, reject) => {\n wss.once(\"listening\", () => resolve());\n wss.once(\"error\", (err) => reject(err));\n });\n const address = wss.address();\n const bound = typeof address === \"object\" && address !== null ? address.port : port;\n const url = `ws://${host}:${bound}`;\n const core = new FakeRelayCore(url, relayOpts);\n\n wss.on(\"connection\", (socket) => {\n const transport: RelayTransport = {\n send: (data) => socket.send(data),\n close: () => socket.close(),\n };\n const session = core.connect(transport);\n socket.on(\"message\", (data: unknown) => {\n core.handleMessage(session, String(data));\n });\n socket.on(\"close\", () => core.detach(session));\n socket.on(\"error\", () => core.detach(session));\n });\n\n return {\n url,\n relay: core,\n close: async () =>\n new Promise((resolve) => {\n core.disconnect();\n for (const client of wss.clients) {\n client.terminate();\n }\n wss.close(() => resolve());\n }),\n };\n}\n","import { EventBuilder, Keys } from \"../core/index.ts\";\nimport type { Event } from \"../core/index.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\n\nexport { type Filter } from \"../core/filter.ts\";\n\nexport type EventStoreConformanceCase = {\n name: string;\n run: (store: EventStore) => Promise<void>;\n};\n\nconst ALICE_SK = \"0000000000000000000000000000000000000000000000000000000000000101\";\nconst BOB_SK = \"0000000000000000000000000000000000000000000000000000000000000102\";\n\nfunction alice(): Keys {\n return Keys.fromSecretKey(ALICE_SK);\n}\nfunction bob(): Keys {\n return Keys.fromSecretKey(BOB_SK);\n}\n\nfunction note(keys: Keys, content: string, createdAt: number, tags: string[][] = []): Event {\n return new EventBuilder(1, content).tags(tags).createdAt(createdAt).signWithKeys(keys);\n}\n\nfunction replaceable(keys: Keys, kind: number, content: string, createdAt: number): Event {\n return new EventBuilder(kind, content).createdAt(createdAt).signWithKeys(keys);\n}\n\nfunction addressable(\n keys: Keys,\n kind: number,\n d: string,\n content: string,\n createdAt: number,\n): Event {\n return new EventBuilder(kind, content)\n .tags([[\"d\", d]])\n .createdAt(createdAt)\n .signWithKeys(keys);\n}\n\nfunction fail(message: string): never {\n throw new Error(`EventStore conformance: ${message}`);\n}\n\nfunction eq<T>(got: T, want: T, what: string): void {\n if (JSON.stringify(got) !== JSON.stringify(want)) {\n fail(`${what}: expected ${JSON.stringify(want)}, got ${JSON.stringify(got)}`);\n }\n}\n\nfunction ids(events: ReadonlyArray<Event>): string[] {\n return events.map((e) => e.id);\n}\n\n/**\n * Framework-agnostic {@link EventStore} conformance cases. Each `run` throws on failure; register\n * them with the test framework of your choice: `for (const c of eventStoreConformanceCases)\n * test(c.name, () => c.run(store()))`.\n */\nexport const eventStoreConformanceCases: ReadonlyArray<EventStoreConformanceCase> = [\n {\n name: \"put accepted then duplicate\",\n async run(store) {\n const e = note(alice(), \"hello\", 1);\n eq(await store.put(e), \"accepted\", \"first put\");\n eq(await store.put(e), \"duplicate\", \"second put\");\n eq(await store.get(e.id), e, \"get after put\");\n eq(\n await store.putMany([note(alice(), \"a\", 2), note(alice(), \"b\", 3)]),\n [\"accepted\", \"accepted\"],\n \"putMany results\",\n );\n },\n },\n {\n name: \"ephemeral event returns ephemeral and is not stored\",\n async run(store) {\n const e = replaceable(alice(), 20001, \"ephemeral\", 1);\n eq(await store.put(e), \"ephemeral\", \"put ephemeral\");\n eq(await store.get(e.id), undefined, \"ephemeral not retrievable\");\n eq(await store.query([{ kinds: [20001] }]), [], \"ephemeral not queryable\");\n eq(await store.count([{ kinds: [20001] }]), 0, \"ephemeral not counted\");\n },\n },\n {\n name: \"replaceable event keeps newest and rejects stale\",\n async run(store) {\n const older = replaceable(alice(), 0, \"old\", 1);\n const newer = replaceable(alice(), 0, \"new\", 2);\n eq(await store.put(older), \"accepted\", \"first replaceable\");\n eq(await store.put(newer), \"replaced\", \"newer replaces\");\n eq(await store.put(older), \"rejected\", \"stale replaceable rejected\");\n eq(await store.get(older.id), undefined, \"replaced event gone\");\n eq(\n ids(await store.query([{ kinds: [0], authors: [alice().publicKey] }])),\n [newer.id],\n \"newest kept\",\n );\n },\n },\n {\n name: \"addressable event replaces by address\",\n async run(store) {\n const v1 = addressable(alice(), 30001, \"x\", \"v1\", 1);\n const v2 = addressable(alice(), 30001, \"x\", \"v2\", 2);\n const other = addressable(alice(), 30001, \"y\", \"other\", 3);\n eq(await store.put(v1), \"accepted\", \"first addressable\");\n eq(await store.put(v2), \"replaced\", \"same address replaced\");\n eq(await store.put(v1), \"rejected\", \"stale addressable rejected\");\n eq(await store.put(other), \"accepted\", \"different address independent\");\n eq(await store.get(v1.id), undefined, \"v1 gone\");\n eq(\n ids(await store.query([{ kinds: [30001], authors: [alice().publicKey] }])).sort(),\n [other.id, v2.id].sort(),\n \"independent addresses\",\n );\n },\n },\n {\n name: \"deletion removes same-author e-tag targets only\",\n async run(store) {\n const mine = note(alice(), \"mine\", 1);\n const theirs = note(bob(), \"theirs\", 1);\n await store.put(mine);\n await store.put(theirs);\n const delForeign = EventBuilder.deletion([theirs.id]).createdAt(2).signWithKeys(alice());\n eq(await store.put(delForeign), \"deleted\", \"kind 5 accepted\");\n eq(await store.get(theirs.id), theirs, \"other author's event survives\");\n const delMine = EventBuilder.deletion([mine.id]).createdAt(3).signWithKeys(alice());\n eq(await store.put(delMine), \"deleted\", \"kind 5 accepted\");\n eq(await store.get(mine.id), undefined, \"own event deleted\");\n eq(await store.query([{ ids: [mine.id] }]), [], \"deleted event not queryable\");\n eq(await store.put(mine), \"duplicate\", \"deleted event cannot be re-put\");\n },\n },\n {\n name: \"deletion removes addressable via a tag and tombstones re-put\",\n async run(store) {\n const target = addressable(alice(), 30001, \"z\", \"target\", 1);\n await store.put(target);\n const coord = `30001:${alice().publicKey}:z`;\n const del = EventBuilder.deletion([{ address: coord }], \"\")\n .createdAt(2)\n .signWithKeys(alice());\n eq(await store.put(del), \"deleted\", \"a-tag deletion\");\n eq(await store.get(target.id), undefined, \"addressable deleted\");\n const stillCovered = addressable(alice(), 30001, \"z\", \"covered\", 1);\n eq(await store.put(stillCovered), \"duplicate\", \"tombstoned address rejects re-put\");\n eq(await store.query([{ kinds: [30001], authors: [alice().publicKey] }]), [], \"none left\");\n const after = addressable(alice(), 30001, \"z\", \"after\", 3);\n eq(await store.put(after), \"accepted\", \"events newer than the deletion are kept\");\n },\n },\n {\n name: \"query orders newest first and applies limit\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n const b = note(alice(), \"b\", 3);\n const c = note(alice(), \"c\", 2);\n await store.putMany([a, b, c]);\n eq(\n ids(await store.query([{ kinds: [1], authors: [alice().publicKey] }])),\n [b.id, c.id, a.id],\n \"descending created_at\",\n );\n eq(\n ids(await store.query([{ kinds: [1], authors: [alice().publicKey], limit: 2 }])),\n [b.id, c.id],\n \"limit applies\",\n );\n },\n },\n {\n name: \"query filters by kinds, authors, #e, #p, since, until\",\n async run(store) {\n const target = note(bob(), \"target\", 1);\n const tagged = note(alice(), \"tagged\", 2, [\n [\"e\", target.id],\n [\"p\", bob().publicKey],\n ]);\n const plain = note(alice(), \"plain\", 3);\n await store.putMany([target, tagged, plain]);\n const all = await store.query([{ kinds: [1] }]);\n eq(all.length, 3, \"kind filter\");\n eq(ids(await store.query([{ authors: [bob().publicKey] }])), [target.id], \"authors\");\n eq(ids(await store.query([{ \"#e\": [target.id] }])), [tagged.id], \"#e\");\n eq(ids(await store.query([{ \"#p\": [bob().publicKey] }])), [tagged.id], \"#p\");\n eq(ids(await store.query([{ kinds: [1], since: 2 }])), [plain.id, tagged.id], \"since\");\n eq(ids(await store.query([{ kinds: [1], until: 2 }])), [tagged.id, target.id], \"until\");\n eq(\n ids(await store.query([{ ids: [target.id, tagged.id] }])).sort(),\n [tagged.id, target.id].sort(),\n \"ids filter\",\n );\n },\n },\n {\n name: \"count matches query cardinality across overlapping filters\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n const b = note(bob(), \"b\", 2);\n await store.putMany([a, b]);\n eq(await store.count([{ kinds: [1] }]), 2, \"count all\");\n eq(\n await store.count([\n { authors: [alice().publicKey] },\n { authors: [bob().publicKey] },\n { ids: [a.id] },\n ]),\n 2,\n \"count dedupes union\",\n );\n eq(await store.count([{ kinds: [2] }]), 0, \"count none\");\n },\n },\n {\n name: \"negentropyItems sorted by created_at then id and respects limit\",\n async run(store) {\n const a = note(alice(), \"a\", 2);\n const b = note(alice(), \"b\", 1);\n const c = note(bob(), \"c\", 3);\n await store.putMany([a, b, c]);\n const items = await store.negentropyItems({ kinds: [1] });\n eq(\n items.map((i) => i.id),\n [b.id, a.id, c.id],\n \"created_at asc ordering\",\n );\n const limited = await store.negentropyItems({ kinds: [1], limit: 2 });\n eq(\n limited.map((i) => i.id),\n [a.id, c.id],\n \"limit keeps newest two, presented ascending\",\n );\n eq(await store.negentropyItems({ kinds: [2] }), [], \"no match\");\n const filtered = await store.negentropyItems({ authors: [bob().publicKey] });\n eq(filtered, [{ id: c.id, created_at: 3 }], \"filter\");\n },\n },\n {\n name: \"outbox bounds roundtrip\",\n async run(store) {\n eq(await store.getOutboxBound(alice().publicKey, 1), undefined, \"unset bound\");\n await store.setOutboxBound(alice().publicKey, 1, { oldest: 10, newest: 20 });\n eq(\n await store.getOutboxBound(alice().publicKey, 1),\n { oldest: 10, newest: 20 },\n \"bound read\",\n );\n await store.setOutboxBound(alice().publicKey, 1, { oldest: 5, newest: 30 });\n eq(\n await store.getOutboxBound(alice().publicKey, 1),\n { oldest: 5, newest: 30 },\n \"bound overwrite\",\n );\n },\n },\n {\n name: \"remove deletes by id and tombstones\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n await store.put(a);\n eq(await store.remove([a.id]), 1, \"remove count\");\n eq(await store.get(a.id), undefined, \"removed\");\n eq(await store.remove([a.id]), 0, \"second remove is noop\");\n eq(await store.put(a), \"duplicate\", \"removed id tombstoned\");\n },\n },\n {\n name: \"clear wipes events and bounds\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n await store.put(a);\n await store.setOutboxBound(alice().publicKey, 1, { oldest: 1, newest: 1 });\n await store.clear();\n eq(await store.get(a.id), undefined, \"event gone\");\n eq(await store.query([{ kinds: [1] }]), [], \"query empty\");\n eq(await store.getOutboxBound(alice().publicKey, 1), undefined, \"bound gone\");\n eq(await store.put(a), \"accepted\", \"store usable after clear\");\n },\n },\n];\n","import { Keys, finalizeEvent } from \"../core/index.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { isTag } from \"../core/tag.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport {\n getConversationKey,\n decrypt as nip44Decrypt,\n encrypt as nip44Encrypt,\n} from \"../nips/nip44.ts\";\nimport { decodeNip46Request, encodeNip46Response } from \"../nips/nip46.ts\";\nimport type { Nip46Response } from \"../nips/nip46.ts\";\nimport type { FakeRelayNetwork } from \"./network.ts\";\n\nexport type FakeNip46SignerOptions = {\n /** The network the fake signer joins as a client of `relayUrl`. */\n network: FakeRelayNetwork;\n relayUrl: string;\n /** Pubkey of the NIP-46 client under test. */\n clientPubkey: string;\n /** Remote-signer key; random when omitted. */\n bunkerSk?: string;\n /** The user key the signer signs for; random when omitted. */\n userSk?: string;\n /** First answer `auth_url` (result) with this URL in the error field, then the real response. */\n authUrl?: string;\n authUrlMethods?: ReadonlyArray<string>;\n /** Delay in ms before the real response after an `auth_url` reply. */\n authReplyDelayMs?: number;\n /** Collected RPC requests (mutated as they arrive). */\n requests?: Array<{ method: string; params: string[] }>;\n /** `switch_relays` result. Default `\"null\"`. */\n switchRelays?: string[] | undefined;\n /** Override `connect` RPC result. Default `\"ack\"`. */\n connectResult?: string;\n /** Reply with neither `result` nor `error` for these methods. */\n emptyMethods?: ReadonlyArray<string>;\n /**\n * Serialize the response JSON; default {@link encodeNip46Response}, which omits absent fields.\n * Lets tests put explicit `null`s on the wire like some remote signers do.\n */\n encodeResponse?: (res: Nip46Response) => string;\n};\n\nexport type FakeNip46Signer = {\n readonly bunkerPubkey: string;\n readonly userPublicKey: string;\n /** Also answer RPCs on another relay of the same network (e.g. after switch_relays). */\n attach: (relayUrl: string) => void;\n /** Publish the nostrconnect handshake secret confirmation as the bunker. */\n confirmHandshake: (secret: string) => void;\n close: () => void;\n};\n\n/**\n * In-process NIP-46 remote signer: subscribes to kind:24133 requests on `relayUrl` and answers as a\n * bunker, encrypted to `clientPubkey` with NIP-44.\n */\nexport function createFakeNip46Signer(opts: FakeNip46SignerOptions): FakeNip46Signer {\n const bunkerKeys =\n opts.bunkerSk !== undefined && opts.bunkerSk !== \"\"\n ? Keys.fromSecretKey(opts.bunkerSk)\n : Keys.generate();\n const userKeys =\n opts.userSk !== undefined && opts.userSk !== \"\"\n ? Keys.fromSecretKey(opts.userSk)\n : Keys.generate();\n const convKey = getConversationKey(bunkerKeys.secretKey.bytes, opts.clientPubkey);\n const handled = new Set<string>();\n const authPending = new Set<string>();\n const authMethods = new Set(opts.authUrlMethods ?? [\"connect\"]);\n let closed = false;\n\n const sockets = new Set<{ close: () => void }>();\n const listen = (relayUrl: string): void => {\n const ws = new opts.network.websocketImplementation(relayUrl);\n ws.addEventListener(\"open\", () => {\n ws.send(\n JSON.stringify([\n \"REQ\",\n \"fake-nip46-signer\",\n { kinds: [Kind.NostrConnect], \"#p\": [bunkerKeys.publicKey] },\n ]),\n );\n });\n ws.addEventListener(\"message\", (ev) => onMessage(ev, ws));\n sockets.add(ws);\n };\n\n const onMessage = (ev: unknown, ws: { send: (data: string) => void }): void => {\n if (typeof ev !== \"object\" || ev === null || !(\"data\" in ev)) {\n return;\n }\n const { data } = ev;\n let msg: unknown;\n try {\n msg = JSON.parse(String(data));\n } catch {\n return;\n }\n if (!Array.isArray(msg) || msg[0] !== \"EVENT\") {\n return;\n }\n const parts: unknown[] = msg;\n const rawEvent = parts.at(2);\n if (!isRecord(rawEvent)) {\n return;\n }\n const { kind, pubkey, content, id } = rawEvent;\n if (kind !== Kind.NostrConnect) {\n return;\n }\n if (typeof pubkey !== \"string\" || typeof content !== \"string\" || typeof id !== \"string\") {\n return;\n }\n if (pubkey !== opts.clientPubkey || handled.has(id)) {\n return;\n }\n\n try {\n const req = decodeNip46Request(nip44Decrypt(content, convKey));\n if (\n opts.authUrl !== undefined &&\n opts.authUrl !== \"\" &&\n authMethods.has(req.method) &&\n !authPending.has(req.id)\n ) {\n authPending.add(req.id);\n reply(ws, opts.clientPubkey, req.id, \"auth_url\", opts.authUrl);\n }\n handled.add(id);\n opts.requests?.push({ method: req.method, params: req.params });\n\n let result: string | undefined;\n let error: string | undefined;\n switch (opts.emptyMethods?.includes(req.method) === true ? \"#empty\" : req.method) {\n case \"connect\":\n result = opts.connectResult ?? \"ack\";\n break;\n case \"get_public_key\":\n result = userKeys.publicKey;\n break;\n case \"ping\":\n result = \"pong\";\n break;\n case \"switch_relays\":\n result = opts.switchRelays === undefined ? \"null\" : JSON.stringify(opts.switchRelays);\n break;\n case \"logout\":\n result = \"ack\";\n break;\n case \"sign_event\": {\n const rawTemplate: unknown = JSON.parse(req.params.at(0) ?? \"null\");\n if (\n !isRecord(rawTemplate) ||\n typeof rawTemplate[\"kind\"] !== \"number\" ||\n !Array.isArray(rawTemplate[\"tags\"]) ||\n !rawTemplate[\"tags\"].every(isTag) ||\n typeof rawTemplate[\"content\"] !== \"string\" ||\n typeof rawTemplate[\"created_at\"] !== \"number\"\n ) {\n throw new Error(\"invalid sign_event template\");\n }\n result = JSON.stringify(\n finalizeEvent(\n {\n kind: rawTemplate[\"kind\"],\n tags: rawTemplate[\"tags\"],\n content: rawTemplate[\"content\"],\n created_at: rawTemplate[\"created_at\"],\n },\n userKeys.secretKey,\n ),\n );\n break;\n }\n case \"#empty\":\n break;\n default:\n error = `unsupported method ${req.method}`;\n }\n if (authPending.has(req.id) && opts.authReplyDelayMs !== undefined) {\n const pendingId = req.id;\n const pendingResult = result;\n const pendingError = error;\n setTimeout(\n () => reply(ws, opts.clientPubkey, pendingId, pendingResult, pendingError),\n opts.authReplyDelayMs,\n );\n } else {\n reply(ws, opts.clientPubkey, req.id, result, error);\n }\n } catch {\n handled.add(id);\n }\n };\n\n const reply = (\n ws: { send: (data: string) => void },\n clientPubkey: string,\n id: string,\n result?: string,\n error?: string,\n ): void => {\n if (closed) {\n return;\n }\n const payload = (opts.encodeResponse ?? encodeNip46Response)({ id, result, error });\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [[\"p\", clientPubkey]],\n content: nip44Encrypt(payload, convKey),\n created_at: Math.floor(Date.now() / 1000),\n },\n bunkerKeys.secretKey,\n );\n ws.send(JSON.stringify([\"EVENT\", event]));\n };\n\n listen(opts.relayUrl);\n\n return {\n bunkerPubkey: bunkerKeys.publicKey,\n userPublicKey: userKeys.publicKey,\n confirmHandshake(secret: string): void {\n const payload = encodeNip46Response({ id: \"handshake\", result: secret });\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [[\"p\", opts.clientPubkey]],\n content: nip44Encrypt(payload, convKey),\n created_at: Math.floor(Date.now() / 1000),\n },\n bunkerKeys.secretKey,\n );\n opts.network.relay(opts.relayUrl).inject(event);\n },\n attach(relayUrl: string): void {\n listen(relayUrl);\n },\n close(): void {\n closed = true;\n for (const ws of sockets) {\n ws.close();\n }\n sockets.clear();\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { t as Event } from "./event-fU3Y01PR.mjs";
2
+ import { t as Filter } from "./filter-C0IMByE3.mjs";
3
+ //#region src/storage/types.d.ts
4
+ /**
5
+ * `"invalid"`: the event failed canonical shape validation (see `validateSignedEvent`); it was not
6
+ * stored and no deletion state changed.
7
+ */
8
+ type PutResult = "accepted" | "duplicate" | "replaced" | "rejected" | "ephemeral" | "deleted" | "invalid";
9
+ /** NIP-77 item: event id + created_at. Sorted created_at asc, then id. */
10
+ type NegentropyItem = {
11
+ id: string;
12
+ created_at: number;
13
+ };
14
+ /** Inclusive created_at window of stored live events for one author+kind. */
15
+ type OutboxBound = {
16
+ oldest: number;
17
+ newest: number;
18
+ };
19
+ /**
20
+ * Event store contract (aligned with nula-storage NostrDatabase, narrowed for v0). Implementations
21
+ * apply replaceable / addressable / deletion semantics on put.
22
+ */
23
+ type EventStore = {
24
+ put: (event: Event) => Promise<PutResult>;
25
+ /**
26
+ * Persist in input order. IndexedDB: one transaction, abort rolls the batch back. Memory:
27
+ * sequential; put does not throw, so a rejected item does not undo earlier accepts.
28
+ */
29
+ putMany: (events: ReadonlyArray<Event>) => Promise<PutResult[]>;
30
+ get: (id: string) => Promise<Event | undefined>;
31
+ query: (filters: Filter[]) => Promise<Event[]>;
32
+ /** Unique events matching `filters` (same cardinality as {@link query}). */
33
+ count: (filters: Filter[]) => Promise<number>;
34
+ /**
35
+ * Matching `{ id, created_at }` for one filter, sorted created_at asc then id. Does not allocate
36
+ * an `Event[]`.
37
+ */
38
+ negentropyItems: (filter: Filter) => Promise<NegentropyItem[]>;
39
+ getOutboxBound: (pubkey: string, kind: number) => Promise<OutboxBound | undefined>;
40
+ setOutboxBound: (pubkey: string, kind: number, bound: OutboxBound) => Promise<void>;
41
+ /** Remove by id (does not publish NIP-09). */
42
+ remove: (ids: string[]) => Promise<number>;
43
+ clear: () => Promise<void>;
44
+ };
45
+ //#endregion
46
+ export { PutResult as i, NegentropyItem as n, OutboxBound as r, EventStore as t };
47
+ //# sourceMappingURL=types-2pCUprRU.d.mts.map
@@ -0,0 +1,19 @@
1
+ import { r as UnsignedEvent, t as Event } from "./event-fU3Y01PR.mjs";
2
+ //#region src/signer/types.d.ts
3
+ /**
4
+ * Universal signing interface (aligned with nula's NostrSigner). Implementations: KeysSigner,
5
+ * Nip07Signer, Nip46Signer, …
6
+ */
7
+ type NostrSigner = {
8
+ getPublicKey: () => Promise<string>;
9
+ signEvent: (unsigned: UnsignedEvent) => Promise<Event>;
10
+ /** Optional NIP-04 (legacy). Unsupported signers reject. */
11
+ nip04Encrypt?: (peer: string, plaintext: string) => Promise<string>;
12
+ nip04Decrypt?: (peer: string, ciphertext: string) => Promise<string>;
13
+ /** Optional NIP-44 v2. Unsupported signers reject. */
14
+ nip44Encrypt?: (peer: string, plaintext: string) => Promise<string>;
15
+ nip44Decrypt?: (peer: string, payload: string) => Promise<string>;
16
+ };
17
+ //#endregion
18
+ export { NostrSigner as t };
19
+ //# sourceMappingURL=types-CRQEk0Oi.d.mts.map
@@ -0,0 +1,113 @@
1
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
2
+ //#region src/core/limits.ts
3
+ /** NIP-01 event id length in bytes. */
4
+ const EVENT_ID_BYTES = 32;
5
+ /** BIP-340 signature length in bytes. */
6
+ const SIGNATURE_BYTES = 64;
7
+ /** BIP-340 public key length in bytes (x-only). */
8
+ const PUBLIC_KEY_BYTES = 32;
9
+ /** BIP-340 secret key length in bytes. */
10
+ const SECRET_KEY_BYTES = 32;
11
+ /** NIP-01 subscription id max character length. */
12
+ const SUBSCRIPTION_ID_MAX_CHARS = 64;
13
+ //#endregion
14
+ //#region src/core/error.ts
15
+ /** Base error for all @qntx/nostr failures. */
16
+ var NostrError = class extends Error {
17
+ name = "NostrError";
18
+ };
19
+ /** Invalid hex encoding or length. */
20
+ var HexError = class extends NostrError {
21
+ name = "HexError";
22
+ };
23
+ /** Invalid URL / relay URL. */
24
+ var UrlError = class extends NostrError {
25
+ name = "UrlError";
26
+ };
27
+ /** Event shape / wire validation failure. */
28
+ var EventValidationError = class extends NostrError {
29
+ name = "EventValidationError";
30
+ };
31
+ /** Cryptographic operation failure (keys, signatures). */
32
+ var CryptoError = class extends NostrError {
33
+ name = "CryptoError";
34
+ };
35
+ /** Message parse / encode failure. */
36
+ var MessageError = class extends NostrError {
37
+ name = "MessageError";
38
+ };
39
+ /** Wasm verify instance aborted; later verifies on that instance fail. */
40
+ var WasmVerifyPoisonedError = class extends NostrError {
41
+ name = "WasmVerifyPoisonedError";
42
+ };
43
+ //#endregion
44
+ //#region src/core/util.ts
45
+ const utf8Encoder = new TextEncoder();
46
+ const utf8Decoder = new TextDecoder();
47
+ const HEX32_RE = /^[0-9a-f]{64}$/;
48
+ const HEX64_RE = /^[0-9a-f]{128}$/;
49
+ /** Lowercase hex encode. */
50
+ function bytesToHex$1(bytes) {
51
+ return bytesToHex(bytes);
52
+ }
53
+ /** Decode lowercase or mixed-case hex to bytes. */
54
+ function hexToBytes$1(hex) {
55
+ try {
56
+ return hexToBytes(hex);
57
+ } catch (error) {
58
+ throw new HexError(`invalid hex string of length ${hex.length}`, { cause: error instanceof Error ? error : void 0 });
59
+ }
60
+ }
61
+ /** True when value is canonical NIP-01 lowercase hex of 32 bytes (64 chars). */
62
+ function isHex32(value) {
63
+ return HEX32_RE.test(value);
64
+ }
65
+ /** True when value is canonical NIP-01 lowercase hex of 64 bytes (128 chars). */
66
+ function isHex64(value) {
67
+ return HEX64_RE.test(value);
68
+ }
69
+ /** Caller input of any case: lowercases first, then requires canonical hex shape. */
70
+ function assertHex32(value, label) {
71
+ const normalized = value.toLowerCase();
72
+ if (!isHex32(normalized)) throw new HexError(`invalid ${label}: expected 64-char hex`);
73
+ return normalized;
74
+ }
75
+ function assertByteLength(bytes, expected, label) {
76
+ if (bytes.length !== expected) throw new HexError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);
77
+ }
78
+ function assertSecretKeyBytes(bytes) {
79
+ assertByteLength(bytes, 32, "secret key");
80
+ }
81
+ /** Structural guard: a plain record (not `null`, not an array). */
82
+ function isRecord(value) {
83
+ return typeof value === "object" && value !== null && !Array.isArray(value);
84
+ }
85
+ /**
86
+ * Normalize a relay URL to a stable form: `http:`/`https:` are rewritten to `ws:`/`wss:` (a bare
87
+ * host gets `wss://`), any other scheme throws UrlError. The result has a lowercased host, the
88
+ * default port removed, duplicate path slashes collapsed, a sorted query, and no fragment. `URL`
89
+ * serialization keeps a trailing `/` on the root path (`wss://a.example/`).
90
+ */
91
+ function normalizeURL(url) {
92
+ try {
93
+ let input = url;
94
+ if (!input.includes("://")) input = `wss://${input}`;
95
+ const p = new URL(input);
96
+ if (p.protocol === "http:") p.protocol = "ws:";
97
+ else if (p.protocol === "https:") p.protocol = "wss:";
98
+ if (p.protocol !== "ws:" && p.protocol !== "wss:") throw new UrlError(`unsupported relay URL scheme: ${p.protocol}`);
99
+ p.pathname = p.pathname.replaceAll(/\/+/g, "/");
100
+ if (p.pathname.endsWith("/") && p.pathname.length > 1) p.pathname = p.pathname.slice(0, -1);
101
+ if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:") p.port = "";
102
+ p.searchParams.sort();
103
+ p.hash = "";
104
+ return p.toString();
105
+ } catch (error) {
106
+ if (error instanceof UrlError) throw error;
107
+ throw new UrlError(`invalid URL: ${url}`, { cause: error instanceof Error ? error : void 0 });
108
+ }
109
+ }
110
+ //#endregion
111
+ export { SUBSCRIPTION_ID_MAX_CHARS as C, SIGNATURE_BYTES as S, UrlError as _, hexToBytes$1 as a, PUBLIC_KEY_BYTES as b, isRecord as c, utf8Encoder as d, CryptoError as f, NostrError as g, MessageError as h, bytesToHex$1 as i, normalizeURL as l, HexError as m, assertHex32 as n, isHex32 as o, EventValidationError as p, assertSecretKeyBytes as r, isHex64 as s, assertByteLength as t, utf8Decoder as u, WasmVerifyPoisonedError as v, SECRET_KEY_BYTES as x, EVENT_ID_BYTES as y };
112
+
113
+ //# sourceMappingURL=util-LfQirgDk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util-LfQirgDk.mjs","names":["bytesToHex","nobleBytesToHex","hexToBytes","nobleHexToBytes"],"sources":["../src/core/limits.ts","../src/core/error.ts","../src/core/util.ts"],"sourcesContent":["/** NIP-01 event id length in bytes. */\nexport const EVENT_ID_BYTES = 32;\n\n/** BIP-340 signature length in bytes. */\nexport const SIGNATURE_BYTES = 64;\n\n/** BIP-340 public key length in bytes (x-only). */\nexport const PUBLIC_KEY_BYTES = 32;\n\n/** BIP-340 secret key length in bytes. */\nexport const SECRET_KEY_BYTES = 32;\n\n/** NIP-01 subscription id max character length. */\nexport const SUBSCRIPTION_ID_MAX_CHARS = 64;\n","/** Base error for all @qntx/nostr failures. */\nexport class NostrError extends Error {\n override name = \"NostrError\";\n}\n\n/** Invalid hex encoding or length. */\nexport class HexError extends NostrError {\n override name = \"HexError\";\n}\n\n/** Invalid URL / relay URL. */\nexport class UrlError extends NostrError {\n override name = \"UrlError\";\n}\n\n/** Event shape / wire validation failure. */\nexport class EventValidationError extends NostrError {\n override name = \"EventValidationError\";\n}\n\n/** Cryptographic operation failure (keys, signatures). */\nexport class CryptoError extends NostrError {\n override name = \"CryptoError\";\n}\n\n/** Message parse / encode failure. */\nexport class MessageError extends NostrError {\n override name = \"MessageError\";\n}\n\n/** Wasm verify instance aborted; later verifies on that instance fail. */\nexport class WasmVerifyPoisonedError extends NostrError {\n override name = \"WasmVerifyPoisonedError\";\n}\n","import {\n bytesToHex as nobleBytesToHex,\n hexToBytes as nobleHexToBytes,\n} from \"@noble/hashes/utils.js\";\n\nimport { HexError, UrlError } from \"./error.ts\";\nimport { SECRET_KEY_BYTES } from \"./limits.ts\";\n\nexport const utf8Encoder: TextEncoder = new TextEncoder();\nexport const utf8Decoder: TextDecoder = new TextDecoder();\n\nconst HEX32_RE = /^[0-9a-f]{64}$/;\nconst HEX64_RE = /^[0-9a-f]{128}$/;\n\n/** Lowercase hex encode. */\nexport function bytesToHex(bytes: Uint8Array): string {\n return nobleBytesToHex(bytes);\n}\n\n/** Decode lowercase or mixed-case hex to bytes. */\nexport function hexToBytes(hex: string): Uint8Array {\n try {\n return nobleHexToBytes(hex);\n } catch (error) {\n throw new HexError(`invalid hex string of length ${hex.length}`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n}\n\n/** True when value is canonical NIP-01 lowercase hex of 32 bytes (64 chars). */\nexport function isHex32(value: string): boolean {\n return HEX32_RE.test(value);\n}\n\n/** True when value is canonical NIP-01 lowercase hex of 64 bytes (128 chars). */\nexport function isHex64(value: string): boolean {\n return HEX64_RE.test(value);\n}\n\n/** Caller input of any case: lowercases first, then requires canonical hex shape. */\nexport function assertHex32(value: string, label: string): string {\n const normalized = value.toLowerCase();\n if (!isHex32(normalized)) {\n throw new HexError(`invalid ${label}: expected 64-char hex`);\n }\n return normalized;\n}\n\nexport function assertByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new HexError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nexport function assertSecretKeyBytes(bytes: Uint8Array): void {\n assertByteLength(bytes, SECRET_KEY_BYTES, \"secret key\");\n}\n\n/** Structural guard: a plain record (not `null`, not an array). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize a relay URL to a stable form: `http:`/`https:` are rewritten to `ws:`/`wss:` (a bare\n * host gets `wss://`), any other scheme throws UrlError. The result has a lowercased host, the\n * default port removed, duplicate path slashes collapsed, a sorted query, and no fragment. `URL`\n * serialization keeps a trailing `/` on the root path (`wss://a.example/`).\n */\nexport function normalizeURL(url: string): string {\n try {\n let input = url;\n if (!input.includes(\"://\")) {\n input = `wss://${input}`;\n }\n const p = new URL(input);\n if (p.protocol === \"http:\") {\n p.protocol = \"ws:\";\n } else if (p.protocol === \"https:\") {\n p.protocol = \"wss:\";\n }\n if (p.protocol !== \"ws:\" && p.protocol !== \"wss:\") {\n throw new UrlError(`unsupported relay URL scheme: ${p.protocol}`);\n }\n p.pathname = p.pathname.replaceAll(/\\/+/g, \"/\");\n if (p.pathname.endsWith(\"/\") && p.pathname.length > 1) {\n p.pathname = p.pathname.slice(0, -1);\n }\n if ((p.port === \"80\" && p.protocol === \"ws:\") || (p.port === \"443\" && p.protocol === \"wss:\")) {\n p.port = \"\";\n }\n p.searchParams.sort();\n p.hash = \"\";\n return p.toString();\n } catch (error) {\n if (error instanceof UrlError) {\n throw error;\n }\n throw new UrlError(`invalid URL: ${url}`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n}\n"],"mappings":";;;AACA,MAAa,iBAAiB;;AAG9B,MAAa,kBAAkB;;AAG/B,MAAa,mBAAmB;;AAGhC,MAAa,mBAAmB;;AAGhC,MAAa,4BAA4B;;;;ACZzC,IAAa,aAAb,cAAgC,MAAM;CACpC,OAAgB;AAClB;;AAGA,IAAa,WAAb,cAA8B,WAAW;CACvC,OAAgB;AAClB;;AAGA,IAAa,WAAb,cAA8B,WAAW;CACvC,OAAgB;AAClB;;AAGA,IAAa,uBAAb,cAA0C,WAAW;CACnD,OAAgB;AAClB;;AAGA,IAAa,cAAb,cAAiC,WAAW;CAC1C,OAAgB;AAClB;;AAGA,IAAa,eAAb,cAAkC,WAAW;CAC3C,OAAgB;AAClB;;AAGA,IAAa,0BAAb,cAA6C,WAAW;CACtD,OAAgB;AAClB;;;ACzBA,MAAa,cAA2B,IAAI,YAAY;AACxD,MAAa,cAA2B,IAAI,YAAY;AAExD,MAAM,WAAW;AACjB,MAAM,WAAW;;AAGjB,SAAgBA,aAAW,OAA2B;CACpD,OAAOC,WAAgB,KAAK;AAC9B;;AAGA,SAAgBC,aAAW,KAAyB;CAClD,IAAI;EACF,OAAOC,WAAgB,GAAG;CAC5B,SAAS,OAAO;EACd,MAAM,IAAI,SAAS,gCAAgC,IAAI,UAAU,EAC/D,OAAO,iBAAiB,QAAQ,QAAQ,KAAA,EAC1C,CAAC;CACH;AACF;;AAGA,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;;AAGA,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;;AAGA,SAAgB,YAAY,OAAe,OAAuB;CAChE,MAAM,aAAa,MAAM,YAAY;CACrC,IAAI,CAAC,QAAQ,UAAU,GACrB,MAAM,IAAI,SAAS,WAAW,MAAM,uBAAuB;CAE7D,OAAO;AACT;AAEA,SAAgB,iBAAiB,OAAmB,UAAkB,OAAqB;CACzF,IAAI,MAAM,WAAW,UACnB,MAAM,IAAI,SAAS,WAAW,MAAM,oBAAoB,SAAS,QAAQ,MAAM,QAAQ;AAE3F;AAEA,SAAgB,qBAAqB,OAAyB;CAC5D,iBAAiB,OAAA,IAAyB,YAAY;AACxD;;AAGA,SAAgB,SAAS,OAAkD;CACzE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;;;;;AAQA,SAAgB,aAAa,KAAqB;CAChD,IAAI;EACF,IAAI,QAAQ;EACZ,IAAI,CAAC,MAAM,SAAS,KAAK,GACvB,QAAQ,SAAS;EAEnB,MAAM,IAAI,IAAI,IAAI,KAAK;EACvB,IAAI,EAAE,aAAa,SACjB,EAAE,WAAW;OACR,IAAI,EAAE,aAAa,UACxB,EAAE,WAAW;EAEf,IAAI,EAAE,aAAa,SAAS,EAAE,aAAa,QACzC,MAAM,IAAI,SAAS,iCAAiC,EAAE,UAAU;EAElE,EAAE,WAAW,EAAE,SAAS,WAAW,QAAQ,GAAG;EAC9C,IAAI,EAAE,SAAS,SAAS,GAAG,KAAK,EAAE,SAAS,SAAS,GAClD,EAAE,WAAW,EAAE,SAAS,MAAM,GAAG,EAAE;EAErC,IAAK,EAAE,SAAS,QAAQ,EAAE,aAAa,SAAW,EAAE,SAAS,SAAS,EAAE,aAAa,QACnF,EAAE,OAAO;EAEX,EAAE,aAAa,KAAK;EACpB,EAAE,OAAO;EACT,OAAO,EAAE,SAAS;CACpB,SAAS,OAAO;EACd,IAAI,iBAAiB,UACnB,MAAM;EAER,MAAM,IAAI,SAAS,gBAAgB,OAAO,EACxC,OAAO,iBAAiB,QAAQ,QAAQ,KAAA,EAC1C,CAAC;CACH;AACF"}
package/dist/wasm.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { t as Event } from "./event-B5D2jxt_.mjs";
2
- import { s as WasmVerifyPoisonedError } from "./error-WEFS-R-4.mjs";
1
+ import { t as Event } from "./event-fU3Y01PR.mjs";
2
+ import { s as WasmVerifyPoisonedError } from "./error-CR8Urc84.mjs";
3
3
  //#region src/wasm/load.d.ts
4
4
  type LoadNostrWasmOptions = {
5
5
  /** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */
@@ -13,7 +13,7 @@ type NostrWasm = {
13
13
  publicKey: (seckey: Uint8Array) => Uint8Array;
14
14
  };
15
15
  /** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
16
- declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
16
+ export declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
17
17
  //#endregion
18
- export { type LoadNostrWasmOptions, type NostrWasm, WasmVerifyPoisonedError, loadNostrWasm };
18
+ export { type LoadNostrWasmOptions, type NostrWasm, WasmVerifyPoisonedError };
19
19
  //# sourceMappingURL=wasm.d.mts.map
package/dist/wasm.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import { i as hexToBytes, l as utf8Encoder } from "./util-6tfLQ9JF.mjs";
2
- import { s as WasmVerifyPoisonedError, t as CryptoError } from "./error-DZEs5OuZ.mjs";
3
- import { c as serializeEvent, n as isMarkedFailed, o as markUnverified, p as validateSignedEvent, r as isMarkedVerified, s as markVerified } from "./event-CzoQEFMF.mjs";
1
+ import { a as hexToBytes, d as utf8Encoder, f as CryptoError, v as WasmVerifyPoisonedError } from "./util-LfQirgDk.mjs";
2
+ import { c as markVerified, i as isMarkedVerified, l as serializeEvent, m as validateSignedEvent, r as isMarkedFailed, s as markUnverified } from "./event-D8Nfoh4K.mjs";
4
3
  //#region src/wasm/abi.ts
5
4
  /** Imports 0.2.122 may request. Instantiation fails if anything else appears. */
6
5
  const ALLOWED_WASM_IMPORTS = [{
@@ -43,17 +42,19 @@ function requireFn(value, name) {
43
42
  return value;
44
43
  }
45
44
  function asExports(raw) {
46
- return {
47
- memory: requireMemory(raw.memory),
48
- verify: requireFn(raw.verify, "verify"),
49
- verify_serialized: requireFn(raw.verify_serialized, "verify_serialized"),
50
- sign: requireFn(raw.sign, "sign"),
51
- public_key: requireFn(raw.public_key, "public_key"),
52
- __wbindgen_export: requireFn(raw.__wbindgen_export, "__wbindgen_export"),
53
- __wbindgen_export2: requireFn(raw.__wbindgen_export2, "__wbindgen_export2"),
54
- __wbindgen_add_to_stack_pointer: requireFn(raw.__wbindgen_add_to_stack_pointer, "__wbindgen_add_to_stack_pointer"),
55
- __wbindgen_start: typeof raw.__wbindgen_start === "function" ? raw.__wbindgen_start : void 0
45
+ const exports = {
46
+ memory: requireMemory(raw["memory"]),
47
+ verify: requireFn(raw["verify"], "verify"),
48
+ verify_serialized: requireFn(raw["verify_serialized"], "verify_serialized"),
49
+ sign: requireFn(raw["sign"], "sign"),
50
+ public_key: requireFn(raw["public_key"], "public_key"),
51
+ __wbindgen_export: requireFn(raw["__wbindgen_export"], "__wbindgen_export"),
52
+ __wbindgen_export2: requireFn(raw["__wbindgen_export2"], "__wbindgen_export2"),
53
+ __wbindgen_add_to_stack_pointer: requireFn(raw["__wbindgen_add_to_stack_pointer"], "__wbindgen_add_to_stack_pointer")
56
54
  };
55
+ const start = raw["__wbindgen_start"];
56
+ if (typeof start === "function") exports.__wbindgen_start = requireFn(start, "__wbindgen_start");
57
+ return exports;
57
58
  }
58
59
  function passBytes(exports, bytes) {
59
60
  const len = bytes.length;
@@ -64,23 +65,18 @@ function passBytes(exports, bytes) {
64
65
  len
65
66
  };
66
67
  }
67
- function callWithBytes(exports, arrays, invoke) {
68
- return invoke(arrays.map((bytes) => passBytes(exports, bytes)).flatMap(({ ptr, len }) => [ptr, len])) !== 0;
69
- }
70
68
  function wasmVerify(exports, id, pubkey, sig) {
71
- return callWithBytes(exports, [
72
- id,
73
- pubkey,
74
- sig
75
- ], (args) => exports.verify(args[0], args[1], args[2], args[3], args[4], args[5]));
69
+ const idP = passBytes(exports, id);
70
+ const pkP = passBytes(exports, pubkey);
71
+ const sigP = passBytes(exports, sig);
72
+ return exports.verify(idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;
76
73
  }
77
74
  function wasmVerifySerialized(exports, serialized, id, pubkey, sig) {
78
- return callWithBytes(exports, [
79
- serialized,
80
- id,
81
- pubkey,
82
- sig
83
- ], (args) => exports.verify_serialized(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]));
75
+ const serP = passBytes(exports, serialized);
76
+ const idP = passBytes(exports, id);
77
+ const pkP = passBytes(exports, pubkey);
78
+ const sigP = passBytes(exports, sig);
79
+ return exports.verify_serialized(serP.ptr, serP.len, idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;
84
80
  }
85
81
  function takeBytes(exports, ptr, len) {
86
82
  const out = new Uint8Array(len);
@@ -90,29 +86,28 @@ function takeBytes(exports, ptr, len) {
90
86
  }
91
87
  return out;
92
88
  }
93
- function callReturningBytes(exports, arrays, invoke) {
94
- const args = arrays.map((bytes) => passBytes(exports, bytes)).flatMap(({ ptr, len }) => [ptr, len]);
89
+ function callReturningBytes(exports, invoke) {
95
90
  const retptr = exports.__wbindgen_add_to_stack_pointer(-16);
96
91
  try {
97
- invoke(retptr, args);
92
+ invoke(retptr);
98
93
  const view = new DataView(exports.memory.buffer);
99
- return takeBytes(exports, view.getInt32(retptr, true) >>> 0, view.getInt32(retptr + 4, true) >>> 0);
94
+ return takeBytes(exports, view.getUint32(retptr, true), view.getUint32(retptr + 4, true));
100
95
  } finally {
101
96
  exports.__wbindgen_add_to_stack_pointer(16);
102
97
  }
103
98
  }
104
99
  function wasmSign(exports, id, seckey, aux) {
105
- return callReturningBytes(exports, [
106
- id,
107
- seckey,
108
- aux
109
- ], (retptr, args) => {
110
- exports.sign(retptr, args[0], args[1], args[2], args[3], args[4], args[5]);
100
+ const idP = passBytes(exports, id);
101
+ const skP = passBytes(exports, seckey);
102
+ const auxP = passBytes(exports, aux);
103
+ return callReturningBytes(exports, (retptr) => {
104
+ exports.sign(retptr, idP.ptr, idP.len, skP.ptr, skP.len, auxP.ptr, auxP.len);
111
105
  });
112
106
  }
113
107
  function wasmPublicKey(exports, seckey) {
114
- return callReturningBytes(exports, [seckey], (retptr, args) => {
115
- exports.public_key(retptr, args[0], args[1]);
108
+ const skP = passBytes(exports, seckey);
109
+ return callReturningBytes(exports, (retptr) => {
110
+ exports.public_key(retptr, skP.ptr, skP.len);
116
111
  });
117
112
  }
118
113
  async function instantiateCryptoWasm(bytes) {
@@ -136,16 +131,16 @@ function makeVerifyEvent(wasm, poison) {
136
131
  }
137
132
  try {
138
133
  const serialized = utf8Encoder.encode(serializeEvent(event));
139
- const id = hexToBytes(event.id.toLowerCase());
140
- const pubkey = hexToBytes(event.pubkey.toLowerCase());
141
- const sig = hexToBytes(event.sig.toLowerCase());
134
+ const id = hexToBytes(event.id);
135
+ const pubkey = hexToBytes(event.pubkey);
136
+ const sig = hexToBytes(event.sig);
142
137
  const ok = wasm.verifySerialized(serialized, id, pubkey, sig);
143
138
  if (ok) markVerified(event);
144
139
  else markUnverified(event);
145
140
  return ok;
146
- } catch (e) {
147
- if (e instanceof WebAssembly.RuntimeError) {
148
- poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: e });
141
+ } catch (error) {
142
+ if (error instanceof WebAssembly.RuntimeError) {
143
+ poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: error });
149
144
  throw poison.error;
150
145
  }
151
146
  markUnverified(event);
@@ -157,13 +152,15 @@ function makeVerifyEvent(wasm, poison) {
157
152
  //#region src/wasm/load.ts
158
153
  let interned;
159
154
  function isNode() {
160
- return typeof process !== "undefined" && typeof process.versions === "object" && process.versions !== null && typeof process.versions.node === "string";
155
+ if (!("process" in globalThis)) return false;
156
+ const proc = globalThis.process;
157
+ return typeof proc === "object" && proc !== null && "versions" in proc && typeof proc.versions === "object" && proc.versions !== null && "node" in proc.versions && typeof proc.versions.node === "string";
161
158
  }
162
159
  function isWasmBytes(value) {
163
160
  return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
164
161
  }
165
162
  async function defaultWasmHref() {
166
- return (await import("./nostr_crypto_wasm_bg-hi5aXi5P.mjs")).default;
163
+ return (await import("./nostr_crypto_wasm_bg-Czrdty7Q.mjs")).default;
167
164
  }
168
165
  async function readWasmUrl(url) {
169
166
  if (isNode() && url.protocol === "file:") {
@@ -187,12 +184,12 @@ function wrapPoison(poison, fn) {
187
184
  if (poison.error) throw poison.error;
188
185
  try {
189
186
  return fn();
190
- } catch (e) {
191
- if (e instanceof WebAssembly.RuntimeError) {
192
- poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: e });
187
+ } catch (error) {
188
+ if (error instanceof WebAssembly.RuntimeError) {
189
+ poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: error });
193
190
  throw poison.error;
194
191
  }
195
- throw e;
192
+ throw error;
196
193
  }
197
194
  }
198
195
  function bindExports(exports) {
@@ -222,14 +219,16 @@ async function instantiateNostrWasm(opts) {
222
219
  return bindExports(await instantiateCryptoWasm(await wasmBytes(opts)));
223
220
  }
224
221
  /** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
225
- function loadNostrWasm(opts) {
222
+ async function loadNostrWasm(opts) {
226
223
  if (interned) return interned;
227
- const pending = instantiateNostrWasm(opts).catch((error) => {
224
+ const pending = instantiateNostrWasm(opts);
225
+ interned = pending;
226
+ try {
227
+ return await pending;
228
+ } catch (error) {
228
229
  if (interned === pending) interned = void 0;
229
230
  throw error;
230
- });
231
- interned = pending;
232
- return pending;
231
+ }
233
232
  }
234
233
  //#endregion
235
234
  export { WasmVerifyPoisonedError, loadNostrWasm };