@qntx/nostr 0.1.0 → 0.2.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/abort-Ba8tDrOI.mjs +38 -0
- package/dist/abort-Ba8tDrOI.mjs.map +1 -0
- package/dist/{builder-BphJa-Y-.d.mts → builder-BWn55Paf.d.mts} +20 -14
- package/dist/{builder-q0VsvnYE.mjs → builder-CyrGKRVP.mjs} +32 -16
- package/dist/builder-CyrGKRVP.mjs.map +1 -0
- package/dist/{client-Bd8B1mYm.mjs → client-BWsX9Cv1.mjs} +354 -195
- package/dist/client-BWsX9Cv1.mjs.map +1 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/core.d.mts +8 -8
- package/dist/core.mjs +8 -9
- package/dist/error-BW7re1UN.d.mts +9 -0
- package/dist/error-B__OMBRY.mjs +14 -0
- package/dist/error-B__OMBRY.mjs.map +1 -0
- package/dist/{error-WEFS-R-4.d.mts → error-CR8Urc84.d.mts} +20 -8
- package/dist/{error-CwBxle6N.mjs → error-DrEIM7FO.mjs} +5 -3
- package/dist/error-DrEIM7FO.mjs.map +1 -0
- package/dist/{event-CzoQEFMF.mjs → event-D8Nfoh4K.mjs} +40 -32
- package/dist/event-D8Nfoh4K.mjs.map +1 -0
- package/dist/{event-B5D2jxt_.d.mts → event-fU3Y01PR.d.mts} +23 -20
- package/dist/{filter-BxwjEkZp.mjs → filter-BQl3GlHt.mjs} +42 -35
- package/dist/filter-BQl3GlHt.mjs.map +1 -0
- package/dist/filter-C0IMByE3.d.mts +37 -0
- package/dist/{gossip-C5RVB1UB.d.mts → gossip-BRQwIM_q.d.mts} +25 -23
- package/dist/{gossip-3xkRRCm_.mjs → gossip-oloDMWEj.mjs} +52 -34
- package/dist/gossip-oloDMWEj.mjs.map +1 -0
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/{http-6vevbBlu.d.mts → http-C4HwIu4B.d.mts} +7 -7
- package/dist/{http-D2rhokZo.mjs → http-CuazNRIP.mjs} +10 -6
- package/dist/http-CuazNRIP.mjs.map +1 -0
- package/dist/index-B425CAcQ.d.mts +328 -0
- package/dist/index-BVyfUBuG.d.mts +181 -0
- package/dist/{index-BYMnhRIC.d.mts → index-Ba7bJ7DD.d.mts} +68 -50
- package/dist/{index-DaRyjo7O.d.mts → index-Boe8FshM.d.mts} +13 -7
- package/dist/index-CUIvFQdE.d.mts +73 -0
- package/dist/index-JdaS_uce.d.mts +207 -0
- package/dist/index.d.mts +22 -20
- package/dist/index.mjs +19 -18
- package/dist/{key-Dn-aX4x4.mjs → key-Bbtys6o7.mjs} +22 -14
- package/dist/key-Bbtys6o7.mjs.map +1 -0
- package/dist/{key-BiGxGLhg.d.mts → key-BlsYhN1V.d.mts} +9 -6
- package/dist/{kind-BLl4cLOc.mjs → kind-Cxwhhkx8.mjs} +2 -1
- package/dist/kind-Cxwhhkx8.mjs.map +1 -0
- package/dist/{loaders-BNQszDAn.mjs → loaders-o6YXB_Ri.mjs} +329 -305
- package/dist/loaders-o6YXB_Ri.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -3
- package/dist/loaders.mjs +2 -2
- package/dist/memory-C2EVx0_O.mjs +46 -0
- package/dist/memory-C2EVx0_O.mjs.map +1 -0
- package/dist/{memory-BCmhZPek.mjs → memory-index-Do1mz0WF.mjs} +212 -82
- package/dist/memory-index-Do1mz0WF.mjs.map +1 -0
- package/dist/{message-C_Uj-Y-c.mjs → message-DcY6Fi9o.mjs} +38 -24
- package/dist/message-DcY6Fi9o.mjs.map +1 -0
- package/dist/{message-DJC-Jz6T.d.mts → message-iGPIqnn0.d.mts} +15 -8
- package/dist/{nip17-BWq-Kfq5.d.mts → nip17-DNEkz8rM.d.mts} +18 -17
- package/dist/{nip19-D7905oIv.d.mts → nip19-BevCJZsp.d.mts} +23 -3
- package/dist/{nip46-C_DoxiS_.d.mts → nip46-DDV4dC56.d.mts} +13 -12
- package/dist/{nip59-DljW_sYh.d.mts → nip59-zQgdLcEr.d.mts} +28 -25
- package/dist/{nip65-Di5hZRuV.d.mts → nip65-DBfh2smt.d.mts} +8 -3
- package/dist/{nip77-ByxlgoQO.d.mts → nip77-DH4RhS5r.d.mts} +9 -8
- package/dist/nips/blossom.d.mts +37 -37
- package/dist/nips/blossom.mjs +67 -52
- package/dist/nips/blossom.mjs.map +1 -1
- package/dist/nips/nip04.d.mts +2 -3
- package/dist/nips/nip04.mjs +6 -10
- package/dist/nips/nip04.mjs.map +1 -1
- package/dist/nips/nip05.d.mts +37 -43
- package/dist/nips/nip05.mjs +57 -57
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +18 -19
- package/dist/nips/nip10.mjs +76 -61
- package/dist/nips/nip10.mjs.map +1 -1
- package/dist/nips/nip11.d.mts +9 -8
- package/dist/nips/nip11.mjs +14 -11
- package/dist/nips/nip11.mjs.map +1 -1
- package/dist/nips/nip13.d.mts +9 -9
- package/dist/nips/nip13.mjs +15 -17
- package/dist/nips/nip13.mjs.map +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +17 -12
- package/dist/nips/nip17.mjs.map +1 -1
- package/dist/nips/nip19.d.mts +1 -1
- package/dist/nips/nip19.mjs +52 -29
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.d.mts +5 -6
- package/dist/nips/nip21.mjs +8 -7
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +7 -8
- package/dist/nips/nip27.mjs +26 -25
- package/dist/nips/nip27.mjs.map +1 -1
- package/dist/nips/nip42.d.mts +5 -6
- package/dist/nips/nip42.mjs +3 -3
- package/dist/nips/nip42.mjs.map +1 -1
- package/dist/nips/nip44.d.mts +24 -7
- package/dist/nips/nip44.mjs +25 -15
- package/dist/nips/nip44.mjs.map +1 -1
- package/dist/nips/nip46.d.mts +1 -1
- package/dist/nips/nip46.mjs +52 -49
- package/dist/nips/nip46.mjs.map +1 -1
- package/dist/nips/nip49.d.mts +8 -7
- package/dist/nips/nip49.mjs +16 -12
- package/dist/nips/nip49.mjs.map +1 -1
- package/dist/nips/nip51.d.mts +25 -27
- package/dist/nips/nip51.mjs +47 -36
- package/dist/nips/nip51.mjs.map +1 -1
- package/dist/nips/nip57.d.mts +12 -13
- package/dist/nips/nip57.mjs +35 -38
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.d.mts +1 -1
- package/dist/nips/nip59.mjs +14 -18
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +1 -1
- package/dist/nips/nip65.mjs +11 -8
- package/dist/nips/nip65.mjs.map +1 -1
- package/dist/nips/nip77.d.mts +1 -1
- package/dist/nips/nip77.mjs +56 -34
- package/dist/nips/nip77.mjs.map +1 -1
- package/dist/nips/nip96.d.mts +21 -12
- package/dist/nips/nip96.mjs +59 -36
- package/dist/nips/nip96.mjs.map +1 -1
- package/dist/nips/nip98.d.mts +12 -12
- package/dist/nips/nip98.mjs +18 -19
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/{pool-C_j1OmBB.mjs → pool-XmAGaufS.mjs} +611 -487
- package/dist/pool-XmAGaufS.mjs.map +1 -0
- package/dist/pool-tEr7c5bG.d.mts +302 -0
- package/dist/reactive-DDlThDSZ.mjs +324 -0
- package/dist/reactive-DDlThDSZ.mjs.map +1 -0
- package/dist/reactive-DFpqtIf_.d.mts +66 -0
- package/dist/relay.d.mts +5 -4
- package/dist/relay.mjs +2 -2
- package/dist/report-CHld4uWj.mjs +32 -0
- package/dist/report-CHld4uWj.mjs.map +1 -0
- package/dist/{signer-CZ6K6FUc.mjs → signer-CKR9EHce.mjs} +107 -72
- package/dist/signer-CKR9EHce.mjs.map +1 -0
- package/dist/signer.d.mts +3 -3
- package/dist/signer.mjs +3 -2
- package/dist/storage-xXxLGCVb.mjs +1376 -0
- package/dist/storage-xXxLGCVb.mjs.map +1 -0
- package/dist/storage.d.mts +4 -4
- package/dist/storage.mjs +5 -4
- package/dist/store.d.mts +2 -0
- package/dist/store.mjs +2 -0
- package/dist/testing.d.mts +125 -0
- package/dist/testing.mjs +957 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/types-2pCUprRU.d.mts +47 -0
- package/dist/types-CRQEk0Oi.d.mts +19 -0
- package/dist/util-LfQirgDk.mjs +113 -0
- package/dist/util-LfQirgDk.mjs.map +1 -0
- package/dist/wasm.d.mts +4 -4
- package/dist/wasm.mjs +54 -55
- package/dist/wasm.mjs.map +1 -1
- package/dist/websocket-CmeqvAkp.d.mts +27 -0
- package/package.json +31 -9
- package/dist/builder-q0VsvnYE.mjs.map +0 -1
- package/dist/client-Bd8B1mYm.mjs.map +0 -1
- package/dist/error-B49rbDzT.d.mts +0 -7
- package/dist/error-CwBxle6N.mjs.map +0 -1
- package/dist/error-DZEs5OuZ.mjs +0 -24
- package/dist/error-DZEs5OuZ.mjs.map +0 -1
- package/dist/event-CzoQEFMF.mjs.map +0 -1
- package/dist/filter-BxwjEkZp.mjs.map +0 -1
- package/dist/filter-DUEKP3q1.d.mts +0 -40
- package/dist/gossip-3xkRRCm_.mjs.map +0 -1
- package/dist/http-D2rhokZo.mjs.map +0 -1
- package/dist/index-C0C4e-Gn.d.mts +0 -55
- package/dist/index-DgOugrpF.d.mts +0 -275
- package/dist/index-EwL6fHLo.d.mts +0 -267
- package/dist/index-k2YhCgsh.d.mts +0 -57
- package/dist/key-Dn-aX4x4.mjs.map +0 -1
- package/dist/kind-BLl4cLOc.mjs.map +0 -1
- package/dist/loaders-BNQszDAn.mjs.map +0 -1
- package/dist/memory-BCmhZPek.mjs.map +0 -1
- package/dist/message-C_Uj-Y-c.mjs.map +0 -1
- package/dist/pool-C_j1OmBB.mjs.map +0 -1
- package/dist/pool-DhRi7l-b.d.mts +0 -297
- package/dist/signer-CZ6K6FUc.mjs.map +0 -1
- package/dist/storage-DOy0iLRE.mjs +0 -870
- package/dist/storage-DOy0iLRE.mjs.map +0 -1
- package/dist/types-BzyADqnw.d.mts +0 -19
- package/dist/types-Dn24TPFs.d.mts +0 -43
- package/dist/util-6tfLQ9JF.mjs +0 -73
- package/dist/util-6tfLQ9JF.mjs.map +0 -1
package/dist/wasm.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm.mjs","names":[],"sources":["../src/wasm/abi.ts","../src/wasm/adapter.ts","../src/wasm/load.ts"],"sourcesContent":["/** wasm-bindgen 0.2.122 bundler-produced exports used by interned TS glue. */\nexport type CryptoWasmExports = {\n memory: WebAssembly.Memory;\n verify: (\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n verify_serialized: (\n serPtr: number,\n serLen: number,\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n sign: (\n retptr: number,\n idPtr: number,\n idLen: number,\n skPtr: number,\n skLen: number,\n auxPtr: number,\n auxLen: number,\n ) => void;\n public_key: (retptr: number, skPtr: number, skLen: number) => void;\n /** 0.2.122 name for `__wbindgen_malloc(size, align)`. */\n __wbindgen_export: (size: number, align: number) => number;\n /** 0.2.122 name for `__wbindgen_free(ptr, size, align)` after malloc claimed `__wbindgen_export`. */\n __wbindgen_export2: (ptr: number, size: number, align: number) => void;\n __wbindgen_add_to_stack_pointer: (delta: number) => number;\n __wbindgen_start?: () => void;\n};\n\n/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */\nexport const ALLOWED_WASM_IMPORTS: ReadonlyArray<{ module: string; name: string }> = [\n { module: \"wbg\", name: \"__wbindgen_throw\" },\n { module: \"./nostr_crypto_wasm_bg.js\", name: \"__wbindgen_throw\" },\n];\n\nconst utf8 = new TextDecoder();\n\nfunction decodeUtf8(memory: WebAssembly.Memory, ptr: number, len: number): string {\n return utf8.decode(new Uint8Array(memory.buffer, ptr, len));\n}\n\nfunction makeWbgImports(holder: { exports?: CryptoWasmExports }): WebAssembly.Imports {\n const throwRuntime = (ptr: number, len: number): never => {\n const mem = holder.exports?.memory;\n const msg = mem ? decodeUtf8(mem, ptr, len) : \"wasm panic\";\n throw new WebAssembly.RuntimeError(msg);\n };\n const wbg = {\n __wbindgen_throw: throwRuntime,\n };\n return {\n wbg,\n \"./nostr_crypto_wasm_bg.js\": wbg,\n };\n}\n\n/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */\nexport function assertAllowedWasmImports(mod: WebAssembly.Module): void {\n const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\\0${item.name}`));\n for (const imp of WebAssembly.Module.imports(mod)) {\n if (imp.kind !== \"function\") {\n throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);\n }\n if (!allowed.has(`${imp.module}\\0${imp.name}`)) {\n throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);\n }\n }\n}\n\nfunction requireMemory(value: WebAssembly.ExportValue | undefined): WebAssembly.Memory {\n if (!(value instanceof WebAssembly.Memory)) {\n throw new TypeError(\"wasm missing memory export\");\n }\n return value;\n}\n\nfunction requireFn<T extends (...args: never[]) => unknown>(\n value: WebAssembly.ExportValue | undefined,\n name: string,\n): T {\n if (typeof value !== \"function\") {\n throw new TypeError(`wasm missing ${name} export`);\n }\n return value as T;\n}\n\nfunction asExports(raw: WebAssembly.Exports): CryptoWasmExports {\n return {\n memory: requireMemory(raw.memory),\n verify: requireFn(raw.verify, \"verify\"),\n verify_serialized: requireFn(raw.verify_serialized, \"verify_serialized\"),\n sign: requireFn(raw.sign, \"sign\"),\n public_key: requireFn(raw.public_key, \"public_key\"),\n __wbindgen_export: requireFn(raw.__wbindgen_export, \"__wbindgen_export\"),\n __wbindgen_export2: requireFn(raw.__wbindgen_export2, \"__wbindgen_export2\"),\n __wbindgen_add_to_stack_pointer: requireFn(\n raw.__wbindgen_add_to_stack_pointer,\n \"__wbindgen_add_to_stack_pointer\",\n ),\n __wbindgen_start:\n typeof raw.__wbindgen_start === \"function\" ? (raw.__wbindgen_start as () => void) : undefined,\n };\n}\n\nfunction passBytes(exports: CryptoWasmExports, bytes: Uint8Array): { ptr: number; len: number } {\n const len = bytes.length;\n const ptr = exports.__wbindgen_export(len, 1) >>> 0;\n new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);\n return { ptr, len };\n}\n\nfunction callWithBytes(\n exports: CryptoWasmExports,\n arrays: readonly Uint8Array[],\n invoke: (args: number[]) => number,\n): boolean {\n const passed = arrays.map((bytes) => passBytes(exports, bytes));\n const args = passed.flatMap(({ ptr, len }) => [ptr, len]);\n return invoke(args) !== 0;\n}\n\nexport function wasmVerify(\n exports: CryptoWasmExports,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n return callWithBytes(exports, [id, pubkey, sig], (args) =>\n exports.verify(args[0]!, args[1]!, args[2]!, args[3]!, args[4]!, args[5]!),\n );\n}\n\nexport function wasmVerifySerialized(\n exports: CryptoWasmExports,\n serialized: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n return callWithBytes(exports, [serialized, id, pubkey, sig], (args) =>\n exports.verify_serialized(\n args[0]!,\n args[1]!,\n args[2]!,\n args[3]!,\n args[4]!,\n args[5]!,\n args[6]!,\n args[7]!,\n ),\n );\n}\n\nfunction takeBytes(exports: CryptoWasmExports, ptr: number, len: number): Uint8Array {\n const out = new Uint8Array(len);\n if (len > 0) {\n out.set(new Uint8Array(exports.memory.buffer, ptr, len));\n exports.__wbindgen_export2(ptr, len, 1);\n }\n return out;\n}\n\nfunction callReturningBytes(\n exports: CryptoWasmExports,\n arrays: readonly Uint8Array[],\n invoke: (retptr: number, args: number[]) => void,\n): Uint8Array {\n const passed = arrays.map((bytes) => passBytes(exports, bytes));\n const args = passed.flatMap(({ ptr, len }) => [ptr, len]);\n const retptr = exports.__wbindgen_add_to_stack_pointer(-16);\n try {\n invoke(retptr, args);\n const view = new DataView(exports.memory.buffer);\n const ptr = view.getInt32(retptr, true) >>> 0;\n const len = view.getInt32(retptr + 4, true) >>> 0;\n return takeBytes(exports, ptr, len);\n } finally {\n exports.__wbindgen_add_to_stack_pointer(16);\n }\n}\n\nexport function wasmSign(\n exports: CryptoWasmExports,\n id: Uint8Array,\n seckey: Uint8Array,\n aux: Uint8Array,\n): Uint8Array {\n return callReturningBytes(exports, [id, seckey, aux], (retptr, args) => {\n exports.sign(retptr, args[0]!, args[1]!, args[2]!, args[3]!, args[4]!, args[5]!);\n });\n}\n\nexport function wasmPublicKey(exports: CryptoWasmExports, seckey: Uint8Array): Uint8Array {\n return callReturningBytes(exports, [seckey], (retptr, args) => {\n exports.public_key(retptr, args[0]!, args[1]!);\n });\n}\n\nexport async function instantiateCryptoWasm(\n bytes: ArrayBuffer | ArrayBufferView,\n): Promise<CryptoWasmExports> {\n const holder: { exports?: CryptoWasmExports } = {};\n const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));\n assertAllowedWasmImports(module);\n holder.exports = asExports(instance.exports);\n holder.exports.__wbindgen_start?.();\n return holder.exports;\n}\n","import { WasmVerifyPoisonedError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n isMarkedFailed,\n isMarkedVerified,\n markUnverified,\n markVerified,\n serializeEvent,\n validateSignedEvent,\n} from \"../core/event.ts\";\nimport { hexToBytes, utf8Encoder } from \"../core/util.ts\";\n\nexport { WasmVerifyPoisonedError };\n\nexport type WasmSerializedVerify = {\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n};\n\nexport function makeVerifyEvent(\n wasm: WasmSerializedVerify,\n poison: { error?: Error },\n): (event: Event) => boolean {\n return (event: Event): boolean => {\n if (poison.error) throw poison.error;\n if (isMarkedVerified(event)) return true;\n if (isMarkedFailed(event)) return false;\n if (!validateSignedEvent(event)) {\n markUnverified(event);\n return false;\n }\n try {\n const serialized = utf8Encoder.encode(serializeEvent(event));\n const id = hexToBytes(event.id.toLowerCase());\n const pubkey = hexToBytes(event.pubkey.toLowerCase());\n const sig = hexToBytes(event.sig.toLowerCase());\n const ok = wasm.verifySerialized(serialized, id, pubkey, sig);\n if (ok) markVerified(event);\n else markUnverified(event);\n return ok;\n } catch (e) {\n if (e instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: e,\n });\n throw poison.error;\n }\n markUnverified(event);\n return false;\n }\n };\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n instantiateCryptoWasm,\n wasmPublicKey,\n wasmSign,\n wasmVerify,\n wasmVerifySerialized,\n type CryptoWasmExports,\n} from \"./abi.ts\";\nimport { makeVerifyEvent, WasmVerifyPoisonedError } from \"./adapter.ts\";\n\nexport type LoadNostrWasmOptions = {\n /** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */\n module?: ArrayBuffer | ArrayBufferView | URL;\n};\n\nexport type NostrWasm = {\n verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n verifyEvent: (event: Event) => boolean;\n sign: (id: Uint8Array, seckey: Uint8Array, aux: Uint8Array) => Uint8Array;\n publicKey: (seckey: Uint8Array) => Uint8Array;\n};\n\nexport { WasmVerifyPoisonedError };\n\nlet interned: Promise<NostrWasm> | undefined;\n\nfunction isNode(): boolean {\n return (\n typeof process !== \"undefined\" &&\n typeof process.versions === \"object\" &&\n process.versions !== null &&\n typeof process.versions.node === \"string\"\n );\n}\n\nfunction isWasmBytes(value: object): value is ArrayBuffer | ArrayBufferView {\n return value instanceof ArrayBuffer || ArrayBuffer.isView(value);\n}\n\nasync function defaultWasmHref(): Promise<string> {\n const mod = await import(\"./nostr_crypto_wasm_bg.wasm?url\");\n return mod.default;\n}\n\nasync function readWasmUrl(url: URL): Promise<Uint8Array> {\n if (isNode() && url.protocol === \"file:\") {\n const { readFile } = await import(\"node:fs/promises\");\n const { fileURLToPath } = await import(\"node:url\");\n return new Uint8Array(await readFile(fileURLToPath(url)));\n }\n const res = await fetch(url);\n if (!res.ok) {\n throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n\nasync function wasmBytes(opts?: LoadNostrWasmOptions): Promise<ArrayBuffer | ArrayBufferView> {\n const source = opts?.module;\n if (source !== undefined && isWasmBytes(source)) return source;\n const href = source instanceof URL ? source : new URL(await defaultWasmHref(), import.meta.url);\n return readWasmUrl(href);\n}\n\nfunction requireByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nfunction wrapPoison<T>(poison: { error?: Error }, fn: () => T): T {\n if (poison.error) throw poison.error;\n try {\n return fn();\n } catch (e) {\n if (e instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: e,\n });\n throw poison.error;\n }\n throw e;\n }\n}\n\nfunction bindExports(exports: CryptoWasmExports): NostrWasm {\n const poison: { error?: Error } = {};\n const rawSerialized = (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ): boolean => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);\n return {\n verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),\n verifySerialized: (serializedUtf8, id, pubkey, sig) =>\n wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),\n verifyEvent: makeVerifyEvent({ verifySerialized: rawSerialized }, poison),\n sign: (id, seckey, aux) =>\n wrapPoison(poison, () => {\n requireByteLength(id, 32, \"id\");\n requireByteLength(seckey, 32, \"secret key\");\n requireByteLength(aux, 32, \"aux\");\n const sig = wasmSign(exports, id, seckey, aux);\n if (sig.length !== 64) throw new CryptoError(\"wasm sign failed\");\n return sig;\n }),\n publicKey: (seckey) =>\n wrapPoison(poison, () => {\n requireByteLength(seckey, 32, \"secret key\");\n const pk = wasmPublicKey(exports, seckey);\n if (pk.length !== 32) throw new CryptoError(\"wasm publicKey failed\");\n return pk;\n }),\n };\n}\n\nasync function instantiateNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n const bytes = await wasmBytes(opts);\n const exports = await instantiateCryptoWasm(bytes);\n return bindExports(exports);\n}\n\n/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\nexport function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n if (interned) return interned;\n const pending = instantiateNostrWasm(opts).catch((error: unknown) => {\n if (interned === pending) interned = undefined;\n throw error;\n });\n interned = pending;\n return pending;\n}\n\n/** Clears intern so tests can re-instantiate. Not exported from the wasm subpath. */\nexport function resetNostrWasmForTests(): void {\n interned = undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wasm.mjs","names":[],"sources":["../src/wasm/abi.ts","../src/wasm/adapter.ts","../src/wasm/load.ts"],"sourcesContent":["/** Wasm-bindgen 0.2.122 bundler-produced exports used by interned TS glue. */\nexport type CryptoWasmExports = {\n memory: WebAssembly.Memory;\n verify: (\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n verify_serialized: (\n serPtr: number,\n serLen: number,\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n sign: (\n retptr: number,\n idPtr: number,\n idLen: number,\n skPtr: number,\n skLen: number,\n auxPtr: number,\n auxLen: number,\n ) => void;\n public_key: (retptr: number, skPtr: number, skLen: number) => void;\n /** 0.2.122 name for `__wbindgen_malloc(size, align)`. */\n __wbindgen_export: (size: number, align: number) => number;\n /** 0.2.122 name for `__wbindgen_free(ptr, size, align)` after malloc claimed `__wbindgen_export`. */\n __wbindgen_export2: (ptr: number, size: number, align: number) => void;\n __wbindgen_add_to_stack_pointer: (delta: number) => number;\n __wbindgen_start?: () => void;\n};\n\n/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */\nexport const ALLOWED_WASM_IMPORTS: ReadonlyArray<{ module: string; name: string }> = [\n { module: \"wbg\", name: \"__wbindgen_throw\" },\n { module: \"./nostr_crypto_wasm_bg.js\", name: \"__wbindgen_throw\" },\n];\n\nconst utf8 = new TextDecoder();\n\nfunction decodeUtf8(memory: WebAssembly.Memory, ptr: number, len: number): string {\n return utf8.decode(new Uint8Array(memory.buffer, ptr, len));\n}\n\nfunction makeWbgImports(holder: { exports?: CryptoWasmExports }): WebAssembly.Imports {\n const throwRuntime = (ptr: number, len: number): never => {\n const mem = holder.exports?.memory;\n const msg = mem ? decodeUtf8(mem, ptr, len) : \"wasm panic\";\n throw new WebAssembly.RuntimeError(msg);\n };\n const wbg = {\n __wbindgen_throw: throwRuntime,\n };\n return {\n wbg,\n \"./nostr_crypto_wasm_bg.js\": wbg,\n };\n}\n\n/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */\nexport function assertAllowedWasmImports(mod: WebAssembly.Module): void {\n const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\\0${item.name}`));\n for (const imp of WebAssembly.Module.imports(mod)) {\n if (imp.kind !== \"function\") {\n throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);\n }\n if (!allowed.has(`${imp.module}\\0${imp.name}`)) {\n throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);\n }\n }\n}\n\nfunction requireMemory(value: WebAssembly.ExportValue | undefined): WebAssembly.Memory {\n if (!(value instanceof WebAssembly.Memory)) {\n throw new TypeError(\"wasm missing memory export\");\n }\n return value;\n}\n\n// oxlint-disable-next-line no-unnecessary-type-parameters -- T binds the declared ABI signature at each call site\nfunction requireFn<T extends (...args: number[]) => unknown>(\n value: WebAssembly.ExportValue | undefined,\n name: string,\n): T {\n if (typeof value !== \"function\") {\n throw new TypeError(`wasm missing ${name} export`);\n }\n // oxlint-disable-next-line no-unsafe-type-assertion -- wasm exports are opaque; each name is bound to the signature the ABI contract requires\n return value as T;\n}\n\nfunction asExports(raw: WebAssembly.Exports): CryptoWasmExports {\n const exports: CryptoWasmExports = {\n memory: requireMemory(raw[\"memory\"]),\n verify: requireFn(raw[\"verify\"], \"verify\"),\n verify_serialized: requireFn(raw[\"verify_serialized\"], \"verify_serialized\"),\n sign: requireFn(raw[\"sign\"], \"sign\"),\n public_key: requireFn(raw[\"public_key\"], \"public_key\"),\n __wbindgen_export: requireFn(raw[\"__wbindgen_export\"], \"__wbindgen_export\"),\n __wbindgen_export2: requireFn(raw[\"__wbindgen_export2\"], \"__wbindgen_export2\"),\n __wbindgen_add_to_stack_pointer: requireFn(\n raw[\"__wbindgen_add_to_stack_pointer\"],\n \"__wbindgen_add_to_stack_pointer\",\n ),\n };\n const start = raw[\"__wbindgen_start\"];\n if (typeof start === \"function\") {\n exports.__wbindgen_start = requireFn<() => void>(start, \"__wbindgen_start\");\n }\n return exports;\n}\n\nfunction passBytes(exports: CryptoWasmExports, bytes: Uint8Array): { ptr: number; len: number } {\n const len = bytes.length;\n const ptr = exports.__wbindgen_export(len, 1) >>> 0;\n new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);\n return { ptr, len };\n}\n\nexport function wasmVerify(\n exports: CryptoWasmExports,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return exports.verify(idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;\n}\n\nexport function wasmVerifySerialized(\n exports: CryptoWasmExports,\n serialized: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const serP = passBytes(exports, serialized);\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return (\n exports.verify_serialized(\n serP.ptr,\n serP.len,\n idP.ptr,\n idP.len,\n pkP.ptr,\n pkP.len,\n sigP.ptr,\n sigP.len,\n ) !== 0\n );\n}\n\nfunction takeBytes(exports: CryptoWasmExports, ptr: number, len: number): Uint8Array {\n const out = new Uint8Array(len);\n if (len > 0) {\n out.set(new Uint8Array(exports.memory.buffer, ptr, len));\n exports.__wbindgen_export2(ptr, len, 1);\n }\n return out;\n}\n\nfunction callReturningBytes(\n exports: CryptoWasmExports,\n invoke: (retptr: number) => void,\n): Uint8Array {\n const retptr = exports.__wbindgen_add_to_stack_pointer(-16);\n try {\n invoke(retptr);\n const view = new DataView(exports.memory.buffer);\n const ptr = view.getUint32(retptr, true);\n const len = view.getUint32(retptr + 4, true);\n return takeBytes(exports, ptr, len);\n } finally {\n exports.__wbindgen_add_to_stack_pointer(16);\n }\n}\n\nexport function wasmSign(\n exports: CryptoWasmExports,\n id: Uint8Array,\n seckey: Uint8Array,\n aux: Uint8Array,\n): Uint8Array {\n const idP = passBytes(exports, id);\n const skP = passBytes(exports, seckey);\n const auxP = passBytes(exports, aux);\n return callReturningBytes(exports, (retptr) => {\n exports.sign(retptr, idP.ptr, idP.len, skP.ptr, skP.len, auxP.ptr, auxP.len);\n });\n}\n\nexport function wasmPublicKey(exports: CryptoWasmExports, seckey: Uint8Array): Uint8Array {\n const skP = passBytes(exports, seckey);\n return callReturningBytes(exports, (retptr) => {\n exports.public_key(retptr, skP.ptr, skP.len);\n });\n}\n\nexport async function instantiateCryptoWasm(\n bytes: ArrayBuffer | ArrayBufferView,\n): Promise<CryptoWasmExports> {\n const holder: { exports?: CryptoWasmExports } = {};\n const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));\n assertAllowedWasmImports(module);\n holder.exports = asExports(instance.exports);\n holder.exports.__wbindgen_start?.();\n return holder.exports;\n}\n","import { WasmVerifyPoisonedError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n isMarkedFailed,\n isMarkedVerified,\n markUnverified,\n markVerified,\n serializeEvent,\n validateSignedEvent,\n} from \"../core/event.ts\";\nimport { hexToBytes, utf8Encoder } from \"../core/util.ts\";\n\nexport { WasmVerifyPoisonedError } from \"../core/error.ts\";\n\nexport type WasmSerializedVerify = {\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n};\n\nexport function makeVerifyEvent(\n wasm: WasmSerializedVerify,\n poison: { error?: Error },\n): (event: Event) => boolean {\n return (event: Event): boolean => {\n if (poison.error) {\n throw poison.error;\n }\n if (isMarkedVerified(event)) {\n return true;\n }\n if (isMarkedFailed(event)) {\n return false;\n }\n if (!validateSignedEvent(event)) {\n markUnverified(event);\n return false;\n }\n try {\n const serialized = utf8Encoder.encode(serializeEvent(event));\n const id = hexToBytes(event.id);\n const pubkey = hexToBytes(event.pubkey);\n const sig = hexToBytes(event.sig);\n const ok = wasm.verifySerialized(serialized, id, pubkey, sig);\n if (ok) {\n markVerified(event);\n } else {\n markUnverified(event);\n }\n return ok;\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n markUnverified(event);\n return false;\n }\n };\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport {\n instantiateCryptoWasm,\n wasmPublicKey,\n wasmSign,\n wasmVerify,\n wasmVerifySerialized,\n} from \"./abi.ts\";\nimport type { CryptoWasmExports } from \"./abi.ts\";\nimport { makeVerifyEvent, WasmVerifyPoisonedError } from \"./adapter.ts\";\n\nexport { WasmVerifyPoisonedError } from \"./adapter.ts\";\nexport type LoadNostrWasmOptions = {\n /** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */\n module?: ArrayBuffer | ArrayBufferView | URL;\n};\n\nexport type NostrWasm = {\n verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n verifyEvent: (event: Event) => boolean;\n sign: (id: Uint8Array, seckey: Uint8Array, aux: Uint8Array) => Uint8Array;\n publicKey: (seckey: Uint8Array) => Uint8Array;\n};\n\nlet interned: Promise<NostrWasm> | undefined;\n\nfunction isNode(): boolean {\n if (!(\"process\" in globalThis)) {\n return false;\n }\n const proc: unknown = globalThis.process;\n return (\n typeof proc === \"object\" &&\n proc !== null &&\n \"versions\" in proc &&\n typeof proc.versions === \"object\" &&\n proc.versions !== null &&\n \"node\" in proc.versions &&\n typeof proc.versions.node === \"string\"\n );\n}\n\nfunction isWasmBytes(value: unknown): value is ArrayBuffer | ArrayBufferView {\n return value instanceof ArrayBuffer || ArrayBuffer.isView(value);\n}\n\nasync function defaultWasmHref(): Promise<string> {\n const mod = await import(\"./nostr_crypto_wasm_bg.wasm?url\");\n return mod.default;\n}\n\nasync function readWasmUrl(url: URL): Promise<Uint8Array> {\n if (isNode() && url.protocol === \"file:\") {\n const { readFile } = await import(\"node:fs/promises\");\n const { fileURLToPath } = await import(\"node:url\");\n return new Uint8Array(await readFile(fileURLToPath(url)));\n }\n const res = await fetch(url);\n if (!res.ok) {\n throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n\nasync function wasmBytes(opts?: LoadNostrWasmOptions): Promise<ArrayBuffer | ArrayBufferView> {\n const source = opts?.module;\n if (source !== undefined && isWasmBytes(source)) {\n return source;\n }\n const href = source instanceof URL ? source : new URL(await defaultWasmHref(), import.meta.url);\n return readWasmUrl(href);\n}\n\nfunction requireByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nfunction wrapPoison<T>(poison: { error?: Error }, fn: () => T): T {\n if (poison.error) {\n throw poison.error;\n }\n try {\n return fn();\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n throw error;\n }\n}\n\nfunction bindExports(exports: CryptoWasmExports): NostrWasm {\n const poison: { error?: Error } = {};\n const rawSerialized = (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ): boolean => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);\n return {\n verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),\n verifySerialized: (serializedUtf8, id, pubkey, sig) =>\n wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),\n verifyEvent: makeVerifyEvent({ verifySerialized: rawSerialized }, poison),\n sign: (id, seckey, aux) =>\n wrapPoison(poison, () => {\n requireByteLength(id, 32, \"id\");\n requireByteLength(seckey, 32, \"secret key\");\n requireByteLength(aux, 32, \"aux\");\n const sig = wasmSign(exports, id, seckey, aux);\n if (sig.length !== 64) {\n throw new CryptoError(\"wasm sign failed\");\n }\n return sig;\n }),\n publicKey: (seckey) =>\n wrapPoison(poison, () => {\n requireByteLength(seckey, 32, \"secret key\");\n const pk = wasmPublicKey(exports, seckey);\n if (pk.length !== 32) {\n throw new CryptoError(\"wasm publicKey failed\");\n }\n return pk;\n }),\n };\n}\n\nasync function instantiateNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n const bytes = await wasmBytes(opts);\n const exports = await instantiateCryptoWasm(bytes);\n return bindExports(exports);\n}\n\n/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\nexport async function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n if (interned) {\n return interned;\n }\n const pending = instantiateNostrWasm(opts);\n interned = pending;\n try {\n return await pending;\n } catch (error) {\n if (interned === pending) {\n interned = undefined;\n }\n throw error;\n }\n}\n\n/** Clears intern so tests can re-instantiate. Not exported from the wasm subpath. */\nexport function resetNostrWasmForTests(): void {\n interned = undefined;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/relay/websocket.d.ts
|
|
2
|
+
/** Minimal WebSocket surface used by Relay (browser or `ws`). */
|
|
3
|
+
type WebSocketLike = {
|
|
4
|
+
readyState: number;
|
|
5
|
+
send: (data: string) => void;
|
|
6
|
+
close: (code?: number, reason?: string) => void;
|
|
7
|
+
addEventListener: (type: string, listener: (ev: unknown) => void) => void;
|
|
8
|
+
removeEventListener: (type: string, listener: (ev: unknown) => void) => void;
|
|
9
|
+
ping?: () => void;
|
|
10
|
+
/** Node `ws` emits `pong` on the EventEmitter; `addEventListener("pong")` is a no-op. */
|
|
11
|
+
once?: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
12
|
+
on?: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
13
|
+
off?: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
14
|
+
};
|
|
15
|
+
type WebSocketConstructor = {
|
|
16
|
+
new (url: string): WebSocketLike;
|
|
17
|
+
readonly OPEN: number;
|
|
18
|
+
readonly CONNECTING: number;
|
|
19
|
+
readonly CLOSING: number;
|
|
20
|
+
readonly CLOSED: number;
|
|
21
|
+
};
|
|
22
|
+
/** Inject a WebSocket implementation (required on Node unless undici/global is present). */
|
|
23
|
+
declare function useWebSocketImplementation(websocketImplementation: WebSocketConstructor): void;
|
|
24
|
+
declare function getWebSocketImplementation(): WebSocketConstructor;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { useWebSocketImplementation as i, WebSocketLike as n, getWebSocketImplementation as r, WebSocketConstructor as t };
|
|
27
|
+
//# sourceMappingURL=websocket-CmeqvAkp.d.mts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qntx/nostr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Nostr protocol implementation and SDK in TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"decentralized",
|
|
@@ -145,23 +145,36 @@
|
|
|
145
145
|
"types": "./dist/storage.d.mts",
|
|
146
146
|
"import": "./dist/storage.mjs"
|
|
147
147
|
},
|
|
148
|
+
"./store": {
|
|
149
|
+
"types": "./dist/store.d.mts",
|
|
150
|
+
"import": "./dist/store.mjs"
|
|
151
|
+
},
|
|
152
|
+
"./testing": {
|
|
153
|
+
"types": "./dist/testing.d.mts",
|
|
154
|
+
"import": "./dist/testing.mjs"
|
|
155
|
+
},
|
|
156
|
+
"./package.json": "./package.json",
|
|
148
157
|
"./wasm": {
|
|
149
158
|
"types": "./dist/wasm.d.mts",
|
|
150
159
|
"import": "./dist/wasm.mjs"
|
|
151
|
-
}
|
|
152
|
-
"./package.json": "./package.json"
|
|
160
|
+
}
|
|
153
161
|
},
|
|
154
162
|
"publishConfig": {
|
|
155
163
|
"access": "public"
|
|
156
164
|
},
|
|
157
165
|
"scripts": {
|
|
158
166
|
"build": "vp pack",
|
|
159
|
-
"build:wasm": "bash scripts/build-wasm.sh && WASM_PACK=1 vp pack && ls dist/*.wasm >/dev/null",
|
|
167
|
+
"build:wasm": "bash scripts/build-wasm.sh && WASM_PACK=1 vp pack && ls dist/*.wasm >/dev/null && publint && attw --pack . --profile esm-only",
|
|
160
168
|
"dev": "vp pack --watch",
|
|
161
169
|
"test": "vp test",
|
|
162
170
|
"test:wasm": "WASM_TEST=1 vp test wasm-tests/verify.ts wasm-tests/node-load.ts wasm-tests/sign.ts",
|
|
163
171
|
"bench:wasm": "WASM_TEST=1 vp test wasm-tests/bench.ts",
|
|
164
|
-
"
|
|
172
|
+
"bench:store": "STORE_BENCH=1 vp test bench/reactive-store.bench.ts",
|
|
173
|
+
"bench:store:sqlite": "STORE_BENCH=1 vp test bench/sqlite-store.bench.ts",
|
|
174
|
+
"lint": "vp check",
|
|
175
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.src.json",
|
|
176
|
+
"smoke:hermes": "bun scripts/hermes-smoke.ts",
|
|
177
|
+
"check:pkg": "WASM_PACK=1 vp pack && publint && attw --pack . --profile esm-only",
|
|
165
178
|
"prepublishOnly": "bun run build:wasm",
|
|
166
179
|
"pack:local": "vp pack && bun pm pack",
|
|
167
180
|
"release": "bumpp --commit --tag --push",
|
|
@@ -174,11 +187,20 @@
|
|
|
174
187
|
"@scure/base": "2.4.0"
|
|
175
188
|
},
|
|
176
189
|
"devDependencies": {
|
|
177
|
-
"@
|
|
190
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
191
|
+
"@qntx/oxfmt": "^1.0.4",
|
|
192
|
+
"@qntx/oxlint": "^1.0.4",
|
|
193
|
+
"@qntx/tsconfig": "^1.0.1",
|
|
194
|
+
"@types/node": "^26.6.3",
|
|
195
|
+
"@types/ws": "8.18.1",
|
|
196
|
+
"buffer": "6.0.3",
|
|
178
197
|
"bumpp": "^12.3.0",
|
|
198
|
+
"publint": "^0.3.24",
|
|
179
199
|
"typescript": "^7.0.2",
|
|
180
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@0.
|
|
181
|
-
"vite-plus": "
|
|
200
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.3",
|
|
201
|
+
"vite-plus": "0.3.3",
|
|
202
|
+
"whatwg-url": "7.1.0",
|
|
203
|
+
"ws": "8.21.3"
|
|
182
204
|
},
|
|
183
205
|
"peerDependencies": {
|
|
184
206
|
"ws": "^8.18.0"
|
|
@@ -189,7 +211,7 @@
|
|
|
189
211
|
}
|
|
190
212
|
},
|
|
191
213
|
"overrides": {
|
|
192
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@0.
|
|
214
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.3"
|
|
193
215
|
},
|
|
194
216
|
"devEngines": {
|
|
195
217
|
"packageManager": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"builder-q0VsvnYE.mjs","names":["#kind","#content","#tags","#createdAt"],"sources":["../src/core/builder.ts"],"sourcesContent":["import { EventValidationError } from \"./error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"./event.ts\";\nimport { Kind, isAddressableKind, isReplaceableKind } from \"./kind.ts\";\nimport { Keys, finalizeEvent } from \"./key.ts\";\nimport { Tag, formatEventAddress, getDTag } from \"./tag.ts\";\nimport { normalizeURL } from \"./util.ts\";\n\nfunction hasProtectedTag(event: Event): boolean {\n for (const tag of event.tags) {\n if (tag[0] === \"-\") return true;\n }\n return false;\n}\n\n/** NIP-18 e third entry MUST be a relay URL; empty string is not one. */\nfunction requireRelayUrl(relayHint: string | undefined): string {\n if (!relayHint) {\n throw new EventValidationError(\"relayHint must be a relay URL\");\n }\n return normalizeURL(relayHint);\n}\n\n/** Profile metadata JSON (kind 0 content). NIP-05 is not verified here. */\nexport type ProfileMetadata = {\n name?: string;\n display_name?: string;\n about?: string;\n picture?: string;\n banner?: string;\n website?: string;\n nip05?: string;\n lud06?: string;\n lud16?: string;\n};\n\n/**\n * Fluent builder for event templates.\n * Decouples intent (kind/content/tags) from signing (Keys / NostrSigner).\n */\nexport class EventBuilder {\n #kind: number;\n #content: string;\n #tags: Tag[];\n #createdAt: number | undefined;\n\n constructor(kind: number, content = \"\") {\n this.#kind = kind;\n this.#content = content;\n this.#tags = [];\n this.#createdAt = undefined;\n }\n\n static textNote(content: string): EventBuilder {\n return new EventBuilder(Kind.TextNote, content);\n }\n\n static metadata(meta: ProfileMetadata): EventBuilder {\n return new EventBuilder(Kind.Metadata, JSON.stringify(meta));\n }\n\n static contacts(pubkeys: string[]): EventBuilder {\n const b = new EventBuilder(Kind.Contacts, \"\");\n for (const pk of pubkeys) b.#tags.push(Tag.p(pk));\n return b;\n }\n\n static deletion(\n ids: string[],\n reason = \"\",\n opts?: { kinds?: readonly number[]; addresses?: readonly string[] },\n ): EventBuilder {\n const b = new EventBuilder(Kind.EventDeletion, reason);\n for (const id of ids) b.#tags.push(Tag.e(id));\n if (opts?.kinds) {\n for (const kind of opts.kinds) b.#tags.push(Tag.k(kind));\n }\n if (opts?.addresses) {\n for (const address of opts.addresses) b.#tags.push(Tag.a(address));\n }\n return b;\n }\n\n static reaction(target: Event, content = \"+\", opts?: { relayHint?: string }): EventBuilder {\n const hint = opts?.relayHint === undefined ? undefined : requireRelayUrl(opts.relayHint);\n let coord: string | undefined;\n if (isAddressableKind(target.kind)) {\n const d = getDTag(target.tags);\n if (d === undefined) {\n throw new EventValidationError(\"addressable event is missing d tag\");\n }\n coord = formatEventAddress(target.kind, target.pubkey, d);\n }\n\n const b = new EventBuilder(Kind.Reaction, content);\n // NIP-25 e is [e, id, relay, pubkey]; Tag.e third arg is a NIP-10 marker.\n b.#tags.push([\"e\", target.id.toLowerCase(), hint ?? \"\", target.pubkey.toLowerCase()]);\n b.#tags.push(Tag.p(target.pubkey, hint));\n b.#tags.push([\"k\", String(target.kind)]);\n if (coord !== undefined) {\n b.#tags.push(Tag.a(coord, hint));\n }\n return b;\n }\n\n static repost(target: Event, opts: { relayHint: string }): EventBuilder {\n if (target.kind !== Kind.TextNote) {\n throw new EventValidationError(\"non-kind-1 uses EventBuilder.genericRepost\");\n }\n const hint = requireRelayUrl(opts?.relayHint);\n const content = hasProtectedTag(target) ? \"\" : JSON.stringify(target);\n const b = new EventBuilder(Kind.Repost, content);\n b.#tags.push(Tag.e(target.id, hint));\n b.#tags.push(Tag.p(target.pubkey));\n return b;\n }\n\n static genericRepost(target: Event, opts: { relayHint: string; pPubkey?: string }): EventBuilder {\n if (target.kind === Kind.TextNote) {\n throw new EventValidationError(\"kind 1 uses EventBuilder.repost\");\n }\n const hint = requireRelayUrl(opts?.relayHint);\n const replaceable = isReplaceableKind(target.kind);\n const addressable = isAddressableKind(target.kind);\n const d = getDTag(target.tags);\n if (addressable && d === undefined) {\n throw new EventValidationError(\"addressable event is missing d tag\");\n }\n\n const content =\n hasProtectedTag(target) || replaceable || addressable ? \"\" : JSON.stringify(target);\n const b = new EventBuilder(Kind.GenericRepost, content);\n b.#tags.push(Tag.e(target.id, hint));\n b.#tags.push(Tag.p(opts?.pPubkey ?? target.pubkey));\n b.#tags.push(Tag.k(target.kind));\n if (replaceable || addressable) {\n b.#tags.push(Tag.a(formatEventAddress(target.kind, target.pubkey, d ?? \"\")));\n }\n return b;\n }\n\n kind(kind: number): this {\n this.#kind = kind;\n return this;\n }\n\n content(content: string): this {\n this.#content = content;\n return this;\n }\n\n tag(tag: Tag): this {\n this.#tags.push(tag);\n return this;\n }\n\n tags(tags: Iterable<Tag>): this {\n for (const t of tags) this.#tags.push(t);\n return this;\n }\n\n createdAt(ts: number): this {\n this.#createdAt = ts;\n return this;\n }\n\n get currentKind(): number {\n return this.#kind;\n }\n\n get currentContent(): string {\n return this.#content;\n }\n\n get currentTags(): readonly Tag[] {\n return this.#tags;\n }\n\n get currentCreatedAt(): number | undefined {\n return this.#createdAt;\n }\n\n /** Snapshot as EventTemplate (uses wall clock if created_at unset). */\n toTemplate(): EventTemplate {\n return {\n kind: this.#kind,\n content: this.#content,\n tags: this.#tags.slice(),\n created_at: this.#createdAt ?? Math.floor(Date.now() / 1000),\n };\n }\n\n /** Build unsigned event with the given pubkey. */\n buildUnsigned(pubkey: string): UnsignedEvent {\n const template = this.toTemplate();\n return {\n ...template,\n pubkey: pubkey.toLowerCase(),\n };\n }\n\n /** Sign with local Keys (synchronous). */\n signWithKeys(keys: Keys | SecretKeyLike): Event {\n if (keys instanceof Keys) {\n return finalizeEvent(this.toTemplate(), keys.secretKey);\n }\n return finalizeEvent(this.toTemplate(), keys);\n }\n\n /**\n * Sign via any NostrSigner-shaped object.\n * Accepts a structural type so core does not depend on the signer module.\n */\n async sign(signer: {\n getPublicKey(): Promise<string>;\n signEvent(unsigned: UnsignedEvent): Promise<Event>;\n }): Promise<Event> {\n const pubkey = await signer.getPublicKey();\n return signer.signEvent(this.buildUnsigned(pubkey));\n }\n}\n\ntype SecretKeyLike = import(\"./key.ts\").SecretKey | Uint8Array | string;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-Bd8B1mYm.mjs","names":["#opts","#signer","#relays","#persistEvents","#shutdown","#assertAlive","#flushing","#ingestMeta","#persistQueue","#armFlush","#flushLoop","#defaultRelays","#wantObserve","#requireNip59Crypto","#throwIfAborted","#dmDeps","#syncDeps"],"sources":["../src/client/builder.ts","../src/client/dm.ts","../src/client/gossip-io.ts","../src/client/types.ts","../src/client/sync.ts","../src/client/client.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { WebSocketConstructor } from \"../relay/websocket.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport type { StorageError } from \"../storage/error.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport { Client } from \"./client.ts\";\nimport type { ClientOptions } from \"./types.ts\";\n\n/** Fluent constructor for {@link Client}. */\nexport class ClientBuilder {\n #opts: ClientOptions = {};\n\n signer(signer: NostrSigner): this {\n this.#opts = { ...this.#opts, signer };\n return this;\n }\n\n relays(urls: readonly string[]): this {\n this.#opts = { ...this.#opts, relays: [...urls] };\n return this;\n }\n\n addRelay(url: string): this {\n this.#opts = { ...this.#opts, relays: [...(this.#opts.relays ?? []), url] };\n return this;\n }\n\n websocketImplementation(impl: WebSocketConstructor): this {\n this.#opts = { ...this.#opts, websocketImplementation: impl };\n return this;\n }\n\n verifyEvent(fn: (event: Event) => boolean): this {\n this.#opts = { ...this.#opts, verifyEvent: fn };\n return this;\n }\n\n connectTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, connectTimeoutMs: ms };\n return this;\n }\n\n publishTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, publishTimeoutMs: ms };\n return this;\n }\n\n automaticAuth(enabled: boolean): this {\n this.#opts = { ...this.#opts, automaticAuth: enabled };\n return this;\n }\n\n enableReconnect(enabled: boolean): this {\n this.#opts = { ...this.#opts, enableReconnect: enabled };\n return this;\n }\n\n enablePing(enabled: boolean): this {\n this.#opts = { ...this.#opts, enablePing: enabled };\n return this;\n }\n\n pingIntervalMs(ms: number): this {\n this.#opts = { ...this.#opts, pingIntervalMs: ms };\n return this;\n }\n\n pingTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, pingTimeoutMs: ms };\n return this;\n }\n\n /**\n * Local event store. Defaults to {@link MemoryEventStore}.\n * Browser apps that want persistence must pass {@link IndexedDbEventStore} and `await open()`.\n */\n storage(store: EventStore): this {\n this.#opts = { ...this.#opts, storage: store };\n return this;\n }\n\n /** When false, Client will not auto-write events to storage. Default true. */\n persistEvents(enabled: boolean): this {\n this.#opts = { ...this.#opts, persistEvents: enabled };\n return this;\n }\n\n gossip(gossip: Gossip): this {\n this.#opts = { ...this.#opts, gossip };\n return this;\n }\n\n onstorageerror(fn: (err: StorageError) => void): this {\n this.#opts = { ...this.#opts, onstorageerror: fn };\n return this;\n }\n\n build(): Client {\n return new Client(this.#opts);\n }\n}\n","import type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { EventBuilder } from \"../core/builder.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { Pool, PoolPublishResult } from \"../relay/pool.ts\";\nimport {\n Nip17Error,\n buildChatMessageRumor,\n dmRelayListEventBuilder,\n normalizeRecipients,\n requireDmRelays,\n wrapDirectMessage,\n type Recipient,\n} from \"../nips/nip17.ts\";\nimport { unwrap, type Nip59Crypto } from \"../nips/nip59.ts\";\nimport type {\n FetchPrivateMessagesOptions,\n PrivateMessageSendResult,\n PublishOptions,\n ReceivedPrivateMessage,\n SendPrivateMessageOptions,\n SubscribePrivateMessagesOptions,\n} from \"./types.ts\";\n\nexport type DmDeps = {\n pool: Pool;\n gossip: Gossip;\n hydrateGossip: (pubkeys: readonly string[]) => Promise<void>;\n observe: (event: Event) => void;\n assertAlive: () => void;\n requireNip59Crypto: () => Nip59Crypto;\n throwIfAborted: (signal?: AbortSignal) => void;\n wantObserve: (flag?: boolean) => boolean;\n publish: (\n eventOrBuilder: Event | EventBuilder,\n opts?: PublishOptions,\n ) => Promise<PoolPublishResult[]>;\n};\n\nexport function giftWrapRelays(gossip: Gossip, event: Event): string[] {\n const targets: string[] = [];\n for (const tag of event.tags) {\n if (tag[0] === \"p\" && tag[1]) targets.push(tag[1].toLowerCase());\n }\n if (targets.length === 0) {\n throw new Nip17Error(\"gift wrap has no p-tag recipient\");\n }\n if (targets.length !== 1) {\n throw new Nip17Error(\"gift wrap must have exactly one p-tag recipient\");\n }\n const relays = gossip.dmRelays(targets[0]!);\n if (relays.length === 0) {\n throw new Nip17Error(\"no kind 10050 in gossip; use sendPrivateMessage or pass relays\");\n }\n return relays;\n}\n\nexport async function setDmRelays(\n deps: DmDeps,\n relays: readonly string[],\n opts?: PublishOptions,\n): Promise<PoolPublishResult[]> {\n return deps.publish(dmRelayListEventBuilder(relays), { gossip: true, ...opts });\n}\n\nexport async function sendPrivateMessage(\n deps: DmDeps,\n recipients: string | Recipient | readonly (string | Recipient)[],\n content: string,\n opts?: SendPrivateMessageOptions,\n): Promise<PrivateMessageSendResult> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const sender = await crypto.getPublicKey();\n const list = normalizeRecipients(recipients);\n if (list.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n\n const targets = new Set<string>([sender.toLowerCase(), ...list.map((r) => r.pubkey)]);\n await deps.hydrateGossip([...targets]);\n for (const pk of targets) {\n requireDmRelays(pk, deps.gossip.dmRelays(pk));\n }\n\n const rumor = buildChatMessageRumor(sender, list, content, {\n created_at: opts?.created_at,\n subject: opts?.subject,\n replyTo: opts?.replyTo,\n });\n const wraps = await wrapDirectMessage(crypto, list, rumor);\n const sent = await Promise.all(\n wraps.map(async ({ recipient, wrap }) => {\n const relays = requireDmRelays(recipient, deps.gossip.dmRelays(recipient));\n const results = await deps.pool.publish(relays, wrap, { timeoutMs: opts?.timeoutMs });\n if (results.some((r) => r.result?.ok) && deps.wantObserve(opts?.observe)) {\n deps.observe(wrap);\n }\n return { recipient, wrap, results };\n }),\n );\n return { rumor, wraps: sent };\n}\n\nexport async function fetchPrivateMessages(\n deps: DmDeps,\n opts?: FetchPrivateMessagesOptions,\n): Promise<ReceivedPrivateMessage[]> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const self = await crypto.getPublicKey();\n deps.throwIfAborted(opts?.signal);\n await deps.hydrateGossip([self]);\n deps.throwIfAborted(opts?.signal);\n const relays = requireDmRelays(self, deps.gossip.dmRelays(self));\n const events = await deps.pool.fetch(\n relays,\n [\n {\n kinds: [Kind.GiftWrap],\n \"#p\": [self],\n since: opts?.since,\n until: opts?.until,\n },\n ],\n { timeoutMs: opts?.timeoutMs, signal: opts?.signal },\n );\n\n const byRumor = new Map<string, ReceivedPrivateMessage>();\n for (const wrap of events) {\n try {\n const rumor = await unwrap(crypto, wrap);\n if (deps.wantObserve(opts?.observe)) deps.observe(wrap);\n byRumor.set(rumor.id, { wrap, rumor });\n } catch {\n // junk / forgery / key mismatch — not stored\n }\n }\n\n return [...byRumor.values()].sort((a, b) => {\n if (a.rumor.created_at !== b.rumor.created_at) {\n return a.rumor.created_at - b.rumor.created_at;\n }\n return a.rumor.id.localeCompare(b.rumor.id);\n });\n}\n\nexport async function subscribePrivateMessages(\n deps: DmDeps,\n opts?: SubscribePrivateMessagesOptions,\n): Promise<{ close: (reason?: string) => void }> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const self = await crypto.getPublicKey();\n deps.throwIfAborted(opts?.signal);\n await deps.hydrateGossip([self]);\n deps.throwIfAborted(opts?.signal);\n const relays = requireDmRelays(self, deps.gossip.dmRelays(self));\n\n const seen = new Set<string>();\n let tail = Promise.resolve();\n let closed = false;\n const markClosed = (): void => {\n closed = true;\n };\n if (opts?.signal?.aborted) markClosed();\n else opts?.signal?.addEventListener(\"abort\", markClosed, { once: true });\n\n const inner = deps.pool.subscribe(\n relays,\n // 21059 is ephemeral (relays MUST NOT store); live inbox has to REQ it.\n [{ kinds: [Kind.GiftWrap, Kind.GiftWrapEphemeral], \"#p\": [self], since: opts?.since }],\n {\n signal: opts?.signal,\n oneose: opts?.oneose,\n onclose: (reason) => {\n markClosed();\n opts?.onclose?.(reason);\n },\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n onevent: (wrap) => {\n if (closed) return;\n tail = tail\n .then(async () => {\n if (closed) return;\n try {\n const rumor = await unwrap(crypto, wrap);\n if (closed) return;\n if (seen.has(rumor.id)) return;\n seen.add(rumor.id);\n if (deps.wantObserve(opts?.observe)) deps.observe(wrap);\n opts?.onevent?.({ wrap, rumor });\n } catch {\n // junk / forgery — not stored\n }\n })\n .catch(() => {\n // keep the queue alive if a handler throws\n });\n },\n },\n );\n\n return {\n close: (reason?: string) => {\n markClosed();\n inner.close(reason);\n },\n };\n}\n","import type { Event } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport { fanIn, fetchRouted, type FanInOptions, type RoutedJob } from \"../relay/fan-in.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\n\n/** Remainder is one job on defaults; throw before any REQ when defaults are empty. */\nexport function jobsForFilters(\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n): RoutedJob[] {\n const routed = filters.map((f) => gossip.route(f));\n const needsDefaults = routed.some((r) => r.remainder !== undefined);\n const defaults = needsDefaults ? defaultRelays() : undefined;\n const jobs: RoutedJob[] = [];\n for (const r of routed) {\n for (const [url, sub] of r.perRelay) jobs.push({ urls: [url], filters: [sub] });\n if (r.remainder) jobs.push({ urls: defaults!, filters: [r.remainder] });\n }\n return jobs;\n}\n\nexport function fetchGossip(\n pool: Pool,\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n opts?: { timeoutMs?: number; signal?: AbortSignal },\n): Promise<Event[]> {\n return fetchRouted(pool, jobsForFilters(gossip, filters, defaultRelays), {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n}\n\nexport function subscribeGossip(\n pool: Pool,\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n opts: FanInOptions,\n): { close: (reason?: string) => void } {\n const jobs = jobsForFilters(gossip, filters, defaultRelays);\n if (jobs.length === 0) {\n queueMicrotask(() => opts.oneose?.());\n return { close: () => {} };\n }\n return fanIn(pool, jobs, opts);\n}\n","import { NostrError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { PoolPublishResult } from \"../relay/pool.ts\";\nimport type { WebSocketConstructor } from \"../relay/websocket.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport type { StorageError } from \"../storage/error.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport type { ReplyTo } from \"../nips/nip17.ts\";\nimport type { Rumor } from \"../nips/nip59.ts\";\n\nexport const SyncDirection = {\n Up: \"up\",\n Down: \"down\",\n Both: \"both\",\n} as const;\n\nexport type SyncDirectionName = (typeof SyncDirection)[keyof typeof SyncDirection];\n\nexport type SyncOptions = {\n relays?: readonly string[];\n direction?: SyncDirectionName;\n /**\n * Wall-clock deadline for the Negentropy reconciliation session\n * (`NEG-OPEN` through `NEG-CLOSE`), in milliseconds.\n * One clock for the whole session — not reset per `NEG-MSG`.\n * Default: the relay `publishTimeoutMs`.\n * Upload/download phases reuse this value as their per-call timeout.\n */\n timeoutMs?: number;\n signal?: AbortSignal;\n dryRun?: boolean;\n /** When false, skip observe/storage on downloaded events. Default true. */\n observe?: boolean;\n};\n\nexport type SyncSummary = {\n local: string[];\n remote: string[];\n sent: string[];\n received: string[];\n sendFailures: Record<string, string>;\n persistFailures: Record<string, string>;\n};\n\nexport type ClientOptions = {\n signer?: NostrSigner;\n relays?: readonly string[];\n websocketImplementation?: WebSocketConstructor;\n /** Injected EVENT verifier. Default is core BIP-340. */\n verifyEvent?: (event: Event) => boolean;\n connectTimeoutMs?: number;\n publishTimeoutMs?: number;\n /** When true (default if signer present), answer NIP-42 AUTH automatically. */\n automaticAuth?: boolean;\n /** When true (default), relays reconnect with backoff after disconnect. */\n enableReconnect?: boolean;\n /** Keepalive ping. Default false. */\n enablePing?: boolean;\n pingIntervalMs?: number;\n pingTimeoutMs?: number;\n gossip?: Gossip;\n /**\n * Local event store. Defaults to {@link MemoryEventStore}.\n * Browser apps that want persistence must pass {@link IndexedDbEventStore} and `await open()`.\n */\n storage?: EventStore;\n /**\n * When true (default), every ingested event is written to storage.\n * Set false to disable automatic persistence while keeping the store for manual use.\n */\n persistEvents?: boolean;\n /**\n * Storage I/O failures: live `putMany` flush and `fetchEvents({ localFirst: true })` query.\n * Those paths do not throw.\n */\n onstorageerror?: (err: StorageError) => void;\n};\n\nexport type FetchEventsOptions = {\n relays?: string[];\n timeoutMs?: number;\n signal?: AbortSignal;\n gossip?: boolean;\n /**\n * When true, query local storage first and merge with network results.\n * Defaults to false.\n */\n localFirst?: boolean;\n /** When false, skip writing fetched events to storage/observe. Default true. */\n observe?: boolean;\n};\n\nexport type SubscribeOptions = {\n relays?: string[];\n onevent?: (event: Event) => void;\n oneose?: () => void;\n onclose?: (reason: string) => void;\n signal?: AbortSignal;\n id?: string;\n /**\n * If set, fire `oneose` once after this many ms if not all relays have EOSEd.\n * Does not close the subscription.\n */\n eoseTimeoutMs?: number;\n /** Fan out REQs via NIP-65 gossip routes when available. */\n gossip?: boolean;\n /** When false, skip writing received events to storage/observe. Default true. */\n observe?: boolean;\n};\n\nexport type PublishOptions = {\n relays?: string[];\n timeoutMs?: number;\n gossip?: boolean;\n /** When false, skip writing the published event to storage/observe. Default true. */\n observe?: boolean;\n};\n\nexport type SendPrivateMessageOptions = {\n readonly subject?: string;\n readonly replyTo?: ReplyTo;\n readonly created_at?: number;\n readonly timeoutMs?: number;\n readonly observe?: boolean;\n};\n\nexport type PrivateMessageSendResult = {\n rumor: Rumor;\n wraps: ReadonlyArray<{\n recipient: string;\n wrap: Event;\n results: PoolPublishResult[];\n }>;\n};\n\nexport type ReceivedPrivateMessage = {\n wrap: Event;\n rumor: Rumor;\n};\n\nexport type FetchPrivateMessagesOptions = {\n readonly since?: number;\n readonly until?: number;\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n readonly observe?: boolean;\n};\n\nexport type SubscribePrivateMessagesOptions = {\n readonly since?: number;\n readonly onevent?: (msg: ReceivedPrivateMessage) => void;\n readonly oneose?: () => void;\n readonly onclose?: (reason: string) => void;\n readonly signal?: AbortSignal;\n readonly eoseTimeoutMs?: number;\n readonly observe?: boolean;\n};\n\n/** Client lifecycle, configuration, or abort failure (not cryptographic). */\nexport class ClientError extends NostrError {}\n","import type { Event } from \"../core/event.ts\";\nimport { canonicalizeFilter, type Filter } from \"../core/filter.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\nimport type { EventStore, PutResult } from \"../storage/types.ts\";\nimport { storageFromItems, type NegentropyStorageVector } from \"../nips/nip77.ts\";\nimport { SyncDirection, type SyncOptions, type SyncSummary } from \"./types.ts\";\n\nexport type SyncDeps = {\n pool: Pool;\n storage: EventStore;\n persistEvents: boolean;\n assertAlive: () => void;\n throwIfAborted: (signal?: AbortSignal) => void;\n wantObserve: (flag?: boolean) => boolean;\n ingestMeta: (event: Event) => void;\n defaultRelays: (urls?: string[]) => string[];\n};\n\nconst SYNC_ID_BATCH = 100;\nconst SYNC_UPLOAD_CONCURRENCY = 8;\n\nfunction uniqueIds(ids: readonly string[]): string[] {\n return [...new Set(ids)];\n}\n\nfunction emptySummary(): SyncSummary {\n return {\n local: [],\n remote: [],\n sent: [],\n received: [],\n sendFailures: {},\n persistFailures: {},\n };\n}\n\nfunction mergeSyncSummary(into: SyncSummary, other: SyncSummary): SyncSummary {\n const sendFailures = { ...into.sendFailures, ...other.sendFailures };\n const persistFailures = { ...into.persistFailures, ...other.persistFailures };\n return {\n local: uniqueIds([...into.local, ...other.local]),\n remote: uniqueIds([...into.remote, ...other.remote]),\n sent: uniqueIds([...into.sent, ...other.sent]),\n received: uniqueIds([...into.received, ...other.received]),\n sendFailures,\n persistFailures,\n };\n}\n\n/**\n * NIP-77 sync against one relay: reconcile, then optionally upload\n * local-only events and/or download remote-only events.\n * `observe: false` skips putMany and ingestMeta; received ids are still listed.\n * `persistEvents: false` skips putMany, still ingestMeta when observe is on.\n */\nexport async function syncToRelay(\n deps: SyncDeps,\n url: string,\n filter: Filter,\n opts?: Omit<SyncOptions, \"relays\">,\n): Promise<SyncSummary> {\n deps.assertAlive();\n deps.throwIfAborted(opts?.signal);\n const direction = opts?.direction ?? SyncDirection.Down;\n filter = canonicalizeFilter(filter);\n const items = await deps.storage.negentropyItems(filter);\n const storage: NegentropyStorageVector = storageFromItems(items);\n const relay = await deps.pool.ensureRelay(url, { signal: opts?.signal });\n const { have, need } = await relay.negReconcile(filter, storage, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n\n const summary: SyncSummary = {\n local: have,\n remote: need,\n sent: [],\n received: [],\n sendFailures: {},\n persistFailures: {},\n };\n\n if (opts?.dryRun) return summary;\n\n if (direction === SyncDirection.Up || direction === SyncDirection.Both) {\n if (have.length > 0) {\n const found = await deps.storage.query([{ ids: have }]);\n const foundById = new Map(found.map((event) => [event.id, event]));\n for (const id of have) {\n if (!foundById.has(id)) {\n summary.sendFailures[id] = \"event not found in local store\";\n }\n }\n for (let i = 0; i < found.length; i += SYNC_UPLOAD_CONCURRENCY) {\n const chunk = found.slice(i, i + SYNC_UPLOAD_CONCURRENCY);\n await Promise.all(\n chunk.map(async (event) => {\n try {\n const results = await deps.pool.publish([url], event, {\n timeoutMs: opts?.timeoutMs,\n });\n const ok = results.some((r) => r.result?.ok);\n if (ok) summary.sent.push(event.id);\n else {\n summary.sendFailures[event.id] =\n results[0]?.error ?? results[0]?.result?.message ?? \"publish failed\";\n }\n } catch (error) {\n summary.sendFailures[event.id] =\n error instanceof Error ? error.message : String(error);\n }\n }),\n );\n }\n }\n }\n\n if ((direction === SyncDirection.Down || direction === SyncDirection.Both) && need.length > 0) {\n const shouldObserve = deps.wantObserve(opts?.observe);\n for (let i = 0; i < need.length; i += SYNC_ID_BATCH) {\n const batch = need.slice(i, i + SYNC_ID_BATCH);\n deps.throwIfAborted(opts?.signal);\n const events = await deps.pool.fetch([url], [{ ids: batch }], {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n if (!shouldObserve) {\n for (const event of events) summary.received.push(event.id);\n continue;\n }\n if (!deps.persistEvents) {\n for (const event of events) {\n deps.ingestMeta(event);\n summary.received.push(event.id);\n }\n continue;\n }\n let results: PutResult[];\n try {\n results = await deps.storage.putMany(events);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n for (const event of events) summary.persistFailures[event.id] = message;\n break;\n }\n for (let j = 0; j < events.length; j++) {\n const event = events[j]!;\n if (results[j] === \"rejected\") continue;\n deps.ingestMeta(event);\n summary.received.push(event.id);\n }\n }\n }\n\n return summary;\n}\n\n/**\n * NIP-77 sync against the given relays (or Client default relays).\n * Independent sessions run in parallel. Fulfilled summaries are merged;\n * if every relay rejects, throws the first rejection in URL order.\n */\nexport async function sync(\n deps: SyncDeps,\n filter: Filter,\n opts?: SyncOptions,\n): Promise<SyncSummary> {\n deps.assertAlive();\n const urls = deps.defaultRelays(opts?.relays ? [...opts.relays] : undefined);\n const results = await Promise.allSettled(urls.map((url) => syncToRelay(deps, url, filter, opts)));\n let merged = emptySummary();\n let fulfilled = 0;\n let firstRejection: unknown;\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n fulfilled += 1;\n merged = mergeSyncSummary(merged, result.value);\n } else {\n firstRejection ??= result.reason;\n }\n }\n if (urls.length > 0 && fulfilled === 0) throw firstRejection;\n return merged;\n}\n","import { EventBuilder } from \"../core/builder.ts\";\nimport { sortedEvents, type Event, type EventTemplate, type UnsignedEvent } from \"../core/event.ts\";\nimport { canonicalizeFilters, type Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { Gossip } from \"../gossip/index.ts\";\nimport {\n createLoaders,\n createOutboxFeed,\n type Loaders,\n type OutboxFeed,\n} from \"../loaders/index.ts\";\nimport type { Recipient } from \"../nips/nip17.ts\";\nimport { isGiftWrapKind, requireNip59Crypto, type Nip59Crypto } from \"../nips/nip59.ts\";\nimport { Pool, type PoolPublishResult } from \"../relay/pool.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport { toStorageError, type StorageError } from \"../storage/error.ts\";\nimport { MemoryEventStore } from \"../storage/memory.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport { ClientBuilder } from \"./builder.ts\";\nimport {\n fetchPrivateMessages,\n giftWrapRelays,\n sendPrivateMessage,\n setDmRelays,\n subscribePrivateMessages,\n type DmDeps,\n} from \"./dm.ts\";\nimport { fetchGossip, subscribeGossip } from \"./gossip-io.ts\";\nimport { sync, syncToRelay, type SyncDeps } from \"./sync.ts\";\nimport {\n ClientError,\n type ClientOptions,\n type FetchEventsOptions,\n type FetchPrivateMessagesOptions,\n type PrivateMessageSendResult,\n type PublishOptions,\n type ReceivedPrivateMessage,\n type SendPrivateMessageOptions,\n type SubscribeOptions,\n type SubscribePrivateMessagesOptions,\n type SyncOptions,\n type SyncSummary,\n} from \"./types.ts\";\n\n/**\n * Layer-5 facade: signer + default relays + pool + loaders + gossip + event store.\n */\nexport class Client {\n readonly pool: Pool;\n readonly loaders: Loaders;\n readonly gossip: Gossip;\n readonly storage: EventStore;\n onstorageerror: ((err: StorageError) => void) | null;\n #signer: NostrSigner | undefined;\n #relays: string[];\n #shutdown = false;\n #persistEvents: boolean;\n #persistQueue: Event[] = [];\n #flushing: Promise<void> | undefined;\n\n constructor(opts: ClientOptions = {}) {\n this.#signer = opts.signer;\n this.#relays = [...(opts.relays ?? [])];\n this.gossip = opts.gossip ?? new Gossip();\n this.storage = opts.storage ?? new MemoryEventStore();\n this.#persistEvents = opts.persistEvents ?? true;\n this.onstorageerror = opts.onstorageerror ?? null;\n const autoAuth = opts.automaticAuth ?? Boolean(opts.signer);\n this.pool = new Pool({\n websocketImplementation: opts.websocketImplementation,\n verifyEvent: opts.verifyEvent,\n enablePing: opts.enablePing,\n pingIntervalMs: opts.pingIntervalMs,\n pingTimeoutMs: opts.pingTimeoutMs,\n connectTimeoutMs: opts.connectTimeoutMs,\n publishTimeoutMs: opts.publishTimeoutMs,\n enableReconnect: opts.enableReconnect ?? true,\n automaticallyAuth: autoAuth\n ? () => {\n const signer = this.#signer;\n if (!signer) return null;\n return async (template) => {\n const pk = await signer.getPublicKey();\n return signer.signEvent({ ...template, pubkey: pk });\n };\n }\n : undefined,\n });\n this.loaders = createLoaders({\n pool: this.pool,\n relays: this.#relays,\n });\n }\n\n static builder(): ClientBuilder {\n return new ClientBuilder();\n }\n\n get signer(): NostrSigner | undefined {\n return this.#signer;\n }\n\n get relays(): readonly string[] {\n return this.#relays;\n }\n\n get isShutdown(): boolean {\n return this.#shutdown;\n }\n\n setSigner(signer: NostrSigner): void {\n this.#signer = signer;\n }\n\n addRelay(url: string): void {\n if (!this.#relays.includes(url)) {\n this.#relays.push(url);\n this.loaders.context.addRelay(url);\n }\n }\n\n removeRelay(url: string): void {\n this.#relays = this.#relays.filter((r) => r !== url);\n this.loaders.context.removeRelay(url);\n this.pool.close([url]);\n }\n\n /** Connect all configured relays (best-effort; failures are ignored). */\n async connect(opts?: { signal?: AbortSignal }): Promise<void> {\n this.#assertAlive();\n await Promise.allSettled(\n this.#relays.map((url) => this.pool.ensureRelay(url, { signal: opts?.signal })),\n );\n }\n\n async shutdown(): Promise<void> {\n this.#shutdown = true;\n while (this.#flushing) await this.#flushing;\n this.pool.close();\n this.loaders.context.cache.clear();\n }\n\n #assertAlive(): void {\n if (this.#shutdown) throw new ClientError(\"client is shut down\");\n }\n\n #defaultRelays(urls?: string[]): string[] {\n const list = urls ?? this.#relays;\n if (list.length === 0) throw new ClientError(\"no relays configured\");\n return list;\n }\n\n #wantObserve(flag?: boolean): boolean {\n return flag !== false;\n }\n\n /**\n * Unified ingest pipeline: gossip + replaceable loader cache immediately;\n * storage writes are coalesced into a single-flight `putMany`.\n */\n observe(event: Event): void {\n this.#ingestMeta(event);\n if (!this.#persistEvents) return;\n this.#persistQueue.push(event);\n this.#armFlush();\n }\n\n /** Observe many events (deduped by id, order preserved) as one persist batch. */\n observeAll(events: readonly Event[]): void {\n const seen = new Set<string>();\n for (const event of events) {\n if (seen.has(event.id)) continue;\n seen.add(event.id);\n this.#ingestMeta(event);\n if (this.#persistEvents) this.#persistQueue.push(event);\n }\n if (this.#persistEvents && this.#persistQueue.length > 0) this.#armFlush();\n }\n\n #ingestMeta(event: Event): void {\n this.gossip.ingest(event);\n if (\n event.kind === Kind.Metadata ||\n event.kind === Kind.Contacts ||\n event.kind === Kind.MuteList ||\n event.kind === Kind.RelayList ||\n event.kind === Kind.DirectMessageRelaysList\n ) {\n this.loaders.context.cache.putIfNewer(event);\n }\n }\n\n #armFlush(): void {\n if (this.#flushing) return;\n this.#flushing = this.#flushLoop();\n }\n\n async #flushLoop(): Promise<void> {\n try {\n await new Promise<void>((resolve) => {\n queueMicrotask(resolve);\n });\n while (this.#persistQueue.length > 0) {\n const batch = this.#persistQueue.splice(0);\n try {\n await this.storage.putMany(batch);\n } catch (err) {\n this.onstorageerror?.(toStorageError(err));\n }\n }\n } finally {\n this.#flushing = undefined;\n if (this.#persistQueue.length > 0) this.#armFlush();\n }\n }\n\n /**\n * Explicitly load kind:10002 and kind:10050 lists for pubkeys and feed gossip.\n * Does not background-fetch unknown authors on every subscribe (predictable DX).\n */\n async hydrateGossip(\n pubkeys: readonly string[],\n opts?: { hints?: string[]; force?: boolean },\n ): Promise<void> {\n this.#assertAlive();\n await Promise.all(\n pubkeys.map(async (pk) => {\n const style = opts?.force ? \"force\" : \"default\";\n const [relayList, dmList] = await Promise.all([\n this.loaders.relayList(pk, { hints: opts?.hints, style }),\n this.loaders.dmRelayList(pk, { hints: opts?.hints, style }),\n ]);\n if (relayList.event) this.observe(relayList.event);\n if (dmList.event) this.observe(dmList.event);\n }),\n );\n }\n\n /**\n * Create an outbox-model feed for the given authors (NIP-65 write relays).\n * Live events go through {@link observe}; sync persists via applySync.\n */\n outbox(opts: {\n authors: readonly string[];\n kinds?: readonly number[];\n onEvent?: (event: Event) => void;\n maxRelaysPerAuthor?: number;\n }): OutboxFeed {\n this.#assertAlive();\n return createOutboxFeed({\n pool: this.pool,\n gossip: this.gossip,\n storage: this.storage,\n discoveryRelays: this.#relays,\n authors: opts.authors,\n kinds: opts.kinds,\n onEvent: opts.onEvent,\n maxRelaysPerAuthor: opts.maxRelaysPerAuthor,\n observe: (event) => this.observe(event),\n applySync: async (events) => {\n if (!this.#persistEvents) {\n for (const event of events) this.#ingestMeta(event);\n return [];\n }\n const results = await this.storage.putMany(events);\n const applied: Event[] = [];\n for (let i = 0; i < events.length; i++) {\n if (results[i] === \"rejected\" || results[i] === \"ephemeral\") continue;\n this.#ingestMeta(events[i]!);\n applied.push(events[i]!);\n }\n return applied;\n },\n hydrate: (pubkeys) => this.hydrateGossip(pubkeys),\n });\n }\n\n async getPublicKey(): Promise<string> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return this.#signer.getPublicKey();\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return this.#signer.signEvent(unsigned);\n }\n\n async signEventBuilder(builder: EventBuilder): Promise<Event> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return builder.sign(this.#signer);\n }\n\n async signTemplate(template: EventTemplate): Promise<Event> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n const pubkey = await this.#signer.getPublicKey();\n return this.#signer.signEvent({ ...template, pubkey });\n }\n\n /**\n * Sign (if builder) and publish to relays.\n * With `gossip: true`, prefers the author's NIP-65 outbox relays, tagged `p`\n * inboxes, and up to 5 `e`/`a` tag relay hints when known.\n * On any successful OK, observes the event into storage/gossip.\n */\n async publish(\n eventOrBuilder: Event | EventBuilder,\n opts?: PublishOptions,\n ): Promise<PoolPublishResult[]> {\n this.#assertAlive();\n const event =\n eventOrBuilder instanceof EventBuilder\n ? await this.signEventBuilder(eventOrBuilder)\n : eventOrBuilder;\n\n let relays = opts?.relays;\n if (!relays && isGiftWrapKind(event.kind)) {\n relays = giftWrapRelays(this.gossip, event);\n } else if (!relays && opts?.gossip) {\n const urls: string[] = [];\n const add = (list: readonly string[]) => {\n for (const url of list) {\n if (!urls.includes(url)) urls.push(url);\n }\n };\n add(this.gossip.outboxRelays(event.pubkey));\n for (const tag of event.tags) {\n if (tag[0] === \"p\" && tag[1]) add(this.gossip.inboxRelays(tag[1]));\n }\n let hintCount = 0;\n for (const tag of event.tags) {\n if (hintCount >= 5) break;\n if ((tag[0] !== \"e\" && tag[0] !== \"a\") || !tag[2]) continue;\n try {\n const url = normalizeURL(tag[2]);\n if (!urls.includes(url)) {\n urls.push(url);\n hintCount += 1;\n }\n } catch {\n // not a relay URL\n }\n }\n if (urls.length > 0) relays = urls;\n }\n const results = await this.pool.publish(this.#defaultRelays(relays), event, {\n timeoutMs: opts?.timeoutMs,\n });\n\n const anyOk = results.some((r) => r.result?.ok);\n if (anyOk && this.#wantObserve(opts?.observe)) {\n this.observe(event);\n }\n return results;\n }\n\n /**\n * Fetch events. With `gossip: true`, routes filters by NIP-65 when possible.\n * With `localFirst: true`, merges storage hits with network results.\n */\n async fetchEvents(filter: Filter | Filter[], opts?: FetchEventsOptions): Promise<Event[]> {\n this.#assertAlive();\n const filters = canonicalizeFilters(Array.isArray(filter) ? filter : [filter]);\n const shouldObserve = this.#wantObserve(opts?.observe);\n const byId = new Map<string, Event>();\n\n if (opts?.localFirst) {\n try {\n const local = await this.storage.query(filters);\n for (const e of local) byId.set(e.id, e);\n } catch (err) {\n this.onstorageerror?.(toStorageError(err));\n }\n }\n\n const ingest = (events: Event[]) => {\n for (const e of events) {\n byId.set(e.id, e);\n if (shouldObserve) this.observe(e);\n }\n };\n\n if (!opts?.gossip || opts.relays) {\n ingest(\n await this.pool.fetch(this.#defaultRelays(opts?.relays), filters, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n }),\n );\n return sortedEvents([...byId.values()]);\n }\n\n ingest(\n await fetchGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n }),\n );\n return sortedEvents([...byId.values()]);\n }\n\n /**\n * Query local storage only (no network).\n */\n async queryLocal(filter: Filter | Filter[]): Promise<Event[]> {\n this.#assertAlive();\n const filters = canonicalizeFilters(Array.isArray(filter) ? filter : [filter]);\n return this.storage.query(filters);\n }\n\n subscribe(\n filter: Filter | Filter[],\n opts?: SubscribeOptions,\n ): { close: (reason?: string) => void } {\n this.#assertAlive();\n const filters = canonicalizeFilters(Array.isArray(filter) ? filter : [filter]);\n const shouldObserve = this.#wantObserve(opts?.observe);\n\n const wrapEvent = (event: Event) => {\n if (shouldObserve) this.observe(event);\n opts?.onevent?.(event);\n };\n\n if (!opts?.gossip || opts.relays) {\n return this.pool.subscribe(this.#defaultRelays(opts?.relays), filters, {\n onevent: wrapEvent,\n oneose: opts?.oneose,\n onclose: opts?.onclose,\n signal: opts?.signal,\n id: opts?.id,\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n });\n }\n\n return subscribeGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {\n onevent: wrapEvent,\n oneose: opts?.oneose,\n onclose: opts?.onclose,\n signal: opts?.signal,\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n });\n }\n\n #requireNip59Crypto(): Nip59Crypto {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return requireNip59Crypto(this.#signer);\n }\n\n #throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return;\n if (signal.reason instanceof Error) throw signal.reason;\n throw new ClientError(\"aborted\");\n }\n\n #dmDeps(): DmDeps {\n return {\n pool: this.pool,\n gossip: this.gossip,\n hydrateGossip: (pubkeys) => this.hydrateGossip(pubkeys),\n observe: (event) => this.observe(event),\n assertAlive: () => this.#assertAlive(),\n requireNip59Crypto: () => this.#requireNip59Crypto(),\n throwIfAborted: (signal) => this.#throwIfAborted(signal),\n wantObserve: (flag) => this.#wantObserve(flag),\n publish: (eventOrBuilder, opts) => this.publish(eventOrBuilder, opts),\n };\n }\n\n #syncDeps(): SyncDeps {\n return {\n pool: this.pool,\n storage: this.storage,\n persistEvents: this.#persistEvents,\n assertAlive: () => this.#assertAlive(),\n throwIfAborted: (signal) => this.#throwIfAborted(signal),\n wantObserve: (flag) => this.#wantObserve(flag),\n ingestMeta: (event) => this.#ingestMeta(event),\n defaultRelays: (urls) => this.#defaultRelays(urls),\n };\n }\n\n /** Publish a kind:10050 NIP-17 DM relay list (`relay` tags). Not kind 10002. */\n async setDmRelays(\n relays: readonly string[],\n opts?: PublishOptions,\n ): Promise<PoolPublishResult[]> {\n return setDmRelays(this.#dmDeps(), relays, opts);\n }\n\n async sendPrivateMessage(\n recipients: string | Recipient | readonly (string | Recipient)[],\n content: string,\n opts?: SendPrivateMessageOptions,\n ): Promise<PrivateMessageSendResult> {\n return sendPrivateMessage(this.#dmDeps(), recipients, content, opts);\n }\n\n async fetchPrivateMessages(\n opts?: FetchPrivateMessagesOptions,\n ): Promise<ReceivedPrivateMessage[]> {\n return fetchPrivateMessages(this.#dmDeps(), opts);\n }\n\n async subscribePrivateMessages(\n opts?: SubscribePrivateMessagesOptions,\n ): Promise<{ close: (reason?: string) => void }> {\n return subscribePrivateMessages(this.#dmDeps(), opts);\n }\n\n /**\n * NIP-77 sync against one relay: reconcile, then optionally upload\n * local-only events and/or download remote-only events.\n * `observe: false` skips putMany and ingestMeta; received ids are still listed.\n * `persistEvents: false` skips putMany, still ingestMeta when observe is on.\n */\n async syncToRelay(\n url: string,\n filter: Filter,\n opts?: Omit<SyncOptions, \"relays\">,\n ): Promise<SyncSummary> {\n return syncToRelay(this.#syncDeps(), url, filter, opts);\n }\n\n /**\n * NIP-77 sync against the given relays (or Client default relays).\n * Independent sessions run in parallel. Fulfilled summaries are merged;\n * if every relay rejects, throws the first rejection in URL order.\n */\n async sync(filter: Filter, opts?: SyncOptions): Promise<SyncSummary> {\n return sync(this.#syncDeps(), filter, opts);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { a as NostrError } from "./error-WEFS-R-4.mjs";
|
|
2
|
-
//#region src/storage/error.d.ts
|
|
3
|
-
/** Event-store I/O failure. Message must not include event content. */
|
|
4
|
-
declare class StorageError extends NostrError {}
|
|
5
|
-
//#endregion
|
|
6
|
-
export { StorageError as t };
|
|
7
|
-
//# sourceMappingURL=error-B49rbDzT.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error-CwBxle6N.mjs","names":[],"sources":["../src/storage/error.ts"],"sourcesContent":["import { NostrError } from \"../core/error.ts\";\n\n/** Event-store I/O failure. Message must not include event content. */\nexport class StorageError extends NostrError {}\n\nexport function toStorageError(err: unknown): StorageError {\n if (err instanceof StorageError) return err;\n if (err instanceof Error) return new StorageError(err.message, { cause: err });\n return new StorageError(String(err));\n}\n"],"mappings":";;;AAGA,IAAa,eAAb,cAAkC,WAAW,CAAC;AAE9C,SAAgB,eAAe,KAA4B;CACzD,IAAI,eAAe,cAAc,OAAO;CACxC,IAAI,eAAe,OAAO,OAAO,IAAI,aAAa,IAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7E,OAAO,IAAI,aAAa,OAAO,GAAG,CAAC;AACrC"}
|
package/dist/error-DZEs5OuZ.mjs
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
//#region src/core/error.ts
|
|
2
|
-
/** Base error for all @qntx/nostr failures. */
|
|
3
|
-
var NostrError = class extends Error {
|
|
4
|
-
constructor(message, options) {
|
|
5
|
-
super(message, options);
|
|
6
|
-
this.name = new.target.name;
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
/** Invalid hex encoding or length. */
|
|
10
|
-
var HexError = class extends NostrError {};
|
|
11
|
-
/** Invalid URL / relay URL. */
|
|
12
|
-
var UrlError = class extends NostrError {};
|
|
13
|
-
/** Event shape / wire validation failure. */
|
|
14
|
-
var EventValidationError = class extends NostrError {};
|
|
15
|
-
/** Cryptographic operation failure (keys, signatures). */
|
|
16
|
-
var CryptoError = class extends NostrError {};
|
|
17
|
-
/** Message parse / encode failure. */
|
|
18
|
-
var MessageError = class extends NostrError {};
|
|
19
|
-
/** Wasm verify instance aborted; later verifies on that instance fail. */
|
|
20
|
-
var WasmVerifyPoisonedError = class extends NostrError {};
|
|
21
|
-
//#endregion
|
|
22
|
-
export { NostrError as a, MessageError as i, EventValidationError as n, UrlError as o, HexError as r, WasmVerifyPoisonedError as s, CryptoError as t };
|
|
23
|
-
|
|
24
|
-
//# sourceMappingURL=error-DZEs5OuZ.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error-DZEs5OuZ.mjs","names":[],"sources":["../src/core/error.ts"],"sourcesContent":["/** Base error for all @qntx/nostr failures. */\nexport class NostrError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\n/** Invalid hex encoding or length. */\nexport class HexError extends NostrError {}\n\n/** Invalid URL / relay URL. */\nexport class UrlError extends NostrError {}\n\n/** Event shape / wire validation failure. */\nexport class EventValidationError extends NostrError {}\n\n/** Cryptographic operation failure (keys, signatures). */\nexport class CryptoError extends NostrError {}\n\n/** Message parse / encode failure. */\nexport class MessageError extends NostrError {}\n\n/** Wasm verify instance aborted; later verifies on that instance fail. */\nexport class WasmVerifyPoisonedError extends NostrError {}\n"],"mappings":";;AACA,IAAa,aAAb,cAAgC,MAAM;CACpC,YAAY,SAAiB,SAAwB;EACnD,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO,WAAW;CACzB;AACF;;AAGA,IAAa,WAAb,cAA8B,WAAW,CAAC;;AAG1C,IAAa,WAAb,cAA8B,WAAW,CAAC;;AAG1C,IAAa,uBAAb,cAA0C,WAAW,CAAC;;AAGtD,IAAa,cAAb,cAAiC,WAAW,CAAC;;AAG7C,IAAa,eAAb,cAAkC,WAAW,CAAC;;AAG9C,IAAa,0BAAb,cAA6C,WAAW,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-CzoQEFMF.mjs","names":[],"sources":["../src/core/tag.ts","../src/core/event.ts"],"sourcesContent":["import { isAddressableKind, isReplaceableKind } from \"./kind.ts\";\nimport { isHex32 } from \"./util.ts\";\n\n/** A NIP-01 tag: first element is the name, rest are values. */\nexport type Tag = readonly string[];\n\n/** Mutable tag builder input. */\nexport type TagInput = string[];\n\nexport function isTag(value: unknown): value is Tag {\n if (!Array.isArray(value) || value.length === 0) return false;\n for (const item of value) {\n if (typeof item !== \"string\") return false;\n }\n return true;\n}\n\nexport function tagName(tag: Tag): string {\n return tag[0];\n}\n\nexport function tagValue(tag: Tag): string | undefined {\n return tag[1];\n}\n\n/** Construct common tags. */\nexport const Tag = {\n e(id: string, relay?: string, marker?: string, pubkey?: string): Tag {\n const t: string[] = [\"e\", id.toLowerCase()];\n if (relay !== undefined) t.push(relay);\n if (marker !== undefined) t.push(marker);\n if (pubkey !== undefined) t.push(pubkey.toLowerCase());\n return t;\n },\n p(pubkey: string, relay?: string, petname?: string): Tag {\n const t: string[] = [\"p\", pubkey.toLowerCase()];\n if (relay !== undefined) t.push(relay);\n if (petname !== undefined) t.push(petname);\n return t;\n },\n a(coordinate: string, relay?: string): Tag {\n const t: string[] = [\"a\", coordinate];\n if (relay !== undefined) t.push(relay);\n return t;\n },\n d(identifier: string): Tag {\n return [\"d\", identifier];\n },\n t(hashtag: string): Tag {\n return [\"t\", hashtag];\n },\n r(url: string, marker?: string): Tag {\n const t: string[] = [\"r\", url];\n if (marker !== undefined) t.push(marker);\n return t;\n },\n k(kind: number | string): Tag {\n return [\"k\", String(kind)];\n },\n} as const;\n\n/** First `d` tag value on an event, if any. */\nexport function getDTag(tags: readonly Tag[]): string | undefined {\n for (const tag of tags) {\n if (tag[0] === \"d\" && tag[1] !== undefined) return tag[1];\n }\n return undefined;\n}\n\n/** NIP-01 `a` tag: `kind:pubkey:identifier` (identifier may be empty and may contain extra colons). */\nexport type EventAddress = {\n kind: number;\n pubkey: string;\n identifier: string;\n};\n\n/** Parse a NIP-01 addressable/replaceable coordinate. */\nexport function parseEventAddress(value: string): EventAddress | undefined {\n const first = value.indexOf(\":\");\n if (first <= 0) return undefined;\n const second = value.indexOf(\":\", first + 1);\n if (second < 0) return undefined;\n const kind = Number(value.slice(0, first));\n if (!Number.isInteger(kind) || kind < 0 || kind > 65535) return undefined;\n const pubkey = value.slice(first + 1, second).toLowerCase();\n if (!isHex32(pubkey)) return undefined;\n return { kind, pubkey, identifier: value.slice(second + 1) };\n}\n\nexport function formatEventAddress(kind: number, pubkey: string, identifier = \"\"): string {\n return `${kind}:${pubkey.toLowerCase()}:${identifier}`;\n}\n\n/**\n * Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events.\n * Undefined for regular/ephemeral kinds.\n */\nexport function eventAddress(event: {\n kind: number;\n pubkey: string;\n tags: readonly Tag[];\n}): string | undefined {\n if (isAddressableKind(event.kind)) {\n return formatEventAddress(event.kind, event.pubkey, getDTag(event.tags) ?? \"\");\n }\n if (isReplaceableKind(event.kind)) {\n return formatEventAddress(event.kind, event.pubkey, \"\");\n }\n return undefined;\n}\n","import { EventValidationError } from \"./error.ts\";\nimport { isHex32, isHex64, utf8Encoder } from \"./util.ts\";\nimport type { Tag } from \"./tag.ts\";\nimport { isTag } from \"./tag.ts\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex } from \"./util.ts\";\n\n/** Wire event template before pubkey/id/sig. */\nexport type EventTemplate = {\n readonly kind: number;\n readonly tags: readonly Tag[];\n readonly content: string;\n readonly created_at: number;\n};\n\n/** Event with pubkey, ready to hash and sign. */\nexport type UnsignedEvent = EventTemplate & {\n readonly pubkey: string;\n};\n\n/**\n * Fully formed NIP-01 event (JSON-friendly plain object).\n * Fields are readonly at the type level; wire interop remains plain JSON.\n */\nexport type Event = UnsignedEvent & {\n readonly id: string;\n readonly sig: string;\n};\n\n/** Cache of events whose signatures have been verified successfully. */\nconst verifiedEvents = new WeakSet<object>();\n\n/** Cache of events known to fail verification. */\nconst failedEvents = new WeakSet<object>();\n\nexport function markVerified(event: Event): void {\n verifiedEvents.add(event);\n failedEvents.delete(event);\n}\n\nexport function markUnverified(event: Event): void {\n failedEvents.add(event);\n verifiedEvents.delete(event);\n}\n\nexport function isMarkedVerified(event: Event): boolean {\n return verifiedEvents.has(event);\n}\n\nexport function isMarkedFailed(event: Event): boolean {\n return failedEvents.has(event);\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> =>\n typeof obj === \"object\" && obj !== null && !Array.isArray(obj);\n\n/** Structural validation of an unsigned event (no crypto). */\nexport function validateEvent(event: unknown): event is UnsignedEvent {\n if (!isRecord(event)) return false;\n if (\n typeof event.kind !== \"number\" ||\n !Number.isInteger(event.kind) ||\n event.kind < 0 ||\n event.kind > 65535\n ) {\n return false;\n }\n if (typeof event.content !== \"string\") return false;\n if (typeof event.created_at !== \"number\" || !Number.isInteger(event.created_at)) return false;\n if (typeof event.pubkey !== \"string\" || !isHex32(event.pubkey)) return false;\n if (!Array.isArray(event.tags)) return false;\n for (const tag of event.tags) {\n if (!isTag(tag)) return false;\n }\n return true;\n}\n\n/** Structural validation of a full event including id and sig hex shape. */\nexport function validateSignedEvent(event: unknown): event is Event {\n if (!validateEvent(event)) return false;\n const e = event as Record<string, unknown>;\n if (typeof e.id !== \"string\" || !isHex32(e.id)) return false;\n if (typeof e.sig !== \"string\" || !isHex64(e.sig)) return false;\n return true;\n}\n\n/**\n * Canonical NIP-01 serialization used for hashing:\n * JSON array `[0, pubkey, created_at, kind, tags, content]` with no extra whitespace.\n */\nexport function serializeEvent(event: UnsignedEvent): string {\n if (!validateEvent(event)) {\n throw new EventValidationError(\"cannot serialize event with invalid shape\");\n }\n return JSON.stringify([\n 0,\n event.pubkey.toLowerCase(),\n event.created_at,\n event.kind,\n event.tags,\n event.content,\n ]);\n}\n\n/** SHA-256 of the canonical serialization, lowercase hex. */\nexport function getEventHash(event: UnsignedEvent): string {\n const serialized = serializeEvent(event);\n return bytesToHex(sha256(utf8Encoder.encode(serialized)));\n}\n\nfunction compareEventsDesc(a: Event, b: Event): number {\n if (a.created_at !== b.created_at) return b.created_at - a.created_at;\n return a.id.localeCompare(b.id);\n}\n\n/**\n * Sort events reverse-chronologically by `created_at`, then by `id` lexicographically.\n * Mutates and returns the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort(compareEventsDesc);\n}\n\n/** Non-mutating sort; returns a new array. */\nexport function sortedEvents(events: readonly Event[]): Event[] {\n return events.slice().sort(compareEventsDesc);\n}\n\n/**\n * Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`).\n * Time axis is opposite {@link sortEvents}; id tie-break is the same direction.\n */\nexport function itemCompare(\n a: { id: string; created_at: number },\n b: { id: string; created_at: number },\n): number {\n if (a.created_at !== b.created_at) return a.created_at - b.created_at;\n if (a.id < b.id) return -1;\n if (a.id > b.id) return 1;\n return 0;\n}\n\n/**\n * NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp\n * and lexicographically lower `id`.\n */\nexport function isReplaceableWinner(\n candidate: { created_at: number; id: string },\n incumbent: { created_at: number; id: string },\n): boolean {\n if (candidate.created_at !== incumbent.created_at) {\n return candidate.created_at > incumbent.created_at;\n }\n return candidate.id < incumbent.id;\n}\n\n/** True when a signed event is the signed form of `unsigned` (kind/tags/content/time/pubkey). */\nexport function signedMatchesUnsigned(signed: Event, unsigned: UnsignedEvent): boolean {\n if (signed.kind !== unsigned.kind) return false;\n if (signed.content !== unsigned.content) return false;\n if (signed.created_at !== unsigned.created_at) return false;\n if (JSON.stringify(signed.tags) !== JSON.stringify(unsigned.tags)) return false;\n if (unsigned.pubkey && signed.pubkey.toLowerCase() !== unsigned.pubkey.toLowerCase()) {\n return false;\n }\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filter-BxwjEkZp.mjs","names":[],"sources":["../src/core/filter.ts"],"sourcesContent":["import type { Event } from \"./event.ts\";\nimport { isAddressableKind, isReplaceableKind } from \"./kind.ts\";\n\n/** NIP-01 filter object (immutable-friendly; callers may still pass plain objects). */\nexport type Filter = {\n readonly ids?: readonly string[];\n readonly kinds?: readonly number[];\n readonly authors?: readonly string[];\n readonly since?: number;\n readonly until?: number;\n readonly limit?: number;\n /**\n * NIP-50 full-text search. Relays interpret this.\n * Local `matchFilter` / `query` ignore it.\n */\n readonly search?: string;\n readonly [key: `#${string}`]: readonly string[] | undefined;\n};\n\n/** Local NIP-01 match. `search` is ignored; relays interpret NIP-50. */\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && !filter.ids.some((id) => id.toLowerCase() === event.id.toLowerCase())) {\n return false;\n }\n if (filter.kinds && !filter.kinds.includes(event.kind)) return false;\n if (\n filter.authors &&\n !filter.authors.some((pk) => pk.toLowerCase() === event.pubkey.toLowerCase())\n ) {\n return false;\n }\n\n for (const key of Object.keys(filter)) {\n if (key[0] !== \"#\") continue;\n const tagName = key.slice(1);\n const values = filter[`#${tagName}`];\n if (!values) continue;\n const hexTag = tagName === \"e\" || tagName === \"p\";\n const hit = event.tags.some((tag) => {\n if (tag[0] !== tagName || tag[1] === undefined) return false;\n if (hexTag) {\n return values.some((v) => v.toLowerCase() === tag[1]!.toLowerCase());\n }\n return values.includes(tag[1]);\n });\n if (!hit) return false;\n }\n\n if (filter.since !== undefined && event.created_at < filter.since) return false;\n if (filter.until !== undefined && event.created_at > filter.until) return false;\n\n return true;\n}\n\nexport function matchFilters(filters: readonly Filter[], event: Event): boolean {\n for (const filter of filters) {\n if (matchFilter(filter, event)) return true;\n }\n return false;\n}\n\n/** Merge filters by unioning list fields; returns a new plain object. */\nexport function mergeFilters(...filters: Filter[]): Filter {\n const result: Record<string, unknown> = {};\n for (const filter of filters) {\n for (const [property, values] of Object.entries(filter)) {\n if (\n property === \"kinds\" ||\n property === \"ids\" ||\n property === \"authors\" ||\n property[0] === \"#\"\n ) {\n const list = (result[property] as (string | number)[] | undefined) ?? [];\n for (const value of values as readonly (string | number)[]) {\n if (!list.includes(value)) list.push(value);\n }\n result[property] = list;\n }\n }\n if (filter.limit !== undefined) {\n const prev = result.limit as number | undefined;\n if (prev === undefined || filter.limit > prev) result.limit = filter.limit;\n }\n if (filter.until !== undefined) {\n const prev = result.until as number | undefined;\n if (prev === undefined || filter.until > prev) result.until = filter.until;\n }\n if (filter.since !== undefined) {\n const prev = result.since as number | undefined;\n if (prev === undefined || filter.since < prev) result.since = filter.since;\n }\n if (filter.search !== undefined) {\n result.search = filter.search;\n }\n }\n return result as Filter;\n}\n\n/**\n * Intrinsic upper bound implied by the filter alone.\n * Returns a positive integer, or `Infinity` when unbounded.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && filter.ids.length === 0) return 0;\n if (filter.kinds && filter.kinds.length === 0) return 0;\n if (filter.authors && filter.authors.length === 0) return 0;\n\n let limit = Infinity;\n if (filter.ids) limit = Math.min(limit, filter.ids.length);\n if (filter.limit !== undefined) limit = Math.min(limit, filter.limit);\n\n if (filter.kinds && filter.authors) {\n const allReplaceable = filter.kinds.every((k) => isReplaceableKind(k) || isAddressableKind(k));\n if (allReplaceable) {\n const dTags = filter[\"#d\"];\n const perAuthor = dTags && dTags.length > 0 ? dTags.length : 1;\n limit = Math.min(limit, filter.authors.length * filter.kinds.length * perAuthor);\n }\n }\n\n return limit;\n}\n\n/** Shallow-clone a filter (for per-relay narrowing). */\nexport function cloneFilter(filter: Filter): Filter {\n return { ...filter };\n}\n\nconst HEX_LIST_KEYS = new Set([\"ids\", \"authors\", \"#e\", \"#p\"]);\n\n/** Lowercase hex lists and sort every array. Omits undefined so `[]` stays distinct from missing. */\nexport function canonicalizeFilter(filter: Filter): Filter {\n const raw = filter as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(raw).sort()) {\n const value = raw[key];\n // omit undefined so a missing key is not `[]` / null\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n if (HEX_LIST_KEYS.has(key)) {\n out[key] = value.map((v) => String(v).toLowerCase()).sort();\n } else if (key === \"kinds\") {\n out[key] = value.map((v) => Number(v)).sort((a, b) => a - b);\n } else {\n out[key] = value.map((v) => String(v)).sort();\n }\n } else {\n out[key] = value;\n }\n }\n return out as Filter;\n}\n\nexport function canonicalizeFilters(filters: readonly Filter[]): Filter[] {\n return filters.map(canonicalizeFilter);\n}\n\n/**\n * Canonical identity for live REQ coalescing.\n * Relays treat a missing list key as unconstrained and `[]` as match-nothing.\n */\nexport function filterFingerprint(filters: readonly Filter[]): string {\n const parts = filters.map((filter) => JSON.stringify(canonicalizeFilter(filter)));\n parts.sort();\n return `[${parts.join(\",\")}]`;\n}\n"],"mappings":"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"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { t as Event } from "./event-B5D2jxt_.mjs";
|
|
2
|
-
//#region src/core/filter.d.ts
|
|
3
|
-
/** NIP-01 filter object (immutable-friendly; callers may still pass plain objects). */
|
|
4
|
-
type Filter = {
|
|
5
|
-
readonly ids?: readonly string[];
|
|
6
|
-
readonly kinds?: readonly number[];
|
|
7
|
-
readonly authors?: readonly string[];
|
|
8
|
-
readonly since?: number;
|
|
9
|
-
readonly until?: number;
|
|
10
|
-
readonly limit?: number;
|
|
11
|
-
/**
|
|
12
|
-
* NIP-50 full-text search. Relays interpret this.
|
|
13
|
-
* Local `matchFilter` / `query` ignore it.
|
|
14
|
-
*/
|
|
15
|
-
readonly search?: string;
|
|
16
|
-
readonly [key: `#${string}`]: readonly string[] | undefined;
|
|
17
|
-
};
|
|
18
|
-
/** Local NIP-01 match. `search` is ignored; relays interpret NIP-50. */
|
|
19
|
-
declare function matchFilter(filter: Filter, event: Event): boolean;
|
|
20
|
-
declare function matchFilters(filters: readonly Filter[], event: Event): boolean;
|
|
21
|
-
/** Merge filters by unioning list fields; returns a new plain object. */
|
|
22
|
-
declare function mergeFilters(...filters: Filter[]): Filter;
|
|
23
|
-
/**
|
|
24
|
-
* Intrinsic upper bound implied by the filter alone.
|
|
25
|
-
* Returns a positive integer, or `Infinity` when unbounded.
|
|
26
|
-
*/
|
|
27
|
-
declare function getFilterLimit(filter: Filter): number;
|
|
28
|
-
/** Shallow-clone a filter (for per-relay narrowing). */
|
|
29
|
-
declare function cloneFilter(filter: Filter): Filter;
|
|
30
|
-
/** Lowercase hex lists and sort every array. Omits undefined so `[]` stays distinct from missing. */
|
|
31
|
-
declare function canonicalizeFilter(filter: Filter): Filter;
|
|
32
|
-
declare function canonicalizeFilters(filters: readonly Filter[]): Filter[];
|
|
33
|
-
/**
|
|
34
|
-
* Canonical identity for live REQ coalescing.
|
|
35
|
-
* Relays treat a missing list key as unconstrained and `[]` as match-nothing.
|
|
36
|
-
*/
|
|
37
|
-
declare function filterFingerprint(filters: readonly Filter[]): string;
|
|
38
|
-
//#endregion
|
|
39
|
-
export { filterFingerprint as a, matchFilters as c, cloneFilter as i, mergeFilters as l, canonicalizeFilter as n, getFilterLimit as o, canonicalizeFilters as r, matchFilter as s, Filter as t };
|
|
40
|
-
//# sourceMappingURL=filter-DUEKP3q1.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gossip-3xkRRCm_.mjs","names":["#routes","#maxRelays","#breakAuthors"],"sources":["../src/gossip/gossip.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { parseDmRelayList } from \"../nips/nip17.ts\";\nimport { parseRelayList, type RelayListItem } from \"../nips/nip65.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\n\nexport type PubkeyRoutes = {\n /** Relays the user writes to (outbox). NIP-65. */\n write: string[];\n /** Relays the user reads from (inbox). NIP-65. */\n read: string[];\n /** Relays for NIP-17 gift-wrap delivery. Kind 10050. */\n dm: string[];\n /** `created_at` of the last accepted kind:10002 list. */\n updatedAt: number;\n /** `created_at` of the last accepted kind:10050 list. */\n dmUpdatedAt: number;\n /** Event id of the last accepted kind:10002 (NIP-01 equal-timestamp tie-break). */\n relayListId?: string;\n /** Event id of the last accepted kind:10050. */\n dmListId?: string;\n};\n\nexport type RoutedFilter = {\n /** url → already-narrowed filter. Empty when nothing routed. */\n perRelay: Map<string, Filter>;\n /**\n * Unrouted work for the caller:\n * - no authors and no #p: original filter (today's \"generic\")\n * - authors/#p all unrouted: original filter (today's \"orphan\")\n * - mixed: narrowed leftover (today's fallback)\n * - all routed: undefined\n */\n remainder?: Filter;\n};\n\nexport type GossipOptions = {\n /** Max relays to keep per direction when ranking. Default 4. */\n maxRelaysPerPubkey?: number;\n};\n\nfunction emptyRoutes(): PubkeyRoutes {\n return {\n write: [],\n read: [],\n dm: [],\n updatedAt: 0,\n dmUpdatedAt: 0,\n };\n}\n\n/**\n * Routing table for NIP-65 (10002) and NIP-17 DM relays (10050).\n * Ingest replaceable list events, then route filters into per-relay REQs.\n */\nexport class Gossip {\n readonly #routes = new Map<string, PubkeyRoutes>();\n readonly #maxRelays: number;\n\n constructor(opts: GossipOptions = {}) {\n this.#maxRelays = opts.maxRelaysPerPubkey ?? 4;\n }\n\n /**\n * Ingest a routing list event.\n * - kind:10002 → write/read (NIP-65)\n * - kind:10050 → dm (NIP-17)\n * Returns true if routes for that list type were updated.\n */\n ingest(event: Event): boolean {\n if (event.kind === Kind.RelayList) {\n let items: RelayListItem[];\n try {\n items = parseRelayList(event);\n } catch {\n return false;\n }\n return this.setRoutes(event.pubkey, items, event.created_at, event.id);\n }\n if (event.kind === Kind.DirectMessageRelaysList) {\n let relays: string[];\n try {\n relays = parseDmRelayList(event);\n } catch {\n return false;\n }\n return this.setDmRoutes(event.pubkey, relays, event.created_at, event.id);\n }\n return false;\n }\n\n setRoutes(\n pubkey: string,\n items: RelayListItem[],\n updatedAt = Math.floor(Date.now() / 1000),\n eventId?: string,\n ): boolean {\n const pk = pubkey.toLowerCase();\n const prev = this.#routes.get(pk) ?? emptyRoutes();\n if (prev.updatedAt > updatedAt) return false;\n if (\n eventId &&\n prev.relayListId &&\n prev.updatedAt === updatedAt &&\n !isReplaceableWinner(\n { created_at: updatedAt, id: eventId },\n { created_at: prev.updatedAt, id: prev.relayListId },\n )\n ) {\n return false;\n }\n\n const write: string[] = [];\n const read: string[] = [];\n for (const item of items) {\n let url: string;\n try {\n url = normalizeURL(item.url);\n } catch {\n continue;\n }\n if (item.write && !write.includes(url)) write.push(url);\n if (item.read && !read.includes(url)) read.push(url);\n }\n\n this.#routes.set(pk, {\n write: write.slice(0, this.#maxRelays),\n read: read.slice(0, this.#maxRelays),\n dm: prev.dm,\n updatedAt,\n dmUpdatedAt: prev.dmUpdatedAt,\n relayListId: eventId ?? prev.relayListId,\n dmListId: prev.dmListId,\n });\n return true;\n }\n\n setDmRoutes(\n pubkey: string,\n relays: readonly string[],\n updatedAt = Math.floor(Date.now() / 1000),\n eventId?: string,\n ): boolean {\n const pk = pubkey.toLowerCase();\n const prev = this.#routes.get(pk) ?? emptyRoutes();\n if (prev.dmUpdatedAt > updatedAt) return false;\n if (\n eventId &&\n prev.dmListId &&\n prev.dmUpdatedAt === updatedAt &&\n !isReplaceableWinner(\n { created_at: updatedAt, id: eventId },\n { created_at: prev.dmUpdatedAt, id: prev.dmListId },\n )\n ) {\n return false;\n }\n\n const dm: string[] = [];\n for (const raw of relays) {\n let url: string;\n try {\n url = normalizeURL(raw);\n } catch {\n continue;\n }\n if (!dm.includes(url)) dm.push(url);\n }\n\n this.#routes.set(pk, {\n write: prev.write,\n read: prev.read,\n dm: dm.slice(0, this.#maxRelays),\n updatedAt: prev.updatedAt,\n dmUpdatedAt: updatedAt,\n relayListId: prev.relayListId,\n dmListId: eventId ?? prev.dmListId,\n });\n return true;\n }\n\n getRoutes(pubkey: string): PubkeyRoutes | undefined {\n return this.#routes.get(pubkey.toLowerCase());\n }\n\n outboxRelays(pubkey: string): string[] {\n return this.#routes.get(pubkey.toLowerCase())?.write ?? [];\n }\n\n inboxRelays(pubkey: string): string[] {\n return this.#routes.get(pubkey.toLowerCase())?.read ?? [];\n }\n\n /** NIP-17 kind:10050 delivery relays for gift-wraps. */\n dmRelays(pubkey: string): string[] {\n return this.#routes.get(pubkey.toLowerCase())?.dm ?? [];\n }\n\n clear(pubkey?: string): void {\n if (pubkey) this.#routes.delete(pubkey.toLowerCase());\n else this.#routes.clear();\n }\n\n get size(): number {\n return this.#routes.size;\n }\n\n /**\n * Route a user-facing filter into per-relay sub-filters plus leftover.\n * - authors → outbox relays, filter narrowed per relay's authors\n * - #p only → inbox relays of those pubkeys\n * - neither / all unrouted → remainder is the original filter\n * - mixed → remainder is the narrowed leftover; all routed → no remainder\n */\n route(filter: Filter): RoutedFilter {\n const authors = filter.authors?.map((a) => a.toLowerCase());\n const pTags = filter[\"#p\"]?.map((p) => p.toLowerCase());\n\n if ((!authors || authors.length === 0) && (!pTags || pTags.length === 0)) {\n return { perRelay: new Map(), remainder: filter };\n }\n\n if (authors && authors.length > 0 && (!pTags || pTags.length === 0)) {\n return this.#breakAuthors(filter, authors, \"write\");\n }\n\n if (pTags && pTags.length > 0 && (!authors || authors.length === 0)) {\n return this.#breakAuthors(\n { ...filter, authors: undefined },\n pTags,\n \"read\",\n (base, pubkeys) => ({ ...base, \"#p\": pubkeys }),\n );\n }\n\n // both authors and #p: send full filter to union of routes\n const unionKeys = new Set([...(authors ?? []), ...(pTags ?? [])]);\n const relays = new Set<string>();\n let anyUnrouted = false;\n for (const pk of unionKeys) {\n const r = this.#routes.get(pk);\n const urls = r ? [...r.write, ...r.read] : [];\n if (urls.length === 0) {\n anyUnrouted = true;\n continue;\n }\n for (const u of urls) relays.add(u);\n }\n if (relays.size === 0) return { perRelay: new Map(), remainder: filter };\n const map = new Map<string, Filter>();\n for (const url of relays) map.set(url, { ...filter });\n return anyUnrouted ? { perRelay: map, remainder: filter } : { perRelay: map };\n }\n\n #breakAuthors(\n filter: Filter,\n pubkeys: string[],\n direction: \"read\" | \"write\",\n narrow: (base: Filter, pubkeys: string[]) => Filter = (base, pks) => ({\n ...base,\n authors: pks,\n }),\n ): RoutedFilter {\n const perRelay = new Map<string, string[]>();\n const unrouted: string[] = [];\n let anyRoute = false;\n\n for (const pk of pubkeys) {\n const routes = this.#routes.get(pk);\n const urls = direction === \"write\" ? routes?.write : routes?.read;\n if (!urls || urls.length === 0) {\n unrouted.push(pk);\n continue;\n }\n anyRoute = true;\n for (const url of urls) {\n const list = perRelay.get(url) ?? [];\n list.push(pk);\n perRelay.set(url, list);\n }\n }\n\n if (!anyRoute) return { perRelay: new Map(), remainder: filter };\n\n const map = new Map<string, Filter>();\n for (const [url, pks] of perRelay) {\n map.set(url, narrow(filter, pks));\n }\n return unrouted.length > 0\n ? { perRelay: map, remainder: narrow(filter, unrouted) }\n : { perRelay: map };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http-D2rhokZo.mjs","names":[],"sources":["../src/nips/http.ts"],"sourcesContent":["/**\n * Shared nips HTTP primitive. Not a pack entry (core has zero network).\n * Callers never pass `redirect`; sendManual always sets `\"manual\"`.\n */\n\nexport type ManualFetch = (\n url: string,\n init?: {\n method?: string;\n headers?: Record<string, string>;\n body?: Blob | FormData | string | null;\n signal?: AbortSignal;\n },\n) => Promise<{\n ok: boolean;\n status: number;\n headers: { get(name: string): string | null };\n json(): Promise<unknown>;\n arrayBuffer(): Promise<ArrayBuffer>;\n}>;\n\ntype ManualInit = NonNullable<Parameters<ManualFetch>[1]>;\n\nexport function requireGlobalFetch(missing: () => Error): ManualFetch {\n if (typeof globalThis.fetch !== \"function\") throw missing();\n return globalThis.fetch.bind(globalThis) as ManualFetch;\n}\n\n/** Always sets redirect:manual. Shared by fetchManual and headStatus. */\nexport async function sendManual(\n fetchImpl: ManualFetch,\n url: string,\n init: ManualInit,\n): Promise<Awaited<ReturnType<ManualFetch>>> {\n return await fetchImpl(url, { ...init, redirect: \"manual\" } as Parameters<ManualFetch>[1]);\n}\n\nexport async function fetchManual(\n fetchImpl: ManualFetch,\n url: string,\n init: ManualInit,\n wrapNetwork: (err: unknown) => Error,\n): Promise<Awaited<ReturnType<ManualFetch>>> {\n try {\n return await sendManual(fetchImpl, url, init);\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") throw err;\n throw wrapNetwork(err);\n }\n}\n"],"mappings":";AAuBA,SAAgB,mBAAmB,SAAmC;CACpE,IAAI,OAAO,WAAW,UAAU,YAAY,MAAM,QAAQ;CAC1D,OAAO,WAAW,MAAM,KAAK,UAAU;AACzC;;AAGA,eAAsB,WACpB,WACA,KACA,MAC2C;CAC3C,OAAO,MAAM,UAAU,KAAK;EAAE,GAAG;EAAM,UAAU;CAAS,CAA+B;AAC3F;AAEA,eAAsB,YACpB,WACA,KACA,MACA,aAC2C;CAC3C,IAAI;EACF,OAAO,MAAM,WAAW,WAAW,KAAK,IAAI;CAC9C,SAAS,KAAK;EACZ,IAAI,eAAe,SAAS,IAAI,SAAS,cAAc,MAAM;EAC7D,MAAM,YAAY,GAAG;CACvB;AACF"}
|