@qntx/nostr 0.11.0 → 0.13.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-GBddxj8i.d.mts → builder-C72nJITG.d.mts} +2 -2
- package/dist/{builder-BQbFDO6S.mjs → builder-CGgM_QHT.mjs} +5 -5
- package/dist/{builder-BQbFDO6S.mjs.map → builder-CGgM_QHT.mjs.map} +1 -1
- package/dist/{client-CTmp5w84.mjs → client-COkEihj_.mjs} +87 -79
- package/dist/client-COkEihj_.mjs.map +1 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/core.d.mts +7 -7
- package/dist/core.mjs +9 -9
- package/dist/{emitter-DkCY6NkU.mjs → emitter-u4kJqQDk.mjs} +2 -2
- package/dist/{emitter-DkCY6NkU.mjs.map → emitter-u4kJqQDk.mjs.map} +1 -1
- package/dist/{error-BquXDmIN.d.mts → error-BPqAU5RB.d.mts} +2 -6
- package/dist/{error-BD_0QFKT.d.mts → error-BjSUsx6M.d.mts} +2 -2
- package/dist/{error-UHkqzWL7.mjs → error-Dyb89ahb.mjs} +7 -3
- package/dist/error-Dyb89ahb.mjs.map +1 -0
- package/dist/{error-DH4guike.mjs → error-QyECUDIp.mjs} +2 -2
- package/dist/{error-DH4guike.mjs.map → error-QyECUDIp.mjs.map} +1 -1
- package/dist/{event-B3ua2_oL.mjs → event-DvM1f03b.mjs} +7 -3
- package/dist/event-DvM1f03b.mjs.map +1 -0
- package/dist/{filter-B16P33dz.mjs → filter-3jOh4uLN.mjs} +50 -20
- package/dist/filter-3jOh4uLN.mjs.map +1 -0
- package/dist/{filter-PG7r79rt.d.mts → filter-oYG2zjJ3.d.mts} +6 -2
- package/dist/{gossip-BTMdlUI7.d.mts → gossip-BvCItMVZ.d.mts} +3 -3
- package/dist/{gossip-K_JIexQs.mjs → gossip-CRyhK6E6.mjs} +4 -4
- package/dist/{gossip-K_JIexQs.mjs.map → gossip-CRyhK6E6.mjs.map} +1 -1
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/http-CuazNRIP.mjs.map +1 -1
- package/dist/{index-DD0Ywpay.d.mts → index-B2JlP2Jf.d.mts} +9 -9
- package/dist/{index-BP94lABY.d.mts → index-DCobP2Jj.d.mts} +10 -10
- package/dist/{index-Hp26bgYG.d.mts → index-Dpj_MUxb.d.mts} +8 -5
- package/dist/{index-rKcmI6ex.d.mts → index-DzHmhHqD.d.mts} +3 -3
- package/dist/{index-N7HUGgwo.d.mts → index-YID-zPDF.d.mts} +58 -8
- package/dist/{index-CSsnE32i.d.mts → index-muydfuYD.d.mts} +21 -21
- package/dist/index.d.mts +19 -20
- package/dist/index.mjs +20 -20
- package/dist/{key-k8LDEPZh.mjs → key-D_oEutQ6.mjs} +32 -9
- package/dist/key-D_oEutQ6.mjs.map +1 -0
- package/dist/{key-CyKN1RTi.d.mts → key-DojW2QZl.d.mts} +14 -4
- package/dist/{kind-D8fENiiL.mjs → kind-I2Tvbe82.mjs} +6 -5
- package/dist/kind-I2Tvbe82.mjs.map +1 -0
- package/dist/{loaders-Dp2nXEFk.mjs → loaders-BRh2riV9.mjs} +17 -16
- package/dist/loaders-BRh2riV9.mjs.map +1 -0
- package/dist/loaders.d.mts +2 -2
- package/dist/loaders.mjs +1 -1
- package/dist/{memory-VyPnOBU3.mjs → memory-D_GdEQYG.mjs} +2 -2
- package/dist/memory-D_GdEQYG.mjs.map +1 -0
- package/dist/memory-index-3GSrPIWj.mjs +671 -0
- package/dist/memory-index-3GSrPIWj.mjs.map +1 -0
- package/dist/{message-pYfVKxPn.mjs → message-BMfreCQc.mjs} +6 -6
- package/dist/message-BMfreCQc.mjs.map +1 -0
- package/dist/{nip17-B7MI82Iq.d.mts → nip17-BZvFQLcs.d.mts} +5 -5
- package/dist/{nip19-DpPN17bY.d.mts → nip19-D4RKn6GC.d.mts} +2 -2
- package/dist/{nip46-BHaxC9TZ.d.mts → nip46-i8L8_nIm.d.mts} +2 -2
- package/dist/{nip51-O_vhOiK2.d.mts → nip51-C_kTYcud.d.mts} +2 -2
- package/dist/{nip59-CdDoJptA.d.mts → nip59-DfJ6Moeu.d.mts} +15 -7
- package/dist/{nip65-BL79HI8N.d.mts → nip65-CPNE0SV0.d.mts} +2 -2
- package/dist/{nip77-wHA_nEV5.d.mts → nip77-DhpoL7d8.d.mts} +2 -2
- package/dist/nips/blossom.d.mts +2 -2
- package/dist/nips/blossom.mjs +3 -3
- package/dist/nips/blossom.mjs.map +1 -1
- package/dist/nips/nip04.d.mts +11 -4
- package/dist/nips/nip04.mjs +44 -21
- package/dist/nips/nip04.mjs.map +1 -1
- package/dist/nips/nip05.d.mts +6 -3
- package/dist/nips/nip05.mjs +6 -3
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +2 -2
- package/dist/nips/nip10.mjs +4 -4
- package/dist/nips/nip11.d.mts +1 -1
- package/dist/nips/nip11.mjs +1 -1
- package/dist/nips/nip13.d.mts +1 -1
- package/dist/nips/nip13.mjs +1 -1
- package/dist/nips/nip13.mjs.map +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +5 -5
- package/dist/nips/nip17.mjs.map +1 -1
- package/dist/nips/nip19.d.mts +1 -1
- package/dist/nips/nip19.mjs +2 -2
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.d.mts +6 -3
- package/dist/nips/nip21.mjs +8 -5
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +1 -1
- package/dist/nips/nip27.mjs +15 -9
- package/dist/nips/nip27.mjs.map +1 -1
- package/dist/nips/nip42.mjs +2 -2
- package/dist/nips/nip44.d.mts +5 -0
- package/dist/nips/nip44.mjs +10 -3
- package/dist/nips/nip44.mjs.map +1 -1
- package/dist/nips/nip46.d.mts +1 -1
- package/dist/nips/nip46.mjs +9 -7
- package/dist/nips/nip46.mjs.map +1 -1
- package/dist/nips/nip49.d.mts +8 -2
- package/dist/nips/nip49.mjs +17 -3
- package/dist/nips/nip49.mjs.map +1 -1
- package/dist/nips/nip51.d.mts +1 -1
- package/dist/nips/nip51.mjs +5 -5
- package/dist/nips/nip51.mjs.map +1 -1
- package/dist/nips/nip57.mjs +6 -5
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.d.mts +1 -1
- package/dist/nips/nip59.mjs +51 -23
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +1 -1
- package/dist/nips/nip65.mjs +3 -3
- package/dist/nips/nip77.d.mts +1 -1
- package/dist/nips/nip77.mjs +1 -1
- package/dist/nips/nip77.mjs.map +1 -1
- package/dist/nips/nip98.d.mts +1 -1
- package/dist/nips/nip98.mjs +18 -7
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/{pool-DUuYJ0x4.d.mts → pool-MehgIIzm.d.mts} +20 -16
- package/dist/{pool-BMUsw2un.mjs → pool-lMT_mvzn.mjs} +25 -25
- package/dist/pool-lMT_mvzn.mjs.map +1 -0
- package/dist/{put-DRmV1wHD.mjs → put-BEM5j8xK.mjs} +5 -5
- package/dist/{put-DRmV1wHD.mjs.map → put-BEM5j8xK.mjs.map} +1 -1
- package/dist/{reactive-jyKrA9ej.d.mts → reactive-B7lPFgTS.d.mts} +3 -3
- package/dist/{reactive--pDpLt2H.mjs → reactive-DFHY-f00.mjs} +24 -9
- package/dist/reactive-DFHY-f00.mjs.map +1 -0
- package/dist/{relay-DXtwUEdX.mjs → relay-DIR77xQ2.mjs} +102 -89
- package/dist/relay-DIR77xQ2.mjs.map +1 -0
- package/dist/relay.d.mts +5 -5
- package/dist/relay.mjs +3 -3
- package/dist/{report-CHld4uWj.mjs → report-D2BM5dgn.mjs} +2 -2
- package/dist/{report-CHld4uWj.mjs.map → report-D2BM5dgn.mjs.map} +1 -1
- package/dist/{signer-CWtxpOxc.mjs → signer-DJcmC4nA.mjs} +176 -17
- package/dist/signer-DJcmC4nA.mjs.map +1 -0
- package/dist/signer.d.mts +2 -2
- package/dist/signer.mjs +3 -3
- package/dist/{storage-B5Wdt_Mn.mjs → storage-n2BE1bdY.mjs} +108 -179
- package/dist/storage-n2BE1bdY.mjs.map +1 -0
- package/dist/storage.d.mts +3 -3
- package/dist/storage.mjs +4 -4
- package/dist/store.d.mts +1 -1
- package/dist/store.mjs +1 -1
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +35 -10
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-CqhnT-Mx.d.mts → types-DiVVyf1e.d.mts} +2 -2
- package/dist/{util-DDpPkiED.mjs → util-DfsyJ9nz.mjs} +30 -10
- package/dist/util-DfsyJ9nz.mjs.map +1 -0
- package/dist/{verifier-CjH1vnP2.mjs → verifier-DEHUy4AD.mjs} +3 -3
- package/dist/{verifier-CjH1vnP2.mjs.map → verifier-DEHUy4AD.mjs.map} +1 -1
- package/dist/{verifier-Cl24c9ph.d.mts → verifier-DhAbqVJF.d.mts} +2 -2
- package/dist/{websocket-CmeqvAkp.d.mts → websocket-DaCvJkF9.d.mts} +2 -5
- package/package.json +4 -3
- package/dist/client-CTmp5w84.mjs.map +0 -1
- package/dist/error-UHkqzWL7.mjs.map +0 -1
- package/dist/event-B3ua2_oL.mjs.map +0 -1
- package/dist/filter-B16P33dz.mjs.map +0 -1
- package/dist/key-k8LDEPZh.mjs.map +0 -1
- package/dist/kind-D8fENiiL.mjs.map +0 -1
- package/dist/loaders-Dp2nXEFk.mjs.map +0 -1
- package/dist/memory-VyPnOBU3.mjs.map +0 -1
- package/dist/memory-index-Bhwe0ZdG.mjs +0 -374
- package/dist/memory-index-Bhwe0ZdG.mjs.map +0 -1
- package/dist/message-pYfVKxPn.mjs.map +0 -1
- package/dist/pool-BMUsw2un.mjs.map +0 -1
- package/dist/reactive--pDpLt2H.mjs.map +0 -1
- package/dist/relay-DXtwUEdX.mjs.map +0 -1
- package/dist/signer-CWtxpOxc.mjs.map +0 -1
- package/dist/storage-B5Wdt_Mn.mjs.map +0 -1
- package/dist/util-DDpPkiED.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer-DJcmC4nA.mjs","names":["hexToBytes","bytesToHex","nip44.getConversationKeyFromSharedSecret","nip44.encrypt","nip44.decrypt","nip04.encrypt","nip04.decrypt","nip04.encryptToPubkey","nip04.decryptFromPubkey","nip44.getConversationKey","nip44.encrypt","nip44.decrypt","decrypt","bytesToHex","encrypt"],"sources":["../src/signer/delegated.ts","../src/signer/keys.ts","../src/signer/nip07.ts","../src/signer/nip46.ts"],"sourcesContent":["import { schnorr } from \"@noble/curves/secp256k1.js\";\n\nimport { CryptoError, EventValidationError } from \"../core/error.ts\";\nimport type { Event, UnsignedEvent } from \"../core/event.ts\";\nimport { getEventHash, markVerified, validateEvent } from \"../core/event.ts\";\nimport { assertHex32, bytesToHex, hexToBytes, isHex32 } from \"../core/util.ts\";\nimport * as nip04 from \"../nips/nip04.ts\";\nimport * as nip44 from \"../nips/nip44.ts\";\nimport { SignerDisposedError } from \"./error.ts\";\nimport type { NostrSigner } from \"./types.ts\";\n\n/**\n * The three operations an external key holder (wallet keyring, NFC card, platform secure store)\n * provides. The secret itself never enters this process.\n */\nexport type NostrKeyOperations = {\n /** Lowercase 64-char hex x-only public key. */\n getPublicKey: () => Promise<string>;\n /** 64-byte BIP-340 signature over the 32-byte event id. */\n signEventId: (id: Uint8Array) => Promise<Uint8Array>;\n /**\n * Optional. 32-byte x-coordinate of `ECDH(secret, lift_x(peer))`, unhashed. Enables NIP-04 and\n * NIP-44.\n */\n sharedSecret?: (peer: string) => Promise<Uint8Array>;\n};\n\n/**\n * {@link NostrSigner} backed by a {@link NostrKeyOperations} key holder. The signer verifies\n * everything the holder returns: the public key shape, the signature length, and the BIP-340\n * signature itself — a misbehaving holder never produces an event relays would reject.\n */\nexport class DelegatedSigner implements NostrSigner {\n readonly #operations: NostrKeyOperations;\n readonly #convKeys = new Map<string, Uint8Array>();\n #pubkey: string | undefined;\n #disposed = false;\n\n constructor(operations: NostrKeyOperations) {\n this.#operations = operations;\n }\n\n #assertUsable(): void {\n if (this.#disposed) {\n throw new SignerDisposedError(\"signer has been disposed\");\n }\n }\n\n async #publicKey(): Promise<string> {\n let pubkey = this.#pubkey;\n if (pubkey === undefined) {\n pubkey = await this.#operations.getPublicKey();\n this.#assertUsable();\n if (!isHex32(pubkey)) {\n throw new CryptoError(\"key holder returned an invalid public key\");\n }\n this.#pubkey = pubkey;\n }\n return pubkey;\n }\n\n async getPublicKey(): Promise<string> {\n this.#assertUsable();\n return this.#publicKey();\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n this.#assertUsable();\n if (!validateEvent(unsigned)) {\n throw new EventValidationError(\"cannot sign invalid unsigned event\");\n }\n const pubkey = await this.#publicKey();\n if (unsigned.pubkey !== pubkey) {\n throw new CryptoError(\"unsigned event pubkey does not match the key holder's public key\");\n }\n const id = getEventHash(unsigned);\n const sig = await this.#operations.signEventId(hexToBytes(id));\n this.#assertUsable();\n if (sig.length !== 64) {\n throw new CryptoError(\"key holder returned an invalid signature length\");\n }\n if (!schnorr.verify(sig, hexToBytes(id), hexToBytes(pubkey))) {\n throw new CryptoError(\"key holder returned a signature that fails verification\");\n }\n const event: Event = { ...unsigned, id, sig: bytesToHex(sig) };\n markVerified(event);\n return event;\n }\n\n /**\n * The normalized lowercase peer pubkey is handed to the holder; the returned 32-byte shared\n * secret is the caller's to wipe.\n */\n async #sharedSecret(peer: string): Promise<Uint8Array> {\n const { sharedSecret } = this.#operations;\n if (!sharedSecret) {\n throw new CryptoError(\"key holder does not support ECDH shared secrets\");\n }\n const shared = await sharedSecret(assertHex32(peer, \"peer public key\"));\n if (this.#disposed) {\n shared.fill(0);\n throw new SignerDisposedError(\"signer has been disposed\");\n }\n if (shared.length !== 32) {\n shared.fill(0);\n throw new CryptoError(\"key holder returned an invalid shared secret\");\n }\n return shared;\n }\n\n async #conversationKey(peer: string): Promise<Uint8Array> {\n const pk = assertHex32(peer, \"peer public key\");\n let key = this.#convKeys.get(pk);\n if (!key) {\n const shared = await this.#sharedSecret(pk);\n try {\n key = nip44.getConversationKeyFromSharedSecret(shared);\n } finally {\n shared.fill(0);\n }\n this.#convKeys.set(pk, key);\n }\n return key;\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n this.#assertUsable();\n return nip44.encrypt(plaintext, await this.#conversationKey(peer));\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n this.#assertUsable();\n return nip44.decrypt(payload, await this.#conversationKey(peer));\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n this.#assertUsable();\n const shared = await this.#sharedSecret(peer);\n try {\n return nip04.encrypt(plaintext, shared);\n } finally {\n shared.fill(0);\n }\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n this.#assertUsable();\n const shared = await this.#sharedSecret(peer);\n try {\n return nip04.decrypt(ciphertext, shared);\n } finally {\n shared.fill(0);\n }\n }\n\n /**\n * Zero-fill and clear every cached NIP-44 conversation key. All later calls reject with\n * {@link SignerDisposedError} and never reach the key holder. Idempotent.\n */\n dispose(): void {\n for (const key of this.#convKeys.values()) {\n key.fill(0);\n }\n this.#convKeys.clear();\n this.#disposed = true;\n }\n}\n","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 { SignerDisposedError } from \"./error.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 #disposed = false;\n\n constructor(secretKey: SecretKeyInput | Keys) {\n this.#keys = secretKey instanceof Keys ? secretKey : Keys.fromSecretKey(secretKey);\n }\n\n /**\n * The live {@link Keys} instance holding the secret material. {@link KeysSigner.dispose} zeroizes\n * it, so a reference obtained earlier reports a zeroized secret afterwards.\n */\n get keys(): Keys {\n return this.#keys;\n }\n\n #assertUsable(): void {\n if (this.#disposed) {\n throw new SignerDisposedError(\"signer has been disposed\");\n }\n }\n\n async getPublicKey(): Promise<string> {\n this.#assertUsable();\n return this.#keys.publicKey;\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n this.#assertUsable();\n return signEvent(unsigned, this.#keys);\n }\n\n async nip04Encrypt(peer: string, plaintext: string): Promise<string> {\n this.#assertUsable();\n const secret = this.#keys.secretKey.bytes;\n try {\n return nip04.encryptToPubkey(plaintext, secret, peer);\n } finally {\n secret.fill(0);\n }\n }\n\n async nip04Decrypt(peer: string, ciphertext: string): Promise<string> {\n this.#assertUsable();\n const secret = this.#keys.secretKey.bytes;\n try {\n return nip04.decryptFromPubkey(ciphertext, secret, peer);\n } finally {\n secret.fill(0);\n }\n }\n\n #conversationKey(peer: string): Uint8Array {\n const pk = peer.toLowerCase();\n let key = this.#convKeys.get(pk);\n if (!key) {\n const secret = this.#keys.secretKey.bytes;\n try {\n key = nip44.getConversationKey(secret, pk);\n } finally {\n secret.fill(0);\n }\n this.#convKeys.set(pk, key);\n }\n return key;\n }\n\n async nip44Encrypt(peer: string, plaintext: string): Promise<string> {\n this.#assertUsable();\n return nip44.encrypt(plaintext, this.#conversationKey(peer));\n }\n\n async nip44Decrypt(peer: string, payload: string): Promise<string> {\n this.#assertUsable();\n return nip44.decrypt(payload, this.#conversationKey(peer));\n }\n\n /**\n * Zeroize the wrapped secret key and every cached NIP-44 conversation key. All later calls reject\n * with {@link SignerDisposedError}. Idempotent.\n */\n dispose(): void {\n this.#keys.secretKey.zeroize();\n for (const key of this.#convKeys.values()) {\n key.fill(0);\n }\n this.#convKeys.clear();\n this.#disposed = true;\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 eslint/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
|
|
3
|
-
export { KeysSigner, Nip07Signer, Nip46Signer, type Nip46SignerOptions, type Nip46SubscribeOptions, type Nip46Transport, NoSignerError, type NostrSigner, type WindowNostr, getWindowNostr, isNip07Available };
|
|
2
|
+
import { a as Nip07Signer, c as isNip07Available, d as NostrKeyOperations, f as NoSignerError, i as Nip46Transport, l as KeysSigner, n as Nip46SignerOptions, o as WindowNostr, p as SignerDisposedError, r as Nip46SubscribeOptions, s as getWindowNostr, t as Nip46Signer, u as DelegatedSigner } from "./index-YID-zPDF.mjs";
|
|
3
|
+
export { DelegatedSigner, KeysSigner, Nip07Signer, Nip46Signer, type Nip46SignerOptions, type Nip46SubscribeOptions, type Nip46Transport, NoSignerError, type NostrKeyOperations, type NostrSigner, SignerDisposedError, 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-
|
|
3
|
-
export { KeysSigner, Nip07Signer, Nip46Signer, NoSignerError, getWindowNostr, isNip07Available };
|
|
1
|
+
import { n as SignerDisposedError, t as NoSignerError } from "./error-Dyb89ahb.mjs";
|
|
2
|
+
import { a as KeysSigner, i as isNip07Available, n as Nip07Signer, o as DelegatedSigner, r as getWindowNostr, t as Nip46Signer } from "./signer-DJcmC4nA.mjs";
|
|
3
|
+
export { DelegatedSigner, KeysSigner, Nip07Signer, Nip46Signer, NoSignerError, SignerDisposedError, getWindowNostr, isNip07Available };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as Kind } from "./kind-
|
|
3
|
-
import { S as parseEventAddress, _ as eventAddress,
|
|
4
|
-
import {
|
|
5
|
-
import { n as toStorageError, t as StorageError } from "./error-
|
|
6
|
-
import {
|
|
1
|
+
import { u as isRecord } from "./util-DfsyJ9nz.mjs";
|
|
2
|
+
import { t as Kind } from "./kind-I2Tvbe82.mjs";
|
|
3
|
+
import { S as parseEventAddress, _ as eventAddress, f as sortEvents, h as validateSignedEvent, o as itemCompare, t as compareEventsDesc, y as formatEventAddress } from "./event-DvM1f03b.mjs";
|
|
4
|
+
import { o as matchFilter } from "./filter-3jOh4uLN.mjs";
|
|
5
|
+
import { n as toStorageError, t as StorageError } from "./error-QyECUDIp.mjs";
|
|
6
|
+
import { i as DeletionState, n as decidePut, r as outboxBoundKey } from "./put-BEM5j8xK.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";
|
|
@@ -50,12 +50,12 @@ async function walkCursor(source, range, direction, visit) {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
function tagRefKey(name, value, id) {
|
|
53
|
-
return `${name}:${value
|
|
53
|
+
return `${name}:${value}:${id}`;
|
|
54
54
|
}
|
|
55
55
|
function writeTagRefs(store, event) {
|
|
56
56
|
for (const tag of event.tags) {
|
|
57
57
|
if (tag[0] !== "e" && tag[0] !== "p" || tag[1] === void 0) continue;
|
|
58
|
-
const value = tag
|
|
58
|
+
const { 1: value } = tag;
|
|
59
59
|
const { id } = event;
|
|
60
60
|
store.put({
|
|
61
61
|
key: tagRefKey(tag[0], value, id),
|
|
@@ -401,40 +401,41 @@ async function scanFilter(tx, filter, accept, take) {
|
|
|
401
401
|
}
|
|
402
402
|
return kWayMerge(openers, accept, take);
|
|
403
403
|
}
|
|
404
|
+
const ALL_STORES = [
|
|
405
|
+
EVENTS,
|
|
406
|
+
TAG_REFS,
|
|
407
|
+
ADDRESSES,
|
|
408
|
+
TOMBSTONES,
|
|
409
|
+
OUTBOX_BOUNDS
|
|
410
|
+
];
|
|
411
|
+
function createSchema(db) {
|
|
412
|
+
const events = db.createObjectStore(EVENTS, { keyPath: "id" });
|
|
413
|
+
events.createIndex("created_at", "created_at");
|
|
414
|
+
events.createIndex("kind_created_at", ["kind", "created_at"]);
|
|
415
|
+
events.createIndex("pubkey_created_at", ["pubkey", "created_at"]);
|
|
416
|
+
events.createIndex("kind_pubkey_created_at", [
|
|
417
|
+
"kind",
|
|
418
|
+
"pubkey",
|
|
419
|
+
"created_at"
|
|
420
|
+
]);
|
|
421
|
+
db.createObjectStore(TAG_REFS, { keyPath: "key" }).createIndex("name_value_created", [
|
|
422
|
+
"name",
|
|
423
|
+
"value",
|
|
424
|
+
"created_at"
|
|
425
|
+
]);
|
|
426
|
+
db.createObjectStore(ADDRESSES, { keyPath: "address" });
|
|
427
|
+
db.createObjectStore(TOMBSTONES, { keyPath: "key" });
|
|
428
|
+
db.createObjectStore(OUTBOX_BOUNDS, { keyPath: "key" });
|
|
429
|
+
}
|
|
404
430
|
async function openDb(dbName) {
|
|
405
431
|
return new Promise((resolve, reject) => {
|
|
406
|
-
const req = globalThis.indexedDB.open(dbName,
|
|
432
|
+
const req = globalThis.indexedDB.open(dbName, 5);
|
|
407
433
|
req.onupgradeneeded = (ev) => {
|
|
408
434
|
const db = req.result;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const events = tx.objectStore(EVENTS);
|
|
414
|
-
events.createIndex("created_at", "created_at");
|
|
415
|
-
events.createIndex("kind_created_at", ["kind", "created_at"]);
|
|
416
|
-
events.createIndex("pubkey_created_at", ["pubkey", "created_at"]);
|
|
417
|
-
events.createIndex("kind_pubkey_created_at", [
|
|
418
|
-
"kind",
|
|
419
|
-
"pubkey",
|
|
420
|
-
"created_at"
|
|
421
|
-
]);
|
|
422
|
-
db.createObjectStore(TAG_REFS, { keyPath: "key" }).createIndex("name_value_created", [
|
|
423
|
-
"name",
|
|
424
|
-
"value",
|
|
425
|
-
"created_at"
|
|
426
|
-
]);
|
|
427
|
-
db.createObjectStore(ADDRESSES, { keyPath: "address" });
|
|
428
|
-
db.createObjectStore(TOMBSTONES, { keyPath: "key" });
|
|
429
|
-
if (oldVersion >= 1) {
|
|
430
|
-
const all = events.getAll();
|
|
431
|
-
all.onsuccess = () => {
|
|
432
|
-
migrateV1Events(tx, all.result ?? []);
|
|
433
|
-
compactSupersededReplaceables(tx);
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
} else if (oldVersion < 3) compactSupersededReplaceables(tx);
|
|
437
|
-
if (oldVersion < 4) db.createObjectStore(OUTBOX_BOUNDS, { keyPath: "key" });
|
|
435
|
+
if (ev.oldVersion !== 0) {
|
|
436
|
+
for (const name of ALL_STORES) if (db.objectStoreNames.contains(name)) db.deleteObjectStore(name);
|
|
437
|
+
}
|
|
438
|
+
createSchema(db);
|
|
438
439
|
};
|
|
439
440
|
let settled = false;
|
|
440
441
|
req.onsuccess = () => {
|
|
@@ -457,106 +458,6 @@ async function openDb(dbName) {
|
|
|
457
458
|
};
|
|
458
459
|
});
|
|
459
460
|
}
|
|
460
|
-
function migrateV1Events(tx, events) {
|
|
461
|
-
const eventsStore = tx.objectStore(EVENTS);
|
|
462
|
-
const tagRefs = tx.objectStore(TAG_REFS);
|
|
463
|
-
const addresses = tx.objectStore(ADDRESSES);
|
|
464
|
-
const tombstones = tx.objectStore(TOMBSTONES);
|
|
465
|
-
const valid = [];
|
|
466
|
-
for (const e of events) {
|
|
467
|
-
if (validateSignedEvent(e)) {
|
|
468
|
-
valid.push(e);
|
|
469
|
-
continue;
|
|
470
|
-
}
|
|
471
|
-
if (typeof e === "object" && e !== null && "id" in e && typeof e.id === "string") eventsStore.delete(e.id);
|
|
472
|
-
}
|
|
473
|
-
const byId = new Map(valid.map((e) => [e.id, e]));
|
|
474
|
-
const deletion = new DeletionState();
|
|
475
|
-
const dels = valid.filter((e) => e.kind === Kind.EventDeletion).sort(itemCompare);
|
|
476
|
-
for (const del of dels) {
|
|
477
|
-
const plan = planDeletion(del, (id) => byId.get(id));
|
|
478
|
-
deletion.absorb(plan);
|
|
479
|
-
for (const c of plan.coordinates) for (const ev of valid) {
|
|
480
|
-
if (ev.kind === Kind.EventDeletion) continue;
|
|
481
|
-
if (eventAddress(ev) === c.key && ev.created_at <= c.until) deletion.ids.add(ev.id);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
for (const id of deletion.ids) tombstones.put({
|
|
485
|
-
key: `id:${id}`,
|
|
486
|
-
type: "id"
|
|
487
|
-
});
|
|
488
|
-
for (const [id, pubkey] of deletion.pending) tombstones.put({
|
|
489
|
-
key: `pending:${id}`,
|
|
490
|
-
type: "pending",
|
|
491
|
-
pubkey
|
|
492
|
-
});
|
|
493
|
-
for (const [key, until] of deletion.coordinates) tombstones.put({
|
|
494
|
-
key: `coord:${key}`,
|
|
495
|
-
type: "coord",
|
|
496
|
-
until
|
|
497
|
-
});
|
|
498
|
-
const winners = /* @__PURE__ */ new Map();
|
|
499
|
-
for (const event of valid) {
|
|
500
|
-
if (deletion.ids.has(event.id) || deletion.covers(event)) {
|
|
501
|
-
eventsStore.delete(event.id);
|
|
502
|
-
continue;
|
|
503
|
-
}
|
|
504
|
-
writeTagRefs(tagRefs, event);
|
|
505
|
-
const addr = eventAddress(event);
|
|
506
|
-
if (addr !== void 0) {
|
|
507
|
-
const prev = winners.get(addr);
|
|
508
|
-
if (!prev || isReplaceableWinner(event, prev)) winners.set(addr, event);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
for (const [address, event] of winners) addresses.put({
|
|
512
|
-
address,
|
|
513
|
-
id: event.id,
|
|
514
|
-
created_at: event.created_at
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
function compactSupersededReplaceables(tx) {
|
|
518
|
-
const eventsStore = tx.objectStore(EVENTS);
|
|
519
|
-
const addressesStore = tx.objectStore(ADDRESSES);
|
|
520
|
-
const evReq = eventsStore.getAll();
|
|
521
|
-
const addrReq = addressesStore.getAll();
|
|
522
|
-
let events;
|
|
523
|
-
let addressRows;
|
|
524
|
-
const run = () => {
|
|
525
|
-
if (events === void 0 || addressRows === void 0) return;
|
|
526
|
-
const byAddr = /* @__PURE__ */ new Map();
|
|
527
|
-
for (const row of addressRows) byAddr.set(row.address, row);
|
|
528
|
-
const kept = [];
|
|
529
|
-
for (const event of events) {
|
|
530
|
-
const addr = eventAddress(event);
|
|
531
|
-
if (addr !== void 0) {
|
|
532
|
-
const row = byAddr.get(addr);
|
|
533
|
-
if (!row || row.id !== event.id) {
|
|
534
|
-
deleteStoredEvent(tx, event, row);
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
kept.push(event);
|
|
539
|
-
}
|
|
540
|
-
addressesStore.clear();
|
|
541
|
-
for (const event of kept) {
|
|
542
|
-
const addr = eventAddress(event);
|
|
543
|
-
if (addr === void 0) continue;
|
|
544
|
-
addressesStore.put({
|
|
545
|
-
address: addr,
|
|
546
|
-
id: event.id,
|
|
547
|
-
created_at: event.created_at
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
};
|
|
551
|
-
evReq.onsuccess = () => {
|
|
552
|
-
events = evReq.result ?? [];
|
|
553
|
-
run();
|
|
554
|
-
};
|
|
555
|
-
addrReq.onsuccess = () => {
|
|
556
|
-
addressRows = addrReq.result ?? [];
|
|
557
|
-
run();
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
461
|
//#endregion
|
|
561
462
|
//#region src/storage/indexeddb.ts
|
|
562
463
|
/**
|
|
@@ -569,6 +470,8 @@ function compactSupersededReplaceables(tx) {
|
|
|
569
470
|
var IndexedDbEventStore = class IndexedDbEventStore {
|
|
570
471
|
#dbName;
|
|
571
472
|
#db;
|
|
473
|
+
/** Shared so concurrent open()/first-use calls cannot open a second connection. */
|
|
474
|
+
#opening;
|
|
572
475
|
/** Set when this connection closed to unblock a newer-version open; ops then fail fast. */
|
|
573
476
|
#yielded = false;
|
|
574
477
|
#deletion = new DeletionState();
|
|
@@ -583,6 +486,16 @@ var IndexedDbEventStore = class IndexedDbEventStore {
|
|
|
583
486
|
}
|
|
584
487
|
async open() {
|
|
585
488
|
if (this.#db) return;
|
|
489
|
+
this.#opening ??= (async () => {
|
|
490
|
+
try {
|
|
491
|
+
await this.#doOpen();
|
|
492
|
+
} finally {
|
|
493
|
+
this.#opening = void 0;
|
|
494
|
+
}
|
|
495
|
+
})();
|
|
496
|
+
await this.#opening;
|
|
497
|
+
}
|
|
498
|
+
async #doOpen() {
|
|
586
499
|
if (!IndexedDbEventStore.isAvailable()) throw new StorageError("IndexedDB is not available in this environment");
|
|
587
500
|
const db = await openDb(this.#dbName);
|
|
588
501
|
const closeOnUpgrade = db.onversionchange;
|
|
@@ -592,7 +505,15 @@ var IndexedDbEventStore = class IndexedDbEventStore {
|
|
|
592
505
|
};
|
|
593
506
|
this.#yielded = false;
|
|
594
507
|
this.#db = db;
|
|
595
|
-
|
|
508
|
+
try {
|
|
509
|
+
await this.#loadCaches(db);
|
|
510
|
+
} catch (error) {
|
|
511
|
+
this.#db = void 0;
|
|
512
|
+
try {
|
|
513
|
+
db.close();
|
|
514
|
+
} catch {}
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
596
517
|
}
|
|
597
518
|
async #ensure() {
|
|
598
519
|
if (this.#yielded) throw new StorageError("IndexedDB connection closed by a newer version");
|
|
@@ -627,13 +548,20 @@ var IndexedDbEventStore = class IndexedDbEventStore {
|
|
|
627
548
|
return this.#writeQueue.run(async () => this.#putManyLocked(events));
|
|
628
549
|
}
|
|
629
550
|
async #putManyLocked(events) {
|
|
551
|
+
return this.#withWriteTx(WRITE_STORES, async (tx) => this.#putAllInTx(tx, events));
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Run `fn` inside a readwrite transaction, snapshotting the in-memory deletion/replaceable
|
|
555
|
+
* mirrors so a transaction abort or thrown error restores them to match the rolled-back rows.
|
|
556
|
+
*/
|
|
557
|
+
async #withWriteTx(stores, fn) {
|
|
630
558
|
let db;
|
|
631
559
|
try {
|
|
632
560
|
db = await this.#ensure();
|
|
633
561
|
} catch (error) {
|
|
634
562
|
throw toStorageError(error);
|
|
635
563
|
}
|
|
636
|
-
const tx = db.transaction(
|
|
564
|
+
const tx = db.transaction(stores, "readwrite");
|
|
637
565
|
const txSettled = new Promise((resolve, reject) => {
|
|
638
566
|
tx.oncomplete = () => resolve();
|
|
639
567
|
tx.onerror = () => reject(tx.error ?? new StorageError("IndexedDB transaction failed"));
|
|
@@ -649,10 +577,10 @@ var IndexedDbEventStore = class IndexedDbEventStore {
|
|
|
649
577
|
})();
|
|
650
578
|
const cache = this.#snapshotCaches();
|
|
651
579
|
try {
|
|
652
|
-
const
|
|
580
|
+
const result = await fn(tx);
|
|
653
581
|
const txErr = await txOutcome;
|
|
654
582
|
if (txErr !== void 0) throw toStorageError(txErr);
|
|
655
|
-
return
|
|
583
|
+
return result;
|
|
656
584
|
} catch (error) {
|
|
657
585
|
this.#restoreCaches(cache);
|
|
658
586
|
try {
|
|
@@ -827,53 +755,45 @@ var IndexedDbEventStore = class IndexedDbEventStore {
|
|
|
827
755
|
return this.#writeQueue.run(async () => this.#setOutboxBoundLocked(pubkey, kind, bound));
|
|
828
756
|
}
|
|
829
757
|
async #setOutboxBoundLocked(pubkey, kind, bound) {
|
|
830
|
-
|
|
831
|
-
const tx = (await this.#ensure()).transaction(OUTBOX_BOUNDS, "readwrite");
|
|
832
|
-
const done = txDone(tx);
|
|
758
|
+
await this.#withWriteTx(OUTBOX_BOUNDS, (tx) => {
|
|
833
759
|
tx.objectStore(OUTBOX_BOUNDS).put({
|
|
834
760
|
key: outboxBoundKey(pubkey, kind),
|
|
835
761
|
oldest: bound.oldest,
|
|
836
762
|
newest: bound.newest
|
|
837
763
|
});
|
|
838
|
-
|
|
839
|
-
} catch (error) {
|
|
840
|
-
throw toStorageError(error);
|
|
841
|
-
}
|
|
764
|
+
});
|
|
842
765
|
}
|
|
843
766
|
async remove(ids) {
|
|
844
767
|
return this.#writeQueue.run(async () => this.#removeLocked(ids));
|
|
845
768
|
}
|
|
846
769
|
async #removeLocked(ids) {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return n;
|
|
770
|
+
return this.#withWriteTx(WRITE_STORES, async (tx) => {
|
|
771
|
+
const tombstones = tx.objectStore(TOMBSTONES);
|
|
772
|
+
let n = 0;
|
|
773
|
+
for (const raw of ids) {
|
|
774
|
+
const id = raw.toLowerCase();
|
|
775
|
+
if (await this.#deleteEventRows(tx, id)) n += 1;
|
|
776
|
+
tombstones.put({
|
|
777
|
+
key: `id:${id}`,
|
|
778
|
+
type: "id"
|
|
779
|
+
});
|
|
780
|
+
tombstones.delete(`pending:${id}`);
|
|
781
|
+
this.#deletion.ids.add(id);
|
|
782
|
+
this.#deletion.pending.delete(id);
|
|
783
|
+
}
|
|
784
|
+
return n;
|
|
785
|
+
});
|
|
864
786
|
}
|
|
865
787
|
async clear() {
|
|
866
788
|
return this.#writeQueue.run(async () => this.#clearLocked());
|
|
867
789
|
}
|
|
868
790
|
async #clearLocked() {
|
|
869
|
-
const db = await this.#ensure();
|
|
870
791
|
const stores = [...WRITE_STORES, OUTBOX_BOUNDS];
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
await done;
|
|
792
|
+
await this.#withWriteTx(stores, (tx) => {
|
|
793
|
+
for (const name of stores) tx.objectStore(name).clear();
|
|
794
|
+
this.#deletion.clear();
|
|
795
|
+
this.#replaceable.clear();
|
|
796
|
+
});
|
|
877
797
|
}
|
|
878
798
|
close() {
|
|
879
799
|
this.#db?.close();
|
|
@@ -927,7 +847,7 @@ var IndexedDbEventStore = class IndexedDbEventStore {
|
|
|
927
847
|
//#region src/storage/sqlite.ts
|
|
928
848
|
/** Bound values per `IN (...)` list; stays below every host's variable limit. */
|
|
929
849
|
const IN_CHUNK = 500;
|
|
930
|
-
const SCHEMA_VERSION =
|
|
850
|
+
const SCHEMA_VERSION = 2;
|
|
931
851
|
const SCHEMA_SQL = `
|
|
932
852
|
CREATE TABLE IF NOT EXISTS events (
|
|
933
853
|
id TEXT PRIMARY KEY,
|
|
@@ -970,6 +890,12 @@ CREATE TABLE IF NOT EXISTS outbox_bounds (
|
|
|
970
890
|
PRIMARY KEY(pubkey, kind)
|
|
971
891
|
);
|
|
972
892
|
`;
|
|
893
|
+
const DROP_SQL = `
|
|
894
|
+
DROP TABLE IF EXISTS tags;
|
|
895
|
+
DROP TABLE IF EXISTS tombstones;
|
|
896
|
+
DROP TABLE IF EXISTS outbox_bounds;
|
|
897
|
+
DROP TABLE IF EXISTS events;
|
|
898
|
+
`;
|
|
973
899
|
function rowToEvent(row) {
|
|
974
900
|
return {
|
|
975
901
|
kind: row.kind,
|
|
@@ -1075,9 +1001,12 @@ var SqliteEventStore = class SqliteEventStore {
|
|
|
1075
1001
|
async #migrate() {
|
|
1076
1002
|
try {
|
|
1077
1003
|
const version = (await this.#driver.all("PRAGMA user_version"))[0]?.user_version ?? 0;
|
|
1078
|
-
if (version
|
|
1079
|
-
await this.#driver.
|
|
1080
|
-
|
|
1004
|
+
if (version === SCHEMA_VERSION) return;
|
|
1005
|
+
await this.#driver.transaction(async (tx) => {
|
|
1006
|
+
if (version !== 0) await tx.exec(DROP_SQL);
|
|
1007
|
+
await tx.exec(SCHEMA_SQL);
|
|
1008
|
+
await tx.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
1009
|
+
});
|
|
1081
1010
|
} catch (error) {
|
|
1082
1011
|
throw toStorageError(error);
|
|
1083
1012
|
}
|
|
@@ -1207,7 +1136,7 @@ var SqliteEventStore = class SqliteEventStore {
|
|
|
1207
1136
|
await tx.run(`INSERT INTO tags (event_id, name, value, created_at) VALUES (?, ?, ?, ?)`, [
|
|
1208
1137
|
event.id,
|
|
1209
1138
|
tag[0],
|
|
1210
|
-
tag[
|
|
1139
|
+
tag[1],
|
|
1211
1140
|
event.created_at
|
|
1212
1141
|
]);
|
|
1213
1142
|
}
|
|
@@ -1359,4 +1288,4 @@ var SqliteEventStore = class SqliteEventStore {
|
|
|
1359
1288
|
//#endregion
|
|
1360
1289
|
export { IndexedDbEventStore as n, SqliteEventStore as t };
|
|
1361
1290
|
|
|
1362
|
-
//# sourceMappingURL=storage-
|
|
1291
|
+
//# sourceMappingURL=storage-n2BE1bdY.mjs.map
|