@qntx/nostr 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{abort-Ba8tDrOI.mjs → abort-DBq2STPj.mjs} +13 -6
- package/dist/abort-DBq2STPj.mjs.map +1 -0
- package/dist/{builder-9tjI6WQ3.mjs → builder-CdLE4J6O.mjs} +11 -17
- package/dist/builder-CdLE4J6O.mjs.map +1 -0
- package/dist/{builder-sSflu6nB.d.mts → builder-DgkqDylK.d.mts} +5 -6
- package/dist/{client-BtIAtxrL.mjs → client-CILhdfsF.mjs} +104 -314
- package/dist/client-CILhdfsF.mjs.map +1 -0
- package/dist/client.d.mts +2 -2
- package/dist/client.mjs +2 -2
- package/dist/collections-DtwMc1NU.mjs +33 -0
- package/dist/collections-DtwMc1NU.mjs.map +1 -0
- package/dist/core.d.mts +9 -8
- package/dist/core.mjs +7 -7
- package/dist/{error-BW7re1UN.d.mts → error-BD_0QFKT.d.mts} +2 -2
- package/dist/{error-CR8Urc84.d.mts → error-BquXDmIN.d.mts} +4 -4
- package/dist/{error-DrEIM7FO.mjs → error-L_QdmSnV.mjs} +2 -2
- package/dist/{error-DrEIM7FO.mjs.map → error-L_QdmSnV.mjs.map} +1 -1
- package/dist/{error-B__OMBRY.mjs → error-gtJvV6YS.mjs} +2 -2
- package/dist/{error-B__OMBRY.mjs.map → error-gtJvV6YS.mjs.map} +1 -1
- package/dist/{event-fU3Y01PR.d.mts → event-DJeb_DIL.d.mts} +4 -2
- package/dist/{event-D8Nfoh4K.mjs → event-DinQMmJ1.mjs} +16 -10
- package/dist/event-DinQMmJ1.mjs.map +1 -0
- package/dist/{filter-C0IMByE3.d.mts → filter-jI_9htF7.d.mts} +2 -2
- package/dist/{gossip-DpIvkBuj.d.mts → gossip-C7HLW5kI.d.mts} +35 -26
- package/dist/{gossip-oloDMWEj.mjs → gossip-CcTp9VpU.mjs} +23 -33
- package/dist/gossip-CcTp9VpU.mjs.map +1 -0
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/{index-CvkvqB16.d.mts → index-DU9tRFTZ.d.mts} +7 -20
- package/dist/{index-q4MDce_r.d.mts → index-DiXwNn2M.d.mts} +6 -8
- package/dist/{index-QxvrpMfF.d.mts → index-DocgD9K0.d.mts} +92 -167
- package/dist/{index-D1bqFHKB.d.mts → index-InQZpHyQ.d.mts} +18 -18
- package/dist/{index-MxC28S4P.d.mts → index-Tx15HGAD.d.mts} +26 -28
- package/dist/{index-Dmc8FJgO.d.mts → index-iLT8UzY3.d.mts} +19 -37
- package/dist/index.d.mts +23 -21
- package/dist/index.mjs +21 -19
- package/dist/instance-BcKzxHIP.mjs +220 -0
- package/dist/instance-BcKzxHIP.mjs.map +1 -0
- package/dist/instance-DjsL8h84.d.mts +15 -0
- package/dist/{key-Cv4_pN3x.d.mts → key-D_5OgGT7.d.mts} +11 -7
- package/dist/{key-Bps-LqX7.mjs → key-bshqfmZL.mjs} +13 -9
- package/dist/key-bshqfmZL.mjs.map +1 -0
- package/dist/{loaders-o6YXB_Ri.mjs → loaders-DD0XAGzw.mjs} +73 -82
- package/dist/loaders-DD0XAGzw.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -3
- package/dist/loaders.mjs +2 -2
- package/dist/{memory-C2EVx0_O.mjs → memory-D_-5-T31.mjs} +2 -2
- package/dist/memory-D_-5-T31.mjs.map +1 -0
- package/dist/{memory-index-Do1mz0WF.mjs → memory-index-C6rujtoc.mjs} +30 -247
- package/dist/memory-index-C6rujtoc.mjs.map +1 -0
- package/dist/message-CWLcFTQ1.mjs +194 -0
- package/dist/message-CWLcFTQ1.mjs.map +1 -0
- package/dist/{message-iGPIqnn0.d.mts → message-CbBZOhq3.d.mts} +3 -3
- package/dist/{nip17-CKIufV98.d.mts → nip17-cTDFfFVt.d.mts} +5 -6
- package/dist/{nip19-BevCJZsp.d.mts → nip19-D1OnJ192.d.mts} +3 -9
- package/dist/{nip46-DDV4dC56.d.mts → nip46-DrsPI8EX.d.mts} +3 -5
- package/dist/nip51-DoPUvQ--.d.mts +87 -0
- package/dist/{nip59-zQgdLcEr.d.mts → nip59-BFIihLYY.d.mts} +3 -4
- package/dist/nip65-52HiwiyD.d.mts +23 -0
- package/dist/{nip77-DH4RhS5r.d.mts → nip77-C9QcZn7b.d.mts} +3 -4
- package/dist/nips/blossom.d.mts +12 -8
- package/dist/nips/blossom.mjs +30 -9
- package/dist/nips/blossom.mjs.map +1 -1
- package/dist/nips/nip04.mjs +17 -7
- package/dist/nips/nip04.mjs.map +1 -1
- package/dist/nips/nip05.d.mts +2 -3
- package/dist/nips/nip05.mjs +1 -4
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +3 -3
- package/dist/nips/nip10.mjs +3 -3
- package/dist/nips/nip11.d.mts +1 -1
- package/dist/nips/nip11.mjs +4 -4
- package/dist/nips/nip11.mjs.map +1 -1
- package/dist/nips/nip13.d.mts +7 -7
- package/dist/nips/nip13.mjs +32 -10
- package/dist/nips/nip13.mjs.map +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +13 -33
- package/dist/nips/nip17.mjs.map +1 -1
- package/dist/nips/nip19.d.mts +2 -2
- package/dist/nips/nip19.mjs +16 -28
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.d.mts +6 -1
- package/dist/nips/nip21.mjs +15 -5
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +4 -4
- package/dist/nips/nip27.mjs.map +1 -1
- package/dist/nips/nip42.d.mts +1 -1
- package/dist/nips/nip42.mjs +2 -1
- package/dist/nips/nip42.mjs.map +1 -1
- package/dist/nips/nip44.mjs +1 -1
- package/dist/nips/nip46.d.mts +2 -2
- package/dist/nips/nip46.mjs +15 -19
- package/dist/nips/nip46.mjs.map +1 -1
- package/dist/nips/nip49.d.mts +5 -5
- package/dist/nips/nip49.mjs +4 -4
- package/dist/nips/nip49.mjs.map +1 -1
- package/dist/nips/nip51.d.mts +2 -86
- package/dist/nips/nip51.mjs +7 -23
- package/dist/nips/nip51.mjs.map +1 -1
- package/dist/nips/nip57.d.mts +7 -5
- package/dist/nips/nip57.mjs +12 -17
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.d.mts +1 -1
- package/dist/nips/nip59.mjs +16 -16
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +2 -2
- package/dist/nips/nip65.mjs +14 -37
- package/dist/nips/nip65.mjs.map +1 -1
- package/dist/nips/nip77.d.mts +1 -1
- package/dist/nips/nip77.mjs +33 -32
- package/dist/nips/nip77.mjs.map +1 -1
- package/dist/nips/nip98.d.mts +5 -5
- package/dist/nips/nip98.mjs +8 -8
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/nostr_crypto_wasm_bg.wasm +0 -0
- package/dist/{pool-DBIYMtwy.d.mts → pool-SzJKPIa3.d.mts} +96 -91
- package/dist/pool-YHRZgcQ3.mjs +596 -0
- package/dist/pool-YHRZgcQ3.mjs.map +1 -0
- package/dist/put-DS0yzVJx.mjs +187 -0
- package/dist/put-DS0yzVJx.mjs.map +1 -0
- package/dist/{reactive-DFpqtIf_.d.mts → reactive-BJ1ggn4d.d.mts} +9 -22
- package/dist/{reactive-DDlThDSZ.mjs → reactive-BJRoVHxU.mjs} +113 -64
- package/dist/reactive-BJRoVHxU.mjs.map +1 -0
- package/dist/{pool-As20OGxB.mjs → relay-CvxPiQ_m.mjs} +178 -721
- package/dist/relay-CvxPiQ_m.mjs.map +1 -0
- package/dist/relay.d.mts +4 -4
- package/dist/relay.mjs +3 -2
- package/dist/serial-Bzpw-xz3.mjs +21 -0
- package/dist/serial-Bzpw-xz3.mjs.map +1 -0
- package/dist/{signer-CYQutDzD.mjs → signer-yW3slDC2.mjs} +12 -14
- package/dist/signer-yW3slDC2.mjs.map +1 -0
- package/dist/signer.d.mts +2 -2
- package/dist/signer.mjs +2 -2
- package/dist/{storage-Dky3wuoH.mjs → storage-CZ52ifcQ.mjs} +17 -42
- package/dist/storage-CZ52ifcQ.mjs.map +1 -0
- package/dist/storage.d.mts +3 -3
- package/dist/storage.mjs +4 -4
- package/dist/store.d.mts +1 -1
- package/dist/store.mjs +1 -1
- package/dist/testing.d.mts +18 -18
- package/dist/testing.mjs +9 -9
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-2pCUprRU.d.mts → types-Cm-XMgtH.d.mts} +6 -6
- package/dist/{types-CRQEk0Oi.d.mts → types-DNmiscfd.d.mts} +2 -2
- package/dist/{util-LfQirgDk.mjs → util-yFYzlbrm.mjs} +29 -7
- package/dist/util-yFYzlbrm.mjs.map +1 -0
- package/dist/{verifier-t5WoWbtY.mjs → verifier-BTLOpo1n.mjs} +3 -3
- package/dist/verifier-BTLOpo1n.mjs.map +1 -0
- package/dist/verifier-CgTFpgsC.d.mts +22 -0
- package/dist/wasm.browser.d.mts +8 -0
- package/dist/wasm.browser.mjs +19 -0
- package/dist/wasm.browser.mjs.map +1 -0
- package/dist/wasm.d.mts +3 -13
- package/dist/wasm.mjs +7 -208
- package/dist/wasm.mjs.map +1 -1
- package/package.json +13 -10
- package/dist/abort-Ba8tDrOI.mjs.map +0 -1
- package/dist/builder-9tjI6WQ3.mjs.map +0 -1
- package/dist/client-BtIAtxrL.mjs.map +0 -1
- package/dist/event-D8Nfoh4K.mjs.map +0 -1
- package/dist/gossip-oloDMWEj.mjs.map +0 -1
- package/dist/key-Bps-LqX7.mjs.map +0 -1
- package/dist/loaders-o6YXB_Ri.mjs.map +0 -1
- package/dist/memory-C2EVx0_O.mjs.map +0 -1
- package/dist/memory-index-Do1mz0WF.mjs.map +0 -1
- package/dist/message-DcY6Fi9o.mjs +0 -193
- package/dist/message-DcY6Fi9o.mjs.map +0 -1
- package/dist/nip65-CjgmdpPB.d.mts +0 -26
- package/dist/nips/nip96.d.mts +0 -40
- package/dist/nips/nip96.mjs +0 -118
- package/dist/nips/nip96.mjs.map +0 -1
- package/dist/pool-As20OGxB.mjs.map +0 -1
- package/dist/reactive-DDlThDSZ.mjs.map +0 -1
- package/dist/signer-CYQutDzD.mjs.map +0 -1
- package/dist/storage-Dky3wuoH.mjs.map +0 -1
- package/dist/util-LfQirgDk.mjs.map +0 -1
- package/dist/verifier-t5WoWbtY.mjs.map +0 -1
package/dist/testing.mjs.map
CHANGED
|
@@ -1 +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 { Kind } from \"../core/kind.ts\";\nimport { bytesToHex, isRecord, normalizeURL } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.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 /**\n * Store an event and broadcast it to matching subscriptions. Unlike client EVENT writes the relay\n * does not verify it here, so forged events (mismatched id/signature) are delivered as-is.\n */\n inject: (event: Event) => void;\n /**\n * Push an event to matching subscriptions without storing it: a resubscription never re-serves\n * it. Use it for forged events (mismatched id/signature) when exercising client-side verification\n * failure handling.\n */\n deliver: (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 deliver(event: Event): void {\n this.#pending = (async (): Promise<void> => {\n await this.#pending;\n this.#deliver(event);\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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"}
|
|
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 { errorMessage } from \"../core/error.ts\";\nimport 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 { Kind } from \"../core/kind.ts\";\nimport { bytesToHex, isRecord, normalizeURL } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.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 | undefined;\n auth?:\n | {\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> | undefined;\n /** EVENT → `[\"OK\", id, false, \"auth-required: ...\"]` until AUTH succeeds. */\n writes?: boolean | undefined;\n }\n | undefined;\n /** EVENT → `[\"OK\", id, false, \"rate-limited: ...\"]`; nothing is stored. */\n rateLimited?: boolean | undefined;\n /** Out-of-order reply: send EOSE first, then the stored events. */\n eoseBeforeEvents?: boolean | undefined;\n};\n\nexport type FakeRelay = {\n readonly url: string;\n seed: (events: ReadonlyArray<Event>) => void;\n events: () => ReadonlyArray<Event>;\n /**\n * Store an event and broadcast it to matching subscriptions. Unlike client EVENT writes the relay\n * does not verify it here, so forged events (mismatched id/signature) are delivered as-is.\n */\n inject: (event: Event) => void;\n /**\n * Push an event to matching subscriptions without storing it: a resubscription never re-serves\n * it. Use it for forged events (mismatched id/signature) when exercising client-side verification\n * failure handling.\n */\n deliver: (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 deliver(event: Event): void {\n this.#pending = (async (): Promise<void> => {\n await this.#pending;\n this.#deliver(event);\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 = errorMessage(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, nowSeconds } 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 | undefined;\n /** The user key the signer signs for; random when omitted. */\n userSk?: string | undefined;\n /** First answer `auth_url` (result) with this URL in the error field, then the real response. */\n authUrl?: string | undefined;\n authUrlMethods?: ReadonlyArray<string> | undefined;\n /** Delay in ms before the real response after an `auth_url` reply. */\n authReplyDelayMs?: number | undefined;\n /** Collected RPC requests (mutated as they arrive). */\n requests?: Array<{ method: string; params: string[] }> | undefined;\n /** `switch_relays` result. Default `\"null\"`. */\n switchRelays?: string[] | undefined;\n /** Override `connect` RPC result. Default `\"ack\"`. */\n connectResult?: string | undefined;\n /** Reply with neither `result` nor `error` for these methods. */\n emptyMethods?: ReadonlyArray<string> | undefined;\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) | undefined;\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: nowSeconds(),\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: nowSeconds(),\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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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as Event } from "./event-
|
|
2
|
-
import { t as Filter } from "./filter-
|
|
1
|
+
import { t as Event } from "./event-DJeb_DIL.mjs";
|
|
2
|
+
import { t as Filter } from "./filter-jI_9htF7.mjs";
|
|
3
3
|
//#region src/storage/types.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* `"invalid"`: the event failed canonical shape validation (see `validateSignedEvent`); it was not
|
|
@@ -28,9 +28,9 @@ type EventStore = {
|
|
|
28
28
|
*/
|
|
29
29
|
putMany: (events: ReadonlyArray<Event>) => Promise<PutResult[]>;
|
|
30
30
|
get: (id: string) => Promise<Event | undefined>;
|
|
31
|
-
query: (filters: Filter
|
|
31
|
+
query: (filters: ReadonlyArray<Filter>) => Promise<Event[]>;
|
|
32
32
|
/** Unique events matching `filters` (same cardinality as {@link query}). */
|
|
33
|
-
count: (filters: Filter
|
|
33
|
+
count: (filters: ReadonlyArray<Filter>) => Promise<number>;
|
|
34
34
|
/**
|
|
35
35
|
* Matching `{ id, created_at }` for one filter, sorted created_at asc then id. Does not allocate
|
|
36
36
|
* an `Event[]`.
|
|
@@ -39,9 +39,9 @@ type EventStore = {
|
|
|
39
39
|
getOutboxBound: (pubkey: string, kind: number) => Promise<OutboxBound | undefined>;
|
|
40
40
|
setOutboxBound: (pubkey: string, kind: number, bound: OutboxBound) => Promise<void>;
|
|
41
41
|
/** Remove by id (does not publish NIP-09). */
|
|
42
|
-
remove: (ids: string
|
|
42
|
+
remove: (ids: ReadonlyArray<string>) => Promise<number>;
|
|
43
43
|
clear: () => Promise<void>;
|
|
44
44
|
};
|
|
45
45
|
//#endregion
|
|
46
46
|
export { PutResult as i, NegentropyItem as n, OutboxBound as r, EventStore as t };
|
|
47
|
-
//# sourceMappingURL=types-
|
|
47
|
+
//# sourceMappingURL=types-Cm-XMgtH.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as UnsignedEvent, t as Event } from "./event-
|
|
1
|
+
import { r as UnsignedEvent, t as Event } from "./event-DJeb_DIL.mjs";
|
|
2
2
|
//#region src/signer/types.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Universal signing interface (aligned with nula's NostrSigner). Implementations: KeysSigner,
|
|
@@ -16,4 +16,4 @@ type NostrSigner = {
|
|
|
16
16
|
};
|
|
17
17
|
//#endregion
|
|
18
18
|
export { NostrSigner as t };
|
|
19
|
-
//# sourceMappingURL=types-
|
|
19
|
+
//# sourceMappingURL=types-DNmiscfd.d.mts.map
|
|
@@ -16,6 +16,10 @@ const SUBSCRIPTION_ID_MAX_CHARS = 64;
|
|
|
16
16
|
var NostrError = class extends Error {
|
|
17
17
|
name = "NostrError";
|
|
18
18
|
};
|
|
19
|
+
/** `error.message` for Error instances, `String(error)` otherwise. */
|
|
20
|
+
function errorMessage(error) {
|
|
21
|
+
return error instanceof Error ? error.message : String(error);
|
|
22
|
+
}
|
|
19
23
|
/** Invalid hex encoding or length. */
|
|
20
24
|
var HexError = class extends NostrError {
|
|
21
25
|
name = "HexError";
|
|
@@ -36,9 +40,9 @@ var CryptoError = class extends NostrError {
|
|
|
36
40
|
var MessageError = class extends NostrError {
|
|
37
41
|
name = "MessageError";
|
|
38
42
|
};
|
|
39
|
-
/** Wasm
|
|
40
|
-
var
|
|
41
|
-
name = "
|
|
43
|
+
/** Wasm instance aborted; later calls on that instance fail. */
|
|
44
|
+
var WasmPoisonedError = class extends NostrError {
|
|
45
|
+
name = "WasmPoisonedError";
|
|
42
46
|
};
|
|
43
47
|
//#endregion
|
|
44
48
|
//#region src/core/util.ts
|
|
@@ -55,7 +59,7 @@ function hexToBytes$1(hex) {
|
|
|
55
59
|
try {
|
|
56
60
|
return hexToBytes(hex);
|
|
57
61
|
} catch (error) {
|
|
58
|
-
throw new HexError(`invalid hex string of length ${hex.length}`, { cause: error
|
|
62
|
+
throw new HexError(`invalid hex string of length ${hex.length}`, { cause: error });
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
/** True when value is canonical NIP-01 lowercase hex of 32 bytes (64 chars). */
|
|
@@ -78,6 +82,10 @@ function assertByteLength(bytes, expected, label) {
|
|
|
78
82
|
function assertSecretKeyBytes(bytes) {
|
|
79
83
|
assertByteLength(bytes, 32, "secret key");
|
|
80
84
|
}
|
|
85
|
+
/** Current unix time in whole seconds (NIP-01 `created_at`). */
|
|
86
|
+
function nowSeconds() {
|
|
87
|
+
return Math.floor(Date.now() / 1e3);
|
|
88
|
+
}
|
|
81
89
|
/** Structural guard: a plain record (not `null`, not an array). */
|
|
82
90
|
function isRecord(value) {
|
|
83
91
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -104,10 +112,24 @@ function normalizeURL(url) {
|
|
|
104
112
|
return p.toString();
|
|
105
113
|
} catch (error) {
|
|
106
114
|
if (error instanceof UrlError) throw error;
|
|
107
|
-
throw new UrlError(`invalid URL: ${url}`, { cause: error
|
|
115
|
+
throw new UrlError(`invalid URL: ${url}`, { cause: error });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Normalize each entry like {@link normalizeURL}; empty or invalid entries are skipped and the
|
|
120
|
+
* results are deduplicated in first-seen order.
|
|
121
|
+
*/
|
|
122
|
+
function normalizeRelayUrls(urls) {
|
|
123
|
+
const seen = /* @__PURE__ */ new Set();
|
|
124
|
+
for (const url of urls) {
|
|
125
|
+
if (url === "") continue;
|
|
126
|
+
try {
|
|
127
|
+
seen.add(normalizeURL(url));
|
|
128
|
+
} catch {}
|
|
108
129
|
}
|
|
130
|
+
return [...seen];
|
|
109
131
|
}
|
|
110
132
|
//#endregion
|
|
111
|
-
export {
|
|
133
|
+
export { PUBLIC_KEY_BYTES as C, SUBSCRIPTION_ID_MAX_CHARS as E, EVENT_ID_BYTES as S, SIGNATURE_BYTES as T, MessageError as _, hexToBytes$1 as a, WasmPoisonedError as b, isRecord as c, nowSeconds as d, utf8Decoder as f, HexError as g, EventValidationError as h, bytesToHex$1 as i, normalizeRelayUrls as l, CryptoError as m, assertHex32 as n, isHex32 as o, utf8Encoder as p, assertSecretKeyBytes as r, isHex64 as s, assertByteLength as t, normalizeURL as u, NostrError as v, SECRET_KEY_BYTES as w, errorMessage as x, UrlError as y };
|
|
112
134
|
|
|
113
|
-
//# sourceMappingURL=util-
|
|
135
|
+
//# sourceMappingURL=util-yFYzlbrm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util-yFYzlbrm.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/** `error.message` for Error instances, `String(error)` otherwise. */\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\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 instance aborted; later calls on that instance fail. */\nexport class WasmPoisonedError extends NostrError {\n override name = \"WasmPoisonedError\";\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,\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/** Current unix time in whole seconds (NIP-01 `created_at`). */\nexport function nowSeconds(): number {\n return Math.floor(Date.now() / 1000);\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,\n });\n }\n}\n\n/**\n * Normalize each entry like {@link normalizeURL}; empty or invalid entries are skipped and the\n * results are deduplicated in first-seen order.\n */\nexport function normalizeRelayUrls(urls: Iterable<string>): string[] {\n const seen = new Set<string>();\n for (const url of urls) {\n if (url === \"\") {\n continue;\n }\n try {\n seen.add(normalizeURL(url));\n } catch {\n // invalid relay urls are skipped\n }\n }\n return [...seen];\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as hexToBytes,
|
|
2
|
-
import { c as markVerified, i as isMarkedVerified, l as serializeEvent, m as validateSignedEvent, r as isMarkedFailed, s as markUnverified } from "./event-
|
|
1
|
+
import { a as hexToBytes, p as utf8Encoder } from "./util-yFYzlbrm.mjs";
|
|
2
|
+
import { c as markVerified, i as isMarkedVerified, l as serializeEvent, m as validateSignedEvent, r as isMarkedFailed, s as markUnverified } from "./event-DinQMmJ1.mjs";
|
|
3
3
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
4
4
|
import { schnorr } from "@noble/curves/secp256k1.js";
|
|
5
5
|
//#region src/core/verifier.ts
|
|
@@ -35,4 +35,4 @@ const verifyEvent = createEventVerifier(nobleSerializedVerify);
|
|
|
35
35
|
//#endregion
|
|
36
36
|
export { verifyEvent as n, createEventVerifier as t };
|
|
37
37
|
|
|
38
|
-
//# sourceMappingURL=verifier-
|
|
38
|
+
//# sourceMappingURL=verifier-BTLOpo1n.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier-BTLOpo1n.mjs","names":[],"sources":["../src/core/verifier.ts"],"sourcesContent":["import { schnorr } from \"@noble/curves/secp256k1.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport {\n isMarkedFailed,\n isMarkedVerified,\n markUnverified,\n markVerified,\n serializeEvent,\n validateSignedEvent,\n} from \"./event.ts\";\nimport type { Event } from \"./event.ts\";\nimport { hexToBytes, utf8Encoder } from \"./util.ts\";\n\n/**\n * Verification backend: return true iff `sha256(serializedUtf8)` equals `id` and `sig` is a valid\n * BIP-340 signature of `id` by the x-only `pubkey`. Inputs are raw bytes (`id`/`pubkey` 32, `sig`\n * 64). Exceptions propagate through the built verifier unmarked — a throwing backend is broken and\n * must surface.\n */\nexport type SerializedEventVerifier = (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n) => boolean;\n\n/** Whole-event verifier: return true iff the event's id and BIP-340 signature verify. */\nexport type EventVerifier = (event: Event) => boolean;\n\n/**\n * Build an event verifier with exactly the semantics of {@link verifyEvent}, delegating the hash and\n * signature check to `backend`. Verified/failed results share `verifyEvent`'s WeakSet caches, so\n * verifiers built this way and `verifyEvent` agree on (and reuse) each other's results.\n */\nexport function createEventVerifier(backend: SerializedEventVerifier): EventVerifier {\n return (event) => {\n if (isMarkedVerified(event)) {\n return true;\n }\n if (isMarkedFailed(event)) {\n return false;\n }\n if (!validateSignedEvent(event)) {\n markUnverified(event);\n return false;\n }\n const ok = backend(\n utf8Encoder.encode(serializeEvent(event)),\n hexToBytes(event.id),\n hexToBytes(event.pubkey),\n hexToBytes(event.sig),\n );\n if (ok) {\n markVerified(event);\n } else {\n markUnverified(event);\n }\n return ok;\n };\n}\n\nconst nobleSerializedVerify: SerializedEventVerifier = (serializedUtf8, id, pubkey, sig) => {\n try {\n const digest = sha256(serializedUtf8);\n if (!digest.every((byte, i) => byte === id[i])) {\n return false;\n }\n return schnorr.verify(sig, id, pubkey);\n } catch {\n return false;\n }\n};\n\n/** Verify event id and BIP-340 signature. Uses WeakSet cache (does not mutate the event). */\nexport const verifyEvent: EventVerifier = createEventVerifier(nobleSerializedVerify);\n"],"mappings":";;;;;;;;;;AAmCA,SAAgB,oBAAoB,SAAiD;CACnF,QAAQ,UAAU;EAChB,IAAI,iBAAiB,KAAK,GACxB,OAAO;EAET,IAAI,eAAe,KAAK,GACtB,OAAO;EAET,IAAI,CAAC,oBAAoB,KAAK,GAAG;GAC/B,eAAe,KAAK;GACpB,OAAO;EACT;EACA,MAAM,KAAK,QACT,YAAY,OAAO,eAAe,KAAK,CAAC,GACxC,WAAW,MAAM,EAAE,GACnB,WAAW,MAAM,MAAM,GACvB,WAAW,MAAM,GAAG,CACtB;EACA,IAAI,IACF,aAAa,KAAK;OAElB,eAAe,KAAK;EAEtB,OAAO;CACT;AACF;AAEA,MAAM,yBAAkD,gBAAgB,IAAI,QAAQ,QAAQ;CAC1F,IAAI;EAEF,IAAI,CADW,OAAO,cACZ,CAAC,CAAC,OAAO,MAAM,MAAM,SAAS,GAAG,EAAE,GAC3C,OAAO;EAET,OAAO,QAAQ,OAAO,KAAK,IAAI,MAAM;CACvC,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,MAAa,cAA6B,oBAAoB,qBAAqB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t as Event } from "./event-DJeb_DIL.mjs";
|
|
2
|
+
//#region src/core/verifier.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Verification backend: return true iff `sha256(serializedUtf8)` equals `id` and `sig` is a valid
|
|
5
|
+
* BIP-340 signature of `id` by the x-only `pubkey`. Inputs are raw bytes (`id`/`pubkey` 32, `sig`
|
|
6
|
+
* 64). Exceptions propagate through the built verifier unmarked — a throwing backend is broken and
|
|
7
|
+
* must surface.
|
|
8
|
+
*/
|
|
9
|
+
type SerializedEventVerifier = (serializedUtf8: Uint8Array, id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
10
|
+
/** Whole-event verifier: return true iff the event's id and BIP-340 signature verify. */
|
|
11
|
+
type EventVerifier = (event: Event) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Build an event verifier with exactly the semantics of {@link verifyEvent}, delegating the hash and
|
|
14
|
+
* signature check to `backend`. Verified/failed results share `verifyEvent`'s WeakSet caches, so
|
|
15
|
+
* verifiers built this way and `verifyEvent` agree on (and reuse) each other's results.
|
|
16
|
+
*/
|
|
17
|
+
declare function createEventVerifier(backend: SerializedEventVerifier): EventVerifier;
|
|
18
|
+
/** Verify event id and BIP-340 signature. Uses WeakSet cache (does not mutate the event). */
|
|
19
|
+
declare const verifyEvent: EventVerifier;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { verifyEvent as i, SerializedEventVerifier as n, createEventVerifier as r, EventVerifier as t };
|
|
22
|
+
//# sourceMappingURL=verifier-CgTFpgsC.d.mts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { s as WasmPoisonedError } from "./error-BquXDmIN.mjs";
|
|
2
|
+
import { n as NostrWasm, t as LoadNostrWasmOptions } from "./instance-DjsL8h84.mjs";
|
|
3
|
+
//#region src/wasm/load.browser.d.ts
|
|
4
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
5
|
+
export declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { type LoadNostrWasmOptions, type NostrWasm, WasmPoisonedError };
|
|
8
|
+
//# sourceMappingURL=wasm.browser.d.mts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { b as WasmPoisonedError, m as CryptoError } from "./util-yFYzlbrm.mjs";
|
|
2
|
+
import { n as fetchWasmUrl, r as isWasmBytes, t as createNostrWasmLoader } from "./instance-BcKzxHIP.mjs";
|
|
3
|
+
//#region src/wasm/load.browser.ts
|
|
4
|
+
async function wasmBytes(opts) {
|
|
5
|
+
const source = opts?.module;
|
|
6
|
+
if (source !== void 0 && isWasmBytes(source)) return source;
|
|
7
|
+
if (source instanceof URL && source.protocol !== "file:") return fetchWasmUrl(source);
|
|
8
|
+
if (source instanceof URL) throw new CryptoError(`cannot fetch wasm from ${source.href}`);
|
|
9
|
+
return fetchWasmUrl(new URL("nostr_crypto_wasm_bg.wasm", import.meta.url));
|
|
10
|
+
}
|
|
11
|
+
const loader = createNostrWasmLoader(wasmBytes);
|
|
12
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
13
|
+
async function loadNostrWasm(opts) {
|
|
14
|
+
return loader.loadNostrWasm(opts);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { WasmPoisonedError, loadNostrWasm };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=wasm.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm.browser.mjs","names":[],"sources":["../src/wasm/load.browser.ts"],"sourcesContent":["import { CryptoError } from \"../core/error.ts\";\nimport { createNostrWasmLoader, fetchWasmUrl, isWasmBytes } from \"./instance.ts\";\nimport type { LoadNostrWasmOptions, NostrWasm } from \"./instance.ts\";\n\nexport type { LoadNostrWasmOptions, NostrWasm } from \"./instance.ts\";\n\nasync function wasmBytes(opts?: LoadNostrWasmOptions): Promise<ArrayBuffer | ArrayBufferView> {\n const source = opts?.module;\n if (source !== undefined && isWasmBytes(source)) {\n return source;\n }\n if (source instanceof URL && source.protocol !== \"file:\") {\n return fetchWasmUrl(source);\n }\n if (source instanceof URL) {\n throw new CryptoError(`cannot fetch wasm from ${source.href}`);\n }\n return fetchWasmUrl(new URL(\"nostr_crypto_wasm_bg.wasm\", import.meta.url));\n}\n\nconst loader = createNostrWasmLoader(wasmBytes);\n\n/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\nexport async function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n return loader.loadNostrWasm(opts);\n}\n"],"mappings":";;;AAMA,eAAe,UAAU,MAAqE;CAC5F,MAAM,SAAS,MAAM;CACrB,IAAI,WAAW,KAAA,KAAa,YAAY,MAAM,GAC5C,OAAO;CAET,IAAI,kBAAkB,OAAO,OAAO,aAAa,SAC/C,OAAO,aAAa,MAAM;CAE5B,IAAI,kBAAkB,KACpB,MAAM,IAAI,YAAY,0BAA0B,OAAO,MAAM;CAE/D,OAAO,aAAa,IAAI,IAAI,6BAA6B,YAAY,GAAG,CAAC;AAC3E;AAEA,MAAM,SAAS,sBAAsB,SAAS;;AAG9C,eAAsB,cAAc,MAAiD;CACnF,OAAO,OAAO,cAAc,IAAI;AAClC"}
|
package/dist/wasm.d.mts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { s as WasmVerifyPoisonedError } from "./error-CR8Urc84.mjs";
|
|
1
|
+
import { s as WasmPoisonedError } from "./error-BquXDmIN.mjs";
|
|
2
|
+
import { n as NostrWasm, t as LoadNostrWasmOptions } from "./instance-DjsL8h84.mjs";
|
|
4
3
|
//#region src/wasm/load.d.ts
|
|
5
|
-
type LoadNostrWasmOptions = {
|
|
6
|
-
/** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */
|
|
7
|
-
module?: ArrayBuffer | ArrayBufferView | URL;
|
|
8
|
-
};
|
|
9
|
-
type NostrWasm = SigningBackend & {
|
|
10
|
-
verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
11
|
-
verifySerialized: (serializedUtf8: Uint8Array, id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
12
|
-
verifyEvent: (event: Event) => boolean;
|
|
13
|
-
};
|
|
14
4
|
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
15
5
|
export declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
|
|
16
6
|
//#endregion
|
|
17
|
-
export { type LoadNostrWasmOptions, type NostrWasm,
|
|
7
|
+
export { type LoadNostrWasmOptions, type NostrWasm, WasmPoisonedError };
|
|
18
8
|
//# sourceMappingURL=wasm.d.mts.map
|