@qntx/nostr 0.2.0 → 0.2.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/README.md +16 -0
- package/dist/{client-BWsX9Cv1.mjs → client-5DhgYV7P.mjs} +20 -2
- package/dist/client-5DhgYV7P.mjs.map +1 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/{index-JdaS_uce.d.mts → index-B-CGNDPS.d.mts} +2 -2
- package/dist/{index-B425CAcQ.d.mts → index-BIhSADwK.d.mts} +14 -3
- 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.d.mts +6 -6
- package/dist/index.mjs +3 -3
- package/dist/loaders.d.mts +1 -1
- package/dist/{pool-tEr7c5bG.d.mts → pool-B7p_reAm.d.mts} +33 -2
- package/dist/{pool-XmAGaufS.mjs → pool-C2xOcsun.mjs} +103 -3
- package/dist/pool-C2xOcsun.mjs.map +1 -0
- package/dist/relay.d.mts +3 -3
- package/dist/relay.mjs +2 -2
- 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 +6 -0
- package/dist/testing.mjs.map +1 -1
- package/package.json +65 -33
- package/dist/client-BWsX9Cv1.mjs.map +0 -1
- package/dist/pool-XmAGaufS.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-xXxLGCVb.mjs","names":[],"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","../src/storage/sqlite.ts"],"sourcesContent":["// oxlint-disable typescript/no-restricted-types -- the *Like types mirror IndexedDB, whose request/transaction fields and event handlers are null-valued\nexport 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: string[] = [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: (\n storeNames: string | string[],\n mode?: \"readonly\" | \"readwrite\",\n ) => 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","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\nimport type { Event } from \"../core/event.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport type { DeletionPlan, DeletionState } from \"./deletion.ts\";\nimport { StorageError } from \"./error.ts\";\nimport { ADDRESSES, EVENTS, TAG_REFS, TOMBSTONES } from \"./idb-types.ts\";\nimport type {\n AddressRow,\n IDBCursorDirectionLike,\n IDBCursorLike,\n IDBKeyRangeLike,\n IDBObjectStoreLike,\n IDBRequestLike,\n IDBTransactionLike,\n TagRef,\n Tombstone,\n} from \"./idb-types.ts\";\nimport type { PutDecision } from \"./put.ts\";\nimport type { PutResult } from \"./types.ts\";\n\nexport async function reqOf<T>(req: IDBRequestLike): Promise<T> {\n return new Promise((resolve, reject) => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- request results are trusted as T at each call site\n req.onsuccess = () => resolve(req.result as T);\n req.onerror = () => reject(req.error ?? new StorageError(\"IndexedDB request failed\"));\n });\n}\n\nexport async 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 async 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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- openCursor resolves with a cursor or null\n const cursor = (req.result ?? undefined) as IDBCursorLike | undefined;\n if (cursor === undefined) {\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}`;\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) {\n continue;\n }\n const value = tag[1].toLowerCase();\n const { id } = event;\n store.put({\n key: tagRefKey(tag[0], value, id),\n name: tag[0],\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: ReadonlyArray<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)) {\n continue;\n }\n store.put({\n key: `pending:${p.id}`,\n type: \"pending\",\n pubkey: p.pubkey,\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 (!isRecord(row)) {\n continue;\n }\n const r = row;\n if (r[\"type\"] === \"id\" && typeof r[\"key\"] === \"string\" && r[\"key\"].startsWith(\"id:\")) {\n plan.removeIds.push(r[\"key\"].slice(3));\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), pubkey: r[\"pubkey\"] });\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 if (d.action === \"skip\") {\n return d.result;\n }\n if (d.action === \"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 }\n if (d.action === \"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) {\n s.deletion.ids.add(id);\n }\n events.put(d.event);\n writeTagRefs(tagRefs, d.event);\n return \"deleted\";\n }\n events.put(d.event);\n writeTagRefs(tagRefs, d.event);\n if (d.address !== undefined) {\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","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\nimport type { Event } from \"../core/event.ts\";\nimport { compareEventsDesc, sortEvents } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { StorageError } from \"./error.ts\";\nimport { reqOf } from \"./idb-helpers.ts\";\nimport { EVENTS, TAG_REFS } from \"./idb-types.ts\";\nimport type {\n IDBCursorDirectionLike,\n IDBCursorLike,\n IDBIndexLike,\n IDBKeyRangeLike,\n IDBObjectStoreLike,\n IDBRequestLike,\n IDBTransactionLike,\n TagRef,\n} from \"./idb-types.ts\";\n\nexport function prefixRange(\n prefix: ReadonlyArray<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: (\n lower: unknown,\n upper: unknown,\n lowerOpen?: boolean,\n upperOpen?: boolean,\n ) => IDBKeyRangeLike;\n} {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis lookup of the platform IDBKeyRange\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 === undefined) {\n continue;\n }\n for (const value of values) {\n out.push({ name, value: value.toLowerCase() });\n }\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- index cursor values are stored Event rows\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- tag_refs cursor values are TagRef rows written by writeTagRefs\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- get resolves with a stored Event row or undefined\n req.onsuccess = () => ok(req.result as Event | undefined);\n },\n };\n}\n\nexport async 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 const rows = await Promise.all(reqs.map(async (req) => reqOf<Event | undefined>(req)));\n const matched: Event[] = [];\n const seen = new Set<string>();\n for (const event of rows) {\n if (event === undefined || seen.has(event.id) || !accept(event)) {\n continue;\n }\n seen.add(event.id);\n matched.push(event);\n }\n sortEvents(matched);\n const out = filter.limit === undefined ? matched : matched.slice(0, filter.limit);\n for (const event of out) {\n if (take(event)) {\n break;\n }\n }\n}\n\n/** IDB auto-commits when onsuccess returns with no outstanding requests. */\nexport async function kWayMerge(\n openers: ReadonlyArray<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\") {\n return;\n }\n phase = \"done\";\n resolve();\n };\n const fail = (error: Error) => {\n if (phase === \"done\") {\n return;\n }\n phase = \"done\";\n reject(error);\n };\n\n const stepCursor = (i: number) => {\n const { cursor } = slots.at(i) ?? { cursor: undefined };\n if (cursor === undefined) {\n return;\n }\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)) {\n continue;\n }\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) {\n return;\n }\n if (phase === \"drain\") {\n emitDrain();\n return;\n }\n let best: Event | undefined;\n for (const slot of slots) {\n const event = slot.head;\n if (event === undefined) {\n continue;\n }\n if (best === undefined || compareEventsDesc(event, best) < 0) {\n best = event;\n }\n }\n if (best === undefined) {\n finish();\n return;\n }\n phase = \"drain\";\n drainT = best.created_at;\n drainBuf = [];\n for (const [i, slot] of slots.entries()) {\n const event = slot.head;\n if (event === undefined || event.created_at !== drainT) {\n continue;\n }\n drainBuf.push(event);\n slot.head = undefined;\n stepCursor(i);\n }\n if (inflight === 0) {\n pump();\n }\n };\n\n const onEvent = (i: number, event: Event | undefined) => {\n if (phase === \"done\") {\n return;\n }\n const slot = slots.at(i);\n if (slot === undefined) {\n return;\n }\n const { cursor } = slot;\n if (event === undefined) {\n if (cursor === undefined) {\n pump();\n } else {\n inflight++;\n cursor.continue();\n }\n return;\n }\n if (phase === \"drain\") {\n if (event.created_at === drainT) {\n drainBuf.push(event);\n if (cursor === undefined) {\n pump();\n } else {\n inflight++;\n cursor.continue();\n }\n return;\n }\n slot.head = event;\n pump();\n return;\n }\n slot.head = event;\n pump();\n };\n\n const openSlot = (i: number, opener: MergeOpener): void => {\n const req = opener.open();\n req.onerror = () => fail(req.error ?? new StorageError(\"IndexedDB cursor failed\"));\n inflight++;\n req.onsuccess = () => {\n inflight--;\n if (phase === \"done\") {\n return;\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- openCursor resolves with a cursor or null\n const cursor = (req.result ?? undefined) as IDBCursorLike | undefined;\n const slot = slots.at(i);\n if (slot === undefined) {\n return;\n }\n if (cursor === undefined) {\n slot.cursor = undefined;\n slot.head = undefined;\n pump();\n return;\n }\n slot.cursor = cursor;\n inflight++;\n opener.read(\n cursor,\n (event) => {\n inflight--;\n onEvent(i, event);\n },\n (error) => {\n inflight--;\n fail(error);\n },\n );\n };\n };\n for (const [i, opener] of openers.entries()) {\n openSlot(i, opener);\n }\n });\n}\n\n/**\n * Cap on cursors opened per filter: beyond it a k-way merge degenerates into one request per match\n * candidate. Past the cap the planner opens fewer, wider cursors and lets `accept` (matchFilter)\n * enforce the remaining terms, so results and per-filter limits are unchanged.\n */\nexport const MAX_MERGE_CURSORS = 64;\n\nexport async 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) {\n return;\n }\n if (filter.since !== undefined && filter.until !== undefined && filter.since > filter.until) {\n return;\n }\n\n if (filter.ids) {\n return scanIds(tx, filter, accept, take);\n }\n\n const events = tx.objectStore(EVENTS);\n const fullScan: MergeOpener = eventCursor(\n events.index(\"created_at\"),\n createdAtRange(filter.since, filter.until),\n );\n const openers: MergeOpener[] = [];\n if (filter.authors && filter.kinds) {\n if (filter.authors.length * filter.kinds.length > MAX_MERGE_CURSORS) {\n // One cursor per kind keeps the bound tight when the kind list is\n // small; otherwise a single created_at scan still fits under the cap.\n if (filter.kinds.length <= MAX_MERGE_CURSORS) {\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 openers.push(fullScan);\n }\n } else {\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 }\n } else if (filter.authors) {\n if (filter.authors.length > MAX_MERGE_CURSORS) {\n openers.push(fullScan);\n } else {\n const index = events.index(\"pubkey_created_at\");\n for (const pk of filter.authors) {\n openers.push(\n eventCursor(index, prefixRange([pk.toLowerCase()], filter.since, filter.until)),\n );\n }\n }\n } else if (filter.kinds) {\n if (filter.kinds.length > MAX_MERGE_CURSORS) {\n openers.push(fullScan);\n } else {\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 }\n } else {\n const tags = epTagPrefixes(filter);\n if (tags.length > MAX_MERGE_CURSORS) {\n openers.push(fullScan);\n } else 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(fullScan);\n }\n }\n return kWayMerge(openers, accept, take);\n}\n","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\nimport type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner, itemCompare, validateSignedEvent } 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 { ADDRESSES, EVENTS, OUTBOX_BOUNDS, TAG_REFS, TOMBSTONES } from \"./idb-types.ts\";\nimport type {\n AddressRow,\n IDBDatabaseLike,\n IDBFactoryLike,\n IDBTransactionLike,\n Tombstone,\n} from \"./idb-types.ts\";\n\nexport const IDB_VERSION = 4;\n\nexport async function openDb(dbName: string): Promise<IDBDatabaseLike> {\n return new Promise((resolve, reject) => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- reads the platform global, which has no ambient types here\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;\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- getAll resolves with the stored legacy event rows\n migrateV1Events(tx, (all.result as unknown[]) ?? []);\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: ReadonlyArray<unknown>): void {\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 // Canonical-input precondition: legacy rows failing validation are dropped.\n const valid: Event[] = [];\n for (const e of events) {\n if (validateSignedEvent(e)) {\n valid.push(e);\n continue;\n }\n if (typeof e === \"object\" && e !== null && \"id\" in e && typeof e.id === \"string\") {\n eventsStore.delete(e.id);\n }\n }\n\n const byId = new Map(valid.map((e) => [e.id, e]));\n const deletion = new DeletionState();\n const dels = valid.filter((e) => e.kind === Kind.EventDeletion).sort(itemCompare);\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 valid) {\n if (ev.kind === Kind.EventDeletion) {\n continue;\n }\n if (eventAddress(ev) === c.key && ev.created_at <= c.until) {\n deletion.ids.add(ev.id);\n }\n }\n }\n }\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({ key: `pending:${id}`, type: \"pending\", pubkey } 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 valid) {\n if (deletion.ids.has(event.id) || deletion.covers(event)) {\n eventsStore.delete(event.id);\n continue;\n }\n writeTagRefs(tagRefs, event);\n const addr = eventAddress(event);\n if (addr !== undefined) {\n const prev = winners.get(addr);\n if (!prev || isReplaceableWinner(event, prev)) {\n winners.set(addr, event);\n }\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) {\n return;\n }\n const byAddr = new Map<string, AddressRow>();\n for (const row of addressRows) {\n byAddr.set(row.address, row);\n }\n const kept: Event[] = [];\n for (const event of events) {\n const addr = eventAddress(event);\n if (addr !== undefined) {\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 === undefined) {\n continue;\n }\n addressesStore.put({ address: addr, id: event.id, created_at: event.created_at });\n }\n };\n evReq.onsuccess = () => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- getAll resolves with the stored Event rows\n events = (evReq.result as Event[]) ?? [];\n run();\n };\n addrReq.onsuccess = () => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- getAll resolves with the stored AddressRow rows\n addressRows = (addrReq.result as AddressRow[]) ?? [];\n run();\n };\n}\n","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\n// oxlint-disable no-await-in-loop -- requests inside one IndexedDB transaction are issued sequentially; awaiting a no-request promise auto-commits the tx\nimport type { Event } from \"../core/event.ts\";\nimport { itemCompare, sortEvents, validateSignedEvent } 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} from \"./idb-types.ts\";\nimport type {\n AddressRow,\n IDBCursorDirectionLike,\n IDBDatabaseLike,\n IDBFactoryLike,\n IDBTransactionLike,\n OutboxBoundRow,\n Tombstone,\n} from \"./idb-types.ts\";\nimport { decidePut, outboxBoundKey } from \"./put.ts\";\nimport type { EventStore, NegentropyItem, OutboxBound, PutResult } from \"./types.ts\";\n\n/** Options for {@link IndexedDbEventStore}. */\nexport type IndexedDbEventStoreOptions = {\n /** IndexedDB database name. */\n dbName?: string;\n};\n\n/**\n * Browser IndexedDB event store with the same replaceable / deletion semantics as\n * {@link MemoryEventStore}. Requires a DOM IndexedDB implementation.\n *\n * `open` loads every tombstone and address row into memory. Fine at 10^4 events; tens of MB at 10^5\n * addressables.\n */\nexport class IndexedDbEventStore implements EventStore {\n readonly #dbName: string;\n #db: IDBDatabaseLike | undefined;\n readonly #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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- reads an optional host global\n return (globalThis as { indexedDB?: IDBFactoryLike }).indexedDB !== undefined;\n }\n\n async open(): Promise<void> {\n if (this.#db) {\n return;\n }\n if (!IndexedDbEventStore.isAvailable()) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n const db = await openDb(this.#dbName);\n this.#db = db;\n await this.#loadCaches(db);\n }\n\n async #ensure(): Promise<IDBDatabaseLike> {\n await this.open();\n const db = this.#db;\n if (db === undefined) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n return db;\n }\n\n /** Loads every tombstone and address row into RAM. Tens of MB at 10^5 addressables. */\n async #loadCaches(db: IDBDatabaseLike): Promise<void> {\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- address cursor values are the stored AddressRow rows\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 async #enqueueWrite<T>(op: () => Promise<T>): Promise<T> {\n const prev = this.#writeTail;\n let release: (() => void) | undefined;\n this.#writeTail = new Promise<void>((resolve) => {\n release = resolve;\n });\n try {\n await prev;\n return await op();\n } finally {\n release?.();\n }\n }\n\n async put(event: Event): Promise<PutResult> {\n const [result] = await this.putMany([event]);\n if (result === undefined) {\n throw new StorageError(\"putMany returned no result\");\n }\n return result;\n }\n\n /** One readwrite transaction; abort rejects the whole batch with no partial persist. */\n async putMany(events: ReadonlyArray<Event>): Promise<PutResult[]> {\n if (events.length === 0) {\n return [];\n }\n return this.#enqueueWrite(async () => this.#putManyLocked(events));\n }\n\n async #putManyLocked(events: ReadonlyArray<Event>): Promise<PutResult[]> {\n let db: IDBDatabaseLike;\n try {\n db = await this.#ensure();\n } catch (error) {\n throw toStorageError(error);\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 = (async (): Promise<unknown> => {\n try {\n await txSettled;\n return undefined;\n } catch (error: unknown) {\n return error;\n }\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) {\n throw toStorageError(txErr);\n }\n return results;\n } catch (error) {\n this.#restoreCaches(cache);\n try {\n tx.abort();\n } catch {\n // already aborted or complete\n }\n await txOutcome;\n throw toStorageError(error);\n }\n }\n\n /** Sequential awaits so the tx stays alive between events. */\n async #putAllInTx(tx: IDBTransactionLike, batch: ReadonlyArray<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 if (!validateSignedEvent(raw)) {\n results.push(\"invalid\");\n continue;\n }\n const event = 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) {\n byId.set(existing.id, existing);\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"e\" || tag[1] === undefined) {\n continue;\n }\n const got = await reqOf<Event | undefined>(eventsStore.get(tag[1].toLowerCase()));\n if (got) {\n byId.set(got.id, got);\n }\n }\n }\n const addrRows = new Map<string, { id: string; created_at: number }>();\n const ownAddr = eventAddress(event);\n if (ownAddr !== undefined) {\n const row = await reqOf<AddressRow | undefined>(addressesStore.get(ownAddr));\n if (row) {\n addrRows.set(ownAddr, { id: row.id, created_at: row.created_at });\n }\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"a\" || tag[1] === undefined) {\n continue;\n }\n const coord = parseEventAddress(tag[1]);\n if (!coord) {\n continue;\n }\n const key = `${coord.kind}:${coord.pubkey}:${coord.identifier}`;\n if (addrRows.has(key)) {\n continue;\n }\n const row = await reqOf<AddressRow | undefined>(addressesStore.get(key));\n if (row) {\n addrRows.set(key, { id: row.id, created_at: row.created_at });\n }\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) {\n await this.#deleteEventRows(tx, id);\n }\n } else if (d.action === \"insert\" && d.replaceId !== undefined) {\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) {\n this.#deletion.ids.add(id);\n }\n this.#deletion.pending.clear();\n for (const [k, v] of snap.pending) {\n this.#deletion.pending.set(k, v);\n }\n this.#deletion.coordinates.clear();\n for (const [k, v] of snap.coordinates) {\n this.#deletion.coordinates.set(k, v);\n }\n }\n\n async get(id: string): Promise<Event | undefined> {\n const key = id.toLowerCase();\n if (this.#deletion.ids.has(key)) {\n return undefined;\n }\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)) {\n continue;\n }\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) {\n seen.add(id);\n }\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)) {\n return false;\n }\n if (this.#deletion.covers(event)) {\n return false;\n }\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 async #scan(\n tx: IDBTransactionLike,\n filter: Filter,\n take: (event: Event) => boolean,\n ): 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 (error) {\n throw toStorageError(error);\n }\n }\n\n async setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n return this.#enqueueWrite(async () => 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 (error) {\n throw toStorageError(error);\n }\n }\n\n async remove(ids: string[]): Promise<number> {\n return this.#enqueueWrite(async () => 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 n += 1;\n }\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(async () => 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) {\n tx.objectStore(name).clear();\n }\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));\n if (!event) {\n return false;\n }\n const addr = eventAddress(event);\n let row: AddressRow | undefined;\n if (addr !== undefined) {\n row = await reqOf<AddressRow | undefined>(tx.objectStore(ADDRESSES).get(addr));\n if (this.#replaceable.get(addr) === event.id) {\n this.#replaceable.delete(addr);\n }\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 = async (\n direction: IDBCursorDirectionLike,\n assign: (createdAt: number) => void,\n ) =>\n walkCursor(index, range, direction, (cursor) => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- index cursor values are stored Event rows\n const event = cursor.value as Event;\n if (!this.#acceptHit(filter, event)) {\n return false;\n }\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) {\n return undefined;\n }\n return { oldest, newest };\n }\n}\n","// oxlint-disable no-await-in-loop -- SqlDriver statements are issued sequentially; drivers are not required to support overlapping statements on one connection\nimport { compareEventsDesc, itemCompare, sortEvents } from \"../core/event.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { matchFilter } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { eventAddress, formatEventAddress, parseEventAddress } from \"../core/tag.ts\";\nimport { DeletionState } from \"./deletion.ts\";\nimport type { DeletionPlan } from \"./deletion.ts\";\nimport { toStorageError } from \"./error.ts\";\nimport { decidePut } from \"./put.ts\";\nimport type { PutDecision, PutLookup } from \"./put.ts\";\nimport type { EventStore, NegentropyItem, OutboxBound, PutResult } from \"./types.ts\";\n\n/** Value bindable to a SQLite statement parameter. */\n// oxlint-disable-next-line typescript/no-restricted-types -- SQL NULL is a first-class bind value\nexport type SqlValue = string | number | null | Uint8Array;\n\n/**\n * Minimal async SQLite driver surface.\n *\n * `transaction` must serialize `fn` exclusively — no interleaved statements from other callers may\n * run while the callback transaction is active. It commits when `fn` resolves and rolls back when\n * `fn` rejects.\n *\n * The store always issues statements sequentially — a driver never sees a second `exec`/`run`/`all`\n * start before the previous one settles, inside or outside a transaction — so drivers need not\n * support overlapping statements on one connection.\n *\n * `expo-sqlite` maps onto this interface without changes to query code:\n *\n * ```ts\n * const db = await openDatabaseAsync(\"nostr.db\");\n * const driver: SqlDriver = {\n * exec: (sql) => db.execAsync(sql),\n * run: async (sql, params = []) => {\n * const r = await db.runAsync(sql, params);\n * return { changes: r.changes };\n * },\n * all: (sql, params = []) => db.getAllAsync(sql, params),\n * transaction: (fn) => db.withExclusiveTransactionAsync(() => fn(driver)),\n * };\n * ```\n */\nexport type SqlDriver = {\n /** Execute SQL without parameters (DDL, PRAGMA, multi-statement batches). */\n exec: (sql: string) => Promise<void>;\n /** Run a statement; resolves with the number of changed rows. */\n run: (sql: string, params?: ReadonlyArray<SqlValue>) => Promise<{ changes: number }>;\n /** Run a query; resolves with all result rows. */\n all: <Row>(sql: string, params?: ReadonlyArray<SqlValue>) => Promise<Row[]>;\n /** Run `fn` inside an exclusive transaction; commit on resolve, roll back on reject. */\n transaction: <T>(fn: (tx: SqlDriver) => Promise<T>) => Promise<T>;\n};\n\n/** Bound values per `IN (...)` list; stays below every host's variable limit. */\nconst IN_CHUNK = 500;\nconst SCHEMA_VERSION = 1;\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n pubkey TEXT NOT NULL,\n kind INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n content TEXT NOT NULL,\n tags TEXT NOT NULL,\n sig TEXT NOT NULL,\n address TEXT\n);\nCREATE UNIQUE INDEX IF NOT EXISTS events_address\n ON events(address) WHERE address IS NOT NULL;\nCREATE INDEX IF NOT EXISTS events_kind_created ON events(kind, created_at DESC, id);\nCREATE INDEX IF NOT EXISTS events_pubkey_kind_created\n ON events(pubkey, kind, created_at DESC, id);\nCREATE INDEX IF NOT EXISTS events_pubkey_created ON events(pubkey, created_at DESC, id);\nCREATE INDEX IF NOT EXISTS events_created ON events(created_at DESC, id);\nCREATE TABLE IF NOT EXISTS tags (\n event_id TEXT NOT NULL REFERENCES events(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS tags_name_value_created\n ON tags(name, value, created_at DESC);\nCREATE TABLE IF NOT EXISTS tombstones (\n kind TEXT NOT NULL CHECK(kind IN ('id', 'pending', 'coord')),\n key TEXT NOT NULL,\n pubkey TEXT,\n until INTEGER,\n PRIMARY KEY(kind, key)\n);\nCREATE TABLE IF NOT EXISTS outbox_bounds (\n pubkey TEXT NOT NULL,\n kind INTEGER NOT NULL,\n oldest INTEGER NOT NULL,\n newest INTEGER NOT NULL,\n PRIMARY KEY(pubkey, kind)\n);\n`;\n\ntype EventRow = {\n id: string;\n pubkey: string;\n kind: number;\n created_at: number;\n content: string;\n tags: string;\n sig: string;\n};\n\ntype TombstoneKind = \"id\" | \"pending\" | \"coord\";\n\ntype TombstoneRow = {\n kind: TombstoneKind;\n key: string;\n // oxlint-disable-next-line typescript/no-restricted-types -- nullable SQL column\n pubkey: string | null;\n // oxlint-disable-next-line typescript/no-restricted-types -- nullable SQL column\n until: number | null;\n};\n\nfunction rowToEvent(row: EventRow): Event {\n // Key order mirrors finalizeEvent's canonical construction so a round-trip\n // through the store JSON-equals the originally signed object.\n return {\n kind: row.kind,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the tags column is written by #insertEvent as JSON.stringify(event.tags)\n tags: JSON.parse(row.tags) as string[][],\n content: row.content,\n created_at: row.created_at,\n pubkey: row.pubkey,\n id: row.id,\n sig: row.sig,\n };\n}\n\nfunction chunkValues<T>(values: ReadonlyArray<T>): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < values.length; i += IN_CHUNK) {\n chunks.push(values.slice(i, i + IN_CHUNK));\n }\n return chunks;\n}\n\nfunction inClause(column: string, count: number): string {\n return `${column} IN (${Array.from({ length: count }, () => \"?\").join(\",\")})`;\n}\n\n/** One query variant of a filter: WHERE terms and bound params. */\ntype FilterPlan = {\n wheres: string[];\n params: SqlValue[];\n};\n\n/**\n * Compile one NIP-01 filter into query variants. `IN` lists are chunked so a variant never binds\n * more than {@link IN_CHUNK} values per list; variants are the cartesian product of chunks across\n * constrained fields. `deferred` means a `#<multi-char>` tag term cannot use the tags index (only\n * single-letter tag names are indexed) and must be checked with `matchFilter` before `limit`.\n * Returns `undefined` when an empty list field makes the filter match nothing.\n */\nfunction compileFilter(filter: Filter): { plans: FilterPlan[]; deferred: boolean } | undefined {\n const variants: FilterPlan[][] = [];\n const pushIn = (values: ReadonlyArray<SqlValue>, clause: (n: number) => string) => {\n variants.push(\n chunkValues(values).map((chunk) => ({\n wheres: [clause(chunk.length)],\n params: [...chunk],\n })),\n );\n };\n\n if (filter.ids) {\n if (filter.ids.length === 0) {\n return undefined;\n }\n pushIn(\n filter.ids.map((id) => id.toLowerCase()),\n (n) => inClause(\"id\", n),\n );\n }\n if (filter.authors) {\n if (filter.authors.length === 0) {\n return undefined;\n }\n pushIn(\n filter.authors.map((pk) => pk.toLowerCase()),\n (n) => inClause(\"pubkey\", n),\n );\n }\n if (filter.kinds) {\n if (filter.kinds.length === 0) {\n return undefined;\n }\n pushIn(filter.kinds, (n) => inClause(\"kind\", n));\n }\n if (filter.since !== undefined) {\n variants.push([{ wheres: [\"created_at >= ?\"], params: [filter.since] }]);\n }\n if (filter.until !== undefined) {\n variants.push([{ wheres: [\"created_at <= ?\"], params: [filter.until] }]);\n }\n\n let deferred = false;\n for (const key of Object.keys(filter)) {\n if (!key.startsWith(\"#\")) {\n continue;\n }\n const name = key.slice(1);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- startsWith(\"#\") above guarantees the template key\n const values = filter[key as `#${string}`];\n if (!values) {\n continue;\n }\n if (name.length !== 1) {\n deferred = true;\n continue;\n }\n if (values.length === 0) {\n return undefined;\n }\n const normalized = name === \"e\" || name === \"p\" ? values.map((v) => v.toLowerCase()) : values;\n variants.push(\n chunkValues(normalized).map((chunk) => ({\n wheres: [\n `EXISTS (SELECT 1 FROM tags t WHERE t.event_id = events.id ` +\n `AND t.name = ? AND ${inClause(\"t.value\", chunk.length)})`,\n ],\n params: [name, ...chunk],\n })),\n );\n }\n\n const plans: FilterPlan[] = [{ wheres: [], params: [] }];\n for (const field of variants) {\n const next: FilterPlan[] = [];\n for (const plan of plans) {\n for (const variant of field) {\n next.push({\n wheres: [...plan.wheres, ...variant.wheres],\n params: [...plan.params, ...variant.params],\n });\n }\n }\n plans.length = 0;\n plans.push(...next);\n }\n return { plans, deferred };\n}\n\n/**\n * SQLite-backed {@link EventStore} for React Native (`expo-sqlite`, `op-sqlite`) and desktop\n * runtimes. Same semantics as {@link MemoryEventStore} and {@link IndexedDbEventStore}: identical\n * `decidePut` insertion policy, NIP-09 tombstones, and filter handling, with the database — not\n * in-memory caches — as the source of truth.\n *\n * Construct via {@link SqliteEventStore.open}; writes are serialized and run inside an exclusive\n * driver transaction.\n */\nexport class SqliteEventStore implements EventStore {\n readonly #driver: SqlDriver;\n #writeTail: Promise<void> = Promise.resolve();\n\n private constructor(driver: SqlDriver) {\n this.#driver = driver;\n }\n\n /** Create the schema on first use and return a ready store. */\n static async open(driver: SqlDriver): Promise<SqliteEventStore> {\n const store = new SqliteEventStore(driver);\n await store.#migrate();\n return store;\n }\n\n async #migrate(): Promise<void> {\n try {\n await this.#driver.exec(\"PRAGMA foreign_keys = ON\");\n const rows = await this.#driver.all<{ user_version: number }>(\"PRAGMA user_version\");\n const version = rows[0]?.user_version ?? 0;\n if (version === 0) {\n await this.#driver.exec(SCHEMA_SQL);\n await this.#driver.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);\n } else if (version !== SCHEMA_VERSION) {\n throw toStorageError(new Error(`unsupported sqlite event store schema version ${version}`));\n }\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async #enqueueWrite<T>(op: () => Promise<T>): Promise<T> {\n const tail = this.#writeTail;\n const result = (async (): Promise<T> => {\n await tail;\n return op();\n })();\n this.#writeTail = (async (): Promise<void> => {\n try {\n await result;\n } catch {\n // a failed write must not wedge later writes\n }\n })();\n return result;\n }\n\n async put(event: Event): Promise<PutResult> {\n const results = await this.putMany([event]);\n const result = results.at(0);\n if (result === undefined) {\n throw toStorageError(new Error(\"putMany returned no result\"));\n }\n return result;\n }\n\n async putMany(events: ReadonlyArray<Event>): Promise<PutResult[]> {\n if (events.length === 0) {\n return [];\n }\n return this.#enqueueWrite(async () => {\n try {\n return await this.#driver.transaction(async (tx) => this.#putAllInTx(tx, events));\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n\n async #putAllInTx(tx: SqlDriver, batch: ReadonlyArray<Event>): Promise<PutResult[]> {\n const results: PutResult[] = [];\n for (const event of batch) {\n const lookup = await this.#buildLookup(tx, event);\n const decision = decidePut(event, lookup);\n await this.#applyDecision(tx, decision);\n results.push(decision.result);\n }\n return results;\n }\n\n async #buildLookup(tx: SqlDriver, event: Event): Promise<PutLookup> {\n const byId = new Map<string, Event>();\n const idList = [event.id];\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] === \"e\" && tag[1] !== undefined && tag[1] !== \"\") {\n idList.push(tag[1].toLowerCase());\n }\n }\n }\n for (const row of await this.#eventRowsByIds(tx, idList)) {\n byId.set(row.id, row);\n }\n\n const byAddress = new Map<string, { id: string; created_at: number }>();\n const addressList: string[] = [];\n const ownAddress = eventAddress(event);\n if (ownAddress !== undefined) {\n addressList.push(ownAddress);\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"a\" || tag[1] === undefined || tag[1] === \"\") {\n continue;\n }\n const coord = parseEventAddress(tag[1]);\n if (coord === undefined) {\n continue;\n }\n const key = formatEventAddress(coord.kind, coord.pubkey, coord.identifier);\n if (!addressList.includes(key)) {\n addressList.push(key);\n }\n }\n }\n const addressRows: Array<{ address: string; id: string; created_at: number }> = [];\n for (const chunk of chunkValues(addressList)) {\n addressRows.push(\n ...(await tx.all<{ address: string; id: string; created_at: number }>(\n `SELECT address, id, created_at FROM events\n WHERE ${inClause(\"address\", chunk.length)}`,\n chunk,\n )),\n );\n }\n for (const row of addressRows.flat()) {\n byAddress.set(row.address, { id: row.id, created_at: row.created_at });\n }\n\n const deletion = new DeletionState();\n const tombstoneRows = await tx.all<TombstoneRow>(\n ownAddress === undefined\n ? `SELECT kind, key, pubkey, until FROM tombstones\n WHERE kind IN ('id', 'pending') AND key = ?`\n : `SELECT kind, key, pubkey, until FROM tombstones\n WHERE (kind IN ('id', 'pending') AND key = ?)\n OR (kind = 'coord' AND key = ?)`,\n ownAddress === undefined ? [event.id] : [event.id, ownAddress],\n );\n for (const row of tombstoneRows) {\n if (row.kind === \"id\") {\n deletion.ids.add(row.key);\n } else if (row.kind === \"pending\" && row.pubkey !== null) {\n deletion.pending.set(row.key, row.pubkey);\n } else if (row.kind === \"coord\" && row.until !== null) {\n deletion.coordinates.set(row.key, row.until);\n }\n }\n\n return {\n deletion,\n getById: (id) => byId.get(id),\n getReplaceable: (address) => byAddress.get(address),\n };\n }\n\n async #eventRowsByIds(tx: SqlDriver, ids: ReadonlyArray<string>): Promise<Event[]> {\n const events: Event[] = [];\n for (const chunk of chunkValues(ids)) {\n const rows = await tx.all<EventRow>(\n `SELECT id, pubkey, kind, created_at, content, tags, sig FROM events\n WHERE ${inClause(\"id\", chunk.length)}`,\n chunk,\n );\n for (const row of rows) {\n events.push(rowToEvent(row));\n }\n }\n return events;\n }\n\n async #applyDecision(tx: SqlDriver, d: PutDecision): Promise<void> {\n switch (d.action) {\n case \"skip\":\n return;\n case \"tombstone\":\n await this.#putTombstone(tx, \"id\", d.event.id);\n await this.#deleteTombstone(tx, \"pending\", d.event.id);\n return;\n case \"delete\":\n await this.#persistPlan(tx, d.event.id, d.plan, d.coordIds);\n for (const id of [...d.plan.removeIds, ...d.coordIds]) {\n await this.#deleteEvent(tx, id);\n }\n await this.#insertEvent(tx, d.event);\n return;\n case \"insert\":\n if (d.replaceId !== undefined) {\n await this.#deleteEvent(tx, d.replaceId);\n }\n await this.#insertEvent(tx, d.event);\n }\n }\n\n /** Persist a deletion plan's tombstones, mirroring `DeletionState.absorb`. */\n async #persistPlan(\n tx: SqlDriver,\n deletionId: string,\n plan: DeletionPlan,\n coordIds: ReadonlyArray<string>,\n ): Promise<void> {\n await this.#deleteTombstone(tx, \"pending\", deletionId);\n for (const id of [...plan.removeIds, ...coordIds]) {\n await this.#putTombstone(tx, \"id\", id);\n await this.#deleteTombstone(tx, \"pending\", id);\n }\n for (const p of plan.pendingIds) {\n const covered = await tx.all<{ found: number }>(\n `SELECT 1 AS found FROM tombstones WHERE kind = 'id' AND key = ?`,\n [p.id],\n );\n if (covered.length === 0) {\n await tx.run(\n `INSERT OR REPLACE INTO tombstones (kind, key, pubkey) VALUES ('pending', ?, ?)`,\n [p.id, p.pubkey],\n );\n }\n }\n for (const c of plan.coordinates) {\n await tx.run(\n `INSERT INTO tombstones (kind, key, until) VALUES ('coord', ?, ?)\n ON CONFLICT(kind, key)\n DO UPDATE SET until = MAX(tombstones.until, excluded.until)`,\n [c.key, c.until],\n );\n }\n }\n\n async #putTombstone(tx: SqlDriver, kind: TombstoneKind, key: string): Promise<void> {\n await tx.run(`INSERT OR REPLACE INTO tombstones (kind, key) VALUES (?, ?)`, [kind, key]);\n }\n\n async #deleteTombstone(tx: SqlDriver, kind: TombstoneKind, key: string): Promise<void> {\n await tx.run(`DELETE FROM tombstones WHERE kind = ? AND key = ?`, [kind, key]);\n }\n\n async #insertEvent(tx: SqlDriver, event: Event): Promise<void> {\n await tx.run(\n `INSERT INTO events (id, pubkey, kind, created_at, content, tags, sig, address)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n event.id,\n event.pubkey,\n event.kind,\n event.created_at,\n event.content,\n JSON.stringify(event.tags),\n event.sig,\n eventAddress(event) ?? null,\n ],\n );\n for (const tag of event.tags) {\n if (tag[0] === undefined || tag[1] === undefined || tag[0].length !== 1) {\n continue;\n }\n await tx.run(`INSERT INTO tags (event_id, name, value, created_at) VALUES (?, ?, ?, ?)`, [\n event.id,\n tag[0],\n tag[0] === \"e\" || tag[0] === \"p\" ? tag[1].toLowerCase() : tag[1],\n event.created_at,\n ]);\n }\n }\n\n async #deleteEvent(tx: SqlDriver, id: string): Promise<number> {\n const result = await tx.run(`DELETE FROM events WHERE id = ?`, [id]);\n return result.changes;\n }\n\n async get(id: string): Promise<Event | undefined> {\n try {\n const rows = await this.#driver.all<EventRow>(\n `SELECT id, pubkey, kind, created_at, content, tags, sig FROM events\n WHERE id = ?`,\n [id.toLowerCase()],\n );\n const row = rows.at(0);\n return row === undefined ? undefined : rowToEvent(row);\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async query(filters: Filter[]): Promise<Event[]> {\n try {\n const perFilter: Event[][] = [];\n for (const filter of filters) {\n perFilter.push(await this.#filterRows(filter, \"*\"));\n }\n const seen = new Set<string>();\n const events: Event[] = [];\n for (const rows of perFilter) {\n for (const event of rows) {\n if (seen.has(event.id)) {\n continue;\n }\n seen.add(event.id);\n events.push(event);\n }\n }\n return sortEvents(events);\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async count(filters: Filter[]): Promise<number> {\n try {\n const perFilter: NegentropyItem[][] = [];\n for (const filter of filters) {\n perFilter.push(await this.#filterRows(filter, \"id, created_at\"));\n }\n const seen = new Set<string>();\n for (const rows of perFilter) {\n for (const row of rows) {\n seen.add(row.id);\n }\n }\n return seen.size;\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async negentropyItems(filter: Filter): Promise<NegentropyItem[]> {\n try {\n const items = await this.#filterRows(filter, \"id, created_at\");\n return [...items].sort(itemCompare);\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n /**\n * Rows matching one filter, deduped, newest-first, with `limit` applied. `select` is a trusted\n * column list for the projection. A filter with a non-indexed (multi-char) `#` tag term falls\n * back to a `matchFilter` pass and cannot push `limit` down.\n */\n async #filterRows(filter: Filter, select: \"*\"): Promise<Event[]>;\n async #filterRows(filter: Filter, select: \"id, created_at\"): Promise<NegentropyItem[]>;\n async #filterRows(\n filter: Filter,\n select: \"*\" | \"id, created_at\",\n ): Promise<Event[] | NegentropyItem[]> {\n if (filter.limit === 0) {\n return [];\n }\n const compiled = compileFilter(filter);\n if (compiled === undefined) {\n return [];\n }\n const { plans, deferred } = compiled;\n\n if (deferred) {\n // A multi-char #tag term bypasses the tags index — matchFilter decides and\n // `limit` cannot be pushed down.\n const merged = await this.#planRows<EventRow>(plans, \"*\", undefined);\n const matched = merged.map(rowToEvent).filter((event) => matchFilter(filter, event));\n const limited = filter.limit === undefined ? matched : matched.slice(0, filter.limit);\n return select === \"*\"\n ? limited\n : limited.map((e) => ({ id: e.id, created_at: e.created_at }));\n }\n\n if (select === \"*\") {\n const merged = await this.#planRows<EventRow>(plans, \"*\", filter.limit);\n return merged.map(rowToEvent);\n }\n return this.#planRows<NegentropyItem>(plans, \"id, created_at\", filter.limit);\n }\n\n /** Rows for the compiled plans of one filter, deduped newest-first, `limit` applied. */\n async #planRows<Row extends { id: string; created_at: number }>(\n plans: ReadonlyArray<FilterPlan>,\n select: string,\n limit: number | undefined,\n ): Promise<Row[]> {\n const tail = ` ORDER BY created_at DESC, id ASC${limit === undefined ? \"\" : \" LIMIT ?\"}`;\n const perPlan: Row[][] = [];\n for (const plan of plans) {\n const where = plan.wheres.length > 0 ? ` WHERE ${plan.wheres.join(\" AND \")}` : \"\";\n const params = limit === undefined ? plan.params : [...plan.params, limit];\n perPlan.push(\n await this.#driver.all<Row>(`SELECT ${select} FROM events${where}${tail}`, params),\n );\n }\n const sorted = perPlan.flat().sort(compareEventsDesc);\n const seen = new Set<string>();\n const merged: Row[] = [];\n for (const row of sorted) {\n if (seen.has(row.id)) {\n continue;\n }\n seen.add(row.id);\n merged.push(row);\n }\n return limit === undefined ? merged : merged.slice(0, limit);\n }\n\n async getOutboxBound(pubkey: string, kind: number): Promise<OutboxBound | undefined> {\n const pk = pubkey.toLowerCase();\n try {\n const rows = await this.#driver.all<{ oldest: number; newest: number }>(\n `SELECT oldest, newest FROM outbox_bounds\n WHERE pubkey = ? AND kind = ?`,\n [pk, kind],\n );\n const row = rows.at(0);\n if (row !== undefined) {\n return { oldest: row.oldest, newest: row.newest };\n }\n const derived = await this.#driver.all<{\n // oxlint-disable-next-line typescript/no-restricted-types -- MIN() of an empty set is SQL NULL\n oldest: number | null;\n // oxlint-disable-next-line typescript/no-restricted-types -- MAX() of an empty set is SQL NULL\n newest: number | null;\n }>(\n `SELECT MIN(created_at) AS oldest, MAX(created_at) AS newest\n FROM events WHERE pubkey = ? AND kind = ?`,\n [pk, kind],\n );\n const d = derived.at(0);\n if (d === undefined || d.oldest === null || d.newest === null) {\n return undefined;\n }\n return { oldest: d.oldest, newest: d.newest };\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n const pk = pubkey.toLowerCase();\n await this.#enqueueWrite(async () => {\n try {\n await this.#driver.transaction(async (tx) => {\n await tx.run(\n `INSERT OR REPLACE INTO outbox_bounds (pubkey, kind, oldest, newest)\n VALUES (?, ?, ?, ?)`,\n [pk, kind, bound.oldest, bound.newest],\n );\n });\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n\n async remove(ids: string[]): Promise<number> {\n const lowered = ids.map((id) => id.toLowerCase());\n return this.#enqueueWrite(async () => {\n try {\n return await this.#driver.transaction(async (tx) => {\n let removed = 0;\n for (const id of lowered) {\n removed += await this.#deleteEvent(tx, id);\n await this.#putTombstone(tx, \"id\", id);\n await this.#deleteTombstone(tx, \"pending\", id);\n }\n return removed;\n });\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n\n async clear(): Promise<void> {\n await this.#enqueueWrite(async () => {\n try {\n await this.#driver.transaction(async (tx) => {\n await tx.run(\"DELETE FROM tags\");\n await tx.run(\"DELETE FROM events\");\n await tx.run(\"DELETE FROM tombstones\");\n await tx.run(\"DELETE FROM outbox_bounds\");\n });\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage-xXxLGCVb.mjs","names":[],"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","../src/storage/sqlite.ts"],"sourcesContent":["// oxlint-disable typescript/no-restricted-types -- the *Like types mirror IndexedDB, whose request/transaction fields and event handlers are null-valued\nexport 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: string[] = [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: (\n storeNames: string | string[],\n mode?: \"readonly\" | \"readwrite\",\n ) => 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","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\nimport type { Event } from \"../core/event.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport type { DeletionPlan, DeletionState } from \"./deletion.ts\";\nimport { StorageError } from \"./error.ts\";\nimport { ADDRESSES, EVENTS, TAG_REFS, TOMBSTONES } from \"./idb-types.ts\";\nimport type {\n AddressRow,\n IDBCursorDirectionLike,\n IDBCursorLike,\n IDBKeyRangeLike,\n IDBObjectStoreLike,\n IDBRequestLike,\n IDBTransactionLike,\n TagRef,\n Tombstone,\n} from \"./idb-types.ts\";\nimport type { PutDecision } from \"./put.ts\";\nimport type { PutResult } from \"./types.ts\";\n\nexport async function reqOf<T>(req: IDBRequestLike): Promise<T> {\n return new Promise((resolve, reject) => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- request results are trusted as T at each call site\n req.onsuccess = () => resolve(req.result as T);\n req.onerror = () => reject(req.error ?? new StorageError(\"IndexedDB request failed\"));\n });\n}\n\nexport async 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 async 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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- openCursor resolves with a cursor or null\n const cursor = (req.result ?? undefined) as IDBCursorLike | undefined;\n if (cursor === undefined) {\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}`;\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) {\n continue;\n }\n const value = tag[1].toLowerCase();\n const { id } = event;\n store.put({\n key: tagRefKey(tag[0], value, id),\n name: tag[0],\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: ReadonlyArray<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)) {\n continue;\n }\n store.put({\n key: `pending:${p.id}`,\n type: \"pending\",\n pubkey: p.pubkey,\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 (!isRecord(row)) {\n continue;\n }\n const r = row;\n if (r[\"type\"] === \"id\" && typeof r[\"key\"] === \"string\" && r[\"key\"].startsWith(\"id:\")) {\n plan.removeIds.push(r[\"key\"].slice(3));\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), pubkey: r[\"pubkey\"] });\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 if (d.action === \"skip\") {\n return d.result;\n }\n if (d.action === \"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 }\n if (d.action === \"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) {\n s.deletion.ids.add(id);\n }\n events.put(d.event);\n writeTagRefs(tagRefs, d.event);\n return \"deleted\";\n }\n events.put(d.event);\n writeTagRefs(tagRefs, d.event);\n if (d.address !== undefined) {\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","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\nimport type { Event } from \"../core/event.ts\";\nimport { compareEventsDesc, sortEvents } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { StorageError } from \"./error.ts\";\nimport { reqOf } from \"./idb-helpers.ts\";\nimport { EVENTS, TAG_REFS } from \"./idb-types.ts\";\nimport type {\n IDBCursorDirectionLike,\n IDBCursorLike,\n IDBIndexLike,\n IDBKeyRangeLike,\n IDBObjectStoreLike,\n IDBRequestLike,\n IDBTransactionLike,\n TagRef,\n} from \"./idb-types.ts\";\n\nexport function prefixRange(\n prefix: ReadonlyArray<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: (\n lower: unknown,\n upper: unknown,\n lowerOpen?: boolean,\n upperOpen?: boolean,\n ) => IDBKeyRangeLike;\n} {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- globalThis lookup of the platform IDBKeyRange\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 === undefined) {\n continue;\n }\n for (const value of values) {\n out.push({ name, value: value.toLowerCase() });\n }\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- index cursor values are stored Event rows\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- tag_refs cursor values are TagRef rows written by writeTagRefs\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- get resolves with a stored Event row or undefined\n req.onsuccess = () => ok(req.result as Event | undefined);\n },\n };\n}\n\nexport async 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 const rows = await Promise.all(reqs.map(async (req) => reqOf<Event | undefined>(req)));\n const matched: Event[] = [];\n const seen = new Set<string>();\n for (const event of rows) {\n if (event === undefined || seen.has(event.id) || !accept(event)) {\n continue;\n }\n seen.add(event.id);\n matched.push(event);\n }\n sortEvents(matched);\n const out = filter.limit === undefined ? matched : matched.slice(0, filter.limit);\n for (const event of out) {\n if (take(event)) {\n break;\n }\n }\n}\n\n/** IDB auto-commits when onsuccess returns with no outstanding requests. */\nexport async function kWayMerge(\n openers: ReadonlyArray<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\") {\n return;\n }\n phase = \"done\";\n resolve();\n };\n const fail = (error: Error) => {\n if (phase === \"done\") {\n return;\n }\n phase = \"done\";\n reject(error);\n };\n\n const stepCursor = (i: number) => {\n const { cursor } = slots.at(i) ?? { cursor: undefined };\n if (cursor === undefined) {\n return;\n }\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)) {\n continue;\n }\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) {\n return;\n }\n if (phase === \"drain\") {\n emitDrain();\n return;\n }\n let best: Event | undefined;\n for (const slot of slots) {\n const event = slot.head;\n if (event === undefined) {\n continue;\n }\n if (best === undefined || compareEventsDesc(event, best) < 0) {\n best = event;\n }\n }\n if (best === undefined) {\n finish();\n return;\n }\n phase = \"drain\";\n drainT = best.created_at;\n drainBuf = [];\n for (const [i, slot] of slots.entries()) {\n const event = slot.head;\n if (event === undefined || event.created_at !== drainT) {\n continue;\n }\n drainBuf.push(event);\n slot.head = undefined;\n stepCursor(i);\n }\n if (inflight === 0) {\n pump();\n }\n };\n\n const onEvent = (i: number, event: Event | undefined) => {\n if (phase === \"done\") {\n return;\n }\n const slot = slots.at(i);\n if (slot === undefined) {\n return;\n }\n const { cursor } = slot;\n if (event === undefined) {\n if (cursor === undefined) {\n pump();\n } else {\n inflight++;\n cursor.continue();\n }\n return;\n }\n if (phase === \"drain\") {\n if (event.created_at === drainT) {\n drainBuf.push(event);\n if (cursor === undefined) {\n pump();\n } else {\n inflight++;\n cursor.continue();\n }\n return;\n }\n slot.head = event;\n pump();\n return;\n }\n slot.head = event;\n pump();\n };\n\n const openSlot = (i: number, opener: MergeOpener): void => {\n const req = opener.open();\n req.onerror = () => fail(req.error ?? new StorageError(\"IndexedDB cursor failed\"));\n inflight++;\n req.onsuccess = () => {\n inflight--;\n if (phase === \"done\") {\n return;\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- openCursor resolves with a cursor or null\n const cursor = (req.result ?? undefined) as IDBCursorLike | undefined;\n const slot = slots.at(i);\n if (slot === undefined) {\n return;\n }\n if (cursor === undefined) {\n slot.cursor = undefined;\n slot.head = undefined;\n pump();\n return;\n }\n slot.cursor = cursor;\n inflight++;\n opener.read(\n cursor,\n (event) => {\n inflight--;\n onEvent(i, event);\n },\n (error) => {\n inflight--;\n fail(error);\n },\n );\n };\n };\n for (const [i, opener] of openers.entries()) {\n openSlot(i, opener);\n }\n });\n}\n\n/**\n * Cap on cursors opened per filter: beyond it a k-way merge degenerates into one request per match\n * candidate. Past the cap the planner opens fewer, wider cursors and lets `accept` (matchFilter)\n * enforce the remaining terms, so results and per-filter limits are unchanged.\n */\nexport const MAX_MERGE_CURSORS = 64;\n\nexport async 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) {\n return;\n }\n if (filter.since !== undefined && filter.until !== undefined && filter.since > filter.until) {\n return;\n }\n\n if (filter.ids) {\n return scanIds(tx, filter, accept, take);\n }\n\n const events = tx.objectStore(EVENTS);\n const fullScan: MergeOpener = eventCursor(\n events.index(\"created_at\"),\n createdAtRange(filter.since, filter.until),\n );\n const openers: MergeOpener[] = [];\n if (filter.authors && filter.kinds) {\n if (filter.authors.length * filter.kinds.length > MAX_MERGE_CURSORS) {\n // One cursor per kind keeps the bound tight when the kind list is\n // small; otherwise a single created_at scan still fits under the cap.\n if (filter.kinds.length <= MAX_MERGE_CURSORS) {\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 openers.push(fullScan);\n }\n } else {\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 }\n } else if (filter.authors) {\n if (filter.authors.length > MAX_MERGE_CURSORS) {\n openers.push(fullScan);\n } else {\n const index = events.index(\"pubkey_created_at\");\n for (const pk of filter.authors) {\n openers.push(\n eventCursor(index, prefixRange([pk.toLowerCase()], filter.since, filter.until)),\n );\n }\n }\n } else if (filter.kinds) {\n if (filter.kinds.length > MAX_MERGE_CURSORS) {\n openers.push(fullScan);\n } else {\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 }\n } else {\n const tags = epTagPrefixes(filter);\n if (tags.length > MAX_MERGE_CURSORS) {\n openers.push(fullScan);\n } else 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(fullScan);\n }\n }\n return kWayMerge(openers, accept, take);\n}\n","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\nimport type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner, itemCompare, validateSignedEvent } 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 { ADDRESSES, EVENTS, OUTBOX_BOUNDS, TAG_REFS, TOMBSTONES } from \"./idb-types.ts\";\nimport type {\n AddressRow,\n IDBDatabaseLike,\n IDBFactoryLike,\n IDBTransactionLike,\n Tombstone,\n} from \"./idb-types.ts\";\n\nexport const IDB_VERSION = 4;\n\nexport async function openDb(dbName: string): Promise<IDBDatabaseLike> {\n return new Promise((resolve, reject) => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- reads the platform global, which has no ambient types here\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;\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- getAll resolves with the stored legacy event rows\n migrateV1Events(tx, (all.result as unknown[]) ?? []);\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: ReadonlyArray<unknown>): void {\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 // Canonical-input precondition: legacy rows failing validation are dropped.\n const valid: Event[] = [];\n for (const e of events) {\n if (validateSignedEvent(e)) {\n valid.push(e);\n continue;\n }\n if (typeof e === \"object\" && e !== null && \"id\" in e && typeof e.id === \"string\") {\n eventsStore.delete(e.id);\n }\n }\n\n const byId = new Map(valid.map((e) => [e.id, e]));\n const deletion = new DeletionState();\n const dels = valid.filter((e) => e.kind === Kind.EventDeletion).sort(itemCompare);\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 valid) {\n if (ev.kind === Kind.EventDeletion) {\n continue;\n }\n if (eventAddress(ev) === c.key && ev.created_at <= c.until) {\n deletion.ids.add(ev.id);\n }\n }\n }\n }\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({ key: `pending:${id}`, type: \"pending\", pubkey } 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 valid) {\n if (deletion.ids.has(event.id) || deletion.covers(event)) {\n eventsStore.delete(event.id);\n continue;\n }\n writeTagRefs(tagRefs, event);\n const addr = eventAddress(event);\n if (addr !== undefined) {\n const prev = winners.get(addr);\n if (!prev || isReplaceableWinner(event, prev)) {\n winners.set(addr, event);\n }\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) {\n return;\n }\n const byAddr = new Map<string, AddressRow>();\n for (const row of addressRows) {\n byAddr.set(row.address, row);\n }\n const kept: Event[] = [];\n for (const event of events) {\n const addr = eventAddress(event);\n if (addr !== undefined) {\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 === undefined) {\n continue;\n }\n addressesStore.put({ address: addr, id: event.id, created_at: event.created_at });\n }\n };\n evReq.onsuccess = () => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- getAll resolves with the stored Event rows\n events = (evReq.result as Event[]) ?? [];\n run();\n };\n addrReq.onsuccess = () => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- getAll resolves with the stored AddressRow rows\n addressRows = (addrReq.result as AddressRow[]) ?? [];\n run();\n };\n}\n","// oxlint-disable unicorn/prefer-add-event-listener -- the *Like driver interfaces model only the `on*` handler surface\n// oxlint-disable no-await-in-loop -- requests inside one IndexedDB transaction are issued sequentially; awaiting a no-request promise auto-commits the tx\nimport type { Event } from \"../core/event.ts\";\nimport { itemCompare, sortEvents, validateSignedEvent } 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} from \"./idb-types.ts\";\nimport type {\n AddressRow,\n IDBCursorDirectionLike,\n IDBDatabaseLike,\n IDBFactoryLike,\n IDBTransactionLike,\n OutboxBoundRow,\n Tombstone,\n} from \"./idb-types.ts\";\nimport { decidePut, outboxBoundKey } from \"./put.ts\";\nimport type { EventStore, NegentropyItem, OutboxBound, PutResult } from \"./types.ts\";\n\n/** Options for {@link IndexedDbEventStore}. */\nexport type IndexedDbEventStoreOptions = {\n /** IndexedDB database name. */\n dbName?: string;\n};\n\n/**\n * Browser IndexedDB event store with the same replaceable / deletion semantics as\n * {@link MemoryEventStore}. Requires a DOM IndexedDB implementation.\n *\n * `open` loads every tombstone and address row into memory. Fine at 10^4 events; tens of MB at 10^5\n * addressables.\n */\nexport class IndexedDbEventStore implements EventStore {\n readonly #dbName: string;\n #db: IDBDatabaseLike | undefined;\n readonly #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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- reads an optional host global\n return (globalThis as { indexedDB?: IDBFactoryLike }).indexedDB !== undefined;\n }\n\n async open(): Promise<void> {\n if (this.#db) {\n return;\n }\n if (!IndexedDbEventStore.isAvailable()) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n const db = await openDb(this.#dbName);\n this.#db = db;\n await this.#loadCaches(db);\n }\n\n async #ensure(): Promise<IDBDatabaseLike> {\n await this.open();\n const db = this.#db;\n if (db === undefined) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n return db;\n }\n\n /** Loads every tombstone and address row into RAM. Tens of MB at 10^5 addressables. */\n async #loadCaches(db: IDBDatabaseLike): Promise<void> {\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- address cursor values are the stored AddressRow rows\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 async #enqueueWrite<T>(op: () => Promise<T>): Promise<T> {\n const prev = this.#writeTail;\n let release: (() => void) | undefined;\n this.#writeTail = new Promise<void>((resolve) => {\n release = resolve;\n });\n try {\n await prev;\n return await op();\n } finally {\n release?.();\n }\n }\n\n async put(event: Event): Promise<PutResult> {\n const [result] = await this.putMany([event]);\n if (result === undefined) {\n throw new StorageError(\"putMany returned no result\");\n }\n return result;\n }\n\n /** One readwrite transaction; abort rejects the whole batch with no partial persist. */\n async putMany(events: ReadonlyArray<Event>): Promise<PutResult[]> {\n if (events.length === 0) {\n return [];\n }\n return this.#enqueueWrite(async () => this.#putManyLocked(events));\n }\n\n async #putManyLocked(events: ReadonlyArray<Event>): Promise<PutResult[]> {\n let db: IDBDatabaseLike;\n try {\n db = await this.#ensure();\n } catch (error) {\n throw toStorageError(error);\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 = (async (): Promise<unknown> => {\n try {\n await txSettled;\n return undefined;\n } catch (error: unknown) {\n return error;\n }\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) {\n throw toStorageError(txErr);\n }\n return results;\n } catch (error) {\n this.#restoreCaches(cache);\n try {\n tx.abort();\n } catch {\n // already aborted or complete\n }\n await txOutcome;\n throw toStorageError(error);\n }\n }\n\n /** Sequential awaits so the tx stays alive between events. */\n async #putAllInTx(tx: IDBTransactionLike, batch: ReadonlyArray<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 if (!validateSignedEvent(raw)) {\n results.push(\"invalid\");\n continue;\n }\n const event = 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) {\n byId.set(existing.id, existing);\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"e\" || tag[1] === undefined) {\n continue;\n }\n const got = await reqOf<Event | undefined>(eventsStore.get(tag[1].toLowerCase()));\n if (got) {\n byId.set(got.id, got);\n }\n }\n }\n const addrRows = new Map<string, { id: string; created_at: number }>();\n const ownAddr = eventAddress(event);\n if (ownAddr !== undefined) {\n const row = await reqOf<AddressRow | undefined>(addressesStore.get(ownAddr));\n if (row) {\n addrRows.set(ownAddr, { id: row.id, created_at: row.created_at });\n }\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"a\" || tag[1] === undefined) {\n continue;\n }\n const coord = parseEventAddress(tag[1]);\n if (!coord) {\n continue;\n }\n const key = `${coord.kind}:${coord.pubkey}:${coord.identifier}`;\n if (addrRows.has(key)) {\n continue;\n }\n const row = await reqOf<AddressRow | undefined>(addressesStore.get(key));\n if (row) {\n addrRows.set(key, { id: row.id, created_at: row.created_at });\n }\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) {\n await this.#deleteEventRows(tx, id);\n }\n } else if (d.action === \"insert\" && d.replaceId !== undefined) {\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) {\n this.#deletion.ids.add(id);\n }\n this.#deletion.pending.clear();\n for (const [k, v] of snap.pending) {\n this.#deletion.pending.set(k, v);\n }\n this.#deletion.coordinates.clear();\n for (const [k, v] of snap.coordinates) {\n this.#deletion.coordinates.set(k, v);\n }\n }\n\n async get(id: string): Promise<Event | undefined> {\n const key = id.toLowerCase();\n if (this.#deletion.ids.has(key)) {\n return undefined;\n }\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)) {\n continue;\n }\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) {\n seen.add(id);\n }\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)) {\n return false;\n }\n if (this.#deletion.covers(event)) {\n return false;\n }\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 async #scan(\n tx: IDBTransactionLike,\n filter: Filter,\n take: (event: Event) => boolean,\n ): 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 (error) {\n throw toStorageError(error);\n }\n }\n\n async setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n return this.#enqueueWrite(async () => 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 (error) {\n throw toStorageError(error);\n }\n }\n\n async remove(ids: string[]): Promise<number> {\n return this.#enqueueWrite(async () => 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 n += 1;\n }\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(async () => 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) {\n tx.objectStore(name).clear();\n }\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));\n if (!event) {\n return false;\n }\n const addr = eventAddress(event);\n let row: AddressRow | undefined;\n if (addr !== undefined) {\n row = await reqOf<AddressRow | undefined>(tx.objectStore(ADDRESSES).get(addr));\n if (this.#replaceable.get(addr) === event.id) {\n this.#replaceable.delete(addr);\n }\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 = async (\n direction: IDBCursorDirectionLike,\n assign: (createdAt: number) => void,\n ) =>\n walkCursor(index, range, direction, (cursor) => {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- index cursor values are stored Event rows\n const event = cursor.value as Event;\n if (!this.#acceptHit(filter, event)) {\n return false;\n }\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) {\n return undefined;\n }\n return { oldest, newest };\n }\n}\n","// oxlint-disable no-await-in-loop -- SqlDriver statements are issued sequentially; drivers are not required to support overlapping statements on one connection\nimport { compareEventsDesc, itemCompare, sortEvents } from \"../core/event.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { matchFilter } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { eventAddress, formatEventAddress, parseEventAddress } from \"../core/tag.ts\";\nimport { DeletionState } from \"./deletion.ts\";\nimport type { DeletionPlan } from \"./deletion.ts\";\nimport { toStorageError } from \"./error.ts\";\nimport { decidePut } from \"./put.ts\";\nimport type { PutDecision, PutLookup } from \"./put.ts\";\nimport type { EventStore, NegentropyItem, OutboxBound, PutResult } from \"./types.ts\";\n\n/** Value bindable to a SQLite statement parameter. */\n// oxlint-disable-next-line typescript/no-restricted-types -- SQL NULL is a first-class bind value\nexport type SqlValue = string | number | null | Uint8Array;\n\n/**\n * Minimal async SQLite driver surface.\n *\n * `transaction` must serialize `fn` exclusively — no interleaved statements from other callers may\n * run while the callback transaction is active. It commits when `fn` resolves and rolls back when\n * `fn` rejects.\n *\n * The store always issues statements sequentially — a driver never sees a second `exec`/`run`/`all`\n * start before the previous one settles, inside or outside a transaction — so drivers need not\n * support overlapping statements on one connection.\n *\n * `expo-sqlite` maps onto this interface without changes to query code. Note that\n * `withExclusiveTransactionAsync` resolves `void` and statements inside the exclusive transaction\n * must run on the `txn` connection passed to its callback, not on `db` — the result is captured\n * out-of-band:\n *\n * ```ts\n * const toDriver = (db: SQLiteDatabase): SqlDriver => ({\n * exec: (sql) => db.execAsync(sql),\n * run: async (sql, params = []) => ({\n * changes: (await db.runAsync(sql, [...params])).changes,\n * }),\n * all: (sql, params = []) => db.getAllAsync(sql, [...params]),\n * transaction: async (fn) => {\n * let result!: Awaited<ReturnType<typeof fn>>;\n * await db.withExclusiveTransactionAsync(async (txn) => {\n * result = await fn(toDriver(txn));\n * });\n * return result;\n * },\n * });\n * ```\n */\nexport type SqlDriver = {\n /** Execute SQL without parameters (DDL, PRAGMA, multi-statement batches). */\n exec: (sql: string) => Promise<void>;\n /** Run a statement; resolves with the number of changed rows. */\n run: (sql: string, params?: ReadonlyArray<SqlValue>) => Promise<{ changes: number }>;\n /** Run a query; resolves with all result rows. */\n all: <Row>(sql: string, params?: ReadonlyArray<SqlValue>) => Promise<Row[]>;\n /** Run `fn` inside an exclusive transaction; commit on resolve, roll back on reject. */\n transaction: <T>(fn: (tx: SqlDriver) => Promise<T>) => Promise<T>;\n};\n\n/** Bound values per `IN (...)` list; stays below every host's variable limit. */\nconst IN_CHUNK = 500;\nconst SCHEMA_VERSION = 1;\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n pubkey TEXT NOT NULL,\n kind INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n content TEXT NOT NULL,\n tags TEXT NOT NULL,\n sig TEXT NOT NULL,\n address TEXT\n);\nCREATE UNIQUE INDEX IF NOT EXISTS events_address\n ON events(address) WHERE address IS NOT NULL;\nCREATE INDEX IF NOT EXISTS events_kind_created ON events(kind, created_at DESC, id);\nCREATE INDEX IF NOT EXISTS events_pubkey_kind_created\n ON events(pubkey, kind, created_at DESC, id);\nCREATE INDEX IF NOT EXISTS events_pubkey_created ON events(pubkey, created_at DESC, id);\nCREATE INDEX IF NOT EXISTS events_created ON events(created_at DESC, id);\nCREATE TABLE IF NOT EXISTS tags (\n event_id TEXT NOT NULL REFERENCES events(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n value TEXT NOT NULL,\n created_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS tags_name_value_created\n ON tags(name, value, created_at DESC);\nCREATE TABLE IF NOT EXISTS tombstones (\n kind TEXT NOT NULL CHECK(kind IN ('id', 'pending', 'coord')),\n key TEXT NOT NULL,\n pubkey TEXT,\n until INTEGER,\n PRIMARY KEY(kind, key)\n);\nCREATE TABLE IF NOT EXISTS outbox_bounds (\n pubkey TEXT NOT NULL,\n kind INTEGER NOT NULL,\n oldest INTEGER NOT NULL,\n newest INTEGER NOT NULL,\n PRIMARY KEY(pubkey, kind)\n);\n`;\n\ntype EventRow = {\n id: string;\n pubkey: string;\n kind: number;\n created_at: number;\n content: string;\n tags: string;\n sig: string;\n};\n\ntype TombstoneKind = \"id\" | \"pending\" | \"coord\";\n\ntype TombstoneRow = {\n kind: TombstoneKind;\n key: string;\n // oxlint-disable-next-line typescript/no-restricted-types -- nullable SQL column\n pubkey: string | null;\n // oxlint-disable-next-line typescript/no-restricted-types -- nullable SQL column\n until: number | null;\n};\n\nfunction rowToEvent(row: EventRow): Event {\n // Key order mirrors finalizeEvent's canonical construction so a round-trip\n // through the store JSON-equals the originally signed object.\n return {\n kind: row.kind,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the tags column is written by #insertEvent as JSON.stringify(event.tags)\n tags: JSON.parse(row.tags) as string[][],\n content: row.content,\n created_at: row.created_at,\n pubkey: row.pubkey,\n id: row.id,\n sig: row.sig,\n };\n}\n\nfunction chunkValues<T>(values: ReadonlyArray<T>): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < values.length; i += IN_CHUNK) {\n chunks.push(values.slice(i, i + IN_CHUNK));\n }\n return chunks;\n}\n\nfunction inClause(column: string, count: number): string {\n return `${column} IN (${Array.from({ length: count }, () => \"?\").join(\",\")})`;\n}\n\n/** One query variant of a filter: WHERE terms and bound params. */\ntype FilterPlan = {\n wheres: string[];\n params: SqlValue[];\n};\n\n/**\n * Compile one NIP-01 filter into query variants. `IN` lists are chunked so a variant never binds\n * more than {@link IN_CHUNK} values per list; variants are the cartesian product of chunks across\n * constrained fields. `deferred` means a `#<multi-char>` tag term cannot use the tags index (only\n * single-letter tag names are indexed) and must be checked with `matchFilter` before `limit`.\n * Returns `undefined` when an empty list field makes the filter match nothing.\n */\nfunction compileFilter(filter: Filter): { plans: FilterPlan[]; deferred: boolean } | undefined {\n const variants: FilterPlan[][] = [];\n const pushIn = (values: ReadonlyArray<SqlValue>, clause: (n: number) => string) => {\n variants.push(\n chunkValues(values).map((chunk) => ({\n wheres: [clause(chunk.length)],\n params: [...chunk],\n })),\n );\n };\n\n if (filter.ids) {\n if (filter.ids.length === 0) {\n return undefined;\n }\n pushIn(\n filter.ids.map((id) => id.toLowerCase()),\n (n) => inClause(\"id\", n),\n );\n }\n if (filter.authors) {\n if (filter.authors.length === 0) {\n return undefined;\n }\n pushIn(\n filter.authors.map((pk) => pk.toLowerCase()),\n (n) => inClause(\"pubkey\", n),\n );\n }\n if (filter.kinds) {\n if (filter.kinds.length === 0) {\n return undefined;\n }\n pushIn(filter.kinds, (n) => inClause(\"kind\", n));\n }\n if (filter.since !== undefined) {\n variants.push([{ wheres: [\"created_at >= ?\"], params: [filter.since] }]);\n }\n if (filter.until !== undefined) {\n variants.push([{ wheres: [\"created_at <= ?\"], params: [filter.until] }]);\n }\n\n let deferred = false;\n for (const key of Object.keys(filter)) {\n if (!key.startsWith(\"#\")) {\n continue;\n }\n const name = key.slice(1);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- startsWith(\"#\") above guarantees the template key\n const values = filter[key as `#${string}`];\n if (!values) {\n continue;\n }\n if (name.length !== 1) {\n deferred = true;\n continue;\n }\n if (values.length === 0) {\n return undefined;\n }\n const normalized = name === \"e\" || name === \"p\" ? values.map((v) => v.toLowerCase()) : values;\n variants.push(\n chunkValues(normalized).map((chunk) => ({\n wheres: [\n `EXISTS (SELECT 1 FROM tags t WHERE t.event_id = events.id ` +\n `AND t.name = ? AND ${inClause(\"t.value\", chunk.length)})`,\n ],\n params: [name, ...chunk],\n })),\n );\n }\n\n const plans: FilterPlan[] = [{ wheres: [], params: [] }];\n for (const field of variants) {\n const next: FilterPlan[] = [];\n for (const plan of plans) {\n for (const variant of field) {\n next.push({\n wheres: [...plan.wheres, ...variant.wheres],\n params: [...plan.params, ...variant.params],\n });\n }\n }\n plans.length = 0;\n plans.push(...next);\n }\n return { plans, deferred };\n}\n\n/**\n * SQLite-backed {@link EventStore} for React Native (`expo-sqlite`, `op-sqlite`) and desktop\n * runtimes. Same semantics as {@link MemoryEventStore} and {@link IndexedDbEventStore}: identical\n * `decidePut` insertion policy, NIP-09 tombstones, and filter handling, with the database — not\n * in-memory caches — as the source of truth.\n *\n * Construct via {@link SqliteEventStore.open}; writes are serialized and run inside an exclusive\n * driver transaction.\n */\nexport class SqliteEventStore implements EventStore {\n readonly #driver: SqlDriver;\n #writeTail: Promise<void> = Promise.resolve();\n\n private constructor(driver: SqlDriver) {\n this.#driver = driver;\n }\n\n /** Create the schema on first use and return a ready store. */\n static async open(driver: SqlDriver): Promise<SqliteEventStore> {\n const store = new SqliteEventStore(driver);\n await store.#migrate();\n return store;\n }\n\n async #migrate(): Promise<void> {\n try {\n await this.#driver.exec(\"PRAGMA foreign_keys = ON\");\n const rows = await this.#driver.all<{ user_version: number }>(\"PRAGMA user_version\");\n const version = rows[0]?.user_version ?? 0;\n if (version === 0) {\n await this.#driver.exec(SCHEMA_SQL);\n await this.#driver.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);\n } else if (version !== SCHEMA_VERSION) {\n throw toStorageError(new Error(`unsupported sqlite event store schema version ${version}`));\n }\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async #enqueueWrite<T>(op: () => Promise<T>): Promise<T> {\n const tail = this.#writeTail;\n const result = (async (): Promise<T> => {\n await tail;\n return op();\n })();\n this.#writeTail = (async (): Promise<void> => {\n try {\n await result;\n } catch {\n // a failed write must not wedge later writes\n }\n })();\n return result;\n }\n\n async put(event: Event): Promise<PutResult> {\n const results = await this.putMany([event]);\n const result = results.at(0);\n if (result === undefined) {\n throw toStorageError(new Error(\"putMany returned no result\"));\n }\n return result;\n }\n\n async putMany(events: ReadonlyArray<Event>): Promise<PutResult[]> {\n if (events.length === 0) {\n return [];\n }\n return this.#enqueueWrite(async () => {\n try {\n return await this.#driver.transaction(async (tx) => this.#putAllInTx(tx, events));\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n\n async #putAllInTx(tx: SqlDriver, batch: ReadonlyArray<Event>): Promise<PutResult[]> {\n const results: PutResult[] = [];\n for (const event of batch) {\n const lookup = await this.#buildLookup(tx, event);\n const decision = decidePut(event, lookup);\n await this.#applyDecision(tx, decision);\n results.push(decision.result);\n }\n return results;\n }\n\n async #buildLookup(tx: SqlDriver, event: Event): Promise<PutLookup> {\n const byId = new Map<string, Event>();\n const idList = [event.id];\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] === \"e\" && tag[1] !== undefined && tag[1] !== \"\") {\n idList.push(tag[1].toLowerCase());\n }\n }\n }\n for (const row of await this.#eventRowsByIds(tx, idList)) {\n byId.set(row.id, row);\n }\n\n const byAddress = new Map<string, { id: string; created_at: number }>();\n const addressList: string[] = [];\n const ownAddress = eventAddress(event);\n if (ownAddress !== undefined) {\n addressList.push(ownAddress);\n }\n if (event.kind === Kind.EventDeletion) {\n for (const tag of event.tags) {\n if (tag[0] !== \"a\" || tag[1] === undefined || tag[1] === \"\") {\n continue;\n }\n const coord = parseEventAddress(tag[1]);\n if (coord === undefined) {\n continue;\n }\n const key = formatEventAddress(coord.kind, coord.pubkey, coord.identifier);\n if (!addressList.includes(key)) {\n addressList.push(key);\n }\n }\n }\n const addressRows: Array<{ address: string; id: string; created_at: number }> = [];\n for (const chunk of chunkValues(addressList)) {\n addressRows.push(\n ...(await tx.all<{ address: string; id: string; created_at: number }>(\n `SELECT address, id, created_at FROM events\n WHERE ${inClause(\"address\", chunk.length)}`,\n chunk,\n )),\n );\n }\n for (const row of addressRows.flat()) {\n byAddress.set(row.address, { id: row.id, created_at: row.created_at });\n }\n\n const deletion = new DeletionState();\n const tombstoneRows = await tx.all<TombstoneRow>(\n ownAddress === undefined\n ? `SELECT kind, key, pubkey, until FROM tombstones\n WHERE kind IN ('id', 'pending') AND key = ?`\n : `SELECT kind, key, pubkey, until FROM tombstones\n WHERE (kind IN ('id', 'pending') AND key = ?)\n OR (kind = 'coord' AND key = ?)`,\n ownAddress === undefined ? [event.id] : [event.id, ownAddress],\n );\n for (const row of tombstoneRows) {\n if (row.kind === \"id\") {\n deletion.ids.add(row.key);\n } else if (row.kind === \"pending\" && row.pubkey !== null) {\n deletion.pending.set(row.key, row.pubkey);\n } else if (row.kind === \"coord\" && row.until !== null) {\n deletion.coordinates.set(row.key, row.until);\n }\n }\n\n return {\n deletion,\n getById: (id) => byId.get(id),\n getReplaceable: (address) => byAddress.get(address),\n };\n }\n\n async #eventRowsByIds(tx: SqlDriver, ids: ReadonlyArray<string>): Promise<Event[]> {\n const events: Event[] = [];\n for (const chunk of chunkValues(ids)) {\n const rows = await tx.all<EventRow>(\n `SELECT id, pubkey, kind, created_at, content, tags, sig FROM events\n WHERE ${inClause(\"id\", chunk.length)}`,\n chunk,\n );\n for (const row of rows) {\n events.push(rowToEvent(row));\n }\n }\n return events;\n }\n\n async #applyDecision(tx: SqlDriver, d: PutDecision): Promise<void> {\n switch (d.action) {\n case \"skip\":\n return;\n case \"tombstone\":\n await this.#putTombstone(tx, \"id\", d.event.id);\n await this.#deleteTombstone(tx, \"pending\", d.event.id);\n return;\n case \"delete\":\n await this.#persistPlan(tx, d.event.id, d.plan, d.coordIds);\n for (const id of [...d.plan.removeIds, ...d.coordIds]) {\n await this.#deleteEvent(tx, id);\n }\n await this.#insertEvent(tx, d.event);\n return;\n case \"insert\":\n if (d.replaceId !== undefined) {\n await this.#deleteEvent(tx, d.replaceId);\n }\n await this.#insertEvent(tx, d.event);\n }\n }\n\n /** Persist a deletion plan's tombstones, mirroring `DeletionState.absorb`. */\n async #persistPlan(\n tx: SqlDriver,\n deletionId: string,\n plan: DeletionPlan,\n coordIds: ReadonlyArray<string>,\n ): Promise<void> {\n await this.#deleteTombstone(tx, \"pending\", deletionId);\n for (const id of [...plan.removeIds, ...coordIds]) {\n await this.#putTombstone(tx, \"id\", id);\n await this.#deleteTombstone(tx, \"pending\", id);\n }\n for (const p of plan.pendingIds) {\n const covered = await tx.all<{ found: number }>(\n `SELECT 1 AS found FROM tombstones WHERE kind = 'id' AND key = ?`,\n [p.id],\n );\n if (covered.length === 0) {\n await tx.run(\n `INSERT OR REPLACE INTO tombstones (kind, key, pubkey) VALUES ('pending', ?, ?)`,\n [p.id, p.pubkey],\n );\n }\n }\n for (const c of plan.coordinates) {\n await tx.run(\n `INSERT INTO tombstones (kind, key, until) VALUES ('coord', ?, ?)\n ON CONFLICT(kind, key)\n DO UPDATE SET until = MAX(tombstones.until, excluded.until)`,\n [c.key, c.until],\n );\n }\n }\n\n async #putTombstone(tx: SqlDriver, kind: TombstoneKind, key: string): Promise<void> {\n await tx.run(`INSERT OR REPLACE INTO tombstones (kind, key) VALUES (?, ?)`, [kind, key]);\n }\n\n async #deleteTombstone(tx: SqlDriver, kind: TombstoneKind, key: string): Promise<void> {\n await tx.run(`DELETE FROM tombstones WHERE kind = ? AND key = ?`, [kind, key]);\n }\n\n async #insertEvent(tx: SqlDriver, event: Event): Promise<void> {\n await tx.run(\n `INSERT INTO events (id, pubkey, kind, created_at, content, tags, sig, address)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n event.id,\n event.pubkey,\n event.kind,\n event.created_at,\n event.content,\n JSON.stringify(event.tags),\n event.sig,\n eventAddress(event) ?? null,\n ],\n );\n for (const tag of event.tags) {\n if (tag[0] === undefined || tag[1] === undefined || tag[0].length !== 1) {\n continue;\n }\n await tx.run(`INSERT INTO tags (event_id, name, value, created_at) VALUES (?, ?, ?, ?)`, [\n event.id,\n tag[0],\n tag[0] === \"e\" || tag[0] === \"p\" ? tag[1].toLowerCase() : tag[1],\n event.created_at,\n ]);\n }\n }\n\n async #deleteEvent(tx: SqlDriver, id: string): Promise<number> {\n const result = await tx.run(`DELETE FROM events WHERE id = ?`, [id]);\n return result.changes;\n }\n\n async get(id: string): Promise<Event | undefined> {\n try {\n const rows = await this.#driver.all<EventRow>(\n `SELECT id, pubkey, kind, created_at, content, tags, sig FROM events\n WHERE id = ?`,\n [id.toLowerCase()],\n );\n const row = rows.at(0);\n return row === undefined ? undefined : rowToEvent(row);\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async query(filters: Filter[]): Promise<Event[]> {\n try {\n const perFilter: Event[][] = [];\n for (const filter of filters) {\n perFilter.push(await this.#filterRows(filter, \"*\"));\n }\n const seen = new Set<string>();\n const events: Event[] = [];\n for (const rows of perFilter) {\n for (const event of rows) {\n if (seen.has(event.id)) {\n continue;\n }\n seen.add(event.id);\n events.push(event);\n }\n }\n return sortEvents(events);\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async count(filters: Filter[]): Promise<number> {\n try {\n const perFilter: NegentropyItem[][] = [];\n for (const filter of filters) {\n perFilter.push(await this.#filterRows(filter, \"id, created_at\"));\n }\n const seen = new Set<string>();\n for (const rows of perFilter) {\n for (const row of rows) {\n seen.add(row.id);\n }\n }\n return seen.size;\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async negentropyItems(filter: Filter): Promise<NegentropyItem[]> {\n try {\n const items = await this.#filterRows(filter, \"id, created_at\");\n return [...items].sort(itemCompare);\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n /**\n * Rows matching one filter, deduped, newest-first, with `limit` applied. `select` is a trusted\n * column list for the projection. A filter with a non-indexed (multi-char) `#` tag term falls\n * back to a `matchFilter` pass and cannot push `limit` down.\n */\n async #filterRows(filter: Filter, select: \"*\"): Promise<Event[]>;\n async #filterRows(filter: Filter, select: \"id, created_at\"): Promise<NegentropyItem[]>;\n async #filterRows(\n filter: Filter,\n select: \"*\" | \"id, created_at\",\n ): Promise<Event[] | NegentropyItem[]> {\n if (filter.limit === 0) {\n return [];\n }\n const compiled = compileFilter(filter);\n if (compiled === undefined) {\n return [];\n }\n const { plans, deferred } = compiled;\n\n if (deferred) {\n // A multi-char #tag term bypasses the tags index — matchFilter decides and\n // `limit` cannot be pushed down.\n const merged = await this.#planRows<EventRow>(plans, \"*\", undefined);\n const matched = merged.map(rowToEvent).filter((event) => matchFilter(filter, event));\n const limited = filter.limit === undefined ? matched : matched.slice(0, filter.limit);\n return select === \"*\"\n ? limited\n : limited.map((e) => ({ id: e.id, created_at: e.created_at }));\n }\n\n if (select === \"*\") {\n const merged = await this.#planRows<EventRow>(plans, \"*\", filter.limit);\n return merged.map(rowToEvent);\n }\n return this.#planRows<NegentropyItem>(plans, \"id, created_at\", filter.limit);\n }\n\n /** Rows for the compiled plans of one filter, deduped newest-first, `limit` applied. */\n async #planRows<Row extends { id: string; created_at: number }>(\n plans: ReadonlyArray<FilterPlan>,\n select: string,\n limit: number | undefined,\n ): Promise<Row[]> {\n const tail = ` ORDER BY created_at DESC, id ASC${limit === undefined ? \"\" : \" LIMIT ?\"}`;\n const perPlan: Row[][] = [];\n for (const plan of plans) {\n const where = plan.wheres.length > 0 ? ` WHERE ${plan.wheres.join(\" AND \")}` : \"\";\n const params = limit === undefined ? plan.params : [...plan.params, limit];\n perPlan.push(\n await this.#driver.all<Row>(`SELECT ${select} FROM events${where}${tail}`, params),\n );\n }\n const sorted = perPlan.flat().sort(compareEventsDesc);\n const seen = new Set<string>();\n const merged: Row[] = [];\n for (const row of sorted) {\n if (seen.has(row.id)) {\n continue;\n }\n seen.add(row.id);\n merged.push(row);\n }\n return limit === undefined ? merged : merged.slice(0, limit);\n }\n\n async getOutboxBound(pubkey: string, kind: number): Promise<OutboxBound | undefined> {\n const pk = pubkey.toLowerCase();\n try {\n const rows = await this.#driver.all<{ oldest: number; newest: number }>(\n `SELECT oldest, newest FROM outbox_bounds\n WHERE pubkey = ? AND kind = ?`,\n [pk, kind],\n );\n const row = rows.at(0);\n if (row !== undefined) {\n return { oldest: row.oldest, newest: row.newest };\n }\n const derived = await this.#driver.all<{\n // oxlint-disable-next-line typescript/no-restricted-types -- MIN() of an empty set is SQL NULL\n oldest: number | null;\n // oxlint-disable-next-line typescript/no-restricted-types -- MAX() of an empty set is SQL NULL\n newest: number | null;\n }>(\n `SELECT MIN(created_at) AS oldest, MAX(created_at) AS newest\n FROM events WHERE pubkey = ? AND kind = ?`,\n [pk, kind],\n );\n const d = derived.at(0);\n if (d === undefined || d.oldest === null || d.newest === null) {\n return undefined;\n }\n return { oldest: d.oldest, newest: d.newest };\n } catch (error) {\n throw toStorageError(error);\n }\n }\n\n async setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n const pk = pubkey.toLowerCase();\n await this.#enqueueWrite(async () => {\n try {\n await this.#driver.transaction(async (tx) => {\n await tx.run(\n `INSERT OR REPLACE INTO outbox_bounds (pubkey, kind, oldest, newest)\n VALUES (?, ?, ?, ?)`,\n [pk, kind, bound.oldest, bound.newest],\n );\n });\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n\n async remove(ids: string[]): Promise<number> {\n const lowered = ids.map((id) => id.toLowerCase());\n return this.#enqueueWrite(async () => {\n try {\n return await this.#driver.transaction(async (tx) => {\n let removed = 0;\n for (const id of lowered) {\n removed += await this.#deleteEvent(tx, id);\n await this.#putTombstone(tx, \"id\", id);\n await this.#deleteTombstone(tx, \"pending\", id);\n }\n return removed;\n });\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n\n async clear(): Promise<void> {\n await this.#enqueueWrite(async () => {\n try {\n await this.#driver.transaction(async (tx) => {\n await tx.run(\"DELETE FROM tags\");\n await tx.run(\"DELETE FROM events\");\n await tx.run(\"DELETE FROM tombstones\");\n await tx.run(\"DELETE FROM outbox_bounds\");\n });\n } catch (error) {\n throw toStorageError(error);\n }\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/storage.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { i as PutResult, n as NegentropyItem, r as OutboxBound, t as EventStore } from "./types-2pCUprRU.mjs";
|
|
2
2
|
import { t as StorageError } from "./error-BW7re1UN.mjs";
|
|
3
|
-
import { a as IndexedDbEventStoreOptions, c as MemoryIndexOptions, i as IndexedDbEventStore, n as SqlValue, o as MemoryEventStore, r as SqliteEventStore, s as MemoryIndex, t as SqlDriver } from "./index-
|
|
3
|
+
import { a as IndexedDbEventStoreOptions, c as MemoryIndexOptions, i as IndexedDbEventStore, n as SqlValue, o as MemoryEventStore, r as SqliteEventStore, s as MemoryIndex, t as SqlDriver } from "./index-D1bqFHKB.mjs";
|
|
4
4
|
export { type EventStore, IndexedDbEventStore, type IndexedDbEventStoreOptions, MemoryEventStore, MemoryIndex, type MemoryIndexOptions, type NegentropyItem, type OutboxBound, type PutResult, type SqlDriver, type SqlValue, SqliteEventStore, StorageError };
|
package/dist/testing.d.mts
CHANGED
|
@@ -23,7 +23,17 @@ type FakeRelay = {
|
|
|
23
23
|
readonly url: string;
|
|
24
24
|
seed: (events: ReadonlyArray<Event>) => void;
|
|
25
25
|
events: () => ReadonlyArray<Event>;
|
|
26
|
+
/**
|
|
27
|
+
* Store an event and broadcast it to matching subscriptions. Unlike client EVENT writes the relay
|
|
28
|
+
* does not verify it here, so forged events (mismatched id/signature) are delivered as-is.
|
|
29
|
+
*/
|
|
26
30
|
inject: (event: Event) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Push an event to matching subscriptions without storing it: a resubscription never re-serves
|
|
33
|
+
* it. Use it for forged events (mismatched id/signature) when exercising client-side verification
|
|
34
|
+
* failure handling.
|
|
35
|
+
*/
|
|
36
|
+
deliver: (event: Event) => void;
|
|
27
37
|
disconnect: () => void;
|
|
28
38
|
closeSubscriptions: (reason: string) => void;
|
|
29
39
|
configure: (opts: Partial<FakeRelayOptions>) => void;
|
package/dist/testing.mjs
CHANGED
|
@@ -68,6 +68,12 @@ var FakeRelayCore = class {
|
|
|
68
68
|
if (isLivePut(result)) this.#deliver(event);
|
|
69
69
|
})();
|
|
70
70
|
}
|
|
71
|
+
deliver(event) {
|
|
72
|
+
this.#pending = (async () => {
|
|
73
|
+
await this.#pending;
|
|
74
|
+
this.#deliver(event);
|
|
75
|
+
})();
|
|
76
|
+
}
|
|
71
77
|
disconnect() {
|
|
72
78
|
const sessions = [...this.#sessions];
|
|
73
79
|
this.#sessions.clear();
|