@qntx/nostr 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{builder-CVRmUeNm.mjs → builder-BQbFDO6S.mjs} +22 -5
- package/dist/builder-BQbFDO6S.mjs.map +1 -0
- package/dist/{client-CeyDLoyO.mjs → client-CTmp5w84.mjs} +14 -14
- package/dist/{client-CeyDLoyO.mjs.map → client-CTmp5w84.mjs.map} +1 -1
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/core.d.mts +2 -2
- package/dist/core.mjs +7 -7
- package/dist/{error-BILMe3Gr.mjs → error-DH4guike.mjs} +2 -2
- package/dist/{error-BILMe3Gr.mjs.map → error-DH4guike.mjs.map} +1 -1
- package/dist/{error-DlhGW4mJ.mjs → error-UHkqzWL7.mjs} +2 -2
- package/dist/{error-DlhGW4mJ.mjs.map → error-UHkqzWL7.mjs.map} +1 -1
- package/dist/{event-C2eLiPpV.mjs → event-B3ua2_oL.mjs} +24 -11
- package/dist/event-B3ua2_oL.mjs.map +1 -0
- package/dist/{filter-TrF2LEoy.mjs → filter-B16P33dz.mjs} +31 -10
- package/dist/filter-B16P33dz.mjs.map +1 -0
- package/dist/{filter-CfEgQBXt.d.mts → filter-PG7r79rt.d.mts} +6 -2
- package/dist/{gossip-BWb9HmfK.d.mts → gossip-BTMdlUI7.d.mts} +2 -2
- package/dist/{gossip-5ezg0Quo.mjs → gossip-K_JIexQs.mjs} +3 -3
- package/dist/{gossip-5ezg0Quo.mjs.map → gossip-K_JIexQs.mjs.map} +1 -1
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/{index-B1fLejg4.d.mts → index-BP94lABY.d.mts} +5 -5
- package/dist/{index-uCYwXaaP.d.mts → index-CSsnE32i.d.mts} +7 -7
- package/dist/{index-CLJEKFGd.d.mts → index-DD0Ywpay.d.mts} +3 -3
- package/dist/{index-C0mFpelb.d.mts → index-N7HUGgwo.d.mts} +2 -2
- package/dist/{index-CoX7SnO7.d.mts → index-rKcmI6ex.d.mts} +3 -3
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +18 -18
- package/dist/{key-DY_HEIpY.mjs → key-k8LDEPZh.mjs} +3 -3
- package/dist/{key-DY_HEIpY.mjs.map → key-k8LDEPZh.mjs.map} +1 -1
- package/dist/{loaders-DifimjJ7.mjs → loaders-Dp2nXEFk.mjs} +6 -6
- package/dist/{loaders-DifimjJ7.mjs.map → loaders-Dp2nXEFk.mjs.map} +1 -1
- package/dist/loaders.d.mts +2 -2
- package/dist/loaders.mjs +1 -1
- package/dist/{memory-DENGQ_f6.mjs → memory-VyPnOBU3.mjs} +2 -2
- package/dist/{memory-DENGQ_f6.mjs.map → memory-VyPnOBU3.mjs.map} +1 -1
- package/dist/{memory-index-D_lvlYAy.mjs → memory-index-Bhwe0ZdG.mjs} +4 -4
- package/dist/{memory-index-D_lvlYAy.mjs.map → memory-index-Bhwe0ZdG.mjs.map} +1 -1
- package/dist/{message-Rd5Z_17h.mjs → message-pYfVKxPn.mjs} +74 -29
- package/dist/message-pYfVKxPn.mjs.map +1 -0
- package/dist/nips/blossom.mjs +2 -2
- package/dist/nips/nip04.mjs +1 -1
- package/dist/nips/nip05.mjs +1 -1
- package/dist/nips/nip10.mjs +3 -3
- package/dist/nips/nip11.mjs +1 -1
- package/dist/nips/nip13.mjs +1 -1
- package/dist/nips/nip17.mjs +3 -3
- package/dist/nips/nip19.mjs +11 -4
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.mjs +1 -1
- package/dist/nips/nip42.mjs +1 -1
- package/dist/nips/nip44.mjs +1 -1
- package/dist/nips/nip46.mjs +1 -1
- package/dist/nips/nip49.mjs +1 -1
- package/dist/nips/nip51.mjs +3 -3
- package/dist/nips/nip57.mjs +3 -3
- package/dist/nips/nip59.mjs +4 -4
- package/dist/nips/nip65.mjs +2 -2
- package/dist/nips/nip77.mjs +1 -1
- package/dist/nips/nip98.mjs +3 -3
- package/dist/{pool-jok2-iBJ.mjs → pool-BMUsw2un.mjs} +5 -5
- package/dist/{pool-jok2-iBJ.mjs.map → pool-BMUsw2un.mjs.map} +1 -1
- package/dist/{pool-Bfe3Tu40.d.mts → pool-DUuYJ0x4.d.mts} +3 -3
- package/dist/{put-JsiCKMyZ.mjs → put-DRmV1wHD.mjs} +3 -3
- package/dist/{put-JsiCKMyZ.mjs.map → put-DRmV1wHD.mjs.map} +1 -1
- package/dist/{reactive-6Wn9qf_d.mjs → reactive--pDpLt2H.mjs} +5 -5
- package/dist/{reactive-6Wn9qf_d.mjs.map → reactive--pDpLt2H.mjs.map} +1 -1
- package/dist/{reactive-X4p6nABy.d.mts → reactive-jyKrA9ej.d.mts} +3 -3
- package/dist/{relay-__QtO33h.mjs → relay-DXtwUEdX.mjs} +6 -6
- package/dist/{relay-__QtO33h.mjs.map → relay-DXtwUEdX.mjs.map} +1 -1
- package/dist/relay.d.mts +3 -3
- package/dist/relay.mjs +2 -2
- package/dist/{signer-D7PtVvQn.mjs → signer-CWtxpOxc.mjs} +5 -5
- package/dist/{signer-D7PtVvQn.mjs.map → signer-CWtxpOxc.mjs.map} +1 -1
- package/dist/signer.d.mts +1 -1
- package/dist/signer.mjs +2 -2
- package/dist/{storage-oihjE0_x.mjs → storage-B5Wdt_Mn.mjs} +12 -29
- package/dist/storage-B5Wdt_Mn.mjs.map +1 -0
- package/dist/storage.d.mts +2 -2
- package/dist/storage.mjs +4 -4
- package/dist/store.d.mts +1 -1
- package/dist/store.mjs +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +18 -7
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-Ccox7-5v.d.mts → types-CqhnT-Mx.d.mts} +2 -2
- package/dist/{util-DMF9AIO0.mjs → util-DDpPkiED.mjs} +14 -2
- package/dist/util-DDpPkiED.mjs.map +1 -0
- package/dist/{verifier-uC_jd-Nw.mjs → verifier-CjH1vnP2.mjs} +3 -3
- package/dist/{verifier-uC_jd-Nw.mjs.map → verifier-CjH1vnP2.mjs.map} +1 -1
- package/dist/{verifier-9c-bINrv.d.mts → verifier-Cl24c9ph.d.mts} +3 -3
- package/package.json +1 -1
- package/dist/builder-CVRmUeNm.mjs.map +0 -1
- package/dist/event-C2eLiPpV.mjs.map +0 -1
- package/dist/filter-TrF2LEoy.mjs.map +0 -1
- package/dist/message-Rd5Z_17h.mjs.map +0 -1
- package/dist/storage-oihjE0_x.mjs.map +0 -1
- package/dist/util-DMF9AIO0.mjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { S as errorMessage, f as nowSeconds, h as CryptoError, i as bytesToHex$1, n as assertHex32, s as isHex32 } from "./util-DDpPkiED.mjs";
|
|
2
2
|
import { t as Kind } from "./kind-D8fENiiL.mjs";
|
|
3
|
-
import { d as signedMatchesUnsigned, g as Tag, h as validateSignedEvent } from "./event-
|
|
4
|
-
import { i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as toSecretKey, t as Keys } from "./key-
|
|
5
|
-
import { n as verifyEvent } from "./verifier-
|
|
3
|
+
import { d as signedMatchesUnsigned, g as Tag, h as validateSignedEvent } from "./event-B3ua2_oL.mjs";
|
|
4
|
+
import { i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as toSecretKey, t as Keys } from "./key-k8LDEPZh.mjs";
|
|
5
|
+
import { n as verifyEvent } from "./verifier-CjH1vnP2.mjs";
|
|
6
6
|
import { decrypt, encrypt } from "./nips/nip04.mjs";
|
|
7
7
|
import { decrypt as decrypt$1, encrypt as encrypt$1, getConversationKey } from "./nips/nip44.mjs";
|
|
8
8
|
import { i as throwIfAborted } from "./abort-DBq2STPj.mjs";
|
|
@@ -511,4 +511,4 @@ var Nip46Signer = class Nip46Signer {
|
|
|
511
511
|
//#endregion
|
|
512
512
|
export { KeysSigner as a, isNip07Available as i, Nip07Signer as n, getWindowNostr as r, Nip46Signer as t };
|
|
513
513
|
|
|
514
|
-
//# sourceMappingURL=signer-
|
|
514
|
+
//# sourceMappingURL=signer-CWtxpOxc.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signer-D7PtVvQn.mjs","names":["nip04.encrypt","nip04.decrypt","nip44.getConversationKey","nip44.encrypt","nip44.decrypt","decrypt","bytesToHex","encrypt"],"sources":["../src/signer/keys.ts","../src/signer/nip07.ts","../src/signer/nip46.ts"],"sourcesContent":["import type { Event, UnsignedEvent } from \"../core/event.ts\";\nimport type { SecretKeyInput } from \"../core/key.ts\";\nimport { Keys, signEvent } from \"../core/key.ts\";\nimport * as nip04 from \"../nips/nip04.ts\";\nimport * as nip44 from \"../nips/nip44.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Local secret-key signer with NIP-04 (legacy) and NIP-44 support. */\nexport class KeysSigner implements NostrSigner {\n readonly #keys: Keys;\n readonly #convKeys = new Map<string, Uint8Array>();\n\n constructor(secretKey: SecretKeyInput | Keys) {\n this.#keys = secretKey instanceof Keys ? secretKey : Keys.fromSecretKey(secretKey);\n }\n\n get keys(): Keys {\n return this.#keys;\n }\n\n async getPublicKey(): Promise<string> {\n return this.#keys.publicKey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n return signEvent(unsigned, this.#keys);\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip04.encrypt(this.#keys.secretKey.bytes, peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return nip04.decrypt(this.#keys.secretKey.bytes, peer, ciphertext);\n }\n\n #conversationKey(peer: string): Uint8Array {\n const pk = peer.toLowerCase();\n let key = this.#convKeys.get(pk);\n if (!key) {\n key = nip44.getConversationKey(this.#keys.secretKey.bytes, pk);\n this.#convKeys.set(pk, key);\n }\n return key;\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip44.encrypt(plaintext, this.#conversationKey(peer));\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return nip44.decrypt(payload, this.#conversationKey(peer));\n }\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport { assertHex32 } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/**\n * Minimal NIP-07 provider surface (browser extension `window.nostr`).\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/07.md\n */\nexport type WindowNostr = {\n getPublicKey: () => Promise<string>;\n signEvent: (event: EventTemplate) => Promise<Event>;\n nip04?: {\n encrypt: (pubkey: string, plaintext: string) => Promise<string>;\n decrypt: (pubkey: string, ciphertext: string) => Promise<string>;\n };\n nip44?: {\n encrypt: (pubkey: string, plaintext: string) => Promise<string>;\n decrypt: (pubkey: string, ciphertext: string) => Promise<string>;\n };\n};\n\ntype GlobalWithNostr = typeof globalThis & {\n nostr?: WindowNostr;\n window?: { nostr?: WindowNostr };\n};\n\n/** Resolve `window.nostr` / `globalThis.nostr` when present. */\nexport function getWindowNostr(): WindowNostr | undefined {\n const g = globalThis as GlobalWithNostr;\n return g.nostr ?? g.window?.nostr;\n}\n\n/** True when a NIP-07 provider is injected in the current environment. */\nexport function isNip07Available(): boolean {\n const n = getWindowNostr();\n return Boolean(n && typeof n.getPublicKey === \"function\" && typeof n.signEvent === \"function\");\n}\n\n/**\n * Signer backed by a NIP-07 browser extension (or any injected provider). Never holds secret keys\n * in-process.\n */\nexport class Nip07Signer implements NostrSigner {\n readonly #provider: WindowNostr | undefined;\n\n constructor(provider?: WindowNostr) {\n this.#provider = provider;\n }\n\n #resolve(): WindowNostr {\n const provider = this.#provider ?? getWindowNostr();\n if (!provider) {\n throw new CryptoError(\"NIP-07 provider not available (window.nostr missing)\");\n }\n return provider;\n }\n\n async getPublicKey(): Promise<string> {\n const pk = await this.#resolve().getPublicKey();\n try {\n return assertHex32(pk, \"pubkey\");\n } catch (error) {\n throw new CryptoError(\"NIP-07 getPublicKey returned an invalid pubkey\", {\n cause: error,\n });\n }\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const provider = this.#resolve();\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags.map((t) => {\n const [name, ...rest] = t;\n if (name === undefined) {\n throw new CryptoError(\"unsigned event has an empty tag\");\n }\n return [name, ...rest];\n }),\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n\n const signed = await provider.signEvent(template);\n if (!validateSignedEvent(signed)) {\n throw new CryptoError(\"NIP-07 signEvent returned an invalid event\");\n }\n if (!verifyEvent(signed)) {\n throw new CryptoError(\"NIP-07 signed event failed signature verification\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new CryptoError(\"NIP-07 signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n const { nip04 } = this.#resolve();\n if (!nip04?.encrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip04.encrypt\");\n }\n return nip04.encrypt(peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n const { nip04 } = this.#resolve();\n if (!nip04?.decrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip04.decrypt\");\n }\n return nip04.decrypt(peer, ciphertext);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n const { nip44 } = this.#resolve();\n if (!nip44?.encrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip44.encrypt\");\n }\n return nip44.encrypt(peer, plaintext);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n const { nip44 } = this.#resolve();\n if (!nip44?.decrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip44.decrypt\");\n }\n return nip44.decrypt(peer, payload);\n }\n}\n","import { randomBytes } from \"@noble/hashes/utils.js\";\n\nimport { throwIfAborted } from \"../core/abort.ts\";\nimport { errorMessage } from \"../core/error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { SecretKey, finalizeEvent, getPublicKey, toSecretKey } from \"../core/key.ts\";\nimport type { SecretKeyInput } from \"../core/key.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { Tag } from \"../core/tag.ts\";\nimport { bytesToHex, isHex32, nowSeconds } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport { decrypt, encrypt, getConversationKey } from \"../nips/nip44.ts\";\nimport {\n Nip46Error,\n decodeNip46Response,\n encodeNip46Request,\n parseBunkerURL,\n parseNostrConnectURI,\n} from \"../nips/nip46.ts\";\nimport type { BunkerPointer, ClientMetadata, Nip46Request } from \"../nips/nip46.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Subscribe options used by NIP-46 transport (structural subset of Pool). */\nexport type Nip46SubscribeOptions = {\n signal?: AbortSignal | undefined;\n onevent?: ((event: Event) => void) | undefined;\n onclose?: ((reason: string) => void) | undefined;\n};\n\n/**\n * Structural relay transport for NIP-46 RPC. Satisfied by {@link import(\"../relay/pool.ts\").Pool};\n * constructed above the signer layer so `signer` never imports `relay` (see AGENTS.md).\n */\nexport type Nip46Transport = {\n subscribe: (\n relays: ReadonlyArray<string>,\n filters: ReadonlyArray<Filter>,\n opts?: Nip46SubscribeOptions,\n ) => { close: (reason?: string) => void };\n publish: (\n relays: ReadonlyArray<string>,\n event: Event,\n ) => Promise<\n ReadonlyArray<{\n readonly status: \"ok\" | \"rejected\" | \"failed\";\n readonly message?: string;\n readonly error?: Error;\n }>\n >;\n close: () => void;\n};\n\n/** Options for {@link Nip46Signer}: transport, timeouts, and relay hints. */\nexport type Nip46SignerOptions = {\n /** Shared transport. When set, the signer does not close it on {@link Nip46Signer.close}. */\n pool?: Nip46Transport | undefined;\n /**\n * Factory for a private transport when `pool` is omitted. Typical: `() => new Pool({\n * websocketImplementation, enableReconnect: true })`.\n */\n createPool?: (() => Nip46Transport) | undefined;\n /**\n * Relays used when the bunker pointer has none, and merged uniquely onto a nonempty pointer\n * (pointer first).\n */\n relays?: ReadonlyArray<string> | undefined;\n /** Bunker connection secret when the pointer or bunker:// URL has none. */\n secret?: string | undefined;\n /** Local client key used to encrypt RPC (not the remote user key). */\n clientSecretKey?: SecretKeyInput | undefined;\n /** Called when bunker returns `auth_url` for a pending request. */\n onAuthUrl?: ((url: string) => void) | undefined;\n /** Per-request timeout in ms. Default 30s. */\n timeoutMs?: number | undefined;\n /**\n * Timeout in ms applied after the bunker replies `auth_url`: the request keeps waiting for the\n * real response until this elapses. Default 300s.\n */\n authTimeoutMs?: number | undefined;\n /** Requested permissions sent with `connect` (`method[:kind]` list). */\n perms?: ReadonlyArray<string> | undefined;\n /** Client metadata sent with bunker-initiated `connect`. */\n metadata?: ClientMetadata | undefined;\n};\n\nfunction resolveClientSecret(key?: SecretKeyInput): SecretKey {\n if (key === undefined) {\n return SecretKey.generate();\n }\n return toSecretKey(key);\n}\n\nfunction resolveTransport(opts: Nip46SignerOptions): { pool: Nip46Transport; ownsPool: boolean } {\n if (opts.pool) {\n return { pool: opts.pool, ownsPool: false };\n }\n if (opts.createPool) {\n return { pool: opts.createPool(), ownsPool: true };\n }\n throw new Nip46Error(\n \"Nip46Signer requires pool or createPool (inject Pool from @qntx/nostr/relay)\",\n );\n}\n\nfunction applyPointerOpts(pointer: BunkerPointer, opts: Nip46SignerOptions): BunkerPointer {\n let next: BunkerPointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n if (opts.secret !== undefined && next.secret === undefined) {\n next = { ...next, secret: opts.secret };\n }\n\n const relays = next.relays.length > 0 ? next.relays : [...(opts.relays ?? [])];\n if (relays.length === 0) {\n throw new Nip46Error(\"no relays for bunker connection\");\n }\n if (next.relays.length > 0 && opts.relays !== undefined && opts.relays.length > 0) {\n const merged = [...next.relays];\n for (const r of opts.relays) {\n if (!merged.includes(r)) {\n merged.push(r);\n }\n }\n return { ...next, relays: merged };\n }\n return { ...next, relays };\n}\n\nfunction resolveBunkerPointer(input: string | BunkerPointer): BunkerPointer {\n if (typeof input !== \"string\") {\n return {\n pubkey: input.pubkey.toLowerCase(),\n relays: [...input.relays],\n secret: input.secret,\n };\n }\n\n const bunker = parseBunkerURL(input);\n if (bunker) {\n return bunker;\n }\n\n throw new Nip46Error(\"invalid bunker input (expected bunker:// URL or BunkerPointer)\");\n}\n\ntype PendingRequest = {\n resolve: (v: string) => void;\n reject: (e: Error) => void;\n method: string;\n timer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * NIP-46 remote signer (bunker / nostrconnect). Implements {@link NostrSigner}; never holds the\n * remote user's secret key. Network I/O is injected via {@link Nip46Transport} (no relay import).\n */\nexport class Nip46Signer implements NostrSigner {\n readonly #pool: Nip46Transport;\n readonly #ownsPool: boolean;\n readonly #clientSecret: SecretKey;\n readonly #clientPubkey: string;\n readonly #pointer: BunkerPointer;\n readonly #conversationKey: Uint8Array;\n readonly #onAuthUrl: ((url: string) => void) | undefined;\n readonly #timeoutMs: number;\n readonly #authTimeoutMs: number;\n readonly #perms: ReadonlyArray<string> | undefined;\n readonly #metadata: ClientMetadata | undefined;\n #relays: string[];\n readonly #listeners = new Map<string, PendingRequest>();\n #sub: { close: (reason?: string) => void } | undefined;\n #open = false;\n #cachedRemotePubkey: string | undefined;\n\n private constructor(\n clientSecret: SecretKey,\n pointer: BunkerPointer,\n pool: Nip46Transport,\n ownsPool: boolean,\n opts: Nip46SignerOptions,\n ) {\n if (pointer.relays.length === 0) {\n throw new Nip46Error(\"bunker pointer has no relays\");\n }\n this.#clientSecret = clientSecret;\n this.#clientPubkey = getPublicKey(clientSecret);\n this.#pointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n this.#relays = [...pointer.relays];\n this.#pool = pool;\n this.#ownsPool = ownsPool;\n this.#conversationKey = getConversationKey(clientSecret.bytes, this.#pointer.pubkey);\n this.#onAuthUrl = opts.onAuthUrl;\n this.#timeoutMs = opts.timeoutMs ?? 30_000;\n this.#authTimeoutMs = opts.authTimeoutMs ?? 300_000;\n this.#perms = opts.perms;\n this.#metadata = opts.metadata;\n }\n\n get bunker(): Readonly<BunkerPointer> {\n return {\n pubkey: this.#pointer.pubkey,\n relays: [...this.#relays],\n secret: this.#pointer.secret,\n };\n }\n\n get clientPublicKey(): string {\n return this.#clientPubkey;\n }\n\n /**\n * Subscribe to an already-known bunker pointer. Does not send the `connect` RPC (reconnect\n * without a new handshake). Requires `clientSecretKey` — reconnect must reuse the original client\n * identity.\n */\n static fromBunker(\n pointer: BunkerPointer,\n opts: Nip46SignerOptions & { clientSecretKey: SecretKeyInput },\n ): Nip46Signer {\n if (opts.clientSecretKey === undefined) {\n throw new Nip46Error(\"fromBunker requires clientSecretKey\");\n }\n const resolved = applyPointerOpts(pointer, opts);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const { pool, ownsPool } = resolveTransport(opts);\n const signer = new Nip46Signer(sk, resolved, pool, ownsPool, opts);\n signer.#startSubscription();\n return signer;\n }\n\n /**\n * Connect using a `bunker://` URL or pre-parsed pointer. Invalid strings throw. A NIP-05\n * identifier is not a bunker pointer. When both pointer and `opts.relays` are nonempty, unique\n * `opts.relays` are appended.\n */\n static async connect(\n input: string | BunkerPointer,\n opts: Nip46SignerOptions = {},\n ): Promise<Nip46Signer> {\n const pointer = resolveBunkerPointer(input);\n const signer = Nip46Signer.fromBunker(pointer, {\n ...opts,\n clientSecretKey: resolveClientSecret(opts.clientSecretKey),\n });\n try {\n await signer.connectRemote();\n try {\n await signer.switchRelays();\n } catch {\n // Bunker may not implement switch_relays.\n }\n await signer.getPublicKey();\n return signer;\n } catch (error) {\n await signer.close();\n throw error;\n }\n }\n\n /**\n * Wait for a bunker to complete a client-initiated `nostrconnect://` handshake. Requires\n * `clientSecretKey` whose pubkey matches the URI client pubkey (build the URI with\n * {@link createNostrConnectURI} after generating keys).\n */\n static async fromNostrConnectURI(\n connectionURI: string,\n opts: Nip46SignerOptions & {\n clientSecretKey: SecretKeyInput;\n signal?: AbortSignal;\n handshakeTimeoutMs?: number;\n },\n ): Promise<Nip46Signer> {\n throwIfAborted(opts.signal);\n const params = parseNostrConnectURI(connectionURI);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const clientPubkey = getPublicKey(sk);\n\n if (clientPubkey !== params.clientPubkey) {\n throw new Nip46Error(\"client secret key does not match nostrconnect client pubkey\");\n }\n\n const { pool, ownsPool } = resolveTransport(opts);\n const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 300_000;\n\n return new Promise((resolve, reject) => {\n let settled = false;\n let handshaking = false;\n // `let` + later assignment: pool.subscribe may fire onclose synchronously (pre-aborted\n // signal via fanIn) before a const initializer would complete.\n // oxlint-disable-next-line prefer-const\n let sub: { close: (reason?: string) => void } | undefined;\n const finish = (err?: Error, signer?: Nip46Signer) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n sub?.close(err ? \"failed\" : \"connected\");\n if (err) {\n if (ownsPool) {\n pool.close();\n }\n reject(err);\n } else if (signer) {\n resolve(signer);\n }\n };\n\n const timer = setTimeout(() => {\n finish(new Nip46Error(\"nostrconnect handshake timed out\"));\n }, handshakeTimeoutMs);\n\n sub = pool.subscribe(\n params.relays,\n [{ kinds: [Kind.NostrConnect], \"#p\": [clientPubkey], limit: 0 }],\n {\n signal: opts.signal,\n onevent: (event) => {\n try {\n const convKey = getConversationKey(sk.bytes, event.pubkey);\n const payload = decrypt(event.content, convKey);\n const response = decodeNip46Response(payload);\n if (response.result !== params.secret) {\n return;\n }\n // A duplicate connect response must not spin up a second signer.\n if (handshaking) {\n return;\n }\n handshaking = true;\n\n const pointer: BunkerPointer = {\n pubkey: event.pubkey.toLowerCase(),\n relays: params.relays,\n secret: params.secret,\n };\n const signer = new Nip46Signer(sk, pointer, pool, ownsPool, opts);\n signer.#startSubscription();\n void (async () => {\n try {\n await signer.switchRelays();\n } catch {\n // Relay switch at connect time is best-effort.\n }\n try {\n await signer.getPublicKey();\n finish(undefined, signer);\n } catch (error: unknown) {\n // Do not leak the signer's subscription on a shared pool.\n await signer.close();\n finish(error instanceof Error ? error : new Nip46Error(String(error)));\n }\n })();\n } catch {\n // ignore non-matching events\n }\n },\n onclose: (reason) => {\n if (reason !== \"connected\" && reason !== \"failed\") {\n finish(new Nip46Error(`nostrconnect subscription closed: ${reason}`));\n }\n },\n },\n );\n });\n }\n\n #startSubscription(): void {\n this.#sub?.close();\n this.#sub = this.#pool.subscribe(\n this.#relays,\n [\n {\n kinds: [Kind.NostrConnect],\n authors: [this.#pointer.pubkey],\n \"#p\": [this.#clientPubkey],\n limit: 0,\n },\n ],\n {\n onevent: (event) => {\n try {\n const payload = decrypt(event.content, this.#conversationKey);\n const { id, result, error } = decodeNip46Response(payload);\n\n if (result === \"auth_url\" && this.#listeners.has(id)) {\n const listener = this.#listeners.get(id);\n if (!listener) {\n return;\n }\n if (error !== undefined && error !== \"\") {\n invokeSafely(() => this.#onAuthUrl?.(error));\n }\n clearTimeout(listener.timer);\n listener.timer = this.#requestTimer(id, listener, this.#authTimeoutMs);\n return;\n }\n\n const listener = this.#dropRequest(id);\n if (!listener) {\n return;\n }\n if (error !== undefined && error !== \"\") {\n listener.reject(new Nip46Error(error));\n } else if (result === undefined) {\n listener.reject(new Nip46Error(\"empty NIP-46 response\"));\n } else {\n listener.resolve(result);\n }\n } catch {\n // ignore decrypt failures from unrelated events\n }\n },\n onclose: () => {\n this.#sub = undefined;\n },\n },\n );\n this.#open = true;\n }\n\n async connectRemote(overrides?: {\n metadata?: ClientMetadata | undefined;\n perms?: ReadonlyArray<string> | undefined;\n }): Promise<void> {\n const metadata = overrides?.metadata ?? this.#metadata;\n const perms = overrides?.perms ?? this.#perms;\n const params = [this.#pointer.pubkey, this.#pointer.secret ?? \"\"];\n const hasPerms = perms !== undefined && perms.length > 0;\n if (hasPerms || metadata !== undefined) {\n params.push(hasPerms ? perms.join(\",\") : \"\");\n }\n if (metadata !== undefined) {\n params.push(JSON.stringify(metadata));\n }\n const result = await this.#sendRequest(\"connect\", params);\n if (result === \"ack\") {\n return;\n }\n const { secret } = this.#pointer;\n if (secret !== undefined && secret !== \"\" && result === secret) {\n return;\n }\n throw new Nip46Error(`connect result is not ack or secret: ${result}`);\n }\n\n /**\n * Ask the bunker for its preferred relay list and resubscribe when it changes. Spec result is a\n * JSON array of URLs, or `null` when nothing changes.\n */\n async switchRelays(): Promise<string[] | undefined> {\n const resp = await this.#sendRequest(\"switch_relays\", []);\n if (resp === \"null\") {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(resp);\n } catch (error) {\n throw new Nip46Error(\"invalid switch_relays JSON\", {\n cause: error,\n });\n }\n if (\n !Array.isArray(parsed) ||\n parsed.length === 0 ||\n !parsed.every((x) => typeof x === \"string\")\n ) {\n throw new Nip46Error(\"invalid switch_relays result\");\n }\n this.#relays = parsed;\n this.#startSubscription();\n return parsed;\n }\n\n /** Courtesy session teardown. Always closes the local signer afterwards. */\n async logout(): Promise<void> {\n try {\n const resp = await this.#sendRequest(\"logout\", []);\n if (resp !== \"ack\") {\n throw new Nip46Error(`logout result is not ack: ${resp}`);\n }\n } finally {\n await this.close();\n }\n }\n\n async ping(): Promise<void> {\n const resp = await this.#sendRequest(\"ping\", []);\n if (resp !== \"pong\") {\n throw new Nip46Error(`ping result is not pong: ${resp}`);\n }\n }\n\n async getPublicKey(): Promise<string> {\n if (this.#cachedRemotePubkey === undefined) {\n const pk = await this.#sendRequest(\"get_public_key\", []);\n if (!isHex32(pk.toLowerCase())) {\n throw new Nip46Error(\"bunker returned invalid pubkey\");\n }\n this.#cachedRemotePubkey = pk.toLowerCase();\n }\n return this.#cachedRemotePubkey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags,\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n const resp = await this.#sendRequest(\"sign_event\", [JSON.stringify(template)]);\n let signed: unknown;\n try {\n signed = JSON.parse(resp);\n } catch (error) {\n throw new Nip46Error(\"bunker returned invalid sign_event JSON\", {\n cause: error,\n });\n }\n if (!validateSignedEvent(signed) || !verifyEvent(signed)) {\n throw new Nip46Error(\"bunker returned improperly signed event\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new Nip46Error(\"signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip04_encrypt\", [peer, plaintext]);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return this.#sendRequest(\"nip04_decrypt\", [peer, ciphertext]);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip44_encrypt\", [peer, plaintext]);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return this.#sendRequest(\"nip44_decrypt\", [peer, payload]);\n }\n\n async close(): Promise<void> {\n this.#open = false;\n for (const [, listener] of this.#listeners) {\n clearTimeout(listener.timer);\n listener.reject(new Nip46Error(\"signer closed\"));\n }\n this.#listeners.clear();\n this.#sub?.close(\"signer closed\");\n this.#sub = undefined;\n if (this.#ownsPool) {\n this.#pool.close();\n }\n }\n\n async #sendRequest(method: string, params: string[]): Promise<string> {\n if (!this.#open) {\n throw new Nip46Error(\"signer is closed\");\n }\n if (!this.#sub) {\n this.#startSubscription();\n }\n\n const id = bytesToHex(randomBytes(16));\n const req: Nip46Request = { id, method, params };\n const encrypted = encrypt(encodeNip46Request(req), this.#conversationKey);\n\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [Tag.p(this.#pointer.pubkey)],\n content: encrypted,\n created_at: nowSeconds(),\n },\n this.#clientSecret,\n );\n\n const resultPromise = new Promise<string>((resolve, reject) => {\n const listener: PendingRequest = { resolve, reject, method };\n listener.timer = this.#requestTimer(id, listener, this.#timeoutMs);\n this.#listeners.set(id, listener);\n });\n\n let replies;\n try {\n replies = await this.#pool.publish(this.#relays, event);\n } catch (error) {\n this.#dropRequest(id);\n throw error;\n }\n if (!replies.some((reply) => reply.status === \"ok\")) {\n const listener = this.#dropRequest(id);\n const detail = replies\n .map((reply) => (reply.status === \"failed\" ? errorMessage(reply.error) : reply.message))\n .filter((message): message is string => Boolean(message))\n .join(\"; \");\n listener?.reject(new Nip46Error(`request not accepted by any relay: ${detail}`));\n }\n return resultPromise;\n }\n\n #dropRequest(id: string): PendingRequest | undefined {\n const listener = this.#listeners.get(id);\n if (!listener) {\n return undefined;\n }\n clearTimeout(listener.timer);\n this.#listeners.delete(id);\n return listener;\n }\n\n #requestTimer(id: string, listener: PendingRequest, ms: number): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n this.#dropRequest(id);\n listener.reject(new Nip46Error(`NIP-46 request timed out: ${listener.method}`));\n }, ms);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAQA,IAAa,aAAb,MAA+C;CAC7C;CACA,4BAAqB,IAAI,IAAwB;CAEjD,YAAY,WAAkC;EAC5C,KAAK,QAAQ,qBAAqB,OAAO,YAAY,KAAK,cAAc,SAAS;CACnF;CAEA,IAAI,OAAa;EACf,OAAO,KAAK;CACd;CAEA,MAAM,eAAgC;EACpC,OAAO,KAAK,MAAM;CACpB;CAEA,MAAM,UAAU,UAAyC;EACvD,OAAO,UAAU,UAAU,KAAK,KAAK;CACvC;CAEA,MAAM,aAAa,MAAc,WAAoC;EACnE,OAAOA,QAAc,KAAK,MAAM,UAAU,OAAO,MAAM,SAAS;CAClE;CAEA,MAAM,aAAa,MAAc,YAAqC;EACpE,OAAOC,QAAc,KAAK,MAAM,UAAU,OAAO,MAAM,UAAU;CACnE;CAEA,iBAAiB,MAA0B;EACzC,MAAM,KAAK,KAAK,YAAY;EAC5B,IAAI,MAAM,KAAK,UAAU,IAAI,EAAE;EAC/B,IAAI,CAAC,KAAK;GACR,MAAMC,mBAAyB,KAAK,MAAM,UAAU,OAAO,EAAE;GAC7D,KAAK,UAAU,IAAI,IAAI,GAAG;EAC5B;EACA,OAAO;CACT;CAEA,MAAM,aAAa,MAAc,WAAoC;EACnE,OAAOC,UAAc,WAAW,KAAK,iBAAiB,IAAI,CAAC;CAC7D;CAEA,MAAM,aAAa,MAAc,SAAkC;EACjE,OAAOC,UAAc,SAAS,KAAK,iBAAiB,IAAI,CAAC;CAC3D;AACF;;;;ACtBA,SAAgB,iBAA0C;CACxD,MAAM,IAAI;CACV,OAAO,EAAE,SAAS,EAAE,QAAQ;AAC9B;;AAGA,SAAgB,mBAA4B;CAC1C,MAAM,IAAI,eAAe;CACzB,OAAO,QAAQ,KAAK,OAAO,EAAE,iBAAiB,cAAc,OAAO,EAAE,cAAc,UAAU;AAC/F;;;;;AAMA,IAAa,cAAb,MAAgD;CAC9C;CAEA,YAAY,UAAwB;EAClC,KAAK,YAAY;CACnB;CAEA,WAAwB;EACtB,MAAM,WAAW,KAAK,aAAa,eAAe;EAClD,IAAI,CAAC,UACH,MAAM,IAAI,YAAY,sDAAsD;EAE9E,OAAO;CACT;CAEA,MAAM,eAAgC;EACpC,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC,CAAC,aAAa;EAC9C,IAAI;GACF,OAAO,YAAY,IAAI,QAAQ;EACjC,SAAS,OAAO;GACd,MAAM,IAAI,YAAY,kDAAkD,EACtE,OAAO,MACT,CAAC;EACH;CACF;CAEA,MAAM,UAAU,UAAyC;EACvD,MAAM,WAAW,KAAK,SAAS;EAC/B,MAAM,WAA0B;GAC9B,MAAM,SAAS;GACf,MAAM,SAAS,KAAK,KAAK,MAAM;IAC7B,MAAM,CAAC,MAAM,GAAG,QAAQ;IACxB,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,YAAY,iCAAiC;IAEzD,OAAO,CAAC,MAAM,GAAG,IAAI;GACvB,CAAC;GACD,SAAS,SAAS;GAClB,YAAY,SAAS;EACvB;EAEA,MAAM,SAAS,MAAM,SAAS,UAAU,QAAQ;EAChD,IAAI,CAAC,oBAAoB,MAAM,GAC7B,MAAM,IAAI,YAAY,4CAA4C;EAEpE,IAAI,CAAC,YAAY,MAAM,GACrB,MAAM,IAAI,YAAY,mDAAmD;EAE3E,IAAI,CAAC,sBAAsB,QAAQ,QAAQ,GACzC,MAAM,IAAI,YAAY,sDAAsD;EAE9E,OAAO;CACT;CAEA,MAAM,aAAa,MAAc,WAAoC;EACnE,MAAM,EAAE,UAAU,KAAK,SAAS;EAChC,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,YAAY,gDAAgD;EAExE,OAAO,MAAM,QAAQ,MAAM,SAAS;CACtC;CAEA,MAAM,aAAa,MAAc,YAAqC;EACpE,MAAM,EAAE,UAAU,KAAK,SAAS;EAChC,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,YAAY,gDAAgD;EAExE,OAAO,MAAM,QAAQ,MAAM,UAAU;CACvC;CAEA,MAAM,aAAa,MAAc,WAAoC;EACnE,MAAM,EAAE,UAAU,KAAK,SAAS;EAChC,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,YAAY,gDAAgD;EAExE,OAAO,MAAM,QAAQ,MAAM,SAAS;CACtC;CAEA,MAAM,aAAa,MAAc,SAAkC;EACjE,MAAM,EAAE,UAAU,KAAK,SAAS;EAChC,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,YAAY,gDAAgD;EAExE,OAAO,MAAM,QAAQ,MAAM,OAAO;CACpC;AACF;;;AC3CA,SAAS,oBAAoB,KAAiC;CAC5D,IAAI,QAAQ,KAAA,GACV,OAAO,UAAU,SAAS;CAE5B,OAAO,YAAY,GAAG;AACxB;AAEA,SAAS,iBAAiB,MAAuE;CAC/F,IAAI,KAAK,MACP,OAAO;EAAE,MAAM,KAAK;EAAM,UAAU;CAAM;CAE5C,IAAI,KAAK,YACP,OAAO;EAAE,MAAM,KAAK,WAAW;EAAG,UAAU;CAAK;CAEnD,MAAM,IAAI,WACR,8EACF;AACF;AAEA,SAAS,iBAAiB,SAAwB,MAAyC;CACzF,IAAI,OAAsB;EACxB,QAAQ,QAAQ,OAAO,YAAY;EACnC,QAAQ,CAAC,GAAG,QAAQ,MAAM;EAC1B,QAAQ,QAAQ;CAClB;CACA,IAAI,KAAK,WAAW,KAAA,KAAa,KAAK,WAAW,KAAA,GAC/C,OAAO;EAAE,GAAG;EAAM,QAAQ,KAAK;CAAO;CAGxC,MAAM,SAAS,KAAK,OAAO,SAAS,IAAI,KAAK,SAAS,CAAC,GAAI,KAAK,UAAU,CAAC,CAAE;CAC7E,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,WAAW,iCAAiC;CAExD,IAAI,KAAK,OAAO,SAAS,KAAK,KAAK,WAAW,KAAA,KAAa,KAAK,OAAO,SAAS,GAAG;EACjF,MAAM,SAAS,CAAC,GAAG,KAAK,MAAM;EAC9B,KAAK,MAAM,KAAK,KAAK,QACnB,IAAI,CAAC,OAAO,SAAS,CAAC,GACpB,OAAO,KAAK,CAAC;EAGjB,OAAO;GAAE,GAAG;GAAM,QAAQ;EAAO;CACnC;CACA,OAAO;EAAE,GAAG;EAAM;CAAO;AAC3B;AAEA,SAAS,qBAAqB,OAA8C;CAC1E,IAAI,OAAO,UAAU,UACnB,OAAO;EACL,QAAQ,MAAM,OAAO,YAAY;EACjC,QAAQ,CAAC,GAAG,MAAM,MAAM;EACxB,QAAQ,MAAM;CAChB;CAGF,MAAM,SAAS,eAAe,KAAK;CACnC,IAAI,QACF,OAAO;CAGT,MAAM,IAAI,WAAW,gEAAgE;AACvF;;;;;AAaA,IAAa,cAAb,MAAa,YAAmC;CAC9C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,6BAAsB,IAAI,IAA4B;CACtD;CACA,QAAQ;CACR;CAEA,YACE,cACA,SACA,MACA,UACA,MACA;EACA,IAAI,QAAQ,OAAO,WAAW,GAC5B,MAAM,IAAI,WAAW,8BAA8B;EAErD,KAAK,gBAAgB;EACrB,KAAK,gBAAgB,aAAa,YAAY;EAC9C,KAAK,WAAW;GACd,QAAQ,QAAQ,OAAO,YAAY;GACnC,QAAQ,CAAC,GAAG,QAAQ,MAAM;GAC1B,QAAQ,QAAQ;EAClB;EACA,KAAK,UAAU,CAAC,GAAG,QAAQ,MAAM;EACjC,KAAK,QAAQ;EACb,KAAK,YAAY;EACjB,KAAK,mBAAmB,mBAAmB,aAAa,OAAO,KAAK,SAAS,MAAM;EACnF,KAAK,aAAa,KAAK;EACvB,KAAK,aAAa,KAAK,aAAa;EACpC,KAAK,iBAAiB,KAAK,iBAAiB;EAC5C,KAAK,SAAS,KAAK;EACnB,KAAK,YAAY,KAAK;CACxB;CAEA,IAAI,SAAkC;EACpC,OAAO;GACL,QAAQ,KAAK,SAAS;GACtB,QAAQ,CAAC,GAAG,KAAK,OAAO;GACxB,QAAQ,KAAK,SAAS;EACxB;CACF;CAEA,IAAI,kBAA0B;EAC5B,OAAO,KAAK;CACd;;;;;;CAOA,OAAO,WACL,SACA,MACa;EACb,IAAI,KAAK,oBAAoB,KAAA,GAC3B,MAAM,IAAI,WAAW,qCAAqC;EAE5D,MAAM,WAAW,iBAAiB,SAAS,IAAI;EAC/C,MAAM,KAAK,oBAAoB,KAAK,eAAe;EACnD,MAAM,EAAE,MAAM,aAAa,iBAAiB,IAAI;EAChD,MAAM,SAAS,IAAI,YAAY,IAAI,UAAU,MAAM,UAAU,IAAI;EACjE,OAAO,mBAAmB;EAC1B,OAAO;CACT;;;;;;CAOA,aAAa,QACX,OACA,OAA2B,CAAC,GACN;EACtB,MAAM,UAAU,qBAAqB,KAAK;EAC1C,MAAM,SAAS,YAAY,WAAW,SAAS;GAC7C,GAAG;GACH,iBAAiB,oBAAoB,KAAK,eAAe;EAC3D,CAAC;EACD,IAAI;GACF,MAAM,OAAO,cAAc;GAC3B,IAAI;IACF,MAAM,OAAO,aAAa;GAC5B,QAAQ,CAER;GACA,MAAM,OAAO,aAAa;GAC1B,OAAO;EACT,SAAS,OAAO;GACd,MAAM,OAAO,MAAM;GACnB,MAAM;EACR;CACF;;;;;;CAOA,aAAa,oBACX,eACA,MAKsB;EACtB,eAAe,KAAK,MAAM;EAC1B,MAAM,SAAS,qBAAqB,aAAa;EACjD,MAAM,KAAK,oBAAoB,KAAK,eAAe;EACnD,MAAM,eAAe,aAAa,EAAE;EAEpC,IAAI,iBAAiB,OAAO,cAC1B,MAAM,IAAI,WAAW,6DAA6D;EAGpF,MAAM,EAAE,MAAM,aAAa,iBAAiB,IAAI;EAChD,MAAM,qBAAqB,KAAK,sBAAsB;EAEtD,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,UAAU;GACd,IAAI,cAAc;GAIlB,IAAI;GACJ,MAAM,UAAU,KAAa,WAAyB;IACpD,IAAI,SACF;IAEF,UAAU;IACV,aAAa,KAAK;IAClB,KAAK,MAAM,MAAM,WAAW,WAAW;IACvC,IAAI,KAAK;KACP,IAAI,UACF,KAAK,MAAM;KAEb,OAAO,GAAG;IACZ,OAAO,IAAI,QACT,QAAQ,MAAM;GAElB;GAEA,MAAM,QAAQ,iBAAiB;IAC7B,OAAO,IAAI,WAAW,kCAAkC,CAAC;GAC3D,GAAG,kBAAkB;GAErB,MAAM,KAAK,UACT,OAAO,QACP,CAAC;IAAE,OAAO,CAAC,KAAK,YAAY;IAAG,MAAM,CAAC,YAAY;IAAG,OAAO;GAAE,CAAC,GAC/D;IACE,QAAQ,KAAK;IACb,UAAU,UAAU;KAClB,IAAI;MACF,MAAM,UAAU,mBAAmB,GAAG,OAAO,MAAM,MAAM;MACzD,MAAM,UAAUC,UAAQ,MAAM,SAAS,OAAO;MAE9C,IADiB,oBAAoB,OAC1B,CAAC,CAAC,WAAW,OAAO,QAC7B;MAGF,IAAI,aACF;MAEF,cAAc;MAEd,MAAM,UAAyB;OAC7B,QAAQ,MAAM,OAAO,YAAY;OACjC,QAAQ,OAAO;OACf,QAAQ,OAAO;MACjB;MACA,MAAM,SAAS,IAAI,YAAY,IAAI,SAAS,MAAM,UAAU,IAAI;MAChE,OAAO,mBAAmB;MAC1B,CAAM,YAAY;OAChB,IAAI;QACF,MAAM,OAAO,aAAa;OAC5B,QAAQ,CAER;OACA,IAAI;QACF,MAAM,OAAO,aAAa;QAC1B,OAAO,KAAA,GAAW,MAAM;OAC1B,SAAS,OAAgB;QAEvB,MAAM,OAAO,MAAM;QACnB,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,WAAW,OAAO,KAAK,CAAC,CAAC;OACvE;MACF,EAAA,CAAG;KACL,QAAQ,CAER;IACF;IACA,UAAU,WAAW;KACnB,IAAI,WAAW,eAAe,WAAW,UACvC,OAAO,IAAI,WAAW,qCAAqC,QAAQ,CAAC;IAExE;GACF,CACF;EACF,CAAC;CACH;CAEA,qBAA2B;EACzB,KAAK,MAAM,MAAM;EACjB,KAAK,OAAO,KAAK,MAAM,UACrB,KAAK,SACL,CACE;GACE,OAAO,CAAC,KAAK,YAAY;GACzB,SAAS,CAAC,KAAK,SAAS,MAAM;GAC9B,MAAM,CAAC,KAAK,aAAa;GACzB,OAAO;EACT,CACF,GACA;GACE,UAAU,UAAU;IAClB,IAAI;KACF,MAAM,UAAUA,UAAQ,MAAM,SAAS,KAAK,gBAAgB;KAC5D,MAAM,EAAE,IAAI,QAAQ,UAAU,oBAAoB,OAAO;KAEzD,IAAI,WAAW,cAAc,KAAK,WAAW,IAAI,EAAE,GAAG;MACpD,MAAM,WAAW,KAAK,WAAW,IAAI,EAAE;MACvC,IAAI,CAAC,UACH;MAEF,IAAI,UAAU,KAAA,KAAa,UAAU,IACnC,mBAAmB,KAAK,aAAa,KAAK,CAAC;MAE7C,aAAa,SAAS,KAAK;MAC3B,SAAS,QAAQ,KAAK,cAAc,IAAI,UAAU,KAAK,cAAc;MACrE;KACF;KAEA,MAAM,WAAW,KAAK,aAAa,EAAE;KACrC,IAAI,CAAC,UACH;KAEF,IAAI,UAAU,KAAA,KAAa,UAAU,IACnC,SAAS,OAAO,IAAI,WAAW,KAAK,CAAC;UAChC,IAAI,WAAW,KAAA,GACpB,SAAS,OAAO,IAAI,WAAW,uBAAuB,CAAC;UAEvD,SAAS,QAAQ,MAAM;IAE3B,QAAQ,CAER;GACF;GACA,eAAe;IACb,KAAK,OAAO,KAAA;GACd;EACF,CACF;EACA,KAAK,QAAQ;CACf;CAEA,MAAM,cAAc,WAGF;EAChB,MAAM,WAAW,WAAW,YAAY,KAAK;EAC7C,MAAM,QAAQ,WAAW,SAAS,KAAK;EACvC,MAAM,SAAS,CAAC,KAAK,SAAS,QAAQ,KAAK,SAAS,UAAU,EAAE;EAChE,MAAM,WAAW,UAAU,KAAA,KAAa,MAAM,SAAS;EACvD,IAAI,YAAY,aAAa,KAAA,GAC3B,OAAO,KAAK,WAAW,MAAM,KAAK,GAAG,IAAI,EAAE;EAE7C,IAAI,aAAa,KAAA,GACf,OAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;EAEtC,MAAM,SAAS,MAAM,KAAK,aAAa,WAAW,MAAM;EACxD,IAAI,WAAW,OACb;EAEF,MAAM,EAAE,WAAW,KAAK;EACxB,IAAI,WAAW,KAAA,KAAa,WAAW,MAAM,WAAW,QACtD;EAEF,MAAM,IAAI,WAAW,wCAAwC,QAAQ;CACvE;;;;;CAMA,MAAM,eAA8C;EAClD,MAAM,OAAO,MAAM,KAAK,aAAa,iBAAiB,CAAC,CAAC;EACxD,IAAI,SAAS,QACX;EAEF,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,IAAI;EAC1B,SAAS,OAAO;GACd,MAAM,IAAI,WAAW,8BAA8B,EACjD,OAAO,MACT,CAAC;EACH;EACA,IACE,CAAC,MAAM,QAAQ,MAAM,KACrB,OAAO,WAAW,KAClB,CAAC,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ,GAE1C,MAAM,IAAI,WAAW,8BAA8B;EAErD,KAAK,UAAU;EACf,KAAK,mBAAmB;EACxB,OAAO;CACT;;CAGA,MAAM,SAAwB;EAC5B,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,aAAa,UAAU,CAAC,CAAC;GACjD,IAAI,SAAS,OACX,MAAM,IAAI,WAAW,6BAA6B,MAAM;EAE5D,UAAU;GACR,MAAM,KAAK,MAAM;EACnB;CACF;CAEA,MAAM,OAAsB;EAC1B,MAAM,OAAO,MAAM,KAAK,aAAa,QAAQ,CAAC,CAAC;EAC/C,IAAI,SAAS,QACX,MAAM,IAAI,WAAW,4BAA4B,MAAM;CAE3D;CAEA,MAAM,eAAgC;EACpC,IAAI,KAAK,wBAAwB,KAAA,GAAW;GAC1C,MAAM,KAAK,MAAM,KAAK,aAAa,kBAAkB,CAAC,CAAC;GACvD,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC,GAC3B,MAAM,IAAI,WAAW,gCAAgC;GAEvD,KAAK,sBAAsB,GAAG,YAAY;EAC5C;EACA,OAAO,KAAK;CACd;CAEA,MAAM,UAAU,UAAyC;EACvD,MAAM,WAA0B;GAC9B,MAAM,SAAS;GACf,MAAM,SAAS;GACf,SAAS,SAAS;GAClB,YAAY,SAAS;EACvB;EACA,MAAM,OAAO,MAAM,KAAK,aAAa,cAAc,CAAC,KAAK,UAAU,QAAQ,CAAC,CAAC;EAC7E,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,IAAI;EAC1B,SAAS,OAAO;GACd,MAAM,IAAI,WAAW,2CAA2C,EAC9D,OAAO,MACT,CAAC;EACH;EACA,IAAI,CAAC,oBAAoB,MAAM,KAAK,CAAC,YAAY,MAAM,GACrD,MAAM,IAAI,WAAW,yCAAyC;EAEhE,IAAI,CAAC,sBAAsB,QAAQ,QAAQ,GACzC,MAAM,IAAI,WAAW,+CAA+C;EAEtE,OAAO;CACT;CAEA,MAAM,aAAa,MAAc,WAAoC;EACnE,OAAO,KAAK,aAAa,iBAAiB,CAAC,MAAM,SAAS,CAAC;CAC7D;CAEA,MAAM,aAAa,MAAc,YAAqC;EACpE,OAAO,KAAK,aAAa,iBAAiB,CAAC,MAAM,UAAU,CAAC;CAC9D;CAEA,MAAM,aAAa,MAAc,WAAoC;EACnE,OAAO,KAAK,aAAa,iBAAiB,CAAC,MAAM,SAAS,CAAC;CAC7D;CAEA,MAAM,aAAa,MAAc,SAAkC;EACjE,OAAO,KAAK,aAAa,iBAAiB,CAAC,MAAM,OAAO,CAAC;CAC3D;CAEA,MAAM,QAAuB;EAC3B,KAAK,QAAQ;EACb,KAAK,MAAM,GAAG,aAAa,KAAK,YAAY;GAC1C,aAAa,SAAS,KAAK;GAC3B,SAAS,OAAO,IAAI,WAAW,eAAe,CAAC;EACjD;EACA,KAAK,WAAW,MAAM;EACtB,KAAK,MAAM,MAAM,eAAe;EAChC,KAAK,OAAO,KAAA;EACZ,IAAI,KAAK,WACP,KAAK,MAAM,MAAM;CAErB;CAEA,MAAM,aAAa,QAAgB,QAAmC;EACpE,IAAI,CAAC,KAAK,OACR,MAAM,IAAI,WAAW,kBAAkB;EAEzC,IAAI,CAAC,KAAK,MACR,KAAK,mBAAmB;EAG1B,MAAM,KAAKC,aAAW,YAAY,EAAE,CAAC;EAErC,MAAM,YAAYC,UAAQ,mBAAmB;GADjB;GAAI;GAAQ;EACO,CAAC,GAAG,KAAK,gBAAgB;EAExE,MAAM,QAAQ,cACZ;GACE,MAAM,KAAK;GACX,MAAM,CAAC,IAAI,EAAE,KAAK,SAAS,MAAM,CAAC;GAClC,SAAS;GACT,YAAY,WAAW;EACzB,GACA,KAAK,aACP;EAEA,MAAM,gBAAgB,IAAI,SAAiB,SAAS,WAAW;GAC7D,MAAM,WAA2B;IAAE;IAAS;IAAQ;GAAO;GAC3D,SAAS,QAAQ,KAAK,cAAc,IAAI,UAAU,KAAK,UAAU;GACjE,KAAK,WAAW,IAAI,IAAI,QAAQ;EAClC,CAAC;EAED,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,KAAK,MAAM,QAAQ,KAAK,SAAS,KAAK;EACxD,SAAS,OAAO;GACd,KAAK,aAAa,EAAE;GACpB,MAAM;EACR;EACA,IAAI,CAAC,QAAQ,MAAM,UAAU,MAAM,WAAW,IAAI,GAAG;GACnD,MAAM,WAAW,KAAK,aAAa,EAAE;GACrC,MAAM,SAAS,QACZ,KAAK,UAAW,MAAM,WAAW,WAAW,aAAa,MAAM,KAAK,IAAI,MAAM,OAAQ,CAAC,CACvF,QAAQ,YAA+B,QAAQ,OAAO,CAAC,CAAC,CACxD,KAAK,IAAI;GACZ,UAAU,OAAO,IAAI,WAAW,sCAAsC,QAAQ,CAAC;EACjF;EACA,OAAO;CACT;CAEA,aAAa,IAAwC;EACnD,MAAM,WAAW,KAAK,WAAW,IAAI,EAAE;EACvC,IAAI,CAAC,UACH;EAEF,aAAa,SAAS,KAAK;EAC3B,KAAK,WAAW,OAAO,EAAE;EACzB,OAAO;CACT;CAEA,cAAc,IAAY,UAA0B,IAA2C;EAC7F,OAAO,iBAAiB;GACtB,KAAK,aAAa,EAAE;GACpB,SAAS,OAAO,IAAI,WAAW,6BAA6B,SAAS,QAAQ,CAAC;EAChF,GAAG,EAAE;CACP;AACF"}
|
|
1
|
+
{"version":3,"file":"signer-CWtxpOxc.mjs","names":["nip04.encrypt","nip04.decrypt","nip44.getConversationKey","nip44.encrypt","nip44.decrypt","decrypt","bytesToHex","encrypt"],"sources":["../src/signer/keys.ts","../src/signer/nip07.ts","../src/signer/nip46.ts"],"sourcesContent":["import type { Event, UnsignedEvent } from \"../core/event.ts\";\nimport type { SecretKeyInput } from \"../core/key.ts\";\nimport { Keys, signEvent } from \"../core/key.ts\";\nimport * as nip04 from \"../nips/nip04.ts\";\nimport * as nip44 from \"../nips/nip44.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Local secret-key signer with NIP-04 (legacy) and NIP-44 support. */\nexport class KeysSigner implements NostrSigner {\n readonly #keys: Keys;\n readonly #convKeys = new Map<string, Uint8Array>();\n\n constructor(secretKey: SecretKeyInput | Keys) {\n this.#keys = secretKey instanceof Keys ? secretKey : Keys.fromSecretKey(secretKey);\n }\n\n get keys(): Keys {\n return this.#keys;\n }\n\n async getPublicKey(): Promise<string> {\n return this.#keys.publicKey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n return signEvent(unsigned, this.#keys);\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip04.encrypt(this.#keys.secretKey.bytes, peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return nip04.decrypt(this.#keys.secretKey.bytes, peer, ciphertext);\n }\n\n #conversationKey(peer: string): Uint8Array {\n const pk = peer.toLowerCase();\n let key = this.#convKeys.get(pk);\n if (!key) {\n key = nip44.getConversationKey(this.#keys.secretKey.bytes, pk);\n this.#convKeys.set(pk, key);\n }\n return key;\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return nip44.encrypt(plaintext, this.#conversationKey(peer));\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return nip44.decrypt(payload, this.#conversationKey(peer));\n }\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport { assertHex32 } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/**\n * Minimal NIP-07 provider surface (browser extension `window.nostr`).\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/07.md\n */\nexport type WindowNostr = {\n getPublicKey: () => Promise<string>;\n signEvent: (event: EventTemplate) => Promise<Event>;\n nip04?: {\n encrypt: (pubkey: string, plaintext: string) => Promise<string>;\n decrypt: (pubkey: string, ciphertext: string) => Promise<string>;\n };\n nip44?: {\n encrypt: (pubkey: string, plaintext: string) => Promise<string>;\n decrypt: (pubkey: string, ciphertext: string) => Promise<string>;\n };\n};\n\ntype GlobalWithNostr = typeof globalThis & {\n nostr?: WindowNostr;\n window?: { nostr?: WindowNostr };\n};\n\n/** Resolve `window.nostr` / `globalThis.nostr` when present. */\nexport function getWindowNostr(): WindowNostr | undefined {\n const g = globalThis as GlobalWithNostr;\n return g.nostr ?? g.window?.nostr;\n}\n\n/** True when a NIP-07 provider is injected in the current environment. */\nexport function isNip07Available(): boolean {\n const n = getWindowNostr();\n return Boolean(n && typeof n.getPublicKey === \"function\" && typeof n.signEvent === \"function\");\n}\n\n/**\n * Signer backed by a NIP-07 browser extension (or any injected provider). Never holds secret keys\n * in-process.\n */\nexport class Nip07Signer implements NostrSigner {\n readonly #provider: WindowNostr | undefined;\n\n constructor(provider?: WindowNostr) {\n this.#provider = provider;\n }\n\n #resolve(): WindowNostr {\n const provider = this.#provider ?? getWindowNostr();\n if (!provider) {\n throw new CryptoError(\"NIP-07 provider not available (window.nostr missing)\");\n }\n return provider;\n }\n\n async getPublicKey(): Promise<string> {\n const pk = await this.#resolve().getPublicKey();\n try {\n return assertHex32(pk, \"pubkey\");\n } catch (error) {\n throw new CryptoError(\"NIP-07 getPublicKey returned an invalid pubkey\", {\n cause: error,\n });\n }\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const provider = this.#resolve();\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags.map((t) => {\n const [name, ...rest] = t;\n if (name === undefined) {\n throw new CryptoError(\"unsigned event has an empty tag\");\n }\n return [name, ...rest];\n }),\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n\n const signed = await provider.signEvent(template);\n if (!validateSignedEvent(signed)) {\n throw new CryptoError(\"NIP-07 signEvent returned an invalid event\");\n }\n if (!verifyEvent(signed)) {\n throw new CryptoError(\"NIP-07 signed event failed signature verification\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new CryptoError(\"NIP-07 signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n const { nip04 } = this.#resolve();\n if (!nip04?.encrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip04.encrypt\");\n }\n return nip04.encrypt(peer, plaintext);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n const { nip04 } = this.#resolve();\n if (!nip04?.decrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip04.decrypt\");\n }\n return nip04.decrypt(peer, ciphertext);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n const { nip44 } = this.#resolve();\n if (!nip44?.encrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip44.encrypt\");\n }\n return nip44.encrypt(peer, plaintext);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n const { nip44 } = this.#resolve();\n if (!nip44?.decrypt) {\n throw new CryptoError(\"NIP-07 provider does not support nip44.decrypt\");\n }\n return nip44.decrypt(peer, payload);\n }\n}\n","import { randomBytes } from \"@noble/hashes/utils.js\";\n\nimport { throwIfAborted } from \"../core/abort.ts\";\nimport { errorMessage } from \"../core/error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { signedMatchesUnsigned, validateSignedEvent } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { SecretKey, finalizeEvent, getPublicKey, toSecretKey } from \"../core/key.ts\";\nimport type { SecretKeyInput } from \"../core/key.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { Tag } from \"../core/tag.ts\";\nimport { bytesToHex, isHex32, nowSeconds } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport { decrypt, encrypt, getConversationKey } from \"../nips/nip44.ts\";\nimport {\n Nip46Error,\n decodeNip46Response,\n encodeNip46Request,\n parseBunkerURL,\n parseNostrConnectURI,\n} from \"../nips/nip46.ts\";\nimport type { BunkerPointer, ClientMetadata, Nip46Request } from \"../nips/nip46.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/** Subscribe options used by NIP-46 transport (structural subset of Pool). */\nexport type Nip46SubscribeOptions = {\n signal?: AbortSignal | undefined;\n onevent?: ((event: Event) => void) | undefined;\n onclose?: ((reason: string) => void) | undefined;\n};\n\n/**\n * Structural relay transport for NIP-46 RPC. Satisfied by {@link import(\"../relay/pool.ts\").Pool};\n * constructed above the signer layer so `signer` never imports `relay` (see AGENTS.md).\n */\nexport type Nip46Transport = {\n subscribe: (\n relays: ReadonlyArray<string>,\n filters: ReadonlyArray<Filter>,\n opts?: Nip46SubscribeOptions,\n ) => { close: (reason?: string) => void };\n publish: (\n relays: ReadonlyArray<string>,\n event: Event,\n ) => Promise<\n ReadonlyArray<{\n readonly status: \"ok\" | \"rejected\" | \"failed\";\n readonly message?: string;\n readonly error?: Error;\n }>\n >;\n close: () => void;\n};\n\n/** Options for {@link Nip46Signer}: transport, timeouts, and relay hints. */\nexport type Nip46SignerOptions = {\n /** Shared transport. When set, the signer does not close it on {@link Nip46Signer.close}. */\n pool?: Nip46Transport | undefined;\n /**\n * Factory for a private transport when `pool` is omitted. Typical: `() => new Pool({\n * websocketImplementation, enableReconnect: true })`.\n */\n createPool?: (() => Nip46Transport) | undefined;\n /**\n * Relays used when the bunker pointer has none, and merged uniquely onto a nonempty pointer\n * (pointer first).\n */\n relays?: ReadonlyArray<string> | undefined;\n /** Bunker connection secret when the pointer or bunker:// URL has none. */\n secret?: string | undefined;\n /** Local client key used to encrypt RPC (not the remote user key). */\n clientSecretKey?: SecretKeyInput | undefined;\n /** Called when bunker returns `auth_url` for a pending request. */\n onAuthUrl?: ((url: string) => void) | undefined;\n /** Per-request timeout in ms. Default 30s. */\n timeoutMs?: number | undefined;\n /**\n * Timeout in ms applied after the bunker replies `auth_url`: the request keeps waiting for the\n * real response until this elapses. Default 300s.\n */\n authTimeoutMs?: number | undefined;\n /** Requested permissions sent with `connect` (`method[:kind]` list). */\n perms?: ReadonlyArray<string> | undefined;\n /** Client metadata sent with bunker-initiated `connect`. */\n metadata?: ClientMetadata | undefined;\n};\n\nfunction resolveClientSecret(key?: SecretKeyInput): SecretKey {\n if (key === undefined) {\n return SecretKey.generate();\n }\n return toSecretKey(key);\n}\n\nfunction resolveTransport(opts: Nip46SignerOptions): { pool: Nip46Transport; ownsPool: boolean } {\n if (opts.pool) {\n return { pool: opts.pool, ownsPool: false };\n }\n if (opts.createPool) {\n return { pool: opts.createPool(), ownsPool: true };\n }\n throw new Nip46Error(\n \"Nip46Signer requires pool or createPool (inject Pool from @qntx/nostr/relay)\",\n );\n}\n\nfunction applyPointerOpts(pointer: BunkerPointer, opts: Nip46SignerOptions): BunkerPointer {\n let next: BunkerPointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n if (opts.secret !== undefined && next.secret === undefined) {\n next = { ...next, secret: opts.secret };\n }\n\n const relays = next.relays.length > 0 ? next.relays : [...(opts.relays ?? [])];\n if (relays.length === 0) {\n throw new Nip46Error(\"no relays for bunker connection\");\n }\n if (next.relays.length > 0 && opts.relays !== undefined && opts.relays.length > 0) {\n const merged = [...next.relays];\n for (const r of opts.relays) {\n if (!merged.includes(r)) {\n merged.push(r);\n }\n }\n return { ...next, relays: merged };\n }\n return { ...next, relays };\n}\n\nfunction resolveBunkerPointer(input: string | BunkerPointer): BunkerPointer {\n if (typeof input !== \"string\") {\n return {\n pubkey: input.pubkey.toLowerCase(),\n relays: [...input.relays],\n secret: input.secret,\n };\n }\n\n const bunker = parseBunkerURL(input);\n if (bunker) {\n return bunker;\n }\n\n throw new Nip46Error(\"invalid bunker input (expected bunker:// URL or BunkerPointer)\");\n}\n\ntype PendingRequest = {\n resolve: (v: string) => void;\n reject: (e: Error) => void;\n method: string;\n timer?: ReturnType<typeof setTimeout>;\n};\n\n/**\n * NIP-46 remote signer (bunker / nostrconnect). Implements {@link NostrSigner}; never holds the\n * remote user's secret key. Network I/O is injected via {@link Nip46Transport} (no relay import).\n */\nexport class Nip46Signer implements NostrSigner {\n readonly #pool: Nip46Transport;\n readonly #ownsPool: boolean;\n readonly #clientSecret: SecretKey;\n readonly #clientPubkey: string;\n readonly #pointer: BunkerPointer;\n readonly #conversationKey: Uint8Array;\n readonly #onAuthUrl: ((url: string) => void) | undefined;\n readonly #timeoutMs: number;\n readonly #authTimeoutMs: number;\n readonly #perms: ReadonlyArray<string> | undefined;\n readonly #metadata: ClientMetadata | undefined;\n #relays: string[];\n readonly #listeners = new Map<string, PendingRequest>();\n #sub: { close: (reason?: string) => void } | undefined;\n #open = false;\n #cachedRemotePubkey: string | undefined;\n\n private constructor(\n clientSecret: SecretKey,\n pointer: BunkerPointer,\n pool: Nip46Transport,\n ownsPool: boolean,\n opts: Nip46SignerOptions,\n ) {\n if (pointer.relays.length === 0) {\n throw new Nip46Error(\"bunker pointer has no relays\");\n }\n this.#clientSecret = clientSecret;\n this.#clientPubkey = getPublicKey(clientSecret);\n this.#pointer = {\n pubkey: pointer.pubkey.toLowerCase(),\n relays: [...pointer.relays],\n secret: pointer.secret,\n };\n this.#relays = [...pointer.relays];\n this.#pool = pool;\n this.#ownsPool = ownsPool;\n this.#conversationKey = getConversationKey(clientSecret.bytes, this.#pointer.pubkey);\n this.#onAuthUrl = opts.onAuthUrl;\n this.#timeoutMs = opts.timeoutMs ?? 30_000;\n this.#authTimeoutMs = opts.authTimeoutMs ?? 300_000;\n this.#perms = opts.perms;\n this.#metadata = opts.metadata;\n }\n\n get bunker(): Readonly<BunkerPointer> {\n return {\n pubkey: this.#pointer.pubkey,\n relays: [...this.#relays],\n secret: this.#pointer.secret,\n };\n }\n\n get clientPublicKey(): string {\n return this.#clientPubkey;\n }\n\n /**\n * Subscribe to an already-known bunker pointer. Does not send the `connect` RPC (reconnect\n * without a new handshake). Requires `clientSecretKey` — reconnect must reuse the original client\n * identity.\n */\n static fromBunker(\n pointer: BunkerPointer,\n opts: Nip46SignerOptions & { clientSecretKey: SecretKeyInput },\n ): Nip46Signer {\n if (opts.clientSecretKey === undefined) {\n throw new Nip46Error(\"fromBunker requires clientSecretKey\");\n }\n const resolved = applyPointerOpts(pointer, opts);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const { pool, ownsPool } = resolveTransport(opts);\n const signer = new Nip46Signer(sk, resolved, pool, ownsPool, opts);\n signer.#startSubscription();\n return signer;\n }\n\n /**\n * Connect using a `bunker://` URL or pre-parsed pointer. Invalid strings throw. A NIP-05\n * identifier is not a bunker pointer. When both pointer and `opts.relays` are nonempty, unique\n * `opts.relays` are appended.\n */\n static async connect(\n input: string | BunkerPointer,\n opts: Nip46SignerOptions = {},\n ): Promise<Nip46Signer> {\n const pointer = resolveBunkerPointer(input);\n const signer = Nip46Signer.fromBunker(pointer, {\n ...opts,\n clientSecretKey: resolveClientSecret(opts.clientSecretKey),\n });\n try {\n await signer.connectRemote();\n try {\n await signer.switchRelays();\n } catch {\n // Bunker may not implement switch_relays.\n }\n await signer.getPublicKey();\n return signer;\n } catch (error) {\n await signer.close();\n throw error;\n }\n }\n\n /**\n * Wait for a bunker to complete a client-initiated `nostrconnect://` handshake. Requires\n * `clientSecretKey` whose pubkey matches the URI client pubkey (build the URI with\n * {@link createNostrConnectURI} after generating keys).\n */\n static async fromNostrConnectURI(\n connectionURI: string,\n opts: Nip46SignerOptions & {\n clientSecretKey: SecretKeyInput;\n signal?: AbortSignal;\n handshakeTimeoutMs?: number;\n },\n ): Promise<Nip46Signer> {\n throwIfAborted(opts.signal);\n const params = parseNostrConnectURI(connectionURI);\n const sk = resolveClientSecret(opts.clientSecretKey);\n const clientPubkey = getPublicKey(sk);\n\n if (clientPubkey !== params.clientPubkey) {\n throw new Nip46Error(\"client secret key does not match nostrconnect client pubkey\");\n }\n\n const { pool, ownsPool } = resolveTransport(opts);\n const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 300_000;\n\n return new Promise((resolve, reject) => {\n let settled = false;\n let handshaking = false;\n // `let` + later assignment: pool.subscribe may fire onclose synchronously (pre-aborted\n // signal via fanIn) before a const initializer would complete.\n // oxlint-disable-next-line prefer-const\n let sub: { close: (reason?: string) => void } | undefined;\n const finish = (err?: Error, signer?: Nip46Signer) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n sub?.close(err ? \"failed\" : \"connected\");\n if (err) {\n if (ownsPool) {\n pool.close();\n }\n reject(err);\n } else if (signer) {\n resolve(signer);\n }\n };\n\n const timer = setTimeout(() => {\n finish(new Nip46Error(\"nostrconnect handshake timed out\"));\n }, handshakeTimeoutMs);\n\n sub = pool.subscribe(\n params.relays,\n [{ kinds: [Kind.NostrConnect], \"#p\": [clientPubkey], limit: 0 }],\n {\n signal: opts.signal,\n onevent: (event) => {\n try {\n const convKey = getConversationKey(sk.bytes, event.pubkey);\n const payload = decrypt(event.content, convKey);\n const response = decodeNip46Response(payload);\n if (response.result !== params.secret) {\n return;\n }\n // A duplicate connect response must not spin up a second signer.\n if (handshaking) {\n return;\n }\n handshaking = true;\n\n const pointer: BunkerPointer = {\n pubkey: event.pubkey.toLowerCase(),\n relays: params.relays,\n secret: params.secret,\n };\n const signer = new Nip46Signer(sk, pointer, pool, ownsPool, opts);\n signer.#startSubscription();\n void (async () => {\n try {\n await signer.switchRelays();\n } catch {\n // Relay switch at connect time is best-effort.\n }\n try {\n await signer.getPublicKey();\n finish(undefined, signer);\n } catch (error: unknown) {\n // Do not leak the signer's subscription on a shared pool.\n await signer.close();\n finish(error instanceof Error ? error : new Nip46Error(String(error)));\n }\n })();\n } catch {\n // ignore non-matching events\n }\n },\n onclose: (reason) => {\n if (reason !== \"connected\" && reason !== \"failed\") {\n finish(new Nip46Error(`nostrconnect subscription closed: ${reason}`));\n }\n },\n },\n );\n });\n }\n\n #startSubscription(): void {\n this.#sub?.close();\n this.#sub = this.#pool.subscribe(\n this.#relays,\n [\n {\n kinds: [Kind.NostrConnect],\n authors: [this.#pointer.pubkey],\n \"#p\": [this.#clientPubkey],\n limit: 0,\n },\n ],\n {\n onevent: (event) => {\n try {\n const payload = decrypt(event.content, this.#conversationKey);\n const { id, result, error } = decodeNip46Response(payload);\n\n if (result === \"auth_url\" && this.#listeners.has(id)) {\n const listener = this.#listeners.get(id);\n if (!listener) {\n return;\n }\n if (error !== undefined && error !== \"\") {\n invokeSafely(() => this.#onAuthUrl?.(error));\n }\n clearTimeout(listener.timer);\n listener.timer = this.#requestTimer(id, listener, this.#authTimeoutMs);\n return;\n }\n\n const listener = this.#dropRequest(id);\n if (!listener) {\n return;\n }\n if (error !== undefined && error !== \"\") {\n listener.reject(new Nip46Error(error));\n } else if (result === undefined) {\n listener.reject(new Nip46Error(\"empty NIP-46 response\"));\n } else {\n listener.resolve(result);\n }\n } catch {\n // ignore decrypt failures from unrelated events\n }\n },\n onclose: () => {\n this.#sub = undefined;\n },\n },\n );\n this.#open = true;\n }\n\n async connectRemote(overrides?: {\n metadata?: ClientMetadata | undefined;\n perms?: ReadonlyArray<string> | undefined;\n }): Promise<void> {\n const metadata = overrides?.metadata ?? this.#metadata;\n const perms = overrides?.perms ?? this.#perms;\n const params = [this.#pointer.pubkey, this.#pointer.secret ?? \"\"];\n const hasPerms = perms !== undefined && perms.length > 0;\n if (hasPerms || metadata !== undefined) {\n params.push(hasPerms ? perms.join(\",\") : \"\");\n }\n if (metadata !== undefined) {\n params.push(JSON.stringify(metadata));\n }\n const result = await this.#sendRequest(\"connect\", params);\n if (result === \"ack\") {\n return;\n }\n const { secret } = this.#pointer;\n if (secret !== undefined && secret !== \"\" && result === secret) {\n return;\n }\n throw new Nip46Error(`connect result is not ack or secret: ${result}`);\n }\n\n /**\n * Ask the bunker for its preferred relay list and resubscribe when it changes. Spec result is a\n * JSON array of URLs, or `null` when nothing changes.\n */\n async switchRelays(): Promise<string[] | undefined> {\n const resp = await this.#sendRequest(\"switch_relays\", []);\n if (resp === \"null\") {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(resp);\n } catch (error) {\n throw new Nip46Error(\"invalid switch_relays JSON\", {\n cause: error,\n });\n }\n if (\n !Array.isArray(parsed) ||\n parsed.length === 0 ||\n !parsed.every((x) => typeof x === \"string\")\n ) {\n throw new Nip46Error(\"invalid switch_relays result\");\n }\n this.#relays = parsed;\n this.#startSubscription();\n return parsed;\n }\n\n /** Courtesy session teardown. Always closes the local signer afterwards. */\n async logout(): Promise<void> {\n try {\n const resp = await this.#sendRequest(\"logout\", []);\n if (resp !== \"ack\") {\n throw new Nip46Error(`logout result is not ack: ${resp}`);\n }\n } finally {\n await this.close();\n }\n }\n\n async ping(): Promise<void> {\n const resp = await this.#sendRequest(\"ping\", []);\n if (resp !== \"pong\") {\n throw new Nip46Error(`ping result is not pong: ${resp}`);\n }\n }\n\n async getPublicKey(): Promise<string> {\n if (this.#cachedRemotePubkey === undefined) {\n const pk = await this.#sendRequest(\"get_public_key\", []);\n if (!isHex32(pk.toLowerCase())) {\n throw new Nip46Error(\"bunker returned invalid pubkey\");\n }\n this.#cachedRemotePubkey = pk.toLowerCase();\n }\n return this.#cachedRemotePubkey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n const template: EventTemplate = {\n kind: unsigned.kind,\n tags: unsigned.tags,\n content: unsigned.content,\n created_at: unsigned.created_at,\n };\n const resp = await this.#sendRequest(\"sign_event\", [JSON.stringify(template)]);\n let signed: unknown;\n try {\n signed = JSON.parse(resp);\n } catch (error) {\n throw new Nip46Error(\"bunker returned invalid sign_event JSON\", {\n cause: error,\n });\n }\n if (!validateSignedEvent(signed) || !verifyEvent(signed)) {\n throw new Nip46Error(\"bunker returned improperly signed event\");\n }\n if (!signedMatchesUnsigned(signed, unsigned)) {\n throw new Nip46Error(\"signed event does not match unsigned template\");\n }\n return signed;\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip04_encrypt\", [peer, plaintext]);\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n return this.#sendRequest(\"nip04_decrypt\", [peer, ciphertext]);\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n return this.#sendRequest(\"nip44_encrypt\", [peer, plaintext]);\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n return this.#sendRequest(\"nip44_decrypt\", [peer, payload]);\n }\n\n async close(): Promise<void> {\n this.#open = false;\n for (const [, listener] of this.#listeners) {\n clearTimeout(listener.timer);\n listener.reject(new Nip46Error(\"signer closed\"));\n }\n this.#listeners.clear();\n this.#sub?.close(\"signer closed\");\n this.#sub = undefined;\n if (this.#ownsPool) {\n this.#pool.close();\n }\n }\n\n async #sendRequest(method: string, params: string[]): Promise<string> {\n if (!this.#open) {\n throw new Nip46Error(\"signer is closed\");\n }\n if (!this.#sub) {\n this.#startSubscription();\n }\n\n const id = bytesToHex(randomBytes(16));\n const req: Nip46Request = { id, method, params };\n const encrypted = encrypt(encodeNip46Request(req), this.#conversationKey);\n\n const event = finalizeEvent(\n {\n kind: Kind.NostrConnect,\n tags: [Tag.p(this.#pointer.pubkey)],\n content: encrypted,\n created_at: nowSeconds(),\n },\n this.#clientSecret,\n );\n\n const resultPromise = new Promise<string>((resolve, reject) => {\n const listener: PendingRequest = { resolve, reject, method };\n listener.timer = this.#requestTimer(id, listener, this.#timeoutMs);\n this.#listeners.set(id, listener);\n });\n\n let replies;\n try {\n replies = await this.#pool.publish(this.#relays, event);\n } catch (error) {\n this.#dropRequest(id);\n throw error;\n }\n if (!replies.some((reply) => reply.status === \"ok\")) {\n const listener = this.#dropRequest(id);\n const detail = replies\n .map((reply) => (reply.status === \"failed\" ? errorMessage(reply.error) : reply.message))\n .filter((message): message is string => Boolean(message))\n .join(\"; \");\n listener?.reject(new Nip46Error(`request not accepted by any relay: ${detail}`));\n }\n return resultPromise;\n }\n\n #dropRequest(id: string): PendingRequest | undefined {\n const listener = this.#listeners.get(id);\n if (!listener) {\n return undefined;\n }\n clearTimeout(listener.timer);\n this.#listeners.delete(id);\n return listener;\n }\n\n #requestTimer(id: string, listener: PendingRequest, ms: number): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n this.#dropRequest(id);\n listener.reject(new Nip46Error(`NIP-46 request timed out: ${listener.method}`));\n }, ms);\n }\n}\n"],"mappings":"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"}
|
package/dist/signer.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { t as NostrSigner } from "./types-BJ4wZ7JJ.mjs";
|
|
2
|
-
import { a as Nip07Signer, c as isNip07Available, i as Nip46Transport, l as KeysSigner, n as Nip46SignerOptions, o as WindowNostr, r as Nip46SubscribeOptions, s as getWindowNostr, t as Nip46Signer, u as NoSignerError } from "./index-
|
|
2
|
+
import { a as Nip07Signer, c as isNip07Available, i as Nip46Transport, l as KeysSigner, n as Nip46SignerOptions, o as WindowNostr, r as Nip46SubscribeOptions, s as getWindowNostr, t as Nip46Signer, u as NoSignerError } from "./index-N7HUGgwo.mjs";
|
|
3
3
|
export { KeysSigner, Nip07Signer, Nip46Signer, type Nip46SignerOptions, type Nip46SubscribeOptions, type Nip46Transport, NoSignerError, type NostrSigner, type WindowNostr, getWindowNostr, isNip07Available };
|
package/dist/signer.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as NoSignerError } from "./error-
|
|
2
|
-
import { a as KeysSigner, i as isNip07Available, n as Nip07Signer, r as getWindowNostr, t as Nip46Signer } from "./signer-
|
|
1
|
+
import { t as NoSignerError } from "./error-UHkqzWL7.mjs";
|
|
2
|
+
import { a as KeysSigner, i as isNip07Available, n as Nip07Signer, r as getWindowNostr, t as Nip46Signer } from "./signer-CWtxpOxc.mjs";
|
|
3
3
|
export { KeysSigner, Nip07Signer, Nip46Signer, NoSignerError, getWindowNostr, isNip07Available };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as isRecord } from "./util-DDpPkiED.mjs";
|
|
2
2
|
import { t as Kind } from "./kind-D8fENiiL.mjs";
|
|
3
|
-
import { S as parseEventAddress, _ as eventAddress, a as isReplaceableWinner, f as sortEvents, h as validateSignedEvent, o as itemCompare, t as compareEventsDesc, y as formatEventAddress } from "./event-
|
|
4
|
-
import { a as matchFilter } from "./filter-
|
|
5
|
-
import { n as toStorageError, t as StorageError } from "./error-
|
|
6
|
-
import { a as planDeletion, i as DeletionState, n as decidePut, r as outboxBoundKey } from "./put-
|
|
3
|
+
import { S as parseEventAddress, _ as eventAddress, a as isReplaceableWinner, f as sortEvents, h as validateSignedEvent, o as itemCompare, t as compareEventsDesc, y as formatEventAddress } from "./event-B3ua2_oL.mjs";
|
|
4
|
+
import { a as matchFilter } from "./filter-B16P33dz.mjs";
|
|
5
|
+
import { n as toStorageError, t as StorageError } from "./error-DH4guike.mjs";
|
|
6
|
+
import { a as planDeletion, i as DeletionState, n as decidePut, r as outboxBoundKey } from "./put-DRmV1wHD.mjs";
|
|
7
7
|
import { t as SerialQueue } from "./serial-Bzpw-xz3.mjs";
|
|
8
8
|
//#region src/storage/idb-types.ts
|
|
9
9
|
const EVENTS = "events";
|
|
@@ -992,9 +992,8 @@ function inClause(column, count) {
|
|
|
992
992
|
/**
|
|
993
993
|
* Compile one NIP-01 filter into query variants. `IN` lists are chunked so a variant never binds
|
|
994
994
|
* more than {@link IN_CHUNK} values per list; variants are the cartesian product of chunks across
|
|
995
|
-
* constrained fields.
|
|
996
|
-
*
|
|
997
|
-
* Returns `undefined` when an empty list field makes the filter match nothing.
|
|
995
|
+
* constrained fields. Multi-letter `#` keys are not NIP-01 tag conditions and are skipped, exactly
|
|
996
|
+
* like `matchFilter`. Returns `undefined` when an empty list field makes the filter match nothing.
|
|
998
997
|
*/
|
|
999
998
|
function compileFilter(filter) {
|
|
1000
999
|
const variants = [];
|
|
@@ -1024,16 +1023,12 @@ function compileFilter(filter) {
|
|
|
1024
1023
|
wheres: ["created_at <= ?"],
|
|
1025
1024
|
params: [filter.until]
|
|
1026
1025
|
}]);
|
|
1027
|
-
let deferred = false;
|
|
1028
1026
|
for (const key of Object.keys(filter)) {
|
|
1029
1027
|
if (!key.startsWith("#")) continue;
|
|
1030
1028
|
const name = key.slice(1);
|
|
1029
|
+
if (name.length !== 1) continue;
|
|
1031
1030
|
const values = filter[key];
|
|
1032
1031
|
if (!values) continue;
|
|
1033
|
-
if (name.length !== 1) {
|
|
1034
|
-
deferred = true;
|
|
1035
|
-
continue;
|
|
1036
|
-
}
|
|
1037
1032
|
if (values.length === 0) return;
|
|
1038
1033
|
const normalized = name === "e" || name === "p" ? values.map((v) => v.toLowerCase()) : values;
|
|
1039
1034
|
variants.push(chunkValues(normalized).map((chunk) => ({
|
|
@@ -1054,10 +1049,7 @@ function compileFilter(filter) {
|
|
|
1054
1049
|
plans.length = 0;
|
|
1055
1050
|
plans.push(...next);
|
|
1056
1051
|
}
|
|
1057
|
-
return
|
|
1058
|
-
plans,
|
|
1059
|
-
deferred
|
|
1060
|
-
};
|
|
1052
|
+
return plans;
|
|
1061
1053
|
}
|
|
1062
1054
|
/**
|
|
1063
1055
|
* SQLite-backed {@link EventStore} for React Native (`expo-sqlite`, `op-sqlite`) and desktop
|
|
@@ -1269,17 +1261,8 @@ var SqliteEventStore = class SqliteEventStore {
|
|
|
1269
1261
|
}
|
|
1270
1262
|
async #filterRows(filter, select) {
|
|
1271
1263
|
if (filter.limit === 0) return [];
|
|
1272
|
-
const
|
|
1273
|
-
if (
|
|
1274
|
-
const { plans, deferred } = compiled;
|
|
1275
|
-
if (deferred) {
|
|
1276
|
-
const matched = (await this.#planRows(plans, "*", void 0)).map(rowToEvent).filter((event) => matchFilter(filter, event));
|
|
1277
|
-
const limited = filter.limit === void 0 ? matched : matched.slice(0, filter.limit);
|
|
1278
|
-
return select === "*" ? limited : limited.map((e) => ({
|
|
1279
|
-
id: e.id,
|
|
1280
|
-
created_at: e.created_at
|
|
1281
|
-
}));
|
|
1282
|
-
}
|
|
1264
|
+
const plans = compileFilter(filter);
|
|
1265
|
+
if (plans === void 0) return [];
|
|
1283
1266
|
if (select === "*") return (await this.#planRows(plans, "*", filter.limit)).map(rowToEvent);
|
|
1284
1267
|
return this.#planRows(plans, "id, created_at", filter.limit);
|
|
1285
1268
|
}
|
|
@@ -1376,4 +1359,4 @@ var SqliteEventStore = class SqliteEventStore {
|
|
|
1376
1359
|
//#endregion
|
|
1377
1360
|
export { IndexedDbEventStore as n, SqliteEventStore as t };
|
|
1378
1361
|
|
|
1379
|
-
//# sourceMappingURL=storage-
|
|
1362
|
+
//# sourceMappingURL=storage-B5Wdt_Mn.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-B5Wdt_Mn.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 onversionchange: ((ev: unknown) => void) | null;\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 onblocked: ((ev: unknown) => void) | null;\n result: IDBDatabaseLike;\n};\n\nexport type TagRef = {\n readonly key: string;\n readonly name: string;\n readonly value: string;\n readonly id: string;\n readonly created_at: number;\n};\n\nexport type AddressRow = {\n readonly address: string;\n readonly id: string;\n readonly created_at: number;\n};\n\nexport type Tombstone =\n | { readonly key: `id:${string}`; readonly type: \"id\" }\n | { readonly key: `pending:${string}`; readonly type: \"pending\"; readonly pubkey: string }\n | { readonly key: `coord:${string}`; readonly type: \"coord\"; readonly until: number };\n\nexport type OutboxBoundRow = {\n readonly key: string;\n readonly oldest: number;\n readonly newest: number;\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 { 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 removeIds: string[] = [];\n const pendingIds: Array<{ id: string; pubkey: string }> = [];\n const coordinates: Array<{ key: string; until: number }> = [];\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 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 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 coordinates.push({ key: r[\"key\"].slice(6), until: r[\"until\"] });\n }\n }\n return { removeIds, pendingIds, coordinates };\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 let settled = false;\n req.onsuccess = () => {\n const db = req.result;\n if (settled) {\n // The blocked rejection already fired; do not leak this late connection.\n db.close();\n return;\n }\n settled = true;\n // Yield to any newer-version open instead of blocking it forever.\n db.onversionchange = () => db.close();\n resolve(db);\n };\n req.onerror = () => {\n settled = true;\n reject(req.error ?? new StorageError(\"IndexedDB open failed\"));\n };\n req.onblocked = () => {\n settled = true;\n reject(new StorageError(\"IndexedDB open blocked by another connection\"));\n };\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 { SerialQueue } from \"../core/serial.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 | undefined;\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 /** Set when this connection closed to unblock a newer-version open; ops then fail fast. */\n #yielded = false;\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 readonly #writeQueue = new SerialQueue();\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 const closeOnUpgrade = db.onversionchange;\n db.onversionchange = (ev) => {\n closeOnUpgrade?.(ev);\n this.#yielded = true;\n };\n this.#yielded = false;\n this.#db = db;\n await this.#loadCaches(db);\n }\n\n async #ensure(): Promise<IDBDatabaseLike> {\n if (this.#yielded) {\n throw new StorageError(\"IndexedDB connection closed by a newer version\");\n }\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 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.#writeQueue.run(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: ReadonlyArray<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: ReadonlyArray<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.#writeQueue.run(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: ReadonlyArray<string>): Promise<number> {\n return this.#writeQueue.run(async () => this.#removeLocked(ids));\n }\n\n async #removeLocked(ids: ReadonlyArray<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.#writeQueue.run(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 type { Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { SerialQueue } from \"../core/serial.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 * The store does not rely on per-connection PRAGMAs: tag rows are deleted explicitly, so `PRAGMA\n * foreign_keys` may be off on any connection (including transaction connections).\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 INDEX IF NOT EXISTS tags_event_id ON tags(event_id);\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. Multi-letter `#` keys are not NIP-01 tag conditions and are skipped, exactly\n * like `matchFilter`. Returns `undefined` when an empty list field makes the filter match nothing.\n */\nfunction compileFilter(filter: Filter): FilterPlan[] | 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 for (const key of Object.keys(filter)) {\n if (!key.startsWith(\"#\")) {\n continue;\n }\n const name = key.slice(1);\n if (name.length !== 1) {\n continue;\n }\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 (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;\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 readonly #writeQueue = new SerialQueue();\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 const rows = await this.#driver.all<{ user_version: number }>(\"PRAGMA user_version\");\n const version = rows[0]?.user_version ?? 0;\n if (version !== 0 && version !== SCHEMA_VERSION) {\n throw toStorageError(new Error(`unsupported sqlite event store schema version ${version}`));\n }\n // Every statement is IF NOT EXISTS, so this is a no-op on an existing schema and also\n // picks up objects (indexes) added to SCHEMA_SQL after a database was created.\n await this.#driver.exec(SCHEMA_SQL);\n if (version === 0) {\n await this.#driver.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);\n }\n } catch (error) {\n throw toStorageError(error);\n }\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.#writeQueue.run(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) {\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 // Explicit: a transaction may run on a connection where foreign_keys is off\n // (expo-sqlite's withExclusiveTransactionAsync), where ON DELETE CASCADE never fires.\n await tx.run(`DELETE FROM tags WHERE event_id = ?`, [id]);\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: ReadonlyArray<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: ReadonlyArray<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.\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 plans = compileFilter(filter);\n if (plans === undefined) {\n return [];\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.#writeQueue.run(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: ReadonlyArray<string>): Promise<number> {\n const lowered = ids.map((id) => id.toLowerCase());\n return this.#writeQueue.run(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.#writeQueue.run(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
|
-
import { i as PutResult, n as NegentropyItem, r as OutboxBound, t as EventStore } from "./types-
|
|
1
|
+
import { i as PutResult, n as NegentropyItem, r as OutboxBound, t as EventStore } from "./types-CqhnT-Mx.mjs";
|
|
2
2
|
import { t as StorageError } from "./error-BD_0QFKT.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-rKcmI6ex.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/storage.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as StorageError } from "./error-
|
|
2
|
-
import { t as MemoryIndex } from "./memory-index-
|
|
3
|
-
import { t as MemoryEventStore } from "./memory-
|
|
4
|
-
import { n as IndexedDbEventStore, t as SqliteEventStore } from "./storage-
|
|
1
|
+
import { t as StorageError } from "./error-DH4guike.mjs";
|
|
2
|
+
import { t as MemoryIndex } from "./memory-index-Bhwe0ZdG.mjs";
|
|
3
|
+
import { t as MemoryEventStore } from "./memory-VyPnOBU3.mjs";
|
|
4
|
+
import { n as IndexedDbEventStore, t as SqliteEventStore } from "./storage-B5Wdt_Mn.mjs";
|
|
5
5
|
export { IndexedDbEventStore, MemoryEventStore, MemoryIndex, SqliteEventStore, StorageError };
|
package/dist/store.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as Watch, n as ReactiveEventStoreEventMap, r as ReactiveEventStoreOptions, t as ReactiveEventStore } from "./reactive-
|
|
1
|
+
import { i as Watch, n as ReactiveEventStoreEventMap, r as ReactiveEventStoreOptions, t as ReactiveEventStore } from "./reactive-jyKrA9ej.mjs";
|
|
2
2
|
export { ReactiveEventStore, type ReactiveEventStoreEventMap, type ReactiveEventStoreOptions, type Watch };
|
package/dist/store.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ReactiveEventStore } from "./reactive
|
|
1
|
+
import { t as ReactiveEventStore } from "./reactive--pDpLt2H.mjs";
|
|
2
2
|
export { ReactiveEventStore };
|