@qntx/nostr 0.0.1
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/LICENSE +21 -0
- package/README.md +25 -0
- package/dist/builder-BphJa-Y-.d.mts +67 -0
- package/dist/builder-q0VsvnYE.mjs +158 -0
- package/dist/builder-q0VsvnYE.mjs.map +1 -0
- package/dist/client-Bd8B1mYm.mjs +835 -0
- package/dist/client-Bd8B1mYm.mjs.map +1 -0
- package/dist/client.d.mts +2 -0
- package/dist/client.mjs +2 -0
- package/dist/core.d.mts +8 -0
- package/dist/core.mjs +9 -0
- package/dist/error-B49rbDzT.d.mts +7 -0
- package/dist/error-CwBxle6N.mjs +13 -0
- package/dist/error-CwBxle6N.mjs.map +1 -0
- package/dist/error-DZEs5OuZ.mjs +24 -0
- package/dist/error-DZEs5OuZ.mjs.map +1 -0
- package/dist/error-WEFS-R-4.d.mts +20 -0
- package/dist/event-B5D2jxt_.d.mts +108 -0
- package/dist/event-CzoQEFMF.mjs +188 -0
- package/dist/event-CzoQEFMF.mjs.map +1 -0
- package/dist/filter-BxwjEkZp.mjs +113 -0
- package/dist/filter-BxwjEkZp.mjs.map +1 -0
- package/dist/filter-DUEKP3q1.d.mts +40 -0
- package/dist/gossip-3xkRRCm_.mjs +220 -0
- package/dist/gossip-3xkRRCm_.mjs.map +1 -0
- package/dist/gossip-C5RVB1UB.d.mts +71 -0
- package/dist/gossip.d.mts +3 -0
- package/dist/gossip.mjs +2 -0
- package/dist/http-6vevbBlu.d.mts +22 -0
- package/dist/http-D2rhokZo.mjs +24 -0
- package/dist/http-D2rhokZo.mjs.map +1 -0
- package/dist/index-BYMnhRIC.d.mts +161 -0
- package/dist/index-C0C4e-Gn.d.mts +55 -0
- package/dist/index-CaxrMD1A.d.mts +1 -0
- package/dist/index-DaRyjo7O.d.mts +77 -0
- package/dist/index-DgOugrpF.d.mts +275 -0
- package/dist/index-EwL6fHLo.d.mts +267 -0
- package/dist/index-k2YhCgsh.d.mts +57 -0
- package/dist/index.d.mts +22 -0
- package/dist/index.mjs +23 -0
- package/dist/key-BiGxGLhg.d.mts +37 -0
- package/dist/key-Dn-aX4x4.mjs +130 -0
- package/dist/key-Dn-aX4x4.mjs.map +1 -0
- package/dist/kind-BLl4cLOc.mjs +59 -0
- package/dist/kind-BLl4cLOc.mjs.map +1 -0
- package/dist/loaders-BNQszDAn.mjs +767 -0
- package/dist/loaders-BNQszDAn.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -0
- package/dist/loaders.mjs +2 -0
- package/dist/memory-BCmhZPek.mjs +461 -0
- package/dist/memory-BCmhZPek.mjs.map +1 -0
- package/dist/message-C_Uj-Y-c.mjs +179 -0
- package/dist/message-C_Uj-Y-c.mjs.map +1 -0
- package/dist/message-DJC-Jz6T.d.mts +32 -0
- package/dist/nip17-BWq-Kfq5.d.mts +38 -0
- package/dist/nip19-D7905oIv.d.mts +63 -0
- package/dist/nip46-C_DoxiS_.d.mts +51 -0
- package/dist/nip59-DljW_sYh.d.mts +76 -0
- package/dist/nip65-Di5hZRuV.d.mts +21 -0
- package/dist/nip77-ByxlgoQO.d.mts +55 -0
- package/dist/nips/blossom.d.mts +93 -0
- package/dist/nips/blossom.mjs +325 -0
- package/dist/nips/blossom.mjs.map +1 -0
- package/dist/nips/nip04.d.mts +8 -0
- package/dist/nips/nip04.mjs +41 -0
- package/dist/nips/nip04.mjs.map +1 -0
- package/dist/nips/nip05.d.mts +89 -0
- package/dist/nips/nip05.mjs +147 -0
- package/dist/nips/nip05.mjs.map +1 -0
- package/dist/nips/nip10.d.mts +43 -0
- package/dist/nips/nip10.mjs +194 -0
- package/dist/nips/nip10.mjs.map +1 -0
- package/dist/nips/nip11.d.mts +43 -0
- package/dist/nips/nip11.mjs +99 -0
- package/dist/nips/nip11.mjs.map +1 -0
- package/dist/nips/nip13.d.mts +23 -0
- package/dist/nips/nip13.mjs +88 -0
- package/dist/nips/nip13.mjs.map +1 -0
- package/dist/nips/nip17.d.mts +2 -0
- package/dist/nips/nip17.mjs +138 -0
- package/dist/nips/nip17.mjs.map +1 -0
- package/dist/nips/nip19.d.mts +2 -0
- package/dist/nips/nip19.mjs +174 -0
- package/dist/nips/nip19.mjs.map +1 -0
- package/dist/nips/nip21.d.mts +17 -0
- package/dist/nips/nip21.mjs +29 -0
- package/dist/nips/nip21.mjs.map +1 -0
- package/dist/nips/nip27.d.mts +42 -0
- package/dist/nips/nip27.mjs +175 -0
- package/dist/nips/nip27.mjs.map +1 -0
- package/dist/nips/nip42.d.mts +12 -0
- package/dist/nips/nip42.mjs +22 -0
- package/dist/nips/nip42.mjs.map +1 -0
- package/dist/nips/nip44.d.mts +12 -0
- package/dist/nips/nip44.mjs +125 -0
- package/dist/nips/nip44.mjs.map +1 -0
- package/dist/nips/nip46.d.mts +2 -0
- package/dist/nips/nip46.mjs +132 -0
- package/dist/nips/nip46.mjs.map +1 -0
- package/dist/nips/nip49.d.mts +12 -0
- package/dist/nips/nip49.mjs +80 -0
- package/dist/nips/nip49.mjs.map +1 -0
- package/dist/nips/nip51.d.mts +88 -0
- package/dist/nips/nip51.mjs +246 -0
- package/dist/nips/nip51.mjs.map +1 -0
- package/dist/nips/nip57.d.mts +43 -0
- package/dist/nips/nip57.mjs +230 -0
- package/dist/nips/nip57.mjs.map +1 -0
- package/dist/nips/nip59.d.mts +2 -0
- package/dist/nips/nip59.mjs +171 -0
- package/dist/nips/nip59.mjs.map +1 -0
- package/dist/nips/nip65.d.mts +2 -0
- package/dist/nips/nip65.mjs +76 -0
- package/dist/nips/nip65.mjs.map +1 -0
- package/dist/nips/nip77.d.mts +2 -0
- package/dist/nips/nip77.mjs +421 -0
- package/dist/nips/nip77.mjs.map +1 -0
- package/dist/nips/nip96.d.mts +31 -0
- package/dist/nips/nip96.mjs +95 -0
- package/dist/nips/nip96.mjs.map +1 -0
- package/dist/nips/nip98.d.mts +28 -0
- package/dist/nips/nip98.mjs +91 -0
- package/dist/nips/nip98.mjs.map +1 -0
- package/dist/nostr_crypto_wasm_bg-hi5aXi5P.mjs +4 -0
- package/dist/nostr_crypto_wasm_bg.wasm +0 -0
- package/dist/pool-C_j1OmBB.mjs +1881 -0
- package/dist/pool-C_j1OmBB.mjs.map +1 -0
- package/dist/pool-DhRi7l-b.d.mts +297 -0
- package/dist/relay.d.mts +4 -0
- package/dist/relay.mjs +2 -0
- package/dist/signer-CZ6K6FUc.mjs +473 -0
- package/dist/signer-CZ6K6FUc.mjs.map +1 -0
- package/dist/signer.d.mts +3 -0
- package/dist/signer.mjs +2 -0
- package/dist/storage-DOy0iLRE.mjs +870 -0
- package/dist/storage-DOy0iLRE.mjs.map +1 -0
- package/dist/storage.d.mts +4 -0
- package/dist/storage.mjs +4 -0
- package/dist/types-BzyADqnw.d.mts +19 -0
- package/dist/types-Dn24TPFs.d.mts +43 -0
- package/dist/util-6tfLQ9JF.mjs +73 -0
- package/dist/util-6tfLQ9JF.mjs.map +1 -0
- package/dist/wasm.d.mts +19 -0
- package/dist/wasm.mjs +237 -0
- package/dist/wasm.mjs.map +1 -0
- package/package.json +204 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-DOy0iLRE.mjs","names":["#dbName","#db","#loadCaches","#ensure","#deletion","#replaceable","#writeTail","#enqueueWrite","#putManyLocked","#snapshotCaches","#putAllInTx","#restoreCaches","#deleteEventRows","#queryOne","#scan","#acceptHit","#deriveOutboxBound","#setOutboxBoundLocked","#removeLocked","#clearLocked"],"sources":["../src/storage/idb-types.ts","../src/storage/idb-helpers.ts","../src/storage/idb-query.ts","../src/storage/idb-schema.ts","../src/storage/indexeddb.ts"],"sourcesContent":["export const EVENTS = \"events\";\nexport const TAG_REFS = \"tag_refs\";\nexport const ADDRESSES = \"addresses\";\nexport const TOMBSTONES = \"tombstones\";\nexport const OUTBOX_BOUNDS = \"outbox_bounds\";\nexport const WRITE_STORES = [EVENTS, TAG_REFS, ADDRESSES, TOMBSTONES];\n\nexport type IDBCursorDirectionLike = \"next\" | \"prev\";\n\nexport type IDBKeyRangeLike = {\n lower: unknown;\n upper: unknown;\n lowerOpen: boolean;\n upperOpen: boolean;\n};\n\nexport type IDBCursorLike = {\n value?: unknown;\n key: unknown;\n primaryKey: unknown;\n continue(): void;\n};\n\nexport type IDBIndexLike = {\n openCursor(range?: IDBKeyRangeLike, direction?: IDBCursorDirectionLike): IDBRequestLike;\n openKeyCursor(range?: IDBKeyRangeLike, direction?: IDBCursorDirectionLike): IDBRequestLike;\n};\n\nexport type IDBRequestLike = {\n result: unknown;\n error: Error | null;\n onsuccess: ((ev: unknown) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n};\n\nexport type IDBObjectStoreLike = {\n put(value: unknown): unknown;\n get(key: string): IDBRequestLike;\n delete(key: string): unknown;\n clear(): unknown;\n getAll(): IDBRequestLike;\n createIndex(name: string, keyPath: string | string[]): IDBIndexLike;\n index(name: string): IDBIndexLike;\n openCursor(range?: IDBKeyRangeLike, direction?: IDBCursorDirectionLike): IDBRequestLike;\n};\n\nexport type IDBTransactionLike = {\n objectStore(name: string): IDBObjectStoreLike;\n oncomplete: ((ev: unknown) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n onabort: ((ev: unknown) => void) | null;\n error: Error | null;\n abort(): void;\n};\n\nexport type IDBDatabaseLike = {\n objectStoreNames: { contains(name: string): boolean };\n createObjectStore(name: string, options?: { keyPath?: string }): IDBObjectStoreLike;\n transaction(storeNames: string | string[], mode?: \"readonly\" | \"readwrite\"): IDBTransactionLike;\n close(): void;\n};\n\nexport type IDBVersionChangeEventLike = {\n oldVersion: number;\n newVersion: number | null;\n target: { result: IDBDatabaseLike; transaction: IDBTransactionLike };\n};\n\nexport type IDBFactoryLike = {\n open(name: string, version?: number): IDBOpenRequestLike;\n};\n\nexport type IDBOpenRequestLike = IDBRequestLike & {\n onupgradeneeded: ((ev: IDBVersionChangeEventLike) => void) | null;\n result: IDBDatabaseLike;\n};\n\nexport type TagRef = {\n key: string;\n name: string;\n value: string;\n id: string;\n created_at: number;\n};\n\nexport type AddressRow = {\n address: string;\n id: string;\n created_at: number;\n};\n\nexport type Tombstone =\n | { key: `id:${string}`; type: \"id\" }\n | { key: `pending:${string}`; type: \"pending\"; pubkey: string }\n | { key: `coord:${string}`; type: \"coord\"; until: number };\n\nexport type OutboxBoundRow = { key: string; oldest: number; newest: number };\n","import type { Event } from \"../core/event.ts\";\nimport { type DeletionPlan, type DeletionState } from \"./deletion.ts\";\nimport { StorageError } from \"./error.ts\";\nimport {\n ADDRESSES,\n EVENTS,\n TAG_REFS,\n TOMBSTONES,\n type AddressRow,\n type IDBCursorDirectionLike,\n type IDBCursorLike,\n type IDBKeyRangeLike,\n type IDBObjectStoreLike,\n type IDBRequestLike,\n type IDBTransactionLike,\n type TagRef,\n type Tombstone,\n} from \"./idb-types.ts\";\nimport type { PutDecision } from \"./put.ts\";\nimport type { PutResult } from \"./types.ts\";\n\nexport function reqOf<T>(req: IDBRequestLike): Promise<T> {\n return new Promise((resolve, reject) => {\n req.onsuccess = () => resolve(req.result as T);\n req.onerror = () => reject(req.error ?? new StorageError(\"IndexedDB request failed\"));\n });\n}\n\nexport function txDone(tx: IDBTransactionLike): Promise<void> {\n return new Promise((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error ?? new StorageError(\"IndexedDB transaction failed\"));\n });\n}\n\nexport function walkCursor(\n source: {\n openCursor(range?: IDBKeyRangeLike, direction?: IDBCursorDirectionLike): IDBRequestLike;\n },\n range: IDBKeyRangeLike | undefined,\n direction: IDBCursorDirectionLike,\n visit: (cursor: IDBCursorLike) => boolean,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const req = source.openCursor(range, direction);\n req.onerror = () => reject(req.error ?? new StorageError(\"IndexedDB cursor failed\"));\n req.onsuccess = () => {\n const cursor = req.result as IDBCursorLike | undefined;\n if (!cursor) {\n resolve();\n return;\n }\n if (visit(cursor)) {\n resolve();\n return;\n }\n cursor.continue();\n };\n });\n}\n\nexport function tagRefKey(name: string, value: string, id: string): string {\n return `${name}:${value.toLowerCase()}:${id.toLowerCase()}`;\n}\n\nexport function writeTagRefs(store: IDBObjectStoreLike, event: Event): void {\n for (const tag of event.tags) {\n if ((tag[0] !== \"e\" && tag[0] !== \"p\") || tag[1] === undefined) continue;\n const name = tag[0];\n const value = tag[1].toLowerCase();\n const id = event.id.toLowerCase();\n store.put({\n key: tagRefKey(name, value, id),\n name,\n value,\n id,\n created_at: event.created_at,\n } satisfies TagRef);\n }\n}\n\nexport function deleteStoredEvent(\n tx: IDBTransactionLike,\n event: Event,\n addressRow?: AddressRow,\n): void {\n const tagRefs = tx.objectStore(TAG_REFS);\n for (const tag of event.tags) {\n if ((tag[0] === \"e\" || tag[0] === \"p\") && tag[1] !== undefined) {\n tagRefs.delete(tagRefKey(tag[0], tag[1], event.id));\n }\n }\n if (addressRow?.id === event.id) {\n tx.objectStore(ADDRESSES).delete(addressRow.address);\n }\n tx.objectStore(EVENTS).delete(event.id);\n}\n\nexport function persistPlanTombstones(\n store: IDBObjectStoreLike,\n plan: DeletionPlan,\n coordIds: readonly string[],\n deletion: DeletionState,\n): void {\n for (const id of plan.removeIds) {\n store.put({ key: `id:${id}`, type: \"id\" } satisfies Tombstone);\n store.delete(`pending:${id}`);\n }\n for (const id of coordIds) {\n store.put({ key: `id:${id}`, type: \"id\" } satisfies Tombstone);\n store.delete(`pending:${id}`);\n }\n for (const p of plan.pendingIds) {\n if (deletion.ids.has(p.id)) continue;\n store.put({\n key: `pending:${p.id}`,\n type: \"pending\",\n pubkey: p.pubkey.toLowerCase(),\n } satisfies Tombstone);\n }\n for (const c of plan.coordinates) {\n const prev = deletion.coordinates.get(c.key) ?? Number.NEGATIVE_INFINITY;\n store.put({\n key: `coord:${c.key}`,\n type: \"coord\",\n until: Math.max(prev, c.until),\n } satisfies Tombstone);\n }\n}\n\nexport function tombstonesToPlan(rows: unknown[]): DeletionPlan {\n const plan: DeletionPlan = { removeIds: [], pendingIds: [], coordinates: [] };\n for (const row of rows) {\n if (!row || typeof row !== \"object\") continue;\n const r = row as Record<string, unknown>;\n if (r.type === \"id\" && typeof r.key === \"string\" && r.key.startsWith(\"id:\")) {\n plan.removeIds.push(r.key.slice(3).toLowerCase());\n continue;\n }\n if (\n r.type === \"pending\" &&\n typeof r.key === \"string\" &&\n r.key.startsWith(\"pending:\") &&\n typeof r.pubkey === \"string\"\n ) {\n plan.pendingIds.push({ id: r.key.slice(8).toLowerCase(), pubkey: r.pubkey.toLowerCase() });\n continue;\n }\n if (\n r.type === \"coord\" &&\n typeof r.key === \"string\" &&\n r.key.startsWith(\"coord:\") &&\n typeof r.until === \"number\"\n ) {\n plan.coordinates.push({ key: r.key.slice(6), until: r.until });\n }\n }\n return plan;\n}\n\nexport function applyPutIndexedDb(\n tx: IDBTransactionLike,\n s: {\n deletion: DeletionState;\n replaceable: Map<string, string>;\n },\n d: PutDecision,\n): PutResult {\n const events = tx.objectStore(EVENTS);\n const tagRefs = tx.objectStore(TAG_REFS);\n const addresses = tx.objectStore(ADDRESSES);\n const tombstones = tx.objectStore(TOMBSTONES);\n switch (d.action) {\n case \"skip\":\n return d.result;\n case \"tombstone\":\n tombstones.put({ key: `id:${d.event.id}`, type: \"id\" } satisfies Tombstone);\n tombstones.delete(`pending:${d.event.id}`);\n s.deletion.ids.add(d.event.id);\n s.deletion.pending.delete(d.event.id);\n return \"duplicate\";\n case \"delete\": {\n s.deletion.pending.delete(d.event.id);\n persistPlanTombstones(tombstones, d.plan, d.coordIds, s.deletion);\n s.deletion.absorb(d.plan);\n for (const id of d.coordIds) s.deletion.ids.add(id);\n events.put(d.event);\n writeTagRefs(tagRefs, d.event);\n return \"deleted\";\n }\n case \"insert\":\n events.put(d.event);\n writeTagRefs(tagRefs, d.event);\n if (d.address) {\n addresses.put({\n address: d.address,\n id: d.event.id,\n created_at: d.event.created_at,\n });\n s.replaceable.set(d.address, d.event.id);\n }\n return d.result;\n }\n}\n","import type { Event } from \"../core/event.ts\";\nimport { sortEvents } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { StorageError } from \"./error.ts\";\nimport { reqOf } from \"./idb-helpers.ts\";\nimport {\n EVENTS,\n TAG_REFS,\n type IDBCursorDirectionLike,\n type IDBCursorLike,\n type IDBIndexLike,\n type IDBKeyRangeLike,\n type IDBObjectStoreLike,\n type IDBRequestLike,\n type IDBTransactionLike,\n type TagRef,\n} from \"./idb-types.ts\";\n\nfunction compareEventsDesc(\n a: { id: string; created_at: number },\n b: { id: string; created_at: number },\n): number {\n if (a.created_at !== b.created_at) return b.created_at - a.created_at;\n return a.id.localeCompare(b.id);\n}\n\nexport function prefixRange(\n prefix: readonly (string | number)[],\n since?: number,\n until?: number,\n): IDBKeyRangeLike {\n return idbKeyRange().bound(\n [...prefix, since ?? 0],\n [...prefix, until ?? Number.MAX_SAFE_INTEGER],\n );\n}\n\nfunction createdAtRange(since?: number, until?: number): IDBKeyRangeLike {\n return idbKeyRange().bound(since ?? 0, until ?? Number.MAX_SAFE_INTEGER);\n}\n\nfunction idbKeyRange(): {\n bound(lower: unknown, upper: unknown, lowerOpen?: boolean, upperOpen?: boolean): IDBKeyRangeLike;\n} {\n return (globalThis as unknown as { IDBKeyRange: ReturnType<typeof idbKeyRange> }).IDBKeyRange;\n}\n\nexport function epTagPrefixes(filter: Filter): Array<{ name: \"e\" | \"p\"; value: string }> {\n const out: Array<{ name: \"e\" | \"p\"; value: string }> = [];\n for (const name of [\"e\", \"p\"] as const) {\n const values = filter[`#${name}`];\n if (!values) continue;\n for (const value of values) out.push({ name, value: value.toLowerCase() });\n }\n return out;\n}\n\ntype MergeOpener = {\n open(): IDBRequestLike;\n read(\n cursor: IDBCursorLike,\n ok: (event: Event | undefined) => void,\n err: (error: Error) => void,\n ): void;\n};\n\nfunction eventCursor(\n source: {\n openCursor(range?: IDBKeyRangeLike, direction?: IDBCursorDirectionLike): IDBRequestLike;\n },\n range: IDBKeyRangeLike,\n): MergeOpener {\n return {\n open: () => source.openCursor(range, \"prev\"),\n read: (cursor, ok) => {\n ok(cursor.value as Event);\n },\n };\n}\n\nfunction tagCursor(\n index: IDBIndexLike,\n events: IDBObjectStoreLike,\n range: IDBKeyRangeLike,\n): MergeOpener {\n return {\n open: () => index.openCursor(range, \"prev\"),\n read: (cursor, ok, err) => {\n const row = cursor.value as TagRef;\n const req = events.get(row.id);\n req.onerror = () => err(req.error ?? new StorageError(\"IndexedDB get failed\"));\n req.onsuccess = () => ok(req.result as Event | undefined);\n },\n };\n}\n\nexport function scanIds(\n tx: IDBTransactionLike,\n filter: Filter,\n accept: (event: Event) => boolean,\n take: (event: Event) => boolean,\n): Promise<void> {\n const ids = filter.ids ?? [];\n const events = tx.objectStore(EVENTS);\n const reqs = ids.map((id) => events.get(id.toLowerCase()));\n return Promise.all(reqs.map((req) => reqOf<Event | undefined>(req))).then((rows) => {\n const matched: Event[] = [];\n const seen = new Set<string>();\n for (const event of rows) {\n if (!event || seen.has(event.id) || !accept(event)) continue;\n seen.add(event.id);\n matched.push(event);\n }\n sortEvents(matched);\n const out = filter.limit !== undefined ? matched.slice(0, filter.limit) : matched;\n for (const event of out) {\n if (take(event)) break;\n }\n });\n}\n\n/** IDB auto-commits when onsuccess returns with no outstanding requests. */\nexport function kWayMerge(\n openers: readonly MergeOpener[],\n accept: (event: Event) => boolean,\n take: (event: Event) => boolean,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n if (openers.length === 0) {\n resolve();\n return;\n }\n\n type Slot = { cursor: IDBCursorLike | undefined; head: Event | undefined };\n const slots: Slot[] = openers.map(() => ({ cursor: undefined, head: undefined }));\n const seen = new Set<string>();\n let inflight = 0;\n let phase: \"merge\" | \"drain\" | \"done\" = \"merge\";\n let drainT = 0;\n let drainBuf: Event[] = [];\n\n const finish = () => {\n if (phase === \"done\") return;\n phase = \"done\";\n resolve();\n };\n const fail = (error: Error) => {\n if (phase === \"done\") return;\n phase = \"done\";\n reject(error);\n };\n\n const stepCursor = (i: number) => {\n const cursor = slots[i]!.cursor;\n if (!cursor) return;\n inflight++;\n cursor.continue();\n };\n\n const emitDrain = () => {\n sortEvents(drainBuf);\n for (const event of drainBuf) {\n if (seen.has(event.id) || !accept(event)) continue;\n seen.add(event.id);\n if (take(event)) {\n finish();\n return;\n }\n }\n drainBuf = [];\n phase = \"merge\";\n pump();\n };\n\n const pump = () => {\n if (phase === \"done\" || inflight > 0) return;\n if (phase === \"drain\") {\n emitDrain();\n return;\n }\n let best: Event | undefined;\n for (let i = 0; i < slots.length; i++) {\n const event = slots[i]!.head;\n if (!event) continue;\n if (!best || compareEventsDesc(event, best) < 0) best = event;\n }\n if (!best) {\n finish();\n return;\n }\n phase = \"drain\";\n drainT = best.created_at;\n drainBuf = [];\n for (let i = 0; i < slots.length; i++) {\n const event = slots[i]!.head;\n if (!event || event.created_at !== drainT) continue;\n drainBuf.push(event);\n slots[i]!.head = undefined;\n stepCursor(i);\n }\n if (inflight === 0) pump();\n };\n\n const onEvent = (i: number, event: Event | undefined) => {\n if (phase === \"done\") return;\n const slot = slots[i]!;\n const cursor = slot.cursor;\n if (!event) {\n if (cursor) {\n inflight++;\n cursor.continue();\n } else {\n pump();\n }\n return;\n }\n if (phase === \"drain\") {\n if (event.created_at === drainT) {\n drainBuf.push(event);\n if (cursor) {\n inflight++;\n cursor.continue();\n } else {\n pump();\n }\n return;\n }\n slot.head = event;\n pump();\n return;\n }\n slot.head = event;\n pump();\n };\n\n for (let i = 0; i < openers.length; i++) {\n const req = openers[i]!.open();\n req.onerror = () => fail(req.error ?? new StorageError(\"IndexedDB cursor failed\"));\n inflight++;\n req.onsuccess = () => {\n inflight--;\n if (phase === \"done\") return;\n const cursor = req.result as IDBCursorLike | undefined;\n const slot = slots[i]!;\n if (!cursor) {\n slot.cursor = undefined;\n slot.head = undefined;\n pump();\n return;\n }\n slot.cursor = cursor;\n inflight++;\n openers[i]!.read(\n cursor,\n (event) => {\n inflight--;\n onEvent(i, event);\n },\n (error) => {\n inflight--;\n fail(error);\n },\n );\n };\n }\n });\n}\n\nexport function scanFilter(\n tx: IDBTransactionLike,\n filter: Filter,\n accept: (event: Event) => boolean,\n take: (event: Event) => boolean,\n): Promise<void> {\n if (filter.limit === 0) return Promise.resolve();\n if (filter.since !== undefined && filter.until !== undefined && filter.since > filter.until) {\n return Promise.resolve();\n }\n\n if (filter.ids) {\n return scanIds(tx, filter, accept, take);\n }\n\n const events = tx.objectStore(EVENTS);\n const openers: MergeOpener[] = [];\n if (filter.authors && filter.kinds) {\n const index = events.index(\"kind_pubkey_created_at\");\n for (const kind of filter.kinds) {\n for (const pk of filter.authors) {\n openers.push(\n eventCursor(index, prefixRange([kind, pk.toLowerCase()], filter.since, filter.until)),\n );\n }\n }\n } else if (filter.authors) {\n const index = events.index(\"pubkey_created_at\");\n for (const pk of filter.authors) {\n openers.push(eventCursor(index, prefixRange([pk.toLowerCase()], filter.since, filter.until)));\n }\n } else if (filter.kinds) {\n const index = events.index(\"kind_created_at\");\n for (const kind of filter.kinds) {\n openers.push(eventCursor(index, prefixRange([kind], filter.since, filter.until)));\n }\n } else {\n const tags = epTagPrefixes(filter);\n if (tags.length > 0) {\n const index = tx.objectStore(TAG_REFS).index(\"name_value_created\");\n for (const tag of tags) {\n openers.push(\n tagCursor(index, events, prefixRange([tag.name, tag.value], filter.since, filter.until)),\n );\n }\n } else {\n openers.push(\n eventCursor(events.index(\"created_at\"), createdAtRange(filter.since, filter.until)),\n );\n }\n }\n return kWayMerge(openers, accept, take);\n}\n","import type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { eventAddress } from \"../core/tag.ts\";\nimport { DeletionState, planDeletion } from \"./deletion.ts\";\nimport { StorageError } from \"./error.ts\";\nimport { deleteStoredEvent, writeTagRefs } from \"./idb-helpers.ts\";\nimport {\n ADDRESSES,\n EVENTS,\n OUTBOX_BOUNDS,\n TAG_REFS,\n TOMBSTONES,\n type AddressRow,\n type IDBDatabaseLike,\n type IDBFactoryLike,\n type IDBTransactionLike,\n type Tombstone,\n} from \"./idb-types.ts\";\nimport { normalizeEvent } from \"./put.ts\";\n\nexport const IDB_VERSION = 4;\n\nexport function openDb(dbName: string): Promise<IDBDatabaseLike> {\n return new Promise((resolve, reject) => {\n const factory = (globalThis as unknown as { indexedDB: IDBFactoryLike }).indexedDB;\n const req = factory.open(dbName, IDB_VERSION);\n req.onupgradeneeded = (ev) => {\n const db = req.result;\n const oldVersion = ev.oldVersion;\n const tx = ev.target.transaction;\n if (oldVersion < 1) {\n db.createObjectStore(EVENTS, { keyPath: \"id\" });\n }\n if (oldVersion < 2) {\n const events = tx.objectStore(EVENTS);\n events.createIndex(\"created_at\", \"created_at\");\n events.createIndex(\"kind_created_at\", [\"kind\", \"created_at\"]);\n events.createIndex(\"pubkey_created_at\", [\"pubkey\", \"created_at\"]);\n events.createIndex(\"kind_pubkey_created_at\", [\"kind\", \"pubkey\", \"created_at\"]);\n db.createObjectStore(TAG_REFS, { keyPath: \"key\" }).createIndex(\"name_value_created\", [\n \"name\",\n \"value\",\n \"created_at\",\n ]);\n db.createObjectStore(ADDRESSES, { keyPath: \"address\" });\n db.createObjectStore(TOMBSTONES, { keyPath: \"key\" });\n if (oldVersion >= 1) {\n const all = events.getAll();\n all.onsuccess = () => {\n migrateV1Events(tx, (all.result as Event[]) ?? []);\n compactSupersededReplaceables(tx);\n };\n }\n } else if (oldVersion < 3) {\n compactSupersededReplaceables(tx);\n }\n if (oldVersion < 4) {\n db.createObjectStore(OUTBOX_BOUNDS, { keyPath: \"key\" });\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error ?? new StorageError(\"IndexedDB open failed\"));\n });\n}\n\nexport function migrateV1Events(tx: IDBTransactionLike, events: Event[]): void {\n const byId = new Map(events.map((e) => [e.id.toLowerCase(), e]));\n const deletion = new DeletionState();\n const dels = events\n .filter((e) => e.kind === Kind.EventDeletion)\n .sort((a, b) => a.created_at - b.created_at || a.id.localeCompare(b.id));\n for (const del of dels) {\n const plan = planDeletion(del, (id) => byId.get(id));\n deletion.absorb(plan);\n for (const c of plan.coordinates) {\n for (const ev of events) {\n if (ev.kind === Kind.EventDeletion) continue;\n if (eventAddress(ev) === c.key && ev.created_at <= c.until) {\n deletion.ids.add(ev.id.toLowerCase());\n }\n }\n }\n }\n\n const eventsStore = tx.objectStore(EVENTS);\n const tagRefs = tx.objectStore(TAG_REFS);\n const addresses = tx.objectStore(ADDRESSES);\n const tombstones = tx.objectStore(TOMBSTONES);\n\n for (const id of deletion.ids) {\n tombstones.put({ key: `id:${id}`, type: \"id\" } satisfies Tombstone);\n }\n for (const [id, pubkey] of deletion.pending) {\n tombstones.put({\n key: `pending:${id}`,\n type: \"pending\",\n pubkey: pubkey.toLowerCase(),\n } satisfies Tombstone);\n }\n for (const [key, until] of deletion.coordinates) {\n tombstones.put({ key: `coord:${key}`, type: \"coord\", until } satisfies Tombstone);\n }\n\n const winners = new Map<string, Event>();\n for (const event of events) {\n const stored = normalizeEvent(event);\n if (deletion.ids.has(stored.id) || deletion.covers(stored)) {\n eventsStore.delete(event.id);\n continue;\n }\n if (stored.id !== event.id) eventsStore.delete(event.id);\n if (stored !== event) eventsStore.put(stored);\n writeTagRefs(tagRefs, stored);\n const addr = eventAddress(stored);\n if (addr) {\n const prev = winners.get(addr);\n if (!prev || isReplaceableWinner(stored, prev)) winners.set(addr, stored);\n }\n }\n for (const [address, event] of winners) {\n addresses.put({ address, id: event.id, created_at: event.created_at });\n }\n}\n\nexport function compactSupersededReplaceables(tx: IDBTransactionLike): void {\n const eventsStore = tx.objectStore(EVENTS);\n const addressesStore = tx.objectStore(ADDRESSES);\n const evReq = eventsStore.getAll();\n const addrReq = addressesStore.getAll();\n let events: Event[] | undefined;\n let addressRows: AddressRow[] | undefined;\n const run = () => {\n if (events === undefined || addressRows === undefined) return;\n const byAddr = new Map<string, AddressRow>();\n for (const row of addressRows) byAddr.set(row.address, row);\n const kept: Event[] = [];\n for (const event of events) {\n const addr = eventAddress(event);\n if (addr) {\n const row = byAddr.get(addr);\n if (!row || row.id !== event.id) {\n deleteStoredEvent(tx, event, row);\n continue;\n }\n }\n kept.push(event);\n }\n addressesStore.clear();\n for (const event of kept) {\n const addr = eventAddress(event);\n if (!addr) continue;\n addressesStore.put({ address: addr, id: event.id, created_at: event.created_at });\n }\n };\n evReq.onsuccess = () => {\n events = (evReq.result as Event[]) ?? [];\n run();\n };\n addrReq.onsuccess = () => {\n addressRows = (addrReq.result as AddressRow[]) ?? [];\n run();\n };\n}\n","import type { Event } from \"../core/event.ts\";\nimport { itemCompare, sortEvents } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { matchFilter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { eventAddress, parseEventAddress } from \"../core/tag.ts\";\nimport { DeletionState } from \"./deletion.ts\";\nimport { StorageError, toStorageError } from \"./error.ts\";\nimport {\n applyPutIndexedDb,\n deleteStoredEvent,\n reqOf,\n tombstonesToPlan,\n txDone,\n walkCursor,\n} from \"./idb-helpers.ts\";\nimport { prefixRange, scanFilter } from \"./idb-query.ts\";\nimport { openDb } from \"./idb-schema.ts\";\nimport {\n ADDRESSES,\n EVENTS,\n OUTBOX_BOUNDS,\n TAG_REFS,\n TOMBSTONES,\n WRITE_STORES,\n type AddressRow,\n type IDBCursorDirectionLike,\n type IDBDatabaseLike,\n type IDBFactoryLike,\n type IDBTransactionLike,\n type OutboxBoundRow,\n type Tombstone,\n} from \"./idb-types.ts\";\nimport { decidePut, normalizeEvent, outboxBoundKey } from \"./put.ts\";\nimport type { EventStore, NegentropyItem, OutboxBound, PutResult } from \"./types.ts\";\n\nexport type IndexedDbEventStoreOptions = {\n /** IndexedDB database name. */\n dbName?: string;\n};\n\n/**\n * Browser IndexedDB event store with the same replaceable / deletion semantics\n * as {@link MemoryEventStore}. Requires a DOM IndexedDB implementation.\n *\n * `open` loads every tombstone and address row into memory. Fine at 10^4 events;\n * tens of MB at 10^5 addressables.\n */\nexport class IndexedDbEventStore implements EventStore {\n readonly #dbName: string;\n #db: IDBDatabaseLike | undefined;\n #deletion = new DeletionState();\n #replaceable = new Map<string, string>();\n /** Serializes writes so abort restore cannot roll back a committed sibling tx. */\n #writeTail: Promise<void> = Promise.resolve();\n\n constructor(opts: IndexedDbEventStoreOptions = {}) {\n this.#dbName = opts.dbName ?? \"@qntx/nostr\";\n }\n\n static isAvailable(): boolean {\n return typeof (globalThis as { indexedDB?: IDBFactoryLike }).indexedDB !== \"undefined\";\n }\n\n async open(): Promise<void> {\n if (this.#db) return;\n if (!IndexedDbEventStore.isAvailable()) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n this.#db = await openDb(this.#dbName);\n await this.#loadCaches();\n }\n\n async #ensure(): Promise<IDBDatabaseLike> {\n await this.open();\n return this.#db!;\n }\n\n /** Loads every tombstone and address row into RAM. Tens of MB at 10^5 addressables. */\n async #loadCaches(): Promise<void> {\n const db = this.#db!;\n const tx = db.transaction([TOMBSTONES, ADDRESSES], \"readonly\");\n const done = txDone(tx);\n this.#deletion.clear();\n this.#replaceable.clear();\n const tombs = await reqOf<unknown[]>(tx.objectStore(TOMBSTONES).getAll());\n this.#deletion.absorb(tombstonesToPlan(tombs ?? []));\n await walkCursor(tx.objectStore(ADDRESSES), undefined, \"next\", (cursor) => {\n const row = cursor.value as AddressRow;\n this.#replaceable.set(row.address, row.id);\n return false;\n });\n await done;\n }\n\n #enqueueWrite<T>(op: () => Promise<T>): Promise<T> {\n const run = this.#writeTail.then(op, op);\n this.#writeTail = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n async put(event: Event): Promise<PutResult> {\n const [result] = await this.putMany([event]);\n return result!;\n }\n\n /** One readwrite transaction; abort rejects the whole batch with no partial persist. */\n async putMany(events: readonly Event[]): Promise<PutResult[]> {\n if (events.length === 0) return [];\n return this.#enqueueWrite(() => this.#putManyLocked(events));\n }\n\n async #putManyLocked(events: readonly Event[]): Promise<PutResult[]> {\n let db: IDBDatabaseLike;\n try {\n db = await this.#ensure();\n } catch (err) {\n throw toStorageError(err);\n }\n const tx = db.transaction(WRITE_STORES, \"readwrite\");\n const txSettled = new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error ?? new StorageError(\"IndexedDB transaction failed\"));\n tx.onabort = () => reject(tx.error ?? new StorageError(\"IndexedDB transaction aborted\"));\n });\n const txOutcome = txSettled.then(\n () => undefined,\n (err: unknown) => err,\n );\n const cache = this.#snapshotCaches();\n try {\n const results = await this.#putAllInTx(tx, events);\n const txErr = await txOutcome;\n if (txErr !== undefined) throw txErr;\n return results;\n } catch (err) {\n this.#restoreCaches(cache);\n try {\n tx.abort();\n } catch {\n // already aborted or complete\n }\n await txOutcome;\n throw toStorageError(err);\n }\n }\n\n /** Sequential awaits so the tx stays alive between events. */\n async #putAllInTx(tx: IDBTransactionLike, batch: readonly Event[]): Promise<PutResult[]> {\n const eventsStore = tx.objectStore(EVENTS);\n const addressesStore = tx.objectStore(ADDRESSES);\n const results: PutResult[] = [];\n for (const raw of batch) {\n const event = normalizeEvent(raw);\n const byId = new Map<string, Pick<Event, \"id\" | \"pubkey\" | \"kind\" | \"created_at\" | \"tags\">>();\n const existing = await reqOf<Event | undefined>(eventsStore.get(event.id));\n if (existing) byId.set(existing.id, existing);\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"e\" || tag[1] === undefined) continue;\n const got = await reqOf<Event | undefined>(eventsStore.get(tag[1].toLowerCase()));\n if (got) byId.set(got.id, got);\n }\n }\n const addrRows = new Map<string, { id: string; created_at: number }>();\n const ownAddr = eventAddress(event);\n if (ownAddr) {\n const row = await reqOf<AddressRow | undefined>(addressesStore.get(ownAddr));\n if (row) addrRows.set(ownAddr, { id: row.id, created_at: row.created_at });\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"a\" || !tag[1]) continue;\n const coord = parseEventAddress(tag[1]);\n if (!coord) continue;\n const key = `${coord.kind}:${coord.pubkey}:${coord.identifier}`;\n if (addrRows.has(key)) continue;\n const row = await reqOf<AddressRow | undefined>(addressesStore.get(key));\n if (row) addrRows.set(key, { id: row.id, created_at: row.created_at });\n }\n }\n const d = decidePut(event, {\n deletion: this.#deletion,\n getById: (id) => byId.get(id),\n getReplaceable: (address) => addrRows.get(address),\n });\n // Await row deletes in this loop so the next events.get runs in the IDB\n // request continuation. `await` of a no-request promise auto-commits the tx.\n if (d.action === \"delete\") {\n const remove = new Set([...d.plan.removeIds, ...d.coordIds]);\n for (const id of remove) await this.#deleteEventRows(tx, id);\n } else if (d.action === \"insert\" && d.replaceId) {\n await this.#deleteEventRows(tx, d.replaceId);\n }\n results.push(\n applyPutIndexedDb(\n tx,\n {\n deletion: this.#deletion,\n replaceable: this.#replaceable,\n },\n d,\n ),\n );\n }\n return results;\n }\n\n #snapshotCaches(): {\n replaceable: Map<string, string>;\n ids: Set<string>;\n pending: Map<string, string>;\n coordinates: Map<string, number>;\n } {\n return {\n replaceable: new Map(this.#replaceable),\n ids: new Set(this.#deletion.ids),\n pending: new Map(this.#deletion.pending),\n coordinates: new Map(this.#deletion.coordinates),\n };\n }\n\n #restoreCaches(snap: {\n replaceable: Map<string, string>;\n ids: Set<string>;\n pending: Map<string, string>;\n coordinates: Map<string, number>;\n }): void {\n this.#replaceable = snap.replaceable;\n this.#deletion.ids.clear();\n for (const id of snap.ids) this.#deletion.ids.add(id);\n this.#deletion.pending.clear();\n for (const [k, v] of snap.pending) this.#deletion.pending.set(k, v);\n this.#deletion.coordinates.clear();\n for (const [k, v] of snap.coordinates) this.#deletion.coordinates.set(k, v);\n }\n\n async get(id: string): Promise<Event | undefined> {\n const key = id.toLowerCase();\n if (this.#deletion.ids.has(key)) return undefined;\n const db = await this.#ensure();\n const tx = db.transaction(EVENTS, \"readonly\");\n const done = txDone(tx);\n const event = await reqOf<Event | undefined>(tx.objectStore(EVENTS).get(key));\n await done;\n return event;\n }\n\n async query(filters: Filter[]): Promise<Event[]> {\n const db = await this.#ensure();\n const tx = db.transaction([EVENTS, TAG_REFS], \"readonly\");\n const done = txDone(tx);\n const seen = new Set<string>();\n const events: Event[] = [];\n for (const filter of filters) {\n const matched = await this.#queryOne(tx, filter);\n for (const event of matched) {\n if (seen.has(event.id)) continue;\n seen.add(event.id);\n events.push(event);\n }\n }\n await done;\n sortEvents(events);\n return events;\n }\n\n async count(filters: Filter[]): Promise<number> {\n const db = await this.#ensure();\n const tx = db.transaction([EVENTS, TAG_REFS], \"readonly\");\n const done = txDone(tx);\n const seen = new Set<string>();\n for (const filter of filters) {\n const local = new Set<string>();\n await this.#scan(tx, filter, (event) => {\n local.add(event.id);\n return filter.limit !== undefined && local.size >= filter.limit;\n });\n for (const id of local) seen.add(id);\n }\n await done;\n return seen.size;\n }\n\n async negentropyItems(filter: Filter): Promise<NegentropyItem[]> {\n const db = await this.#ensure();\n const tx = db.transaction([EVENTS, TAG_REFS], \"readonly\");\n const done = txDone(tx);\n const items: NegentropyItem[] = [];\n await this.#scan(tx, filter, (event) => {\n items.push({ id: event.id, created_at: event.created_at });\n return filter.limit !== undefined && items.length >= filter.limit;\n });\n await done;\n items.sort(itemCompare);\n return items;\n }\n\n #acceptHit(filter: Filter, event: Event): boolean {\n if (this.#deletion.ids.has(event.id)) return false;\n if (this.#deletion.covers(event)) return false;\n return matchFilter(filter, event);\n }\n\n async #queryOne(tx: IDBTransactionLike, filter: Filter): Promise<Event[]> {\n const matched: Event[] = [];\n await this.#scan(tx, filter, (event) => {\n matched.push(event);\n return filter.limit !== undefined && matched.length >= filter.limit;\n });\n sortEvents(matched);\n return matched;\n }\n\n #scan(tx: IDBTransactionLike, filter: Filter, take: (event: Event) => boolean): Promise<void> {\n return scanFilter(tx, filter, (event) => this.#acceptHit(filter, event), take);\n }\n\n async getOutboxBound(pubkey: string, kind: number): Promise<OutboxBound | undefined> {\n try {\n const db = await this.#ensure();\n const tx = db.transaction(OUTBOX_BOUNDS, \"readonly\");\n const done = txDone(tx);\n const row = await reqOf<OutboxBoundRow | undefined>(\n tx.objectStore(OUTBOX_BOUNDS).get(outboxBoundKey(pubkey, kind)),\n );\n await done;\n if (row && typeof row.oldest === \"number\" && typeof row.newest === \"number\") {\n return { oldest: row.oldest, newest: row.newest };\n }\n return await this.#deriveOutboxBound(pubkey, kind);\n } catch (err) {\n throw toStorageError(err);\n }\n }\n\n async setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n return this.#enqueueWrite(() => this.#setOutboxBoundLocked(pubkey, kind, bound));\n }\n\n async #setOutboxBoundLocked(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n try {\n const db = await this.#ensure();\n const tx = db.transaction(OUTBOX_BOUNDS, \"readwrite\");\n const done = txDone(tx);\n tx.objectStore(OUTBOX_BOUNDS).put({\n key: outboxBoundKey(pubkey, kind),\n oldest: bound.oldest,\n newest: bound.newest,\n } satisfies OutboxBoundRow);\n await done;\n } catch (err) {\n throw toStorageError(err);\n }\n }\n\n async remove(ids: string[]): Promise<number> {\n return this.#enqueueWrite(() => this.#removeLocked(ids));\n }\n\n async #removeLocked(ids: string[]): Promise<number> {\n const db = await this.#ensure();\n const tx = db.transaction(WRITE_STORES, \"readwrite\");\n const tombstones = tx.objectStore(TOMBSTONES);\n const done = txDone(tx);\n let n = 0;\n for (const raw of ids) {\n const id = raw.toLowerCase();\n if (await this.#deleteEventRows(tx, id)) n += 1;\n tombstones.put({ key: `id:${id}`, type: \"id\" } satisfies Tombstone);\n tombstones.delete(`pending:${id}`);\n this.#deletion.ids.add(id);\n this.#deletion.pending.delete(id);\n }\n await done;\n return n;\n }\n\n async clear(): Promise<void> {\n return this.#enqueueWrite(() => this.#clearLocked());\n }\n\n async #clearLocked(): Promise<void> {\n const db = await this.#ensure();\n const stores = [...WRITE_STORES, OUTBOX_BOUNDS];\n const tx = db.transaction(stores, \"readwrite\");\n const done = txDone(tx);\n for (const name of stores) tx.objectStore(name).clear();\n this.#deletion.clear();\n this.#replaceable.clear();\n await done;\n }\n\n close(): void {\n this.#db?.close();\n this.#db = undefined;\n }\n\n async #deleteEventRows(tx: IDBTransactionLike, id: string): Promise<boolean> {\n const events = tx.objectStore(EVENTS);\n const event = await reqOf<Event | undefined>(events.get(id.toLowerCase()));\n if (!event) return false;\n const addr = eventAddress(event);\n let row: AddressRow | undefined;\n if (addr) {\n row = await reqOf<AddressRow | undefined>(tx.objectStore(ADDRESSES).get(addr));\n if (this.#replaceable.get(addr) === event.id) this.#replaceable.delete(addr);\n }\n deleteStoredEvent(tx, event, row);\n return true;\n }\n\n async #deriveOutboxBound(pubkey: string, kind: number): Promise<OutboxBound | undefined> {\n const db = await this.#ensure();\n const pk = pubkey.toLowerCase();\n const tx = db.transaction(EVENTS, \"readonly\");\n const done = txDone(tx);\n const index = tx.objectStore(EVENTS).index(\"kind_pubkey_created_at\");\n const range = prefixRange([kind, pk]);\n const filter: Filter = { authors: [pk], kinds: [kind] };\n let oldest: number | undefined;\n let newest: number | undefined;\n const firstLive = (direction: IDBCursorDirectionLike, assign: (createdAt: number) => void) =>\n walkCursor(index, range, direction, (cursor) => {\n const event = cursor.value as Event;\n if (!this.#acceptHit(filter, event)) return false;\n assign(event.created_at);\n return true;\n });\n await Promise.all([\n firstLive(\"next\", (createdAt) => {\n oldest = createdAt;\n }),\n firstLive(\"prev\", (createdAt) => {\n newest = createdAt;\n }),\n ]);\n await done;\n if (oldest === undefined || newest === undefined) return undefined;\n return { oldest, newest };\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { i as PutResult, n as NegentropyItem, r as OutboxBound, t as EventStore } from "./types-Dn24TPFs.mjs";
|
|
2
|
+
import { t as StorageError } from "./error-B49rbDzT.mjs";
|
|
3
|
+
import { n as IndexedDbEventStoreOptions, r as MemoryEventStore, t as IndexedDbEventStore } from "./index-k2YhCgsh.mjs";
|
|
4
|
+
export { type EventStore, IndexedDbEventStore, type IndexedDbEventStoreOptions, MemoryEventStore, type NegentropyItem, type OutboxBound, type PutResult, StorageError };
|
package/dist/storage.mjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { r as UnsignedEvent, t as Event } from "./event-B5D2jxt_.mjs";
|
|
2
|
+
//#region src/signer/types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Universal signing interface (aligned with nula's NostrSigner).
|
|
5
|
+
* Implementations: KeysSigner, Nip07Signer, Nip46Signer, …
|
|
6
|
+
*/
|
|
7
|
+
interface NostrSigner {
|
|
8
|
+
getPublicKey(): Promise<string>;
|
|
9
|
+
signEvent(unsigned: UnsignedEvent): Promise<Event>;
|
|
10
|
+
/** Optional NIP-04 (legacy). Unsupported signers reject. */
|
|
11
|
+
nip04Encrypt?(peer: string, plaintext: string): Promise<string>;
|
|
12
|
+
nip04Decrypt?(peer: string, ciphertext: string): Promise<string>;
|
|
13
|
+
/** Optional NIP-44 v2. Unsupported signers reject. */
|
|
14
|
+
nip44Encrypt?(peer: string, plaintext: string): Promise<string>;
|
|
15
|
+
nip44Decrypt?(peer: string, payload: string): Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { NostrSigner as t };
|
|
19
|
+
//# sourceMappingURL=types-BzyADqnw.d.mts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { t as Event } from "./event-B5D2jxt_.mjs";
|
|
2
|
+
import { t as Filter } from "./filter-DUEKP3q1.mjs";
|
|
3
|
+
//#region src/storage/types.d.ts
|
|
4
|
+
type PutResult = "accepted" | "duplicate" | "replaced" | "rejected" | "ephemeral" | "deleted";
|
|
5
|
+
/** NIP-77 item: event id + created_at. Sorted created_at asc, then id. */
|
|
6
|
+
type NegentropyItem = {
|
|
7
|
+
id: string;
|
|
8
|
+
created_at: number;
|
|
9
|
+
};
|
|
10
|
+
/** Inclusive created_at window of stored live events for one author+kind. */
|
|
11
|
+
type OutboxBound = {
|
|
12
|
+
oldest: number;
|
|
13
|
+
newest: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Event store contract (aligned with nula-storage NostrDatabase, narrowed for v0).
|
|
17
|
+
* Implementations apply replaceable / addressable / deletion semantics on put.
|
|
18
|
+
*/
|
|
19
|
+
interface EventStore {
|
|
20
|
+
put(event: Event): Promise<PutResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Persist in input order. IndexedDB: one transaction, abort rolls the batch back.
|
|
23
|
+
* Memory: sequential; put does not throw, so a rejected item does not undo earlier accepts.
|
|
24
|
+
*/
|
|
25
|
+
putMany(events: readonly Event[]): Promise<PutResult[]>;
|
|
26
|
+
get(id: string): Promise<Event | undefined>;
|
|
27
|
+
query(filters: Filter[]): Promise<Event[]>;
|
|
28
|
+
/** Unique events matching `filters` (same cardinality as {@link query}). */
|
|
29
|
+
count(filters: Filter[]): Promise<number>;
|
|
30
|
+
/**
|
|
31
|
+
* Matching `{ id, created_at }` for one filter, sorted created_at asc then id.
|
|
32
|
+
* Does not allocate an `Event[]`.
|
|
33
|
+
*/
|
|
34
|
+
negentropyItems(filter: Filter): Promise<NegentropyItem[]>;
|
|
35
|
+
getOutboxBound(pubkey: string, kind: number): Promise<OutboxBound | undefined>;
|
|
36
|
+
setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void>;
|
|
37
|
+
/** Remove by id (does not publish NIP-09). */
|
|
38
|
+
remove(ids: string[]): Promise<number>;
|
|
39
|
+
clear(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { PutResult as i, NegentropyItem as n, OutboxBound as r, EventStore as t };
|
|
43
|
+
//# sourceMappingURL=types-Dn24TPFs.d.mts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { o as UrlError, r as HexError } from "./error-DZEs5OuZ.mjs";
|
|
2
|
+
//#region src/core/limits.ts
|
|
3
|
+
/** NIP-01 event id length in bytes. */
|
|
4
|
+
const EVENT_ID_BYTES = 32;
|
|
5
|
+
/** BIP-340 signature length in bytes. */
|
|
6
|
+
const SIGNATURE_BYTES = 64;
|
|
7
|
+
/** BIP-340 public key length in bytes (x-only). */
|
|
8
|
+
const PUBLIC_KEY_BYTES = 32;
|
|
9
|
+
/** BIP-340 secret key length in bytes. */
|
|
10
|
+
const SECRET_KEY_BYTES = 32;
|
|
11
|
+
/** NIP-01 subscription id max character length. */
|
|
12
|
+
const SUBSCRIPTION_ID_MAX_CHARS = 64;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/core/util.ts
|
|
15
|
+
const utf8Encoder = new TextEncoder();
|
|
16
|
+
const utf8Decoder = new TextDecoder();
|
|
17
|
+
const HEX_RE = /^[0-9a-f]+$/;
|
|
18
|
+
/** Lowercase hex encode. */
|
|
19
|
+
function bytesToHex(bytes) {
|
|
20
|
+
let out = "";
|
|
21
|
+
for (let i = 0; i < bytes.length; i++) out += bytes[i].toString(16).padStart(2, "0");
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/** Decode lowercase or mixed-case hex to bytes. */
|
|
25
|
+
function hexToBytes(hex) {
|
|
26
|
+
const normalized = hex.toLowerCase();
|
|
27
|
+
if (normalized.length % 2 !== 0 || !HEX_RE.test(normalized)) throw new HexError(`invalid hex string of length ${hex.length}`);
|
|
28
|
+
const out = new Uint8Array(normalized.length / 2);
|
|
29
|
+
for (let i = 0; i < out.length; i++) out[i] = Number.parseInt(normalized.slice(i * 2, i * 2 + 2), 16);
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
/** True when value is a 64-char hex string (any case) — 32 bytes. */
|
|
33
|
+
function isHex32(value) {
|
|
34
|
+
return value.length === 64 && HEX_RE.test(value.toLowerCase());
|
|
35
|
+
}
|
|
36
|
+
/** True when value is a 128-char hex string (any case) — 64 bytes. */
|
|
37
|
+
function isHex64(value) {
|
|
38
|
+
return value.length === 128 && HEX_RE.test(value.toLowerCase());
|
|
39
|
+
}
|
|
40
|
+
function assertHex32(value, label) {
|
|
41
|
+
if (!isHex32(value)) throw new HexError(`invalid ${label}: expected 64-char hex`);
|
|
42
|
+
return value.toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
function assertByteLength(bytes, expected, label) {
|
|
45
|
+
if (bytes.length !== expected) throw new HexError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);
|
|
46
|
+
}
|
|
47
|
+
function assertSecretKeyBytes(bytes) {
|
|
48
|
+
assertByteLength(bytes, 32, "secret key");
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Normalize a relay URL to a stable form (wss preferred, no trailing slash, sorted query).
|
|
52
|
+
*/
|
|
53
|
+
function normalizeURL(url) {
|
|
54
|
+
try {
|
|
55
|
+
let input = url;
|
|
56
|
+
if (!input.includes("://")) input = `wss://${input}`;
|
|
57
|
+
const p = new URL(input);
|
|
58
|
+
if (p.protocol === "http:") p.protocol = "ws:";
|
|
59
|
+
else if (p.protocol === "https:") p.protocol = "wss:";
|
|
60
|
+
p.pathname = p.pathname.replace(/\/+/g, "/");
|
|
61
|
+
if (p.pathname.endsWith("/") && p.pathname.length > 1) p.pathname = p.pathname.slice(0, -1);
|
|
62
|
+
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:") p.port = "";
|
|
63
|
+
p.searchParams.sort();
|
|
64
|
+
p.hash = "";
|
|
65
|
+
return p.toString();
|
|
66
|
+
} catch (cause) {
|
|
67
|
+
throw new UrlError(`invalid URL: ${url}`, { cause: cause instanceof Error ? cause : void 0 });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { isHex32 as a, utf8Decoder as c, PUBLIC_KEY_BYTES as d, SECRET_KEY_BYTES as f, hexToBytes as i, utf8Encoder as l, SUBSCRIPTION_ID_MAX_CHARS as m, assertSecretKeyBytes as n, isHex64 as o, SIGNATURE_BYTES as p, bytesToHex as r, normalizeURL as s, assertHex32 as t, EVENT_ID_BYTES as u };
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=util-6tfLQ9JF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util-6tfLQ9JF.mjs","names":[],"sources":["../src/core/limits.ts","../src/core/util.ts"],"sourcesContent":["/** NIP-01 event id length in bytes. */\nexport const EVENT_ID_BYTES = 32;\n\n/** BIP-340 signature length in bytes. */\nexport const SIGNATURE_BYTES = 64;\n\n/** BIP-340 public key length in bytes (x-only). */\nexport const PUBLIC_KEY_BYTES = 32;\n\n/** BIP-340 secret key length in bytes. */\nexport const SECRET_KEY_BYTES = 32;\n\n/** NIP-01 subscription id max character length. */\nexport const SUBSCRIPTION_ID_MAX_CHARS = 64;\n","import { HexError, UrlError } from \"./error.ts\";\nimport { SECRET_KEY_BYTES } from \"./limits.ts\";\n\nexport const utf8Encoder = new TextEncoder();\nexport const utf8Decoder = new TextDecoder();\n\nconst HEX_RE = /^[0-9a-f]+$/;\n\n/** Lowercase hex encode. */\nexport function bytesToHex(bytes: Uint8Array): string {\n let out = \"\";\n for (let i = 0; i < bytes.length; i++) {\n out += bytes[i]!.toString(16).padStart(2, \"0\");\n }\n return out;\n}\n\n/** Decode lowercase or mixed-case hex to bytes. */\nexport function hexToBytes(hex: string): Uint8Array {\n const normalized = hex.toLowerCase();\n if (normalized.length % 2 !== 0 || !HEX_RE.test(normalized)) {\n throw new HexError(`invalid hex string of length ${hex.length}`);\n }\n const out = new Uint8Array(normalized.length / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = Number.parseInt(normalized.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/** True when value is a 64-char hex string (any case) — 32 bytes. */\nexport function isHex32(value: string): boolean {\n return value.length === 64 && HEX_RE.test(value.toLowerCase());\n}\n\n/** True when value is a 128-char hex string (any case) — 64 bytes. */\nexport function isHex64(value: string): boolean {\n return value.length === 128 && HEX_RE.test(value.toLowerCase());\n}\n\nexport function assertHex32(value: string, label: string): string {\n if (!isHex32(value)) {\n throw new HexError(`invalid ${label}: expected 64-char hex`);\n }\n return value.toLowerCase();\n}\n\nexport function assertByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new HexError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nexport function assertSecretKeyBytes(bytes: Uint8Array): void {\n assertByteLength(bytes, SECRET_KEY_BYTES, \"secret key\");\n}\n\n/**\n * Normalize a relay URL to a stable form (wss preferred, no trailing slash, sorted query).\n */\nexport function normalizeURL(url: string): string {\n try {\n let input = url;\n if (!input.includes(\"://\")) input = `wss://${input}`;\n const p = new URL(input);\n if (p.protocol === \"http:\") p.protocol = \"ws:\";\n else if (p.protocol === \"https:\") p.protocol = \"wss:\";\n p.pathname = p.pathname.replace(/\\/+/g, \"/\");\n if (p.pathname.endsWith(\"/\") && p.pathname.length > 1) {\n p.pathname = p.pathname.slice(0, -1);\n }\n if ((p.port === \"80\" && p.protocol === \"ws:\") || (p.port === \"443\" && p.protocol === \"wss:\")) {\n p.port = \"\";\n }\n p.searchParams.sort();\n p.hash = \"\";\n return p.toString();\n } catch (cause) {\n throw new UrlError(`invalid URL: ${url}`, {\n cause: cause instanceof Error ? cause : undefined,\n });\n }\n}\n"],"mappings":";;;AACA,MAAa,iBAAiB;;AAG9B,MAAa,kBAAkB;;AAG/B,MAAa,mBAAmB;;AAGhC,MAAa,mBAAmB;;AAGhC,MAAa,4BAA4B;;;ACVzC,MAAa,cAAc,IAAI,YAAY;AAC3C,MAAa,cAAc,IAAI,YAAY;AAE3C,MAAM,SAAS;;AAGf,SAAgB,WAAW,OAA2B;CACpD,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,OAAO,MAAM,EAAE,CAAE,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG;CAE/C,OAAO;AACT;;AAGA,SAAgB,WAAW,KAAyB;CAClD,MAAM,aAAa,IAAI,YAAY;CACnC,IAAI,WAAW,SAAS,MAAM,KAAK,CAAC,OAAO,KAAK,UAAU,GACxD,MAAM,IAAI,SAAS,gCAAgC,IAAI,QAAQ;CAEjE,MAAM,MAAM,IAAI,WAAW,WAAW,SAAS,CAAC;CAChD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,IAAI,KAAK,OAAO,SAAS,WAAW,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;CAEjE,OAAO;AACT;;AAGA,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,MAAM,WAAW,MAAM,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/D;;AAGA,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,MAAM,WAAW,OAAO,OAAO,KAAK,MAAM,YAAY,CAAC;AAChE;AAEA,SAAgB,YAAY,OAAe,OAAuB;CAChE,IAAI,CAAC,QAAQ,KAAK,GAChB,MAAM,IAAI,SAAS,WAAW,MAAM,uBAAuB;CAE7D,OAAO,MAAM,YAAY;AAC3B;AAEA,SAAgB,iBAAiB,OAAmB,UAAkB,OAAqB;CACzF,IAAI,MAAM,WAAW,UACnB,MAAM,IAAI,SAAS,WAAW,MAAM,oBAAoB,SAAS,QAAQ,MAAM,QAAQ;AAE3F;AAEA,SAAgB,qBAAqB,OAAyB;CAC5D,iBAAiB,OAAA,IAAyB,YAAY;AACxD;;;;AAKA,SAAgB,aAAa,KAAqB;CAChD,IAAI;EACF,IAAI,QAAQ;EACZ,IAAI,CAAC,MAAM,SAAS,KAAK,GAAG,QAAQ,SAAS;EAC7C,MAAM,IAAI,IAAI,IAAI,KAAK;EACvB,IAAI,EAAE,aAAa,SAAS,EAAE,WAAW;OACpC,IAAI,EAAE,aAAa,UAAU,EAAE,WAAW;EAC/C,EAAE,WAAW,EAAE,SAAS,QAAQ,QAAQ,GAAG;EAC3C,IAAI,EAAE,SAAS,SAAS,GAAG,KAAK,EAAE,SAAS,SAAS,GAClD,EAAE,WAAW,EAAE,SAAS,MAAM,GAAG,EAAE;EAErC,IAAK,EAAE,SAAS,QAAQ,EAAE,aAAa,SAAW,EAAE,SAAS,SAAS,EAAE,aAAa,QACnF,EAAE,OAAO;EAEX,EAAE,aAAa,KAAK;EACpB,EAAE,OAAO;EACT,OAAO,EAAE,SAAS;CACpB,SAAS,OAAO;EACd,MAAM,IAAI,SAAS,gBAAgB,OAAO,EACxC,OAAO,iBAAiB,QAAQ,QAAQ,KAAA,EAC1C,CAAC;CACH;AACF"}
|
package/dist/wasm.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { t as Event } from "./event-B5D2jxt_.mjs";
|
|
2
|
+
import { s as WasmVerifyPoisonedError } from "./error-WEFS-R-4.mjs";
|
|
3
|
+
//#region src/wasm/load.d.ts
|
|
4
|
+
type LoadNostrWasmOptions = {
|
|
5
|
+
/** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */
|
|
6
|
+
module?: ArrayBuffer | ArrayBufferView | URL;
|
|
7
|
+
};
|
|
8
|
+
type NostrWasm = {
|
|
9
|
+
verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
10
|
+
verifySerialized: (serializedUtf8: Uint8Array, id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
11
|
+
verifyEvent: (event: Event) => boolean;
|
|
12
|
+
sign: (id: Uint8Array, seckey: Uint8Array, aux: Uint8Array) => Uint8Array;
|
|
13
|
+
publicKey: (seckey: Uint8Array) => Uint8Array;
|
|
14
|
+
};
|
|
15
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
16
|
+
declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { type LoadNostrWasmOptions, type NostrWasm, WasmVerifyPoisonedError, loadNostrWasm };
|
|
19
|
+
//# sourceMappingURL=wasm.d.mts.map
|
package/dist/wasm.mjs
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { i as hexToBytes, l as utf8Encoder } from "./util-6tfLQ9JF.mjs";
|
|
2
|
+
import { s as WasmVerifyPoisonedError, t as CryptoError } from "./error-DZEs5OuZ.mjs";
|
|
3
|
+
import { c as serializeEvent, n as isMarkedFailed, o as markUnverified, p as validateSignedEvent, r as isMarkedVerified, s as markVerified } from "./event-CzoQEFMF.mjs";
|
|
4
|
+
//#region src/wasm/abi.ts
|
|
5
|
+
/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */
|
|
6
|
+
const ALLOWED_WASM_IMPORTS = [{
|
|
7
|
+
module: "wbg",
|
|
8
|
+
name: "__wbindgen_throw"
|
|
9
|
+
}, {
|
|
10
|
+
module: "./nostr_crypto_wasm_bg.js",
|
|
11
|
+
name: "__wbindgen_throw"
|
|
12
|
+
}];
|
|
13
|
+
const utf8 = new TextDecoder();
|
|
14
|
+
function decodeUtf8(memory, ptr, len) {
|
|
15
|
+
return utf8.decode(new Uint8Array(memory.buffer, ptr, len));
|
|
16
|
+
}
|
|
17
|
+
function makeWbgImports(holder) {
|
|
18
|
+
const throwRuntime = (ptr, len) => {
|
|
19
|
+
const mem = holder.exports?.memory;
|
|
20
|
+
const msg = mem ? decodeUtf8(mem, ptr, len) : "wasm panic";
|
|
21
|
+
throw new WebAssembly.RuntimeError(msg);
|
|
22
|
+
};
|
|
23
|
+
const wbg = { __wbindgen_throw: throwRuntime };
|
|
24
|
+
return {
|
|
25
|
+
wbg,
|
|
26
|
+
"./nostr_crypto_wasm_bg.js": wbg
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */
|
|
30
|
+
function assertAllowedWasmImports(mod) {
|
|
31
|
+
const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\0${item.name}`));
|
|
32
|
+
for (const imp of WebAssembly.Module.imports(mod)) {
|
|
33
|
+
if (imp.kind !== "function") throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);
|
|
34
|
+
if (!allowed.has(`${imp.module}\0${imp.name}`)) throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function requireMemory(value) {
|
|
38
|
+
if (!(value instanceof WebAssembly.Memory)) throw new TypeError("wasm missing memory export");
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function requireFn(value, name) {
|
|
42
|
+
if (typeof value !== "function") throw new TypeError(`wasm missing ${name} export`);
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
function asExports(raw) {
|
|
46
|
+
return {
|
|
47
|
+
memory: requireMemory(raw.memory),
|
|
48
|
+
verify: requireFn(raw.verify, "verify"),
|
|
49
|
+
verify_serialized: requireFn(raw.verify_serialized, "verify_serialized"),
|
|
50
|
+
sign: requireFn(raw.sign, "sign"),
|
|
51
|
+
public_key: requireFn(raw.public_key, "public_key"),
|
|
52
|
+
__wbindgen_export: requireFn(raw.__wbindgen_export, "__wbindgen_export"),
|
|
53
|
+
__wbindgen_export2: requireFn(raw.__wbindgen_export2, "__wbindgen_export2"),
|
|
54
|
+
__wbindgen_add_to_stack_pointer: requireFn(raw.__wbindgen_add_to_stack_pointer, "__wbindgen_add_to_stack_pointer"),
|
|
55
|
+
__wbindgen_start: typeof raw.__wbindgen_start === "function" ? raw.__wbindgen_start : void 0
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function passBytes(exports, bytes) {
|
|
59
|
+
const len = bytes.length;
|
|
60
|
+
const ptr = exports.__wbindgen_export(len, 1) >>> 0;
|
|
61
|
+
new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);
|
|
62
|
+
return {
|
|
63
|
+
ptr,
|
|
64
|
+
len
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function callWithBytes(exports, arrays, invoke) {
|
|
68
|
+
return invoke(arrays.map((bytes) => passBytes(exports, bytes)).flatMap(({ ptr, len }) => [ptr, len])) !== 0;
|
|
69
|
+
}
|
|
70
|
+
function wasmVerify(exports, id, pubkey, sig) {
|
|
71
|
+
return callWithBytes(exports, [
|
|
72
|
+
id,
|
|
73
|
+
pubkey,
|
|
74
|
+
sig
|
|
75
|
+
], (args) => exports.verify(args[0], args[1], args[2], args[3], args[4], args[5]));
|
|
76
|
+
}
|
|
77
|
+
function wasmVerifySerialized(exports, serialized, id, pubkey, sig) {
|
|
78
|
+
return callWithBytes(exports, [
|
|
79
|
+
serialized,
|
|
80
|
+
id,
|
|
81
|
+
pubkey,
|
|
82
|
+
sig
|
|
83
|
+
], (args) => exports.verify_serialized(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]));
|
|
84
|
+
}
|
|
85
|
+
function takeBytes(exports, ptr, len) {
|
|
86
|
+
const out = new Uint8Array(len);
|
|
87
|
+
if (len > 0) {
|
|
88
|
+
out.set(new Uint8Array(exports.memory.buffer, ptr, len));
|
|
89
|
+
exports.__wbindgen_export2(ptr, len, 1);
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
function callReturningBytes(exports, arrays, invoke) {
|
|
94
|
+
const args = arrays.map((bytes) => passBytes(exports, bytes)).flatMap(({ ptr, len }) => [ptr, len]);
|
|
95
|
+
const retptr = exports.__wbindgen_add_to_stack_pointer(-16);
|
|
96
|
+
try {
|
|
97
|
+
invoke(retptr, args);
|
|
98
|
+
const view = new DataView(exports.memory.buffer);
|
|
99
|
+
return takeBytes(exports, view.getInt32(retptr, true) >>> 0, view.getInt32(retptr + 4, true) >>> 0);
|
|
100
|
+
} finally {
|
|
101
|
+
exports.__wbindgen_add_to_stack_pointer(16);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function wasmSign(exports, id, seckey, aux) {
|
|
105
|
+
return callReturningBytes(exports, [
|
|
106
|
+
id,
|
|
107
|
+
seckey,
|
|
108
|
+
aux
|
|
109
|
+
], (retptr, args) => {
|
|
110
|
+
exports.sign(retptr, args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function wasmPublicKey(exports, seckey) {
|
|
114
|
+
return callReturningBytes(exports, [seckey], (retptr, args) => {
|
|
115
|
+
exports.public_key(retptr, args[0], args[1]);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function instantiateCryptoWasm(bytes) {
|
|
119
|
+
const holder = {};
|
|
120
|
+
const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));
|
|
121
|
+
assertAllowedWasmImports(module);
|
|
122
|
+
holder.exports = asExports(instance.exports);
|
|
123
|
+
holder.exports.__wbindgen_start?.();
|
|
124
|
+
return holder.exports;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/wasm/adapter.ts
|
|
128
|
+
function makeVerifyEvent(wasm, poison) {
|
|
129
|
+
return (event) => {
|
|
130
|
+
if (poison.error) throw poison.error;
|
|
131
|
+
if (isMarkedVerified(event)) return true;
|
|
132
|
+
if (isMarkedFailed(event)) return false;
|
|
133
|
+
if (!validateSignedEvent(event)) {
|
|
134
|
+
markUnverified(event);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const serialized = utf8Encoder.encode(serializeEvent(event));
|
|
139
|
+
const id = hexToBytes(event.id.toLowerCase());
|
|
140
|
+
const pubkey = hexToBytes(event.pubkey.toLowerCase());
|
|
141
|
+
const sig = hexToBytes(event.sig.toLowerCase());
|
|
142
|
+
const ok = wasm.verifySerialized(serialized, id, pubkey, sig);
|
|
143
|
+
if (ok) markVerified(event);
|
|
144
|
+
else markUnverified(event);
|
|
145
|
+
return ok;
|
|
146
|
+
} catch (e) {
|
|
147
|
+
if (e instanceof WebAssembly.RuntimeError) {
|
|
148
|
+
poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: e });
|
|
149
|
+
throw poison.error;
|
|
150
|
+
}
|
|
151
|
+
markUnverified(event);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/wasm/load.ts
|
|
158
|
+
let interned;
|
|
159
|
+
function isNode() {
|
|
160
|
+
return typeof process !== "undefined" && typeof process.versions === "object" && process.versions !== null && typeof process.versions.node === "string";
|
|
161
|
+
}
|
|
162
|
+
function isWasmBytes(value) {
|
|
163
|
+
return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
164
|
+
}
|
|
165
|
+
async function defaultWasmHref() {
|
|
166
|
+
return (await import("./nostr_crypto_wasm_bg-hi5aXi5P.mjs")).default;
|
|
167
|
+
}
|
|
168
|
+
async function readWasmUrl(url) {
|
|
169
|
+
if (isNode() && url.protocol === "file:") {
|
|
170
|
+
const { readFile } = await import("node:fs/promises");
|
|
171
|
+
const { fileURLToPath } = await import("node:url");
|
|
172
|
+
return new Uint8Array(await readFile(fileURLToPath(url)));
|
|
173
|
+
}
|
|
174
|
+
const res = await fetch(url);
|
|
175
|
+
if (!res.ok) throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);
|
|
176
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
177
|
+
}
|
|
178
|
+
async function wasmBytes(opts) {
|
|
179
|
+
const source = opts?.module;
|
|
180
|
+
if (source !== void 0 && isWasmBytes(source)) return source;
|
|
181
|
+
return readWasmUrl(source instanceof URL ? source : new URL(await defaultWasmHref(), import.meta.url));
|
|
182
|
+
}
|
|
183
|
+
function requireByteLength(bytes, expected, label) {
|
|
184
|
+
if (bytes.length !== expected) throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);
|
|
185
|
+
}
|
|
186
|
+
function wrapPoison(poison, fn) {
|
|
187
|
+
if (poison.error) throw poison.error;
|
|
188
|
+
try {
|
|
189
|
+
return fn();
|
|
190
|
+
} catch (e) {
|
|
191
|
+
if (e instanceof WebAssembly.RuntimeError) {
|
|
192
|
+
poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: e });
|
|
193
|
+
throw poison.error;
|
|
194
|
+
}
|
|
195
|
+
throw e;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function bindExports(exports) {
|
|
199
|
+
const poison = {};
|
|
200
|
+
const rawSerialized = (serializedUtf8, id, pubkey, sig) => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);
|
|
201
|
+
return {
|
|
202
|
+
verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),
|
|
203
|
+
verifySerialized: (serializedUtf8, id, pubkey, sig) => wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),
|
|
204
|
+
verifyEvent: makeVerifyEvent({ verifySerialized: rawSerialized }, poison),
|
|
205
|
+
sign: (id, seckey, aux) => wrapPoison(poison, () => {
|
|
206
|
+
requireByteLength(id, 32, "id");
|
|
207
|
+
requireByteLength(seckey, 32, "secret key");
|
|
208
|
+
requireByteLength(aux, 32, "aux");
|
|
209
|
+
const sig = wasmSign(exports, id, seckey, aux);
|
|
210
|
+
if (sig.length !== 64) throw new CryptoError("wasm sign failed");
|
|
211
|
+
return sig;
|
|
212
|
+
}),
|
|
213
|
+
publicKey: (seckey) => wrapPoison(poison, () => {
|
|
214
|
+
requireByteLength(seckey, 32, "secret key");
|
|
215
|
+
const pk = wasmPublicKey(exports, seckey);
|
|
216
|
+
if (pk.length !== 32) throw new CryptoError("wasm publicKey failed");
|
|
217
|
+
return pk;
|
|
218
|
+
})
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
async function instantiateNostrWasm(opts) {
|
|
222
|
+
return bindExports(await instantiateCryptoWasm(await wasmBytes(opts)));
|
|
223
|
+
}
|
|
224
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
225
|
+
function loadNostrWasm(opts) {
|
|
226
|
+
if (interned) return interned;
|
|
227
|
+
const pending = instantiateNostrWasm(opts).catch((error) => {
|
|
228
|
+
if (interned === pending) interned = void 0;
|
|
229
|
+
throw error;
|
|
230
|
+
});
|
|
231
|
+
interned = pending;
|
|
232
|
+
return pending;
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
235
|
+
export { WasmVerifyPoisonedError, loadNostrWasm };
|
|
236
|
+
|
|
237
|
+
//# sourceMappingURL=wasm.mjs.map
|
|
@@ -0,0 +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\nfunction requireFn<T extends (...args: never[]) => 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 return value as T;\n}\n\nfunction asExports(raw: WebAssembly.Exports): CryptoWasmExports {\n return {\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 __wbindgen_start:\n typeof raw.__wbindgen_start === \"function\" ? (raw.__wbindgen_start as () => void) : undefined,\n };\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\nfunction callWithBytes(\n exports: CryptoWasmExports,\n arrays: readonly Uint8Array[],\n invoke: (args: number[]) => number,\n): boolean {\n const passed = arrays.map((bytes) => passBytes(exports, bytes));\n const args = passed.flatMap(({ ptr, len }) => [ptr, len]);\n return invoke(args) !== 0;\n}\n\nexport function wasmVerify(\n exports: CryptoWasmExports,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n return callWithBytes(exports, [id, pubkey, sig], (args) =>\n exports.verify(args[0]!, args[1]!, args[2]!, args[3]!, args[4]!, args[5]!),\n );\n}\n\nexport function wasmVerifySerialized(\n exports: CryptoWasmExports,\n serialized: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n return callWithBytes(exports, [serialized, id, pubkey, sig], (args) =>\n exports.verify_serialized(\n args[0]!,\n args[1]!,\n args[2]!,\n args[3]!,\n args[4]!,\n args[5]!,\n args[6]!,\n args[7]!,\n ),\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 arrays: readonly Uint8Array[],\n invoke: (retptr: number, args: number[]) => void,\n): Uint8Array {\n const passed = arrays.map((bytes) => passBytes(exports, bytes));\n const args = passed.flatMap(({ ptr, len }) => [ptr, len]);\n const retptr = exports.__wbindgen_add_to_stack_pointer(-16);\n try {\n invoke(retptr, args);\n const view = new DataView(exports.memory.buffer);\n const ptr = view.getInt32(retptr, true) >>> 0;\n const len = view.getInt32(retptr + 4, true) >>> 0;\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 return callReturningBytes(exports, [id, seckey, aux], (retptr, args) => {\n exports.sign(retptr, args[0]!, args[1]!, args[2]!, args[3]!, args[4]!, args[5]!);\n });\n}\n\nexport function wasmPublicKey(exports: CryptoWasmExports, seckey: Uint8Array): Uint8Array {\n return callReturningBytes(exports, [seckey], (retptr, args) => {\n exports.public_key(retptr, args[0]!, args[1]!);\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 };\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) throw poison.error;\n if (isMarkedVerified(event)) return true;\n if (isMarkedFailed(event)) return false;\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.toLowerCase());\n const pubkey = hexToBytes(event.pubkey.toLowerCase());\n const sig = hexToBytes(event.sig.toLowerCase());\n const ok = wasm.verifySerialized(serialized, id, pubkey, sig);\n if (ok) markVerified(event);\n else markUnverified(event);\n return ok;\n } catch (e) {\n if (e instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: e,\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 type CryptoWasmExports,\n} from \"./abi.ts\";\nimport { makeVerifyEvent, WasmVerifyPoisonedError } from \"./adapter.ts\";\n\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\nexport { WasmVerifyPoisonedError };\n\nlet interned: Promise<NostrWasm> | undefined;\n\nfunction isNode(): boolean {\n return (\n typeof process !== \"undefined\" &&\n typeof process.versions === \"object\" &&\n process.versions !== null &&\n typeof process.versions.node === \"string\"\n );\n}\n\nfunction isWasmBytes(value: object): 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)) return source;\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) throw poison.error;\n try {\n return fn();\n } catch (e) {\n if (e instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: e,\n });\n throw poison.error;\n }\n throw e;\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) throw new CryptoError(\"wasm sign failed\");\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) throw new CryptoError(\"wasm publicKey failed\");\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 function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n if (interned) return interned;\n const pending = instantiateNostrWasm(opts).catch((error: unknown) => {\n if (interned === pending) interned = undefined;\n throw error;\n });\n interned = pending;\n return pending;\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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"}
|