@qntx/nostr 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/{builder-CyrGKRVP.mjs → builder-8VQ_Xr6X.mjs} +2 -2
- package/dist/{builder-CyrGKRVP.mjs.map → builder-8VQ_Xr6X.mjs.map} +1 -1
- package/dist/{builder-BWn55Paf.d.mts → builder-C9VuhbfY.d.mts} +2 -2
- package/dist/{client-BWsX9Cv1.mjs → client-BZMG37De.mjs} +21 -3
- package/dist/client-BZMG37De.mjs.map +1 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/core.d.mts +4 -4
- package/dist/core.mjs +4 -3
- package/dist/{gossip-BRQwIM_q.d.mts → gossip-ZnGOJ1fo.d.mts} +2 -2
- package/dist/gossip.d.mts +1 -1
- package/dist/{index-Ba7bJ7DD.d.mts → index-23sRP0wl.d.mts} +2 -2
- package/dist/{index-B425CAcQ.d.mts → index-CLGInxR5.d.mts} +17 -6
- package/dist/{index-Boe8FshM.d.mts → index-CvkvqB16.d.mts} +20 -2
- package/dist/{index-CUIvFQdE.d.mts → index-D-TK_KJG.d.mts} +14 -3
- package/dist/{index-BVyfUBuG.d.mts → index-D1bqFHKB.d.mts} +17 -10
- package/dist/{index-JdaS_uce.d.mts → index-Dj2TED7O.d.mts} +5 -5
- package/dist/index.d.mts +12 -12
- package/dist/index.mjs +7 -6
- package/dist/{key-Bbtys6o7.mjs → key-BZBap2p-.mjs} +3 -26
- package/dist/key-BZBap2p-.mjs.map +1 -0
- package/dist/{key-BlsYhN1V.d.mts → key-C6w9Fskk.d.mts} +2 -4
- package/dist/loaders.d.mts +1 -1
- package/dist/{nip17-DNEkz8rM.d.mts → nip17-jlcdeIQ8.d.mts} +2 -2
- package/dist/{nip65-DBfh2smt.d.mts → nip65-BlSAp_8P.d.mts} +2 -2
- package/dist/nips/blossom.d.mts +1 -1
- package/dist/nips/blossom.mjs +1 -1
- package/dist/nips/nip10.d.mts +1 -1
- package/dist/nips/nip10.mjs +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +1 -1
- package/dist/nips/nip51.d.mts +1 -1
- package/dist/nips/nip51.mjs +1 -1
- package/dist/nips/nip57.mjs +1 -1
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.mjs +2 -1
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +1 -1
- package/dist/nips/nip65.mjs +1 -1
- package/dist/nips/nip98.mjs +1 -1
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/{pool-tEr7c5bG.d.mts → pool-B7p_reAm.d.mts} +33 -2
- package/dist/{pool-XmAGaufS.mjs → pool-BGVx59yd.mjs} +104 -4
- package/dist/pool-BGVx59yd.mjs.map +1 -0
- package/dist/relay.d.mts +3 -3
- package/dist/relay.mjs +2 -2
- package/dist/{signer-CKR9EHce.mjs → signer-BGSpLC7e.mjs} +3 -2
- package/dist/signer-BGSpLC7e.mjs.map +1 -0
- package/dist/signer.d.mts +1 -1
- package/dist/signer.mjs +1 -1
- package/dist/storage-xXxLGCVb.mjs.map +1 -1
- package/dist/storage.d.mts +1 -1
- package/dist/testing.d.mts +10 -0
- package/dist/testing.mjs +9 -2
- package/dist/testing.mjs.map +1 -1
- package/dist/verifier-t5WoWbtY.mjs +38 -0
- package/dist/verifier-t5WoWbtY.mjs.map +1 -0
- package/dist/wasm.mjs +14 -21
- package/dist/wasm.mjs.map +1 -1
- package/package.json +65 -33
- package/dist/client-BWsX9Cv1.mjs.map +0 -1
- package/dist/key-Bbtys6o7.mjs.map +0 -1
- package/dist/pool-XmAGaufS.mjs.map +0 -1
- package/dist/signer-CKR9EHce.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 { verifyEvent } from \"../core/key.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { bytesToHex, isRecord, normalizeURL } from \"../core/util.ts\";\nimport { Negentropy, PROTOCOL_VERSION, storageFromEvents } from \"../nips/nip77.ts\";\nimport { MemoryEventStore } from \"../storage/memory.ts\";\nimport type { PutResult } from \"../storage/types.ts\";\n\nexport type FakeRelayOptions = {\n /** Delay before every relay→client message. */\n latencyMs?: number;\n auth?: {\n /** Sent as `[\"AUTH\", challenge]` right after the socket opens. */\n challenge: string;\n /** REQ whose filters can match these kinds is CLOSED `auth-required:` until AUTH succeeds. */\n readKinds?: ReadonlyArray<number>;\n /** EVENT → `[\"OK\", id, false, \"auth-required: ...\"]` until AUTH succeeds. */\n writes?: boolean;\n };\n /** EVENT → `[\"OK\", id, false, \"rate-limited: ...\"]`; nothing is stored. */\n rateLimited?: boolean;\n /** Out-of-order reply: send EOSE first, then the stored events. */\n eoseBeforeEvents?: boolean;\n};\n\nexport type FakeRelay = {\n readonly url: string;\n seed: (events: ReadonlyArray<Event>) => void;\n events: () => ReadonlyArray<Event>;\n inject: (event: Event) => void;\n disconnect: () => void;\n closeSubscriptions: (reason: string) => void;\n configure: (opts: Partial<FakeRelayOptions>) => void;\n /** Every parsed client→relay message received, in arrival order. */\n clientMessages: () => ReadonlyArray<unknown>;\n};\n\n/** One relay→client transport (an in-process socket or a `ws` connection). */\nexport type RelayTransport = {\n send: (data: string) => void;\n close: () => void;\n};\n\nexport type FakeRelaySession = {\n transport: RelayTransport;\n subs: Map<string, Filter[]>;\n negs: Map<string, Negentropy>;\n authed: boolean;\n queue: Promise<void>;\n};\n\n/** Wire filters are trusted as NIP-01 filters once they are records. */\nfunction isFilter(value: unknown): value is Filter {\n return isRecord(value);\n}\n\nfunction searchMatch(filter: Filter, event: Event): boolean {\n if (filter.search === undefined) {\n return true;\n }\n return event.content.toLowerCase().includes(filter.search.toLowerCase());\n}\n\nfunction subMatches(filters: ReadonlyArray<Filter>, event: Event): boolean {\n return filters.some((f) => matchFilter(f, event) && searchMatch(f, event));\n}\n\n/** Put outcomes that made the event part of the relay's live stream. */\nfunction isLivePut(result: PutResult): boolean {\n return (\n result === \"accepted\" || result === \"replaced\" || result === \"deleted\" || result === \"ephemeral\"\n );\n}\n\nfunction mayReadKinds(filters: ReadonlyArray<Filter>, readKinds: ReadonlyArray<number>): boolean {\n return filters.some((f) => f.kinds === undefined || f.kinds.some((k) => readKinds.includes(k)));\n}\n\n/**\n * Transport-agnostic fake relay: one NIP-01/42/45/50/77 session state machine per connection,\n * storage via {@link MemoryEventStore}. No timers except `latencyMs`; no global state.\n */\nexport class FakeRelayCore implements FakeRelay {\n readonly url: string;\n #opts: FakeRelayOptions;\n readonly #store = new MemoryEventStore();\n readonly #sessions = new Set<FakeRelaySession>();\n #mirror = new Map<string, Event>();\n readonly #inbox: unknown[] = [];\n #pending: Promise<void> = Promise.resolve();\n\n constructor(url: string, opts: FakeRelayOptions = {}) {\n this.url = normalizeURL(url);\n this.#opts = opts;\n }\n\n configure(opts: Partial<FakeRelayOptions>): void {\n this.#opts = { ...this.#opts, ...opts };\n }\n\n seed(events: ReadonlyArray<Event>): void {\n for (const event of events) {\n this.#mirror.set(event.id, event);\n }\n this.#pending = (async (): Promise<void> => {\n await this.#pending;\n for (const event of events) {\n // Sequential puts keep per-event store ordering for replaceables.\n // oxlint-disable-next-line eslint/no-await-in-loop\n await this.#store.put(event);\n }\n await this.#refreshMirror();\n })();\n }\n\n events(): ReadonlyArray<Event> {\n return [...this.#mirror.values()];\n }\n\n inject(event: Event): void {\n this.#pending = (async (): Promise<void> => {\n await this.#pending;\n const result = await this.#store.put(event);\n await this.#refreshMirror();\n if (isLivePut(result)) {\n this.#deliver(event);\n }\n })();\n }\n\n disconnect(): void {\n const sessions: FakeRelaySession[] = [...this.#sessions];\n this.#sessions.clear();\n for (const session of sessions) {\n session.transport.close();\n }\n }\n\n closeSubscriptions(reason: string): void {\n for (const session of this.#sessions) {\n for (const id of session.subs.keys()) {\n this.#send(session, [\"CLOSED\", id, reason]);\n }\n session.subs.clear();\n session.negs.clear();\n }\n }\n\n clientMessages(): ReadonlyArray<unknown> {\n return this.#inbox;\n }\n\n /** Attach a transport; returns a handle for {@link handleMessage}/detach. */\n connect(transport: RelayTransport): FakeRelaySession {\n const session: FakeRelaySession = {\n transport,\n subs: new Map(),\n negs: new Map(),\n authed: false,\n queue: Promise.resolve(),\n };\n this.#sessions.add(session);\n if (this.#opts.auth) {\n this.#send(session, [\"AUTH\", this.#opts.auth.challenge]);\n }\n return session;\n }\n\n detach(session: FakeRelaySession): void {\n this.#sessions.delete(session);\n }\n\n /** Feed a raw client→relay frame. Messages of one session are handled in order. */\n handleMessage(session: FakeRelaySession, raw: string): void {\n // A handler throw must not poison the session queue: NOTICE and continue.\n session.queue = (async (): Promise<void> => {\n try {\n await session.queue;\n await this.#handle(session, raw);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n try {\n this.#send(session, [\"NOTICE\", `error: ${message}`]);\n } catch {\n // transport gone\n }\n }\n })();\n }\n\n async #refreshMirror(): Promise<void> {\n const all = await this.#store.query([{}]);\n this.#mirror = new Map(all.map((e) => [e.id, e]));\n }\n\n #send(session: FakeRelaySession, message: unknown[]): void {\n const payload = JSON.stringify(message);\n const { latencyMs } = this.#opts;\n if (latencyMs !== undefined && latencyMs > 0) {\n setTimeout(() => session.transport.send(payload), latencyMs);\n return;\n }\n session.transport.send(payload);\n }\n\n #deliver(event: Event): void {\n for (const session of this.#sessions) {\n for (const [id, filters] of session.subs) {\n if (subMatches(filters, event)) {\n this.#send(session, [\"EVENT\", id, event]);\n }\n }\n }\n }\n\n async #matched(filters: Filter[]): Promise<Event[]> {\n // Per-filter NIP-01 limit: query unbounded, apply search, keep that\n // filter's newest — never a cross-filter minimum.\n const keptPerFilter = await Promise.all(\n filters.map(async (filter): Promise<Event[]> => {\n const unbounded = { ...filter };\n delete unbounded.limit;\n const queried = await this.#store.query([unbounded]);\n const rows = queried.filter((event) => searchMatch(filter, event));\n rows.sort(compareEventsDesc);\n return filter.limit === undefined ? rows : rows.slice(0, filter.limit);\n }),\n );\n const seen = new Map<string, Event>();\n for (const kept of keptPerFilter) {\n for (const event of kept) {\n if (!seen.has(event.id)) {\n seen.set(event.id, event);\n }\n }\n }\n const matched = [...seen.values()];\n matched.sort(compareEventsDesc);\n return matched;\n }\n\n async #handle(session: FakeRelaySession, raw: string): Promise<void> {\n await this.#pending;\n let msg: unknown;\n try {\n msg = JSON.parse(raw);\n } catch {\n this.#send(session, [\"NOTICE\", \"error: invalid message\"]);\n return;\n }\n if (!Array.isArray(msg)) {\n this.#send(session, [\"NOTICE\", \"error: invalid message\"]);\n return;\n }\n const items: unknown[] = msg;\n const [type] = items;\n if (typeof type !== \"string\") {\n this.#send(session, [\"NOTICE\", \"error: invalid message\"]);\n return;\n }\n this.#inbox.push(msg);\n\n switch (type) {\n case \"EVENT\": {\n const [, rawEvent] = items;\n if (!isRecord(rawEvent) || typeof rawEvent[\"id\"] !== \"string\") {\n this.#send(session, [\"NOTICE\", \"invalid: malformed event\"]);\n return;\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- wire record trusted as Event; verifyEvent below is the authoritative check\n const event = rawEvent as Event;\n if (this.#opts.rateLimited === true) {\n this.#send(session, [\"OK\", event.id, false, \"rate-limited: slow down\"]);\n return;\n }\n if (this.#opts.auth?.writes === true && !session.authed) {\n this.#send(session, [\"OK\", event.id, false, \"auth-required: login first\"]);\n return;\n }\n if (!verifyEvent(event)) {\n this.#send(session, [\"OK\", event.id, false, \"invalid: signature or id\"]);\n return;\n }\n const result = await this.#store.put(event);\n await this.#refreshMirror();\n if (result === \"rejected\") {\n this.#send(session, [\n \"OK\",\n event.id,\n false,\n \"invalid: a newer version of this event exists\",\n ]);\n return;\n }\n if (result === \"invalid\") {\n this.#send(session, [\"OK\", event.id, false, \"invalid: malformed event\"]);\n return;\n }\n if (result === \"duplicate\") {\n this.#send(session, [\"OK\", event.id, true, \"duplicate: already have this event\"]);\n return;\n }\n this.#send(session, [\"OK\", event.id, true, \"\"]);\n this.#deliver(event);\n return;\n }\n case \"REQ\": {\n const [, id] = items;\n const filters = items.slice(2);\n if (typeof id !== \"string\" || filters.length === 0 || !filters.every(isFilter)) {\n this.#send(session, [\"NOTICE\", \"error: invalid REQ\"]);\n return;\n }\n const readKinds = this.#opts.auth?.readKinds;\n if (readKinds !== undefined && !session.authed && mayReadKinds(filters, readKinds)) {\n this.#send(session, [\"CLOSED\", id, \"auth-required: we only serve to authed users\"]);\n return;\n }\n session.subs.set(id, filters);\n const matched = await this.#matched(filters);\n if (this.#opts.eoseBeforeEvents === true) {\n this.#send(session, [\"EOSE\", id]);\n }\n for (const event of matched) {\n this.#send(session, [\"EVENT\", id, event]);\n }\n if (this.#opts.eoseBeforeEvents !== true) {\n this.#send(session, [\"EOSE\", id]);\n }\n return;\n }\n case \"CLOSE\": {\n const [, id] = items;\n if (typeof id === \"string\") {\n session.subs.delete(id);\n }\n return;\n }\n case \"COUNT\": {\n const [, id] = items;\n const filters = items.slice(2);\n if (typeof id !== \"string\" || !filters.every(isFilter)) {\n this.#send(session, [\"NOTICE\", \"error: invalid COUNT\"]);\n return;\n }\n const matched = await this.#matched(filters);\n this.#send(session, [\"COUNT\", id, { count: matched.length }]);\n return;\n }\n case \"AUTH\": {\n const { auth } = this.#opts;\n const [, rawAuth] = items;\n if (!validateSignedEvent(rawAuth)) {\n this.#send(session, [\"OK\", \"0\".repeat(64), false, \"error: invalid auth event\"]);\n return;\n }\n const challengeTag = rawAuth.tags.find((t) => t[0] === \"challenge\")?.[1];\n const relayTag = rawAuth.tags.find((t) => t[0] === \"relay\")?.[1];\n let relayOk = false;\n if (relayTag !== undefined) {\n try {\n relayOk = normalizeURL(relayTag) === this.url;\n } catch {\n // unparseable relay tag\n }\n }\n if (\n auth !== undefined &&\n rawAuth.kind === Kind.ClientAuth &&\n verifyEvent(rawAuth) &&\n challengeTag === auth.challenge &&\n relayOk\n ) {\n session.authed = true;\n this.#send(session, [\"OK\", rawAuth.id, true, \"\"]);\n return;\n }\n this.#send(session, [\"OK\", rawAuth.id, false, \"error: invalid auth event\"]);\n return;\n }\n case \"NEG-OPEN\": {\n if (items.length === 5) {\n this.#send(session, [\"NEG-ERR\", items[1], \"error: obsolete 5-element NEG-OPEN\"]);\n return;\n }\n const [, id, rawFilter, negMessage] = items;\n if (\n items.length !== 4 ||\n typeof id !== \"string\" ||\n !isFilter(rawFilter) ||\n typeof negMessage !== \"string\"\n ) {\n const badId = typeof id === \"string\" ? id : \"\";\n this.#send(session, [\"NEG-ERR\", badId, \"error: invalid NEG-OPEN\"]);\n return;\n }\n // The NIP-77 filter is a plain NIP-01 filter — `limit` applies.\n const matched = await this.#matched([rawFilter]);\n const neg = new Negentropy(storageFromEvents(matched));\n let opened: string | undefined;\n try {\n opened = neg.reconcile(negMessage).nextMessage ?? undefined;\n } catch {\n this.#send(session, [\"NEG-ERR\", id, \"error: invalid negentropy message\"]);\n return;\n }\n session.negs.set(id, neg);\n this.#send(session, [\n \"NEG-MSG\",\n id,\n opened ?? bytesToHex(new Uint8Array([PROTOCOL_VERSION])),\n ]);\n return;\n }\n case \"NEG-MSG\": {\n const [, id, negMessage] = items;\n if (items.length !== 3 || typeof id !== \"string\" || typeof negMessage !== \"string\") {\n return;\n }\n const handle = session.negs.get(id);\n if (handle === undefined) {\n this.#send(session, [\"NEG-ERR\", id, \"closed: unknown subscription\"]);\n return;\n }\n let next: string | undefined;\n try {\n next = handle.reconcile(negMessage).nextMessage ?? undefined;\n } catch {\n session.negs.delete(id);\n this.#send(session, [\"NEG-ERR\", id, \"error: invalid negentropy message\"]);\n return;\n }\n this.#send(session, [\n \"NEG-MSG\",\n id,\n next ?? bytesToHex(new Uint8Array([PROTOCOL_VERSION])),\n ]);\n return;\n }\n case \"NEG-CLOSE\": {\n const [, id] = items;\n if (typeof id === \"string\") {\n session.negs.delete(id);\n }\n return;\n }\n default:\n this.#send(session, [\"NOTICE\", `error: unsupported ${type}`]);\n }\n }\n}\n","import { normalizeURL } from \"../core/util.ts\";\nimport type { WebSocketConstructor } from \"../relay/websocket.ts\";\nimport { FakeRelayCore } from \"./relay-core.ts\";\nimport type { FakeRelay, FakeRelayOptions, RelayTransport } from \"./relay-core.ts\";\n\nexport { type FakeRelay, type FakeRelayOptions } from \"./relay-core.ts\";\nexport type FakeRelayNetwork = {\n /** Pass to `Client` / `Pool` / `useWebSocketImplementation`. */\n readonly websocketImplementation: WebSocketConstructor;\n /** Get-or-create a relay handle by normalized URL. */\n relay: (url: string, opts?: FakeRelayOptions) => FakeRelay;\n close: () => void;\n};\n\ntype Listener = (ev: unknown) => void;\n\n/**\n * In-process fake relay network. `new websocketImplementation(url)` opens a socket bound to the\n * network's relay for that URL; `send` is dispatched to the relay session directly (no polling).\n */\nexport function createFakeRelayNetwork(defaults: FakeRelayOptions = {}): FakeRelayNetwork {\n const cores = new Map<string, FakeRelayCore>();\n\n const coreFor = (url: string, opts?: FakeRelayOptions): FakeRelayCore => {\n const key = normalizeURL(url);\n let core = cores.get(key);\n if (!core) {\n core = new FakeRelayCore(key, { ...defaults, ...opts });\n cores.set(key, core);\n } else if (opts) {\n core.configure(opts);\n }\n return core;\n };\n\n class FakeSocket {\n static readonly OPEN = 1;\n static readonly CONNECTING = 0;\n static readonly CLOSING = 2;\n static readonly CLOSED = 3;\n\n readonly url: string;\n /** Client→relay frames, for tests that inspect wire traffic. */\n readonly sent: string[] = [];\n readyState = FakeSocket.CONNECTING;\n readonly #listeners = new Map<string, Set<Listener>>();\n #session: ReturnType<FakeRelayCore[\"connect\"]> | undefined;\n #queuedSends: string[] = [];\n readonly #core: FakeRelayCore;\n\n constructor(url: string) {\n this.url = url;\n this.#core = coreFor(url);\n queueMicrotask(() => this.#open());\n }\n\n #open(): void {\n if (this.readyState !== FakeSocket.CONNECTING) {\n return;\n }\n this.readyState = FakeSocket.OPEN;\n const transport: RelayTransport = {\n send: (data) => this.#emit(\"message\", { data }),\n close: () => this.#terminate(),\n };\n // \"open\" listeners may send immediately; relay frames (e.g. the AUTH\n // challenge) must follow \"open\", so connect afterwards and flush.\n this.#emit(\"open\", {});\n this.#session = this.#core.connect(transport);\n const queued = this.#queuedSends;\n this.#queuedSends = [];\n for (const data of queued) {\n this.#core.handleMessage(this.#session, data);\n }\n }\n\n send(data: string): void {\n if (this.readyState !== FakeSocket.OPEN) {\n return;\n }\n this.sent.push(data);\n if (this.#session) {\n this.#core.handleMessage(this.#session, data);\n } else {\n this.#queuedSends.push(data);\n }\n }\n\n close(): void {\n this.#terminate();\n }\n\n #terminate(): void {\n if (this.readyState === FakeSocket.CLOSING || this.readyState === FakeSocket.CLOSED) {\n this.readyState = FakeSocket.CLOSED;\n return;\n }\n this.readyState = FakeSocket.CLOSED;\n const session = this.#session;\n this.#session = undefined;\n if (session) {\n this.#core.detach(session);\n }\n this.#emit(\"close\", {});\n }\n\n addEventListener(type: string, listener: Listener): void {\n let set = this.#listeners.get(type);\n if (!set) {\n set = new Set();\n this.#listeners.set(type, set);\n }\n set.add(listener);\n }\n\n removeEventListener(type: string, listener: Listener): void {\n this.#listeners.get(type)?.delete(listener);\n }\n\n #emit(type: string, ev: unknown): void {\n for (const listener of this.#listeners.get(type) ?? []) {\n listener(ev);\n }\n }\n }\n\n return {\n websocketImplementation: FakeSocket,\n relay: coreFor,\n close() {\n for (const core of cores.values()) {\n core.disconnect();\n }\n cores.clear();\n },\n };\n}\n","import { FakeRelayCore } from \"./relay-core.ts\";\nimport type { FakeRelay, FakeRelayOptions, RelayTransport } from \"./relay-core.ts\";\n\nexport type ServedFakeRelay = {\n url: string;\n relay: FakeRelay;\n close: () => Promise<void>;\n};\n\n/**\n * Serve the fake relay on a real WebSocket port via the optional `ws` peer dependency (dynamic\n * import — `@qntx/nostr/testing` never requires `ws` unless you serve). `port: 0` picks an\n * ephemeral port.\n */\nexport async function serveFakeRelay(\n opts: FakeRelayOptions & { port?: number; host?: string } = {},\n): Promise<ServedFakeRelay> {\n const { port = 0, host = \"127.0.0.1\", ...relayOpts } = opts;\n const { WebSocketServer } = await import(\"ws\");\n const wss = new WebSocketServer({ port, host });\n await new Promise<void>((resolve, reject) => {\n wss.once(\"listening\", () => resolve());\n wss.once(\"error\", (err) => reject(err));\n });\n const address = wss.address();\n const bound = typeof address === \"object\" && address !== null ? address.port : port;\n const url = `ws://${host}:${bound}`;\n const core = new FakeRelayCore(url, relayOpts);\n\n wss.on(\"connection\", (socket) => {\n const transport: RelayTransport = {\n send: (data) => socket.send(data),\n close: () => socket.close(),\n };\n const session = core.connect(transport);\n socket.on(\"message\", (data: unknown) => {\n core.handleMessage(session, String(data));\n });\n socket.on(\"close\", () => core.detach(session));\n socket.on(\"error\", () => core.detach(session));\n });\n\n return {\n url,\n relay: core,\n close: async () =>\n new Promise((resolve) => {\n core.disconnect();\n for (const client of wss.clients) {\n client.terminate();\n }\n wss.close(() => resolve());\n }),\n };\n}\n","import { EventBuilder, Keys } from \"../core/index.ts\";\nimport type { Event } from \"../core/index.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\n\nexport { type Filter } from \"../core/filter.ts\";\n\nexport type EventStoreConformanceCase = {\n name: string;\n run: (store: EventStore) => Promise<void>;\n};\n\nconst ALICE_SK = \"0000000000000000000000000000000000000000000000000000000000000101\";\nconst BOB_SK = \"0000000000000000000000000000000000000000000000000000000000000102\";\n\nfunction alice(): Keys {\n return Keys.fromSecretKey(ALICE_SK);\n}\nfunction bob(): Keys {\n return Keys.fromSecretKey(BOB_SK);\n}\n\nfunction note(keys: Keys, content: string, createdAt: number, tags: string[][] = []): Event {\n return new EventBuilder(1, content).tags(tags).createdAt(createdAt).signWithKeys(keys);\n}\n\nfunction replaceable(keys: Keys, kind: number, content: string, createdAt: number): Event {\n return new EventBuilder(kind, content).createdAt(createdAt).signWithKeys(keys);\n}\n\nfunction addressable(\n keys: Keys,\n kind: number,\n d: string,\n content: string,\n createdAt: number,\n): Event {\n return new EventBuilder(kind, content)\n .tags([[\"d\", d]])\n .createdAt(createdAt)\n .signWithKeys(keys);\n}\n\nfunction fail(message: string): never {\n throw new Error(`EventStore conformance: ${message}`);\n}\n\nfunction eq<T>(got: T, want: T, what: string): void {\n if (JSON.stringify(got) !== JSON.stringify(want)) {\n fail(`${what}: expected ${JSON.stringify(want)}, got ${JSON.stringify(got)}`);\n }\n}\n\nfunction ids(events: ReadonlyArray<Event>): string[] {\n return events.map((e) => e.id);\n}\n\n/**\n * Framework-agnostic {@link EventStore} conformance cases. Each `run` throws on failure; register\n * them with the test framework of your choice: `for (const c of eventStoreConformanceCases)\n * test(c.name, () => c.run(store()))`.\n */\nexport const eventStoreConformanceCases: ReadonlyArray<EventStoreConformanceCase> = [\n {\n name: \"put accepted then duplicate\",\n async run(store) {\n const e = note(alice(), \"hello\", 1);\n eq(await store.put(e), \"accepted\", \"first put\");\n eq(await store.put(e), \"duplicate\", \"second put\");\n eq(await store.get(e.id), e, \"get after put\");\n eq(\n await store.putMany([note(alice(), \"a\", 2), note(alice(), \"b\", 3)]),\n [\"accepted\", \"accepted\"],\n \"putMany results\",\n );\n },\n },\n {\n name: \"ephemeral event returns ephemeral and is not stored\",\n async run(store) {\n const e = replaceable(alice(), 20001, \"ephemeral\", 1);\n eq(await store.put(e), \"ephemeral\", \"put ephemeral\");\n eq(await store.get(e.id), undefined, \"ephemeral not retrievable\");\n eq(await store.query([{ kinds: [20001] }]), [], \"ephemeral not queryable\");\n eq(await store.count([{ kinds: [20001] }]), 0, \"ephemeral not counted\");\n },\n },\n {\n name: \"replaceable event keeps newest and rejects stale\",\n async run(store) {\n const older = replaceable(alice(), 0, \"old\", 1);\n const newer = replaceable(alice(), 0, \"new\", 2);\n eq(await store.put(older), \"accepted\", \"first replaceable\");\n eq(await store.put(newer), \"replaced\", \"newer replaces\");\n eq(await store.put(older), \"rejected\", \"stale replaceable rejected\");\n eq(await store.get(older.id), undefined, \"replaced event gone\");\n eq(\n ids(await store.query([{ kinds: [0], authors: [alice().publicKey] }])),\n [newer.id],\n \"newest kept\",\n );\n },\n },\n {\n name: \"addressable event replaces by address\",\n async run(store) {\n const v1 = addressable(alice(), 30001, \"x\", \"v1\", 1);\n const v2 = addressable(alice(), 30001, \"x\", \"v2\", 2);\n const other = addressable(alice(), 30001, \"y\", \"other\", 3);\n eq(await store.put(v1), \"accepted\", \"first addressable\");\n eq(await store.put(v2), \"replaced\", \"same address replaced\");\n eq(await store.put(v1), \"rejected\", \"stale addressable rejected\");\n eq(await store.put(other), \"accepted\", \"different address independent\");\n eq(await store.get(v1.id), undefined, \"v1 gone\");\n eq(\n ids(await store.query([{ kinds: [30001], authors: [alice().publicKey] }])).sort(),\n [other.id, v2.id].sort(),\n \"independent addresses\",\n );\n },\n },\n {\n name: \"deletion removes same-author e-tag targets only\",\n async run(store) {\n const mine = note(alice(), \"mine\", 1);\n const theirs = note(bob(), \"theirs\", 1);\n await store.put(mine);\n await store.put(theirs);\n const delForeign = EventBuilder.deletion([theirs.id]).createdAt(2).signWithKeys(alice());\n eq(await store.put(delForeign), \"deleted\", \"kind 5 accepted\");\n eq(await store.get(theirs.id), theirs, \"other author's event survives\");\n const delMine = EventBuilder.deletion([mine.id]).createdAt(3).signWithKeys(alice());\n eq(await store.put(delMine), \"deleted\", \"kind 5 accepted\");\n eq(await store.get(mine.id), undefined, \"own event deleted\");\n eq(await store.query([{ ids: [mine.id] }]), [], \"deleted event not queryable\");\n eq(await store.put(mine), \"duplicate\", \"deleted event cannot be re-put\");\n },\n },\n {\n name: \"deletion removes addressable via a tag and tombstones re-put\",\n async run(store) {\n const target = addressable(alice(), 30001, \"z\", \"target\", 1);\n await store.put(target);\n const coord = `30001:${alice().publicKey}:z`;\n const del = EventBuilder.deletion([{ address: coord }], \"\")\n .createdAt(2)\n .signWithKeys(alice());\n eq(await store.put(del), \"deleted\", \"a-tag deletion\");\n eq(await store.get(target.id), undefined, \"addressable deleted\");\n const stillCovered = addressable(alice(), 30001, \"z\", \"covered\", 1);\n eq(await store.put(stillCovered), \"duplicate\", \"tombstoned address rejects re-put\");\n eq(await store.query([{ kinds: [30001], authors: [alice().publicKey] }]), [], \"none left\");\n const after = addressable(alice(), 30001, \"z\", \"after\", 3);\n eq(await store.put(after), \"accepted\", \"events newer than the deletion are kept\");\n },\n },\n {\n name: \"query orders newest first and applies limit\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n const b = note(alice(), \"b\", 3);\n const c = note(alice(), \"c\", 2);\n await store.putMany([a, b, c]);\n eq(\n ids(await store.query([{ kinds: [1], authors: [alice().publicKey] }])),\n [b.id, c.id, a.id],\n \"descending created_at\",\n );\n eq(\n ids(await store.query([{ kinds: [1], authors: [alice().publicKey], limit: 2 }])),\n [b.id, c.id],\n \"limit applies\",\n );\n },\n },\n {\n name: \"query filters by kinds, authors, #e, #p, since, until\",\n async run(store) {\n const target = note(bob(), \"target\", 1);\n const tagged = note(alice(), \"tagged\", 2, [\n [\"e\", target.id],\n [\"p\", bob().publicKey],\n ]);\n const plain = note(alice(), \"plain\", 3);\n await store.putMany([target, tagged, plain]);\n const all = await store.query([{ kinds: [1] }]);\n eq(all.length, 3, \"kind filter\");\n eq(ids(await store.query([{ authors: [bob().publicKey] }])), [target.id], \"authors\");\n eq(ids(await store.query([{ \"#e\": [target.id] }])), [tagged.id], \"#e\");\n eq(ids(await store.query([{ \"#p\": [bob().publicKey] }])), [tagged.id], \"#p\");\n eq(ids(await store.query([{ kinds: [1], since: 2 }])), [plain.id, tagged.id], \"since\");\n eq(ids(await store.query([{ kinds: [1], until: 2 }])), [tagged.id, target.id], \"until\");\n eq(\n ids(await store.query([{ ids: [target.id, tagged.id] }])).sort(),\n [tagged.id, target.id].sort(),\n \"ids filter\",\n );\n },\n },\n {\n name: \"count matches query cardinality across overlapping filters\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n const b = note(bob(), \"b\", 2);\n await store.putMany([a, b]);\n eq(await store.count([{ kinds: [1] }]), 2, \"count all\");\n eq(\n await store.count([\n { authors: [alice().publicKey] },\n { authors: [bob().publicKey] },\n { ids: [a.id] },\n ]),\n 2,\n \"count dedupes union\",\n );\n eq(await store.count([{ kinds: [2] }]), 0, \"count none\");\n },\n },\n {\n name: \"negentropyItems sorted by created_at then id and respects limit\",\n async run(store) {\n const a = note(alice(), \"a\", 2);\n const b = note(alice(), \"b\", 1);\n const c = note(bob(), \"c\", 3);\n await store.putMany([a, b, c]);\n const items = await store.negentropyItems({ kinds: [1] });\n eq(\n items.map((i) => i.id),\n [b.id, a.id, c.id],\n \"created_at asc ordering\",\n );\n const limited = await store.negentropyItems({ kinds: [1], limit: 2 });\n eq(\n limited.map((i) => i.id),\n [a.id, c.id],\n \"limit keeps newest two, presented ascending\",\n );\n eq(await store.negentropyItems({ kinds: [2] }), [], \"no match\");\n const filtered = await store.negentropyItems({ authors: [bob().publicKey] });\n eq(filtered, [{ id: c.id, created_at: 3 }], \"filter\");\n },\n },\n {\n name: \"outbox bounds roundtrip\",\n async run(store) {\n eq(await store.getOutboxBound(alice().publicKey, 1), undefined, \"unset bound\");\n await store.setOutboxBound(alice().publicKey, 1, { oldest: 10, newest: 20 });\n eq(\n await store.getOutboxBound(alice().publicKey, 1),\n { oldest: 10, newest: 20 },\n \"bound read\",\n );\n await store.setOutboxBound(alice().publicKey, 1, { oldest: 5, newest: 30 });\n eq(\n await store.getOutboxBound(alice().publicKey, 1),\n { oldest: 5, newest: 30 },\n \"bound overwrite\",\n );\n },\n },\n {\n name: \"remove deletes by id and tombstones\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n await store.put(a);\n eq(await store.remove([a.id]), 1, \"remove count\");\n eq(await store.get(a.id), undefined, \"removed\");\n eq(await store.remove([a.id]), 0, \"second remove is noop\");\n eq(await store.put(a), \"duplicate\", \"removed id tombstoned\");\n },\n },\n {\n name: \"clear wipes events and bounds\",\n async run(store) {\n const a = note(alice(), \"a\", 1);\n await store.put(a);\n await store.setOutboxBound(alice().publicKey, 1, { oldest: 1, newest: 1 });\n await store.clear();\n eq(await store.get(a.id), undefined, \"event gone\");\n eq(await store.query([{ kinds: [1] }]), [], \"query empty\");\n eq(await store.getOutboxBound(alice().publicKey, 1), undefined, \"bound gone\");\n eq(await store.put(a), \"accepted\", \"store usable after clear\");\n },\n },\n];\n","import { Keys, finalizeEvent } from \"../core/index.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { isTag } from \"../core/tag.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport {\n getConversationKey,\n decrypt as nip44Decrypt,\n encrypt as nip44Encrypt,\n} from \"../nips/nip44.ts\";\nimport { decodeNip46Request, encodeNip46Response } from \"../nips/nip46.ts\";\nimport type { Nip46Response } from \"../nips/nip46.ts\";\nimport type { FakeRelayNetwork } from \"./network.ts\";\n\nexport type FakeNip46SignerOptions = {\n /** The network the fake signer joins as a client of `relayUrl`. */\n network: FakeRelayNetwork;\n relayUrl: string;\n /** Pubkey of the NIP-46 client under test. */\n clientPubkey: string;\n /** Remote-signer key; random when omitted. */\n bunkerSk?: string;\n /** The user key the signer signs for; random when omitted. */\n userSk?: string;\n /** First answer `auth_url` (result) with this URL in the error field, then the real response. */\n authUrl?: string;\n authUrlMethods?: ReadonlyArray<string>;\n /** Delay in ms before the real response after an `auth_url` reply. */\n authReplyDelayMs?: number;\n /** Collected RPC requests (mutated as they arrive). */\n requests?: Array<{ method: string; params: string[] }>;\n /** `switch_relays` result. Default `\"null\"`. */\n switchRelays?: string[] | undefined;\n /** Override `connect` RPC result. Default `\"ack\"`. */\n connectResult?: string;\n /** Reply with neither `result` nor `error` for these methods. */\n emptyMethods?: ReadonlyArray<string>;\n /**\n * Serialize the response JSON; default {@link encodeNip46Response}, which omits absent fields.\n * Lets tests put explicit `null`s on the wire like some remote signers do.\n */\n encodeResponse?: (res: Nip46Response) => string;\n};\n\nexport type FakeNip46Signer = {\n readonly bunkerPubkey: string;\n readonly userPublicKey: string;\n /** Also answer RPCs on another relay of the same network (e.g. after switch_relays). */\n attach: (relayUrl: string) => void;\n /** Publish the nostrconnect handshake secret confirmation as the bunker. */\n confirmHandshake: (secret: string) => void;\n close: () => void;\n};\n\n/**\n * In-process NIP-46 remote signer: subscribes to kind:24133 requests on `relayUrl` and answers as a\n * bunker, encrypted to `clientPubkey` with NIP-44.\n */\nexport function createFakeNip46Signer(opts: FakeNip46SignerOptions): FakeNip46Signer {\n const bunkerKeys =\n opts.bunkerSk !== undefined && opts.bunkerSk !== \"\"\n ? Keys.fromSecretKey(opts.bunkerSk)\n : Keys.generate();\n const userKeys =\n opts.userSk !== undefined && opts.userSk !== \"\"\n ? Keys.fromSecretKey(opts.userSk)\n : Keys.generate();\n const convKey = getConversationKey(bunkerKeys.secretKey.bytes, opts.clientPubkey);\n const handled = new Set<string>();\n const authPending = new Set<string>();\n const authMethods = new Set(opts.authUrlMethods ?? [\"connect\"]);\n let closed = false;\n\n const sockets = new Set<{ close: () => void }>();\n const listen = (relayUrl: string): void => {\n const ws = new opts.network.websocketImplementation(relayUrl);\n ws.addEventListener(\"open\", () => {\n ws.send(\n JSON.stringify([\n \"REQ\",\n \"fake-nip46-signer\",\n { kinds: [Kind.NostrConnect], \"#p\": [bunkerKeys.publicKey] },\n ]),\n );\n });\n ws.addEventListener(\"message\", (ev) => onMessage(ev, ws));\n sockets.add(ws);\n };\n\n const onMessage = (ev: unknown, ws: { send: (data: string) => void }): void => {\n if (typeof ev !== \"object\" || ev === null || !(\"data\" in ev)) {\n return;\n }\n const { data } = ev;\n let msg: unknown;\n try {\n msg = JSON.parse(String(data));\n } catch {\n return;\n }\n if (!Array.isArray(msg) || msg[0] !== \"EVENT\") {\n return;\n }\n const parts: unknown[] = msg;\n const rawEvent = parts.at(2);\n if (!isRecord(rawEvent)) {\n return;\n }\n const { kind, pubkey, content, id } = rawEvent;\n if (kind !== Kind.NostrConnect) {\n return;\n }\n if (typeof pubkey !== \"string\" || typeof content !== \"string\" || typeof id !== \"string\") {\n return;\n }\n if (pubkey !== opts.clientPubkey || handled.has(id)) {\n return;\n }\n\n try {\n const req = decodeNip46Request(nip44Decrypt(content, convKey));\n if (\n opts.authUrl !== undefined &&\n opts.authUrl !== \"\" &&\n authMethods.has(req.method) &&\n !authPending.has(req.id)\n ) {\n authPending.add(req.id);\n reply(ws, opts.clientPubkey, req.id, \"auth_url\", opts.authUrl);\n }\n handled.add(id);\n opts.requests?.push({ method: req.method, params: req.params });\n\n let result: string | undefined;\n let error: string | undefined;\n switch (opts.emptyMethods?.includes(req.method) === true ? \"#empty\" : req.method) {\n case \"connect\":\n result = opts.connectResult ?? \"ack\";\n break;\n case \"get_public_key\":\n result = userKeys.publicKey;\n break;\n case \"ping\":\n result = \"pong\";\n break;\n case \"switch_relays\":\n result = opts.switchRelays === undefined ? \"null\" : JSON.stringify(opts.switchRelays);\n break;\n case \"logout\":\n result = \"ack\";\n break;\n case \"sign_event\": {\n const rawTemplate: unknown = JSON.parse(req.params.at(0) ?? \"null\");\n if (\n !isRecord(rawTemplate) ||\n typeof rawTemplate[\"kind\"] !== \"number\" ||\n !Array.isArray(rawTemplate[\"tags\"]) ||\n !rawTemplate[\"tags\"].every(isTag) ||\n typeof rawTemplate[\"content\"] !== \"string\" ||\n typeof rawTemplate[\"created_at\"] !== \"number\"\n ) {\n throw new Error(\"invalid sign_event template\");\n }\n result = JSON.stringify(\n finalizeEvent(\n {\n kind: rawTemplate[\"kind\"],\n tags: rawTemplate[\"tags\"],\n content: rawTemplate[\"content\"],\n created_at: rawTemplate[\"created_at\"],\n },\n userKeys.secretKey,\n ),\n );\n break;\n }\n case \"#empty\":\n break;\n default:\n error = `unsupported method ${req.method}`;\n }\n if (authPending.has(req.id) && opts.authReplyDelayMs !== undefined) {\n const pendingId = req.id;\n const pendingResult = result;\n const pendingError = error;\n setTimeout(\n () => reply(ws, opts.clientPubkey, pendingId, pendingResult, pendingError),\n opts.authReplyDelayMs,\n );\n } else {\n reply(ws, opts.clientPubkey, req.id, result, error);\n }\n } catch {\n handled.add(id);\n }\n };\n\n const reply = (\n ws: { send: (data: string) => void },\n clientPubkey: string,\n id: string,\n result?: string,\n error?: string,\n ): void => {\n if (closed) {\n return;\n }\n const payload = (opts.encodeResponse ?? encodeNip46Response)({ id, result, error });\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [[\"p\", clientPubkey]],\n content: nip44Encrypt(payload, convKey),\n created_at: Math.floor(Date.now() / 1000),\n },\n bunkerKeys.secretKey,\n );\n ws.send(JSON.stringify([\"EVENT\", event]));\n };\n\n listen(opts.relayUrl);\n\n return {\n bunkerPubkey: bunkerKeys.publicKey,\n userPublicKey: userKeys.publicKey,\n confirmHandshake(secret: string): void {\n const payload = encodeNip46Response({ id: \"handshake\", result: secret });\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [[\"p\", opts.clientPubkey]],\n content: nip44Encrypt(payload, convKey),\n created_at: Math.floor(Date.now() / 1000),\n },\n bunkerKeys.secretKey,\n );\n opts.network.relay(opts.relayUrl).inject(event);\n },\n attach(relayUrl: string): void {\n listen(relayUrl);\n },\n close(): void {\n closed = true;\n for (const ws of sockets) {\n ws.close();\n }\n sockets.clear();\n },\n };\n}\n"],"mappings":"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"}
|
|
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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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { a as hexToBytes, d as utf8Encoder } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { c as markVerified, i as isMarkedVerified, l as serializeEvent, m as validateSignedEvent, r as isMarkedFailed, s as markUnverified } from "./event-D8Nfoh4K.mjs";
|
|
3
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
4
|
+
import { schnorr } from "@noble/curves/secp256k1.js";
|
|
5
|
+
//#region src/core/verifier.ts
|
|
6
|
+
/**
|
|
7
|
+
* Build an event verifier with exactly the semantics of {@link verifyEvent}, delegating the hash and
|
|
8
|
+
* signature check to `backend`. Verified/failed results share `verifyEvent`'s WeakSet caches, so
|
|
9
|
+
* verifiers built this way and `verifyEvent` agree on (and reuse) each other's results.
|
|
10
|
+
*/
|
|
11
|
+
function createEventVerifier(backend) {
|
|
12
|
+
return (event) => {
|
|
13
|
+
if (isMarkedVerified(event)) return true;
|
|
14
|
+
if (isMarkedFailed(event)) return false;
|
|
15
|
+
if (!validateSignedEvent(event)) {
|
|
16
|
+
markUnverified(event);
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const ok = backend(utf8Encoder.encode(serializeEvent(event)), hexToBytes(event.id), hexToBytes(event.pubkey), hexToBytes(event.sig));
|
|
20
|
+
if (ok) markVerified(event);
|
|
21
|
+
else markUnverified(event);
|
|
22
|
+
return ok;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const nobleSerializedVerify = (serializedUtf8, id, pubkey, sig) => {
|
|
26
|
+
try {
|
|
27
|
+
if (!sha256(serializedUtf8).every((byte, i) => byte === id[i])) return false;
|
|
28
|
+
return schnorr.verify(sig, id, pubkey);
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/** Verify event id and BIP-340 signature. Uses WeakSet cache (does not mutate the event). */
|
|
34
|
+
const verifyEvent = createEventVerifier(nobleSerializedVerify);
|
|
35
|
+
//#endregion
|
|
36
|
+
export { verifyEvent as n, createEventVerifier as t };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=verifier-t5WoWbtY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier-t5WoWbtY.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/**\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): (event: Event) => boolean {\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: (event: Event) => boolean = createEventVerifier(nobleSerializedVerify);\n"],"mappings":";;;;;;;;;;AAgCA,SAAgB,oBAAoB,SAA6D;CAC/F,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,cAAyC,oBAAoB,qBAAqB"}
|
package/dist/wasm.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { f as CryptoError, v as WasmVerifyPoisonedError } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { t as createEventVerifier } from "./verifier-t5WoWbtY.mjs";
|
|
3
3
|
//#region src/wasm/abi.ts
|
|
4
4
|
/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */
|
|
5
5
|
const ALLOWED_WASM_IMPORTS = [{
|
|
@@ -120,33 +120,26 @@ async function instantiateCryptoWasm(bytes) {
|
|
|
120
120
|
}
|
|
121
121
|
//#endregion
|
|
122
122
|
//#region src/wasm/adapter.ts
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Build the WASM event verifier on {@link createEventVerifier}. A `WebAssembly.RuntimeError` from
|
|
125
|
+
* the module means the instance aborted — it poisons every later call with the same
|
|
126
|
+
* `WasmVerifyPoisonedError`; any other backend error verifies `false` (the event is marked
|
|
127
|
+
* failed).
|
|
128
|
+
*/
|
|
129
|
+
function createWasmEventVerifier(verifySerialized, poison) {
|
|
130
|
+
const backend = (serializedUtf8, id, pubkey, sig) => {
|
|
131
|
+
if (poison.error !== void 0) throw poison.error;
|
|
132
132
|
try {
|
|
133
|
-
|
|
134
|
-
const id = hexToBytes(event.id);
|
|
135
|
-
const pubkey = hexToBytes(event.pubkey);
|
|
136
|
-
const sig = hexToBytes(event.sig);
|
|
137
|
-
const ok = wasm.verifySerialized(serialized, id, pubkey, sig);
|
|
138
|
-
if (ok) markVerified(event);
|
|
139
|
-
else markUnverified(event);
|
|
140
|
-
return ok;
|
|
133
|
+
return verifySerialized(serializedUtf8, id, pubkey, sig);
|
|
141
134
|
} catch (error) {
|
|
142
135
|
if (error instanceof WebAssembly.RuntimeError) {
|
|
143
136
|
poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: error });
|
|
144
137
|
throw poison.error;
|
|
145
138
|
}
|
|
146
|
-
markUnverified(event);
|
|
147
139
|
return false;
|
|
148
140
|
}
|
|
149
141
|
};
|
|
142
|
+
return createEventVerifier(backend);
|
|
150
143
|
}
|
|
151
144
|
//#endregion
|
|
152
145
|
//#region src/wasm/load.ts
|
|
@@ -198,7 +191,7 @@ function bindExports(exports) {
|
|
|
198
191
|
return {
|
|
199
192
|
verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),
|
|
200
193
|
verifySerialized: (serializedUtf8, id, pubkey, sig) => wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),
|
|
201
|
-
verifyEvent:
|
|
194
|
+
verifyEvent: createWasmEventVerifier(rawSerialized, poison),
|
|
202
195
|
sign: (id, seckey, aux) => wrapPoison(poison, () => {
|
|
203
196
|
requireByteLength(id, 32, "id");
|
|
204
197
|
requireByteLength(seckey, 32, "secret key");
|
package/dist/wasm.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm.mjs","names":[],"sources":["../src/wasm/abi.ts","../src/wasm/adapter.ts","../src/wasm/load.ts"],"sourcesContent":["/** Wasm-bindgen 0.2.122 bundler-produced exports used by interned TS glue. */\nexport type CryptoWasmExports = {\n memory: WebAssembly.Memory;\n verify: (\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n verify_serialized: (\n serPtr: number,\n serLen: number,\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n sign: (\n retptr: number,\n idPtr: number,\n idLen: number,\n skPtr: number,\n skLen: number,\n auxPtr: number,\n auxLen: number,\n ) => void;\n public_key: (retptr: number, skPtr: number, skLen: number) => void;\n /** 0.2.122 name for `__wbindgen_malloc(size, align)`. */\n __wbindgen_export: (size: number, align: number) => number;\n /** 0.2.122 name for `__wbindgen_free(ptr, size, align)` after malloc claimed `__wbindgen_export`. */\n __wbindgen_export2: (ptr: number, size: number, align: number) => void;\n __wbindgen_add_to_stack_pointer: (delta: number) => number;\n __wbindgen_start?: () => void;\n};\n\n/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */\nexport const ALLOWED_WASM_IMPORTS: ReadonlyArray<{ module: string; name: string }> = [\n { module: \"wbg\", name: \"__wbindgen_throw\" },\n { module: \"./nostr_crypto_wasm_bg.js\", name: \"__wbindgen_throw\" },\n];\n\nconst utf8 = new TextDecoder();\n\nfunction decodeUtf8(memory: WebAssembly.Memory, ptr: number, len: number): string {\n return utf8.decode(new Uint8Array(memory.buffer, ptr, len));\n}\n\nfunction makeWbgImports(holder: { exports?: CryptoWasmExports }): WebAssembly.Imports {\n const throwRuntime = (ptr: number, len: number): never => {\n const mem = holder.exports?.memory;\n const msg = mem ? decodeUtf8(mem, ptr, len) : \"wasm panic\";\n throw new WebAssembly.RuntimeError(msg);\n };\n const wbg = {\n __wbindgen_throw: throwRuntime,\n };\n return {\n wbg,\n \"./nostr_crypto_wasm_bg.js\": wbg,\n };\n}\n\n/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */\nexport function assertAllowedWasmImports(mod: WebAssembly.Module): void {\n const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\\0${item.name}`));\n for (const imp of WebAssembly.Module.imports(mod)) {\n if (imp.kind !== \"function\") {\n throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);\n }\n if (!allowed.has(`${imp.module}\\0${imp.name}`)) {\n throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);\n }\n }\n}\n\nfunction requireMemory(value: WebAssembly.ExportValue | undefined): WebAssembly.Memory {\n if (!(value instanceof WebAssembly.Memory)) {\n throw new TypeError(\"wasm missing memory export\");\n }\n return value;\n}\n\n// oxlint-disable-next-line no-unnecessary-type-parameters -- T binds the declared ABI signature at each call site\nfunction requireFn<T extends (...args: number[]) => unknown>(\n value: WebAssembly.ExportValue | undefined,\n name: string,\n): T {\n if (typeof value !== \"function\") {\n throw new TypeError(`wasm missing ${name} export`);\n }\n // oxlint-disable-next-line no-unsafe-type-assertion -- wasm exports are opaque; each name is bound to the signature the ABI contract requires\n return value as T;\n}\n\nfunction asExports(raw: WebAssembly.Exports): CryptoWasmExports {\n const exports: CryptoWasmExports = {\n memory: requireMemory(raw[\"memory\"]),\n verify: requireFn(raw[\"verify\"], \"verify\"),\n verify_serialized: requireFn(raw[\"verify_serialized\"], \"verify_serialized\"),\n sign: requireFn(raw[\"sign\"], \"sign\"),\n public_key: requireFn(raw[\"public_key\"], \"public_key\"),\n __wbindgen_export: requireFn(raw[\"__wbindgen_export\"], \"__wbindgen_export\"),\n __wbindgen_export2: requireFn(raw[\"__wbindgen_export2\"], \"__wbindgen_export2\"),\n __wbindgen_add_to_stack_pointer: requireFn(\n raw[\"__wbindgen_add_to_stack_pointer\"],\n \"__wbindgen_add_to_stack_pointer\",\n ),\n };\n const start = raw[\"__wbindgen_start\"];\n if (typeof start === \"function\") {\n exports.__wbindgen_start = requireFn<() => void>(start, \"__wbindgen_start\");\n }\n return exports;\n}\n\nfunction passBytes(exports: CryptoWasmExports, bytes: Uint8Array): { ptr: number; len: number } {\n const len = bytes.length;\n const ptr = exports.__wbindgen_export(len, 1) >>> 0;\n new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);\n return { ptr, len };\n}\n\nexport function wasmVerify(\n exports: CryptoWasmExports,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return exports.verify(idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;\n}\n\nexport function wasmVerifySerialized(\n exports: CryptoWasmExports,\n serialized: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const serP = passBytes(exports, serialized);\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return (\n exports.verify_serialized(\n serP.ptr,\n serP.len,\n idP.ptr,\n idP.len,\n pkP.ptr,\n pkP.len,\n sigP.ptr,\n sigP.len,\n ) !== 0\n );\n}\n\nfunction takeBytes(exports: CryptoWasmExports, ptr: number, len: number): Uint8Array {\n const out = new Uint8Array(len);\n if (len > 0) {\n out.set(new Uint8Array(exports.memory.buffer, ptr, len));\n exports.__wbindgen_export2(ptr, len, 1);\n }\n return out;\n}\n\nfunction callReturningBytes(\n exports: CryptoWasmExports,\n invoke: (retptr: number) => void,\n): Uint8Array {\n const retptr = exports.__wbindgen_add_to_stack_pointer(-16);\n try {\n invoke(retptr);\n const view = new DataView(exports.memory.buffer);\n const ptr = view.getUint32(retptr, true);\n const len = view.getUint32(retptr + 4, true);\n return takeBytes(exports, ptr, len);\n } finally {\n exports.__wbindgen_add_to_stack_pointer(16);\n }\n}\n\nexport function wasmSign(\n exports: CryptoWasmExports,\n id: Uint8Array,\n seckey: Uint8Array,\n aux: Uint8Array,\n): Uint8Array {\n const idP = passBytes(exports, id);\n const skP = passBytes(exports, seckey);\n const auxP = passBytes(exports, aux);\n return callReturningBytes(exports, (retptr) => {\n exports.sign(retptr, idP.ptr, idP.len, skP.ptr, skP.len, auxP.ptr, auxP.len);\n });\n}\n\nexport function wasmPublicKey(exports: CryptoWasmExports, seckey: Uint8Array): Uint8Array {\n const skP = passBytes(exports, seckey);\n return callReturningBytes(exports, (retptr) => {\n exports.public_key(retptr, skP.ptr, skP.len);\n });\n}\n\nexport async function instantiateCryptoWasm(\n bytes: ArrayBuffer | ArrayBufferView,\n): Promise<CryptoWasmExports> {\n const holder: { exports?: CryptoWasmExports } = {};\n const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));\n assertAllowedWasmImports(module);\n holder.exports = asExports(instance.exports);\n holder.exports.__wbindgen_start?.();\n return holder.exports;\n}\n","import { WasmVerifyPoisonedError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n isMarkedFailed,\n isMarkedVerified,\n markUnverified,\n markVerified,\n serializeEvent,\n validateSignedEvent,\n} from \"../core/event.ts\";\nimport { hexToBytes, utf8Encoder } from \"../core/util.ts\";\n\nexport { WasmVerifyPoisonedError } from \"../core/error.ts\";\n\nexport type WasmSerializedVerify = {\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n};\n\nexport function makeVerifyEvent(\n wasm: WasmSerializedVerify,\n poison: { error?: Error },\n): (event: Event) => boolean {\n return (event: Event): boolean => {\n if (poison.error) {\n throw poison.error;\n }\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 try {\n const serialized = utf8Encoder.encode(serializeEvent(event));\n const id = hexToBytes(event.id);\n const pubkey = hexToBytes(event.pubkey);\n const sig = hexToBytes(event.sig);\n const ok = wasm.verifySerialized(serialized, id, pubkey, sig);\n if (ok) {\n markVerified(event);\n } else {\n markUnverified(event);\n }\n return ok;\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n markUnverified(event);\n return false;\n }\n };\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n instantiateCryptoWasm,\n wasmPublicKey,\n wasmSign,\n wasmVerify,\n wasmVerifySerialized,\n} from \"./abi.ts\";\nimport type { CryptoWasmExports } from \"./abi.ts\";\nimport { makeVerifyEvent, WasmVerifyPoisonedError } from \"./adapter.ts\";\n\nexport { WasmVerifyPoisonedError } from \"./adapter.ts\";\nexport type LoadNostrWasmOptions = {\n /** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */\n module?: ArrayBuffer | ArrayBufferView | URL;\n};\n\nexport type NostrWasm = {\n verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n verifyEvent: (event: Event) => boolean;\n sign: (id: Uint8Array, seckey: Uint8Array, aux: Uint8Array) => Uint8Array;\n publicKey: (seckey: Uint8Array) => Uint8Array;\n};\n\nlet interned: Promise<NostrWasm> | undefined;\n\nfunction isNode(): boolean {\n if (!(\"process\" in globalThis)) {\n return false;\n }\n const proc: unknown = globalThis.process;\n return (\n typeof proc === \"object\" &&\n proc !== null &&\n \"versions\" in proc &&\n typeof proc.versions === \"object\" &&\n proc.versions !== null &&\n \"node\" in proc.versions &&\n typeof proc.versions.node === \"string\"\n );\n}\n\nfunction isWasmBytes(value: unknown): value is ArrayBuffer | ArrayBufferView {\n return value instanceof ArrayBuffer || ArrayBuffer.isView(value);\n}\n\nasync function defaultWasmHref(): Promise<string> {\n const mod = await import(\"./nostr_crypto_wasm_bg.wasm?url\");\n return mod.default;\n}\n\nasync function readWasmUrl(url: URL): Promise<Uint8Array> {\n if (isNode() && url.protocol === \"file:\") {\n const { readFile } = await import(\"node:fs/promises\");\n const { fileURLToPath } = await import(\"node:url\");\n return new Uint8Array(await readFile(fileURLToPath(url)));\n }\n const res = await fetch(url);\n if (!res.ok) {\n throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\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 const href = source instanceof URL ? source : new URL(await defaultWasmHref(), import.meta.url);\n return readWasmUrl(href);\n}\n\nfunction requireByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nfunction wrapPoison<T>(poison: { error?: Error }, fn: () => T): T {\n if (poison.error) {\n throw poison.error;\n }\n try {\n return fn();\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n throw error;\n }\n}\n\nfunction bindExports(exports: CryptoWasmExports): NostrWasm {\n const poison: { error?: Error } = {};\n const rawSerialized = (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ): boolean => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);\n return {\n verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),\n verifySerialized: (serializedUtf8, id, pubkey, sig) =>\n wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),\n verifyEvent: makeVerifyEvent({ verifySerialized: rawSerialized }, poison),\n sign: (id, seckey, aux) =>\n wrapPoison(poison, () => {\n requireByteLength(id, 32, \"id\");\n requireByteLength(seckey, 32, \"secret key\");\n requireByteLength(aux, 32, \"aux\");\n const sig = wasmSign(exports, id, seckey, aux);\n if (sig.length !== 64) {\n throw new CryptoError(\"wasm sign failed\");\n }\n return sig;\n }),\n publicKey: (seckey) =>\n wrapPoison(poison, () => {\n requireByteLength(seckey, 32, \"secret key\");\n const pk = wasmPublicKey(exports, seckey);\n if (pk.length !== 32) {\n throw new CryptoError(\"wasm publicKey failed\");\n }\n return pk;\n }),\n };\n}\n\nasync function instantiateNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n const bytes = await wasmBytes(opts);\n const exports = await instantiateCryptoWasm(bytes);\n return bindExports(exports);\n}\n\n/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\nexport async function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n if (interned) {\n return interned;\n }\n const pending = instantiateNostrWasm(opts);\n interned = pending;\n try {\n return await pending;\n } catch (error) {\n if (interned === pending) {\n interned = undefined;\n }\n throw error;\n }\n}\n\n/** Clears intern so tests can re-instantiate. Not exported from the wasm subpath. */\nexport function resetNostrWasmForTests(): void {\n interned = undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wasm.mjs","names":[],"sources":["../src/wasm/abi.ts","../src/wasm/adapter.ts","../src/wasm/load.ts"],"sourcesContent":["/** Wasm-bindgen 0.2.122 bundler-produced exports used by interned TS glue. */\nexport type CryptoWasmExports = {\n memory: WebAssembly.Memory;\n verify: (\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n verify_serialized: (\n serPtr: number,\n serLen: number,\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n sign: (\n retptr: number,\n idPtr: number,\n idLen: number,\n skPtr: number,\n skLen: number,\n auxPtr: number,\n auxLen: number,\n ) => void;\n public_key: (retptr: number, skPtr: number, skLen: number) => void;\n /** 0.2.122 name for `__wbindgen_malloc(size, align)`. */\n __wbindgen_export: (size: number, align: number) => number;\n /** 0.2.122 name for `__wbindgen_free(ptr, size, align)` after malloc claimed `__wbindgen_export`. */\n __wbindgen_export2: (ptr: number, size: number, align: number) => void;\n __wbindgen_add_to_stack_pointer: (delta: number) => number;\n __wbindgen_start?: () => void;\n};\n\n/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */\nexport const ALLOWED_WASM_IMPORTS: ReadonlyArray<{ module: string; name: string }> = [\n { module: \"wbg\", name: \"__wbindgen_throw\" },\n { module: \"./nostr_crypto_wasm_bg.js\", name: \"__wbindgen_throw\" },\n];\n\nconst utf8 = new TextDecoder();\n\nfunction decodeUtf8(memory: WebAssembly.Memory, ptr: number, len: number): string {\n return utf8.decode(new Uint8Array(memory.buffer, ptr, len));\n}\n\nfunction makeWbgImports(holder: { exports?: CryptoWasmExports }): WebAssembly.Imports {\n const throwRuntime = (ptr: number, len: number): never => {\n const mem = holder.exports?.memory;\n const msg = mem ? decodeUtf8(mem, ptr, len) : \"wasm panic\";\n throw new WebAssembly.RuntimeError(msg);\n };\n const wbg = {\n __wbindgen_throw: throwRuntime,\n };\n return {\n wbg,\n \"./nostr_crypto_wasm_bg.js\": wbg,\n };\n}\n\n/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */\nexport function assertAllowedWasmImports(mod: WebAssembly.Module): void {\n const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\\0${item.name}`));\n for (const imp of WebAssembly.Module.imports(mod)) {\n if (imp.kind !== \"function\") {\n throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);\n }\n if (!allowed.has(`${imp.module}\\0${imp.name}`)) {\n throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);\n }\n }\n}\n\nfunction requireMemory(value: WebAssembly.ExportValue | undefined): WebAssembly.Memory {\n if (!(value instanceof WebAssembly.Memory)) {\n throw new TypeError(\"wasm missing memory export\");\n }\n return value;\n}\n\n// oxlint-disable-next-line no-unnecessary-type-parameters -- T binds the declared ABI signature at each call site\nfunction requireFn<T extends (...args: number[]) => unknown>(\n value: WebAssembly.ExportValue | undefined,\n name: string,\n): T {\n if (typeof value !== \"function\") {\n throw new TypeError(`wasm missing ${name} export`);\n }\n // oxlint-disable-next-line no-unsafe-type-assertion -- wasm exports are opaque; each name is bound to the signature the ABI contract requires\n return value as T;\n}\n\nfunction asExports(raw: WebAssembly.Exports): CryptoWasmExports {\n const exports: CryptoWasmExports = {\n memory: requireMemory(raw[\"memory\"]),\n verify: requireFn(raw[\"verify\"], \"verify\"),\n verify_serialized: requireFn(raw[\"verify_serialized\"], \"verify_serialized\"),\n sign: requireFn(raw[\"sign\"], \"sign\"),\n public_key: requireFn(raw[\"public_key\"], \"public_key\"),\n __wbindgen_export: requireFn(raw[\"__wbindgen_export\"], \"__wbindgen_export\"),\n __wbindgen_export2: requireFn(raw[\"__wbindgen_export2\"], \"__wbindgen_export2\"),\n __wbindgen_add_to_stack_pointer: requireFn(\n raw[\"__wbindgen_add_to_stack_pointer\"],\n \"__wbindgen_add_to_stack_pointer\",\n ),\n };\n const start = raw[\"__wbindgen_start\"];\n if (typeof start === \"function\") {\n exports.__wbindgen_start = requireFn<() => void>(start, \"__wbindgen_start\");\n }\n return exports;\n}\n\nfunction passBytes(exports: CryptoWasmExports, bytes: Uint8Array): { ptr: number; len: number } {\n const len = bytes.length;\n const ptr = exports.__wbindgen_export(len, 1) >>> 0;\n new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);\n return { ptr, len };\n}\n\nexport function wasmVerify(\n exports: CryptoWasmExports,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return exports.verify(idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;\n}\n\nexport function wasmVerifySerialized(\n exports: CryptoWasmExports,\n serialized: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const serP = passBytes(exports, serialized);\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return (\n exports.verify_serialized(\n serP.ptr,\n serP.len,\n idP.ptr,\n idP.len,\n pkP.ptr,\n pkP.len,\n sigP.ptr,\n sigP.len,\n ) !== 0\n );\n}\n\nfunction takeBytes(exports: CryptoWasmExports, ptr: number, len: number): Uint8Array {\n const out = new Uint8Array(len);\n if (len > 0) {\n out.set(new Uint8Array(exports.memory.buffer, ptr, len));\n exports.__wbindgen_export2(ptr, len, 1);\n }\n return out;\n}\n\nfunction callReturningBytes(\n exports: CryptoWasmExports,\n invoke: (retptr: number) => void,\n): Uint8Array {\n const retptr = exports.__wbindgen_add_to_stack_pointer(-16);\n try {\n invoke(retptr);\n const view = new DataView(exports.memory.buffer);\n const ptr = view.getUint32(retptr, true);\n const len = view.getUint32(retptr + 4, true);\n return takeBytes(exports, ptr, len);\n } finally {\n exports.__wbindgen_add_to_stack_pointer(16);\n }\n}\n\nexport function wasmSign(\n exports: CryptoWasmExports,\n id: Uint8Array,\n seckey: Uint8Array,\n aux: Uint8Array,\n): Uint8Array {\n const idP = passBytes(exports, id);\n const skP = passBytes(exports, seckey);\n const auxP = passBytes(exports, aux);\n return callReturningBytes(exports, (retptr) => {\n exports.sign(retptr, idP.ptr, idP.len, skP.ptr, skP.len, auxP.ptr, auxP.len);\n });\n}\n\nexport function wasmPublicKey(exports: CryptoWasmExports, seckey: Uint8Array): Uint8Array {\n const skP = passBytes(exports, seckey);\n return callReturningBytes(exports, (retptr) => {\n exports.public_key(retptr, skP.ptr, skP.len);\n });\n}\n\nexport async function instantiateCryptoWasm(\n bytes: ArrayBuffer | ArrayBufferView,\n): Promise<CryptoWasmExports> {\n const holder: { exports?: CryptoWasmExports } = {};\n const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));\n assertAllowedWasmImports(module);\n holder.exports = asExports(instance.exports);\n holder.exports.__wbindgen_start?.();\n return holder.exports;\n}\n","import { WasmVerifyPoisonedError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { createEventVerifier } from \"../core/verifier.ts\";\nimport type { SerializedEventVerifier } from \"../core/verifier.ts\";\n\nexport { WasmVerifyPoisonedError } from \"../core/error.ts\";\n\n/**\n * Build the WASM event verifier on {@link createEventVerifier}. A `WebAssembly.RuntimeError` from\n * the module means the instance aborted — it poisons every later call with the same\n * `WasmVerifyPoisonedError`; any other backend error verifies `false` (the event is marked\n * failed).\n */\nexport function createWasmEventVerifier(\n verifySerialized: SerializedEventVerifier,\n poison: { error?: Error },\n): (event: Event) => boolean {\n const backend: SerializedEventVerifier = (serializedUtf8, id, pubkey, sig) => {\n if (poison.error !== undefined) {\n throw poison.error;\n }\n try {\n return verifySerialized(serializedUtf8, id, pubkey, sig);\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n return false;\n }\n };\n return createEventVerifier(backend);\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n instantiateCryptoWasm,\n wasmPublicKey,\n wasmSign,\n wasmVerify,\n wasmVerifySerialized,\n} from \"./abi.ts\";\nimport type { CryptoWasmExports } from \"./abi.ts\";\nimport { createWasmEventVerifier, WasmVerifyPoisonedError } from \"./adapter.ts\";\n\nexport { WasmVerifyPoisonedError } from \"./adapter.ts\";\nexport type LoadNostrWasmOptions = {\n /** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */\n module?: ArrayBuffer | ArrayBufferView | URL;\n};\n\nexport type NostrWasm = {\n verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n verifyEvent: (event: Event) => boolean;\n sign: (id: Uint8Array, seckey: Uint8Array, aux: Uint8Array) => Uint8Array;\n publicKey: (seckey: Uint8Array) => Uint8Array;\n};\n\nlet interned: Promise<NostrWasm> | undefined;\n\nfunction isNode(): boolean {\n if (!(\"process\" in globalThis)) {\n return false;\n }\n const proc: unknown = globalThis.process;\n return (\n typeof proc === \"object\" &&\n proc !== null &&\n \"versions\" in proc &&\n typeof proc.versions === \"object\" &&\n proc.versions !== null &&\n \"node\" in proc.versions &&\n typeof proc.versions.node === \"string\"\n );\n}\n\nfunction isWasmBytes(value: unknown): value is ArrayBuffer | ArrayBufferView {\n return value instanceof ArrayBuffer || ArrayBuffer.isView(value);\n}\n\nasync function defaultWasmHref(): Promise<string> {\n const mod = await import(\"./nostr_crypto_wasm_bg.wasm?url\");\n return mod.default;\n}\n\nasync function readWasmUrl(url: URL): Promise<Uint8Array> {\n if (isNode() && url.protocol === \"file:\") {\n const { readFile } = await import(\"node:fs/promises\");\n const { fileURLToPath } = await import(\"node:url\");\n return new Uint8Array(await readFile(fileURLToPath(url)));\n }\n const res = await fetch(url);\n if (!res.ok) {\n throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\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 const href = source instanceof URL ? source : new URL(await defaultWasmHref(), import.meta.url);\n return readWasmUrl(href);\n}\n\nfunction requireByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nfunction wrapPoison<T>(poison: { error?: Error }, fn: () => T): T {\n if (poison.error) {\n throw poison.error;\n }\n try {\n return fn();\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n throw error;\n }\n}\n\nfunction bindExports(exports: CryptoWasmExports): NostrWasm {\n const poison: { error?: Error } = {};\n const rawSerialized = (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ): boolean => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);\n return {\n verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),\n verifySerialized: (serializedUtf8, id, pubkey, sig) =>\n wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),\n verifyEvent: createWasmEventVerifier(rawSerialized, poison),\n sign: (id, seckey, aux) =>\n wrapPoison(poison, () => {\n requireByteLength(id, 32, \"id\");\n requireByteLength(seckey, 32, \"secret key\");\n requireByteLength(aux, 32, \"aux\");\n const sig = wasmSign(exports, id, seckey, aux);\n if (sig.length !== 64) {\n throw new CryptoError(\"wasm sign failed\");\n }\n return sig;\n }),\n publicKey: (seckey) =>\n wrapPoison(poison, () => {\n requireByteLength(seckey, 32, \"secret key\");\n const pk = wasmPublicKey(exports, seckey);\n if (pk.length !== 32) {\n throw new CryptoError(\"wasm publicKey failed\");\n }\n return pk;\n }),\n };\n}\n\nasync function instantiateNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n const bytes = await wasmBytes(opts);\n const exports = await instantiateCryptoWasm(bytes);\n return bindExports(exports);\n}\n\n/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\nexport async function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n if (interned) {\n return interned;\n }\n const pending = instantiateNostrWasm(opts);\n interned = pending;\n try {\n return await pending;\n } catch (error) {\n if (interned === pending) {\n interned = undefined;\n }\n throw error;\n }\n}\n\n/** Clears intern so tests can re-instantiate. Not exported from the wasm subpath. */\nexport function resetNostrWasmForTests(): void {\n interned = undefined;\n}\n"],"mappings":"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"}
|