@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-BWsX9Cv1.mjs","names":[],"sources":["../src/client/builder.ts","../src/client/dm.ts","../src/client/types.ts","../src/client/gossip-io.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 type { ReactiveEventStore } from \"../store/reactive.ts\";\nimport type { Client } from \"./client.ts\";\nimport type { ClientOptions } from \"./types.ts\";\n\n/**\n * Fluent constructor for {@link Client}. The constructor is supplied by {@link Client.builder} so\n * this module never imports the `Client` value, keeping the client/builder dependency\n * one-directional.\n */\nexport class ClientBuilder {\n #opts: ClientOptions = {};\n readonly #newClient: (opts: ClientOptions) => Client;\n\n constructor(newClient: (opts: ClientOptions) => Client) {\n this.#newClient = newClient;\n }\n\n signer(signer: NostrSigner): this {\n this.#opts = { ...this.#opts, signer };\n return this;\n }\n\n relays(urls: ReadonlyArray<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 /** Allow `ws://` relays. Default false. */\n allowInsecure(allow: boolean): this {\n this.#opts = { ...this.#opts, allowInsecure: allow };\n return this;\n }\n\n /** `ws://` URLs allowed despite `allowInsecure` being off. */\n trustedInsecureUrls(urls: ReadonlyArray<string>): this {\n this.#opts = { ...this.#opts, trustedInsecureUrls: urls };\n return this;\n }\n\n /** Close idle relays after this many ms. Unset = disabled. */\n idleTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, idleTimeoutMs: ms };\n return this;\n }\n\n /** Soft cap on connected non-pinned relays. */\n maxRelays(n: number): this {\n this.#opts = { ...this.#opts, maxRelays: n };\n return this;\n }\n\n /** Relays never closed by idle cleanup or `maxRelays` eviction. */\n pinnedUrls(urls: ReadonlyArray<string>): this {\n this.#opts = { ...this.#opts, pinnedUrls: urls };\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}. Browser apps that want persistence must\n * 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 /**\n * Synchronous reactive index mirroring ingested events. Defaults to a new\n * {@link ReactiveEventStore}.\n */\n index(index: ReactiveEventStore): this {\n this.#opts = { ...this.#opts, index };\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 this.#newClient(this.#opts);\n }\n}\n","import type { EventBuilder } from \"../core/builder.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { itemCompare } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport {\n Nip17Error,\n buildChatMessageRumor,\n dmRelayListEventBuilder,\n normalizeRecipients,\n requireDmRelays,\n wrapDirectMessage,\n} from \"../nips/nip17.ts\";\nimport type { Recipient } from \"../nips/nip17.ts\";\nimport { unwrap } from \"../nips/nip59.ts\";\nimport type { Nip59Crypto } from \"../nips/nip59.ts\";\nimport type { Pool, PoolPublishResult } from \"../relay/pool.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: ReadonlyArray<string>) => Promise<void>;\n ingest: (event: Event, relayUrl?: string) => void;\n markSeen: (id: string, relayUrl: string) => 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] !== undefined && tag[1] !== \"\") {\n targets.push(tag[1].toLowerCase());\n }\n }\n if (targets.length === 0) {\n throw new Nip17Error(\"gift wrap has no p-tag recipient\");\n }\n const [target] = targets;\n if (targets.length !== 1 || target === undefined) {\n throw new Nip17Error(\"gift wrap must have exactly one p-tag recipient\");\n }\n const relays = gossip.dmRelays(target);\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: ReadonlyArray<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 | ReadonlyArray<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 === true) && deps.wantObserve(opts?.observe)) {\n deps.ingest(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 urls = new Map<string, Set<string>>();\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 {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n onevent: (event, relayUrl) => {\n let set = urls.get(event.id);\n if (!set) {\n urls.set(event.id, (set = new Set()));\n }\n set.add(relayUrl);\n },\n },\n );\n\n const byRumor = new Map<string, ReceivedPrivateMessage>();\n for (const wrap of events) {\n try {\n // oxlint-disable-next-line no-await-in-loop -- unwraps run serially so ingest/seenOn keep relay order\n const rumor = await unwrap(crypto, wrap);\n const wrapUrls = urls.get(wrap.id);\n const firstUrl = wrapUrls?.values().next().value;\n if (deps.wantObserve(opts?.observe)) {\n deps.ingest(wrap, firstUrl);\n // Every other relay that delivered the same wrap is recorded too.\n if (wrapUrls) {\n for (const url of wrapUrls) {\n if (url !== firstUrl) {\n deps.markSeen(wrap.id, url);\n }\n }\n }\n }\n byRumor.set(rumor.id, {\n wrap,\n rumor,\n ...(firstUrl === undefined ? {} : { relayUrl: firstUrl }),\n });\n } catch {\n // junk / forgery / key mismatch — not stored\n }\n }\n\n return [...byRumor.values()].sort((a, b) => itemCompare(a.rumor, b.rumor));\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 // Wrap ids processed (observed) already; receipts before that are buffered\n // so every delivering relay URL lands in seenOn once the wrap is indexed.\n const processed = new Set<string>();\n const pendingUrls = new Map<string, string[]>();\n const flushSeen = (wrapId: string): void => {\n processed.add(wrapId);\n const extra = pendingUrls.get(wrapId);\n if (extra === undefined) {\n return;\n }\n pendingUrls.delete(wrapId);\n for (const url of extra) {\n deps.markSeen(wrapId, url);\n }\n };\n let tail = Promise.resolve();\n let closed = false;\n const markClosed = (): void => {\n closed = true;\n };\n if (opts?.signal?.aborted === true) {\n markClosed();\n } else {\n opts?.signal?.addEventListener(\"abort\", markClosed, { once: true });\n }\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 receivedEvent: (id, relayUrl) => {\n if (closed) {\n return;\n }\n if (processed.has(id)) {\n deps.markSeen(id, relayUrl);\n return;\n }\n const list = pendingUrls.get(id);\n if (list === undefined) {\n pendingUrls.set(id, [relayUrl]);\n } else if (!list.includes(relayUrl)) {\n list.push(relayUrl);\n }\n },\n onevent: (wrap, relayUrl) => {\n if (closed) {\n return;\n }\n const prev = tail;\n let release: (() => void) | undefined;\n tail = new Promise<void>((resolve) => {\n release = resolve;\n });\n void (async () => {\n await prev;\n try {\n if (closed) {\n return;\n }\n const rumor = await unwrap(crypto, wrap);\n if (closed) {\n return;\n }\n if (seen.has(rumor.id)) {\n flushSeen(wrap.id);\n return;\n }\n seen.add(rumor.id);\n if (deps.wantObserve(opts?.observe)) {\n deps.ingest(wrap, relayUrl);\n }\n flushSeen(wrap.id);\n opts?.onevent?.({ wrap, rumor, relayUrl });\n } catch {\n // junk / forgery — not stored; keep the queue alive if a handler throws\n } finally {\n release?.();\n }\n })();\n },\n },\n );\n\n return {\n close: (reason?: string) => {\n markClosed();\n inner.close(reason);\n },\n };\n}\n","import { NostrError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { ReplyTo } from \"../nips/nip17.ts\";\nimport type { Rumor } from \"../nips/nip59.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 { ReactiveEventStore } from \"../store/reactive.ts\";\n\n/** Direction of a {@link Client.sync} run: upload, download, or both. */\nexport const SyncDirection = {\n Up: \"up\",\n Down: \"down\",\n Both: \"both\",\n} as const;\n\n/** Union of the {@link SyncDirection} values. */\nexport type SyncDirectionName = (typeof SyncDirection)[keyof typeof SyncDirection];\n\n/** Options for {@link Client.sync} (NIP-77 set reconciliation). */\nexport type SyncOptions = {\n relays?: ReadonlyArray<string>;\n direction?: SyncDirectionName;\n /**\n * Wall-clock deadline for the Negentropy reconciliation session (`NEG-OPEN` through `NEG-CLOSE`),\n * in milliseconds. One clock for the whole session — not reset per `NEG-MSG`. Default: the relay\n * `publishTimeoutMs`. 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\n/** Outcome of a {@link Client.sync} run: ids compared, sent, received, and failures. */\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\n/** Options for {@link Client.builder} / `ClientOptions` accepted by the builder. */\nexport type ClientOptions = {\n signer?: NostrSigner;\n relays?: ReadonlyArray<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 /**\n * When true (default), answer NIP-42 AUTH automatically. The signer is read at challenge time, so\n * `setSigner()` applies to live connections; challenges received while no signer is set are\n * ignored.\n */\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 /** Forwarded to the pool: when false (default), `ws://` relays are rejected. */\n allowInsecure?: boolean;\n /** Forwarded to the pool: `ws://` URLs allowed despite `allowInsecure`. */\n trustedInsecureUrls?: ReadonlyArray<string>;\n /** Forwarded to the pool: close idle relays after this many ms. */\n idleTimeoutMs?: number;\n /** Forwarded to the pool: soft cap on connected non-pinned relays. */\n maxRelays?: number;\n /** Forwarded to the pool: relays never closed by idle cleanup or `maxRelays`. */\n pinnedUrls?: ReadonlyArray<string>;\n gossip?: Gossip;\n /**\n * Local event store. Defaults to {@link MemoryEventStore}. Browser apps that want persistence must\n * pass {@link IndexedDbEventStore} and `await open()`.\n */\n storage?: EventStore;\n /**\n * Synchronous reactive index that mirrors every ingested event before callbacks and persistence.\n * Defaults to a new {@link ReactiveEventStore}.\n */\n index?: ReactiveEventStore;\n /**\n * When true (default), every ingested event is written to storage. Set false to disable automatic\n * 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. Those\n * 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 /** When true, query local storage first and merge with network results. Defaults to false. */\n localFirst?: boolean;\n /** When false, skip writing fetched events to storage/observe. Default true. */\n observe?: boolean;\n /**\n * Every event of every relay batch, including duplicates across relays. `relayUrl` is the\n * normalized URL of the relay that delivered it.\n */\n onevent?: (event: Event, relayUrl: string) => void;\n};\n\nexport type SubscribeOptions = {\n relays?: string[];\n /**\n * First receipt of each event only (deduped across relays). `relayUrl` is the normalized URL of\n * the relay that delivered it first.\n */\n onevent?: (event: Event, relayUrl: string) => void;\n /** Every receipt from every relay, including duplicates skipped by dedupe. */\n receivedEvent?: (id: string, relayUrl: string) => 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. Does not close the\n * 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\n/** Options for sending a NIP-17 private message. */\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\n/** Result of sending a NIP-17 DM: the rumor plus per-recipient wrap publish results. */\nexport type PrivateMessageSendResult = {\n rumor: Rumor;\n wraps: ReadonlyArray<{\n recipient: string;\n wrap: Event;\n results: PoolPublishResult[];\n }>;\n};\n\n/** An unwrapped NIP-17 private message: the received gift wrap and its inner rumor. */\nexport type ReceivedPrivateMessage = {\n wrap: Event;\n rumor: Rumor;\n /** Normalized URL of the relay that delivered the wrap, when known. */\n relayUrl?: string;\n};\n\n/** Options for fetching NIP-17 private-message history. */\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\n/** Options for a live NIP-17 private-message subscription. */\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 override name = \"ClientError\";\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 } from \"../relay/fan-in.ts\";\nimport type { FanInOptions, RoutedJob } from \"../relay/fan-in.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\nimport { ClientError } from \"./types.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) {\n jobs.push({ urls: [url], filters: [sub] });\n }\n if (r.remainder !== undefined) {\n if (defaults === undefined) {\n throw new ClientError(\"unrouted remainder without default relays\");\n }\n jobs.push({ urls: defaults, filters: [r.remainder] });\n }\n }\n return jobs;\n}\n\nexport async function fetchGossip(\n pool: Pool,\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n opts?: {\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n onevent?: ((event: Event, relayUrl: string) => void) | undefined;\n },\n): Promise<Event[]> {\n return fetchRouted(pool, jobsForFilters(gossip, filters, defaultRelays), {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n onevent: opts?.onevent,\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 {\n close: () => {\n /* empty */\n },\n };\n }\n return fanIn(pool, jobs, opts);\n}\n","import type { Event } from \"../core/event.ts\";\nimport { canonicalizeFilter } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { storageFromItems } from \"../nips/nip77.ts\";\nimport type { NegentropyStorageVector } from \"../nips/nip77.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\nimport type { EventStore, PutResult } from \"../storage/types.ts\";\nimport { SyncDirection } from \"./types.ts\";\nimport type { SyncOptions, 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 /**\n * The client's single ingest path: index (with relay URL) → meta → persistence. `persist: false`\n * when this function already wrote storage via an awaited `putMany`.\n */\n ingest: (event: Event, relayUrl?: string, opts?: { persist?: boolean }) => void;\n /** Record a relay sighting for an id already in the index. */\n markSeen: (id: string, relayUrl: string) => void;\n defaultRelays: (urls?: string[]) => string[];\n};\n\nconst SYNC_ID_BATCH = 100;\nconst SYNC_UPLOAD_CONCURRENCY = 8;\n\nfunction uniqueIds(ids: ReadonlyArray<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 local-only events and/or\n * download remote-only events. `observe: false` skips putMany and ingest; received ids are still\n * listed. `persistEvents: false` skips putMany, still ingests 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 const canon = canonicalizeFilter(filter);\n const items = await deps.storage.negentropyItems(canon);\n const storage: NegentropyStorageVector = storageFromItems(items);\n const relay = await deps.pool.ensureRelay(url, { signal: opts?.signal });\n const { have, need } = await relay.negReconcile(canon, 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 === true) {\n return summary;\n }\n\n if ((direction === SyncDirection.Up || direction === SyncDirection.Both) && 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 // Upload chunks are rate-limited serially.\n // oxlint-disable-next-line no-await-in-loop\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 === true);\n if (ok) {\n 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] = error instanceof Error ? error.message : String(error);\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 // Every relay that delivered an event is recorded once it is ingested.\n const urlsById = new Map<string, string[]>();\n // Id batches are fetched serially so backpressure stays bounded.\n // oxlint-disable-next-line no-await-in-loop\n const events = await deps.pool.fetch([url], [{ ids: batch }], {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n onevent: shouldObserve\n ? (event, relayUrl) => {\n const urls = urlsById.get(event.id);\n if (urls === undefined) {\n urlsById.set(event.id, [relayUrl]);\n } else if (!urls.includes(relayUrl)) {\n urls.push(relayUrl);\n }\n }\n : undefined,\n });\n if (!shouldObserve) {\n for (const event of events) {\n summary.received.push(event.id);\n }\n continue;\n }\n const ingestAll = (event: Event): void => {\n const urls = urlsById.get(event.id) ?? [];\n deps.ingest(event, urls[0], { persist: false });\n for (const url of urls.slice(1)) {\n deps.markSeen(event.id, url);\n }\n };\n if (!deps.persistEvents) {\n for (const event of events) {\n ingestAll(event);\n summary.received.push(event.id);\n }\n continue;\n }\n // The awaited putMany reports persistFailures; accepted events then go\n // through the ingest path with persistence already done.\n let results: PutResult[];\n try {\n // Persisted serially per batch so failures land on the right ids.\n // oxlint-disable-next-line no-await-in-loop\n results = await deps.storage.putMany(events);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n for (const event of events) {\n summary.persistFailures[event.id] = message;\n }\n break;\n }\n for (const [j, event] of events.entries()) {\n if (results[j] === \"rejected\" || results[j] === \"invalid\") {\n continue;\n }\n ingestAll(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). Independent sessions run in\n * parallel. Fulfilled summaries are merged; if every relay rejects, throws the first rejection in\n * 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(\n urls.map(async (url) => syncToRelay(deps, url, filter, opts)),\n );\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) {\n throw firstRejection;\n }\n return merged;\n}\n","import { throwIfAborted } from \"../core/abort.ts\";\nimport { EventBuilder } from \"../core/builder.ts\";\nimport { sortedEvents } from \"../core/event.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"../core/event.ts\";\nimport { canonicalizeFilters, matchFilters } from \"../core/filter.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { Gossip } from \"../gossip/index.ts\";\nimport { createLoaders, createOutboxFeed } from \"../loaders/index.ts\";\nimport type { Loaders, OutboxFeed } from \"../loaders/index.ts\";\nimport type { Recipient } from \"../nips/nip17.ts\";\nimport { isGiftWrapKind, requireNip59Crypto } from \"../nips/nip59.ts\";\nimport type { Nip59Crypto } from \"../nips/nip59.ts\";\nimport { Pool } from \"../relay/pool.ts\";\nimport type { PoolPublishResult } from \"../relay/pool.ts\";\nimport { NoSignerError } from \"../signer/error.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport { toStorageError } from \"../storage/error.ts\";\nimport type { StorageError } from \"../storage/error.ts\";\nimport { MemoryIndex } from \"../storage/memory-index.ts\";\nimport { MemoryEventStore } from \"../storage/memory.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport { ReactiveEventStore } from \"../store/reactive.ts\";\nimport { ClientBuilder } from \"./builder.ts\";\nimport {\n fetchPrivateMessages,\n giftWrapRelays,\n sendPrivateMessage,\n setDmRelays,\n subscribePrivateMessages,\n} from \"./dm.ts\";\nimport type { DmDeps } from \"./dm.ts\";\nimport { fetchGossip, subscribeGossip } from \"./gossip-io.ts\";\nimport { sync, syncToRelay } from \"./sync.ts\";\nimport type { SyncDeps } from \"./sync.ts\";\nimport { ClientError } from \"./types.ts\";\nimport type {\n ClientOptions,\n FetchEventsOptions,\n FetchPrivateMessagesOptions,\n PrivateMessageSendResult,\n PublishOptions,\n ReceivedPrivateMessage,\n SendPrivateMessageOptions,\n SubscribeOptions,\n SubscribePrivateMessagesOptions,\n SyncOptions,\n SyncSummary,\n} from \"./types.ts\";\n\n/** Layer-5 facade: signer + default relays + pool + loaders + gossip + event store. */\nexport class Client {\n readonly pool: Pool;\n readonly loaders: Loaders;\n readonly gossip: Gossip;\n readonly storage: EventStore;\n readonly index: ReactiveEventStore;\n onstorageerror: ((err: StorageError) => void) | undefined;\n #signer: NostrSigner | undefined;\n #relays: string[];\n #shutdown = false;\n readonly #persistEvents: boolean;\n readonly #persistQueue: Event[] = [];\n #flushing: Promise<void> | undefined;\n\n constructor(opts: ClientOptions = {}) {\n this.#signer = opts.signer;\n this.#relays = [];\n for (const raw of opts.relays ?? []) {\n const url = normalizeURL(raw);\n if (!this.#relays.includes(url)) {\n this.#relays.push(url);\n }\n }\n this.gossip = opts.gossip ?? new Gossip();\n this.storage = opts.storage ?? new MemoryEventStore();\n this.index = opts.index ?? new ReactiveEventStore();\n this.#persistEvents = opts.persistEvents ?? true;\n this.onstorageerror = opts.onstorageerror;\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 allowInsecure: opts.allowInsecure,\n trustedInsecureUrls: opts.trustedInsecureUrls,\n idleTimeoutMs: opts.idleTimeoutMs,\n maxRelays: opts.maxRelays,\n pinnedUrls: opts.pinnedUrls,\n // The sign function resolves the signer at challenge time, so\n // setSigner() takes effect on already-connected relays; challenges\n // without a signer are ignored by the relay (NoSignerError).\n automaticallyAuth:\n (opts.automaticAuth ?? true)\n ? () => async (template) => {\n const signer = this.#signer;\n if (!signer) {\n throw new NoSignerError(\"no signer configured for AUTH\");\n }\n const pk = await signer.getPublicKey();\n return signer.signEvent({ ...template, pubkey: pk });\n }\n : undefined,\n });\n this.loaders = createLoaders({\n pool: this.pool,\n relays: this.#relays,\n index: this.index,\n ingest: (event, relayUrl) => this.#ingest(event, relayUrl),\n });\n }\n\n static builder(): ClientBuilder {\n return new ClientBuilder((opts) => new Client(opts));\n }\n\n get signer(): NostrSigner | undefined {\n return this.#signer;\n }\n\n get relays(): ReadonlyArray<string> {\n return this.#relays;\n }\n\n get isShutdown(): boolean {\n return this.#shutdown;\n }\n\n setSigner(signer: NostrSigner | undefined): void {\n this.#signer = signer;\n // Re-arm relays whose AUTH challenge was ignored or rejected.\n this.pool.resetAuth();\n }\n\n addRelay(url: string): void {\n const normalized = normalizeURL(url);\n if (!this.#relays.includes(normalized)) {\n this.#relays.push(normalized);\n this.loaders.addRelay(normalized);\n }\n }\n\n removeRelay(url: string): void {\n const normalized = normalizeURL(url);\n this.#relays = this.#relays.filter((r) => r !== normalized);\n this.loaders.removeRelay(normalized);\n this.pool.close([normalized]);\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(async (url) => this.pool.ensureRelay(url, { signal: opts?.signal })),\n );\n }\n\n async shutdown(): Promise<void> {\n this.#shutdown = true;\n while (this.#flushing !== undefined) {\n // oxlint-disable-next-line no-await-in-loop -- waits for the current flush to settle before closing\n await this.#flushing;\n }\n this.pool.close();\n }\n\n #assertAlive(): void {\n if (this.#shutdown) {\n throw new ClientError(\"client is shut down\");\n }\n }\n\n #defaultRelays(urls?: string[]): string[] {\n const list = urls ?? this.#relays;\n if (list.length === 0) {\n throw new ClientError(\"no relays configured\");\n }\n return list;\n }\n\n #wantObserve(flag?: boolean): boolean {\n return flag !== false;\n }\n\n /** Ingest one inbound event: index (with relay URL) → meta → persistence. */\n observe(event: Event, relayUrl?: string): void {\n this.#ingest(event, relayUrl);\n }\n\n /** Ingest many events (deduped by id, order preserved) as one persist batch. */\n observeAll(events: ReadonlyArray<Event>): void {\n const seen = new Set<string>();\n for (const event of events) {\n if (seen.has(event.id)) {\n continue;\n }\n seen.add(event.id);\n this.#ingest(event);\n }\n }\n\n /**\n * The single inbound-event pipeline: reactive index add (with the source relay URL recorded in\n * seenOn), gossip routing meta, then the persistence decision. `persist: false` skips the storage\n * queue for callers that persist via their own awaited `putMany` (down-sync); `meta: false` is a\n * pure sighting/index add.\n */\n #ingest(event: Event, relayUrl?: string, opts?: { persist?: boolean; meta?: boolean }): void {\n this.index.add(event, relayUrl);\n if (opts?.meta !== false) {\n this.#ingestMeta(event);\n }\n if (opts?.persist === false || !this.#persistEvents) {\n return;\n }\n this.#persistQueue.push(event);\n this.#armFlush();\n }\n\n /** Record a relay sighting for an id already in the index. */\n #markSeen(id: string, relayUrl: string): void {\n this.index.markSeen(id, relayUrl);\n }\n\n #ingestMeta(event: Event): void {\n this.gossip.ingest(event);\n }\n\n #armFlush(): void {\n if (this.#flushing) {\n return;\n }\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 // oxlint-disable-next-line no-await-in-loop -- queued batches are persisted in order\n await this.storage.putMany(batch);\n } catch (error) {\n invokeSafely(() => this.onstorageerror?.(toStorageError(error)));\n }\n }\n } finally {\n this.#flushing = undefined;\n if (this.#persistQueue.length > 0) {\n this.#armFlush();\n }\n }\n }\n\n /**\n * Explicitly load kind:10002 and kind:10050 lists for pubkeys and feed gossip. Does not\n * background-fetch unknown authors on every subscribe (predictable DX).\n */\n async hydrateGossip(\n pubkeys: ReadonlyArray<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 === true ? \"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) {\n this.observe(relayList.event);\n }\n if (dmList.event) {\n this.observe(dmList.event);\n }\n }),\n );\n }\n\n /**\n * Create an outbox-model feed for the given authors (NIP-65 write relays). Live events go through\n * {@link observe}; sync persists via applySync.\n */\n outbox(opts: {\n authors: ReadonlyArray<string>;\n kinds?: ReadonlyArray<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, relayUrl) => this.observe(event, relayUrl),\n seen: (event, relayUrl) => this.#ingest(event, relayUrl, { persist: false, meta: false }),\n applySync: async (events) => {\n if (!this.#persistEvents) {\n for (const event of events) {\n this.#ingest(event, undefined, { persist: false });\n }\n return [];\n }\n const results = await this.storage.putMany(events);\n const applied: Event[] = [];\n for (const [i, event] of events.entries()) {\n const result = results[i];\n if (result === \"rejected\" || result === \"ephemeral\" || result === \"invalid\") {\n continue;\n }\n this.#ingest(event, undefined, { persist: false });\n applied.push(event);\n }\n return applied;\n },\n hydrate: async (pubkeys) => this.hydrateGossip(pubkeys),\n });\n }\n\n async getPublicKey(): Promise<string> {\n if (!this.#signer) {\n throw new ClientError(\"no signer configured\");\n }\n return this.#signer.getPublicKey();\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n if (!this.#signer) {\n throw new ClientError(\"no signer configured\");\n }\n return this.#signer.signEvent(unsigned);\n }\n\n async signEventBuilder(builder: EventBuilder): Promise<Event> {\n if (!this.#signer) {\n throw new ClientError(\"no signer configured\");\n }\n return builder.sign(this.#signer);\n }\n\n async signTemplate(template: EventTemplate): Promise<Event> {\n if (!this.#signer) {\n throw new ClientError(\"no signer configured\");\n }\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. With `gossip: true`, prefers the author's NIP-65\n * outbox relays, tagged `p` inboxes, and up to 5 `e`/`a` tag relay hints when known. On any\n * 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 === true) {\n const urls: string[] = [];\n const add = (list: ReadonlyArray<string>) => {\n for (const url of list) {\n if (!urls.includes(url)) {\n urls.push(url);\n }\n }\n };\n add(this.gossip.outboxRelays(event.pubkey));\n for (const tag of event.tags) {\n if (tag[0] === \"p\" && tag[1] !== undefined) {\n add(this.gossip.inboxRelays(tag[1]));\n }\n }\n let hintCount = 0;\n for (const tag of event.tags) {\n if (hintCount >= 5) {\n break;\n }\n if ((tag[0] !== \"e\" && tag[0] !== \"a\") || tag[2] === undefined) {\n continue;\n }\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) {\n relays = urls;\n }\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 === true);\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. With `localFirst:\n * 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 candidates: Event[] = [];\n\n if (opts?.localFirst === true) {\n // Persisted storage is merged with the index below; storage may hold a\n // stale replaceable version, so it is only a candidate — the index wins.\n try {\n const local = await this.storage.query(filters);\n for (const e of local) {\n candidates.push(e);\n if (shouldObserve) {\n this.#ingest(e, undefined, { persist: false, meta: false });\n }\n }\n } catch (error) {\n invokeSafely(() => this.onstorageerror?.(toStorageError(error)));\n }\n }\n\n // Every inbound event lands in the index (with its relay URL) before the\n // caller's onevent runs; the batch below re-ingests for persistence.\n const onevent = (event: Event, relayUrl: string) => {\n if (shouldObserve) {\n this.#ingest(event, relayUrl, { persist: false, meta: false });\n }\n opts?.onevent?.(event, relayUrl);\n };\n\n const batch =\n opts?.gossip !== true || opts.relays !== undefined\n ? await this.pool.fetch(this.#defaultRelays(opts?.relays), filters, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n onevent,\n })\n : await fetchGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n onevent,\n });\n for (const e of batch) {\n candidates.push(e);\n if (shouldObserve) {\n this.observe(e);\n }\n }\n\n // Merge through a scratch index so NIP-01 replaceable winners, kind-5\n // deletions, dedupe and per-filter limits all apply to the result.\n // Ephemeral kinds are never stored; matching ones join the result directly.\n const tmp = new MemoryIndex();\n const ephemeral = new Map<string, Event>();\n const merged =\n opts?.localFirst === true ? [...this.index.query(filters), ...candidates] : candidates;\n for (const e of merged) {\n if (tmp.put(e) === \"ephemeral\" && matchFilters(filters, e)) {\n ephemeral.set(e.id, e);\n }\n }\n return sortedEvents([...tmp.query(filters), ...ephemeral.values()]);\n }\n\n /** Query local storage only (no network). */\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, relayUrl: string) => {\n if (shouldObserve) {\n this.observe(event, relayUrl);\n }\n opts?.onevent?.(event, relayUrl);\n };\n\n const wrapReceived = (id: string, relayUrl: string) => {\n if (shouldObserve) {\n this.#markSeen(id, relayUrl);\n }\n opts?.receivedEvent?.(id, relayUrl);\n };\n\n if (opts?.gossip !== true || opts.relays !== undefined) {\n return this.pool.subscribe(this.#defaultRelays(opts?.relays), filters, {\n onevent: wrapEvent,\n receivedEvent: wrapReceived,\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 receivedEvent: wrapReceived,\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) {\n throw new ClientError(\"no signer configured\");\n }\n return requireNip59Crypto(this.#signer);\n }\n\n #throwIfAborted(signal?: AbortSignal): void {\n throwIfAborted(signal);\n }\n\n #dmDeps(): DmDeps {\n return {\n pool: this.pool,\n gossip: this.gossip,\n hydrateGossip: async (pubkeys) => this.hydrateGossip(pubkeys),\n ingest: (event, relayUrl) => this.#ingest(event, relayUrl),\n markSeen: (id, relayUrl) => this.#markSeen(id, relayUrl),\n assertAlive: () => this.#assertAlive(),\n requireNip59Crypto: () => this.#requireNip59Crypto(),\n throwIfAborted: (signal) => this.#throwIfAborted(signal),\n wantObserve: (flag) => this.#wantObserve(flag),\n publish: async (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 ingest: (event, relayUrl, opts) => this.#ingest(event, relayUrl, opts),\n markSeen: (id, relayUrl) => this.#markSeen(id, relayUrl),\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: ReadonlyArray<string>,\n opts?: PublishOptions,\n ): Promise<PoolPublishResult[]> {\n return setDmRelays(this.#dmDeps(), relays, opts);\n }\n\n async sendPrivateMessage(\n recipients: string | Recipient | ReadonlyArray<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 local-only events and/or\n * download remote-only events. `observe: false` skips putMany and ingest; received ids are still\n * listed. `persistEvents: false` skips putMany, still ingests 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). Independent sessions run in\n * parallel. Fulfilled summaries are merged; if every relay rejects, throws the first rejection in\n * URL order.\n */\n async sync(filter: Filter, opts?: SyncOptions): Promise<SyncSummary> {\n return sync(this.#syncDeps(), filter, opts);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAeA,IAAa,gBAAb,MAA2B;CACzB,QAAuB,CAAC;CACxB;CAEA,YAAY,WAA4C;EACtD,KAAK,aAAa;CACpB;CAEA,OAAO,QAA2B;EAChC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO;EAAO;EACrC,OAAO;CACT;CAEA,OAAO,MAAmC;EACxC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,QAAQ,CAAC,GAAG,IAAI;EAAE;EAChD,OAAO;CACT;CAEA,SAAS,KAAmB;EAC1B,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,QAAQ,CAAC,GAAI,KAAK,MAAM,UAAU,CAAC,GAAI,GAAG;EAAE;EAC1E,OAAO;CACT;CAEA,wBAAwB,MAAkC;EACxD,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,yBAAyB;EAAK;EAC5D,OAAO;CACT;CAEA,YAAY,IAAqC;EAC/C,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,aAAa;EAAG;EAC9C,OAAO;CACT;CAEA,iBAAiB,IAAkB;EACjC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,kBAAkB;EAAG;EACnD,OAAO;CACT;CAEA,iBAAiB,IAAkB;EACjC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,kBAAkB;EAAG;EACnD,OAAO;CACT;CAEA,cAAc,SAAwB;EACpC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,eAAe;EAAQ;EACrD,OAAO;CACT;;CAGA,cAAc,OAAsB;EAClC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,eAAe;EAAM;EACnD,OAAO;CACT;;CAGA,oBAAoB,MAAmC;EACrD,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,qBAAqB;EAAK;EACxD,OAAO;CACT;;CAGA,cAAc,IAAkB;EAC9B,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,eAAe;EAAG;EAChD,OAAO;CACT;;CAGA,UAAU,GAAiB;EACzB,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,WAAW;EAAE;EAC3C,OAAO;CACT;;CAGA,WAAW,MAAmC;EAC5C,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,YAAY;EAAK;EAC/C,OAAO;CACT;CAEA,gBAAgB,SAAwB;EACtC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,iBAAiB;EAAQ;EACvD,OAAO;CACT;CAEA,WAAW,SAAwB;EACjC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,YAAY;EAAQ;EAClD,OAAO;CACT;CAEA,eAAe,IAAkB;EAC/B,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,gBAAgB;EAAG;EACjD,OAAO;CACT;CAEA,cAAc,IAAkB;EAC9B,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,eAAe;EAAG;EAChD,OAAO;CACT;;;;;CAMA,QAAQ,OAAyB;EAC/B,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,SAAS;EAAM;EAC7C,OAAO;CACT;;;;;CAMA,MAAM,OAAiC;EACrC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO;EAAM;EACpC,OAAO;CACT;;CAGA,cAAc,SAAwB;EACpC,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,eAAe;EAAQ;EACrD,OAAO;CACT;CAEA,OAAO,QAAsB;EAC3B,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO;EAAO;EACrC,OAAO;CACT;CAEA,eAAe,IAAuC;EACpD,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,gBAAgB;EAAG;EACjD,OAAO;CACT;CAEA,QAAgB;EACd,OAAO,KAAK,WAAW,KAAK,KAAK;CACnC;AACF;;;AC5GA,SAAgB,eAAe,QAAgB,OAAwB;CACrE,MAAM,UAAoB,CAAC;CAC3B,KAAK,MAAM,OAAO,MAAM,MACtB,IAAI,IAAI,OAAO,OAAO,IAAI,OAAO,KAAA,KAAa,IAAI,OAAO,IACvD,QAAQ,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC;CAGrC,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,WAAW,kCAAkC;CAEzD,MAAM,CAAC,UAAU;CACjB,IAAI,QAAQ,WAAW,KAAK,WAAW,KAAA,GACrC,MAAM,IAAI,WAAW,iDAAiD;CAExE,MAAM,SAAS,OAAO,SAAS,MAAM;CACrC,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,WAAW,gEAAgE;CAEvF,OAAO;AACT;AAEA,eAAsB,YACpB,MACA,QACA,MAC8B;CAC9B,OAAO,KAAK,QAAQ,wBAAwB,MAAM,GAAG;EAAE,QAAQ;EAAM,GAAG;CAAK,CAAC;AAChF;AAEA,eAAsB,mBACpB,MACA,YACA,SACA,MACmC;CACnC,KAAK,YAAY;CACjB,MAAM,SAAS,KAAK,mBAAmB;CACvC,MAAM,SAAS,MAAM,OAAO,aAAa;CACzC,MAAM,OAAO,oBAAoB,UAAU;CAC3C,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,WAAW,8BAA8B;CAGrD,MAAM,0BAAU,IAAI,IAAY,CAAC,OAAO,YAAY,GAAG,GAAG,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;CACpF,MAAM,KAAK,cAAc,CAAC,GAAG,OAAO,CAAC;CACrC,KAAK,MAAM,MAAM,SACf,gBAAgB,IAAI,KAAK,OAAO,SAAS,EAAE,CAAC;CAG9C,MAAM,QAAQ,sBAAsB,QAAQ,MAAM,SAAS;EACzD,YAAY,MAAM;EAClB,SAAS,MAAM;EACf,SAAS,MAAM;CACjB,CAAC;CACD,MAAM,QAAQ,MAAM,kBAAkB,QAAQ,MAAM,KAAK;CAWzD,OAAO;EAAE;EAAO,OAAO,MAVJ,QAAQ,IACzB,MAAM,IAAI,OAAO,EAAE,WAAW,WAAW;GACvC,MAAM,SAAS,gBAAgB,WAAW,KAAK,OAAO,SAAS,SAAS,CAAC;GACzE,MAAM,UAAU,MAAM,KAAK,KAAK,QAAQ,QAAQ,MAAM,EAAE,WAAW,MAAM,UAAU,CAAC;GACpF,IAAI,QAAQ,MAAM,MAAM,EAAE,QAAQ,OAAO,IAAI,KAAK,KAAK,YAAY,MAAM,OAAO,GAC9E,KAAK,OAAO,IAAI;GAElB,OAAO;IAAE;IAAW;IAAM;GAAQ;EACpC,CAAC,CACH;CAC4B;AAC9B;AAEA,eAAsB,qBACpB,MACA,MACmC;CACnC,KAAK,YAAY;CACjB,MAAM,SAAS,KAAK,mBAAmB;CACvC,MAAM,OAAO,MAAM,OAAO,aAAa;CACvC,KAAK,eAAe,MAAM,MAAM;CAChC,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC;CAC/B,KAAK,eAAe,MAAM,MAAM;CAChC,MAAM,SAAS,gBAAgB,MAAM,KAAK,OAAO,SAAS,IAAI,CAAC;CAC/D,MAAM,uBAAO,IAAI,IAAyB;CAC1C,MAAM,SAAS,MAAM,KAAK,KAAK,MAC7B,QACA,CACE;EACE,OAAO,CAAC,KAAK,QAAQ;EACrB,MAAM,CAAC,IAAI;EACX,OAAO,MAAM;EACb,OAAO,MAAM;CACf,CACF,GACA;EACE,WAAW,MAAM;EACjB,QAAQ,MAAM;EACd,UAAU,OAAO,aAAa;GAC5B,IAAI,MAAM,KAAK,IAAI,MAAM,EAAE;GAC3B,IAAI,CAAC,KACH,KAAK,IAAI,MAAM,IAAK,sBAAM,IAAI,IAAI,CAAE;GAEtC,IAAI,IAAI,QAAQ;EAClB;CACF,CACF;CAEA,MAAM,0BAAU,IAAI,IAAoC;CACxD,KAAK,MAAM,QAAQ,QACjB,IAAI;EAEF,MAAM,QAAQ,MAAM,OAAO,QAAQ,IAAI;EACvC,MAAM,WAAW,KAAK,IAAI,KAAK,EAAE;EACjC,MAAM,WAAW,UAAU,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;EAC3C,IAAI,KAAK,YAAY,MAAM,OAAO,GAAG;GACnC,KAAK,OAAO,MAAM,QAAQ;GAE1B,IAAI,UACG;SAAA,MAAM,OAAO,UAChB,IAAI,QAAQ,UACV,KAAK,SAAS,KAAK,IAAI,GAAG;GAAA;EAIlC;EACA,QAAQ,IAAI,MAAM,IAAI;GACpB;GACA;GACA,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,SAAS;EACzD,CAAC;CACH,QAAQ,CAER;CAGF,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC;AAC3E;AAEA,eAAsB,yBACpB,MACA,MAC+C;CAC/C,KAAK,YAAY;CACjB,MAAM,SAAS,KAAK,mBAAmB;CACvC,MAAM,OAAO,MAAM,OAAO,aAAa;CACvC,KAAK,eAAe,MAAM,MAAM;CAChC,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC;CAC/B,KAAK,eAAe,MAAM,MAAM;CAChC,MAAM,SAAS,gBAAgB,MAAM,KAAK,OAAO,SAAS,IAAI,CAAC;CAE/D,MAAM,uBAAO,IAAI,IAAY;CAG7B,MAAM,4BAAY,IAAI,IAAY;CAClC,MAAM,8BAAc,IAAI,IAAsB;CAC9C,MAAM,aAAa,WAAyB;EAC1C,UAAU,IAAI,MAAM;EACpB,MAAM,QAAQ,YAAY,IAAI,MAAM;EACpC,IAAI,UAAU,KAAA,GACZ;EAEF,YAAY,OAAO,MAAM;EACzB,KAAK,MAAM,OAAO,OAChB,KAAK,SAAS,QAAQ,GAAG;CAE7B;CACA,IAAI,OAAO,QAAQ,QAAQ;CAC3B,IAAI,SAAS;CACb,MAAM,mBAAyB;EAC7B,SAAS;CACX;CACA,IAAI,MAAM,QAAQ,YAAY,MAC5B,WAAW;MAEX,MAAM,QAAQ,iBAAiB,SAAS,YAAY,EAAE,MAAM,KAAK,CAAC;CAGpE,MAAM,QAAQ,KAAK,KAAK,UACtB,QAEA,CAAC;EAAE,OAAO,CAAC,KAAK,UAAU,KAAK,iBAAiB;EAAG,MAAM,CAAC,IAAI;EAAG,OAAO,MAAM;CAAM,CAAC,GACrF;EACE,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,UAAU,WAAW;GACnB,WAAW;GACX,MAAM,UAAU,MAAM;EACxB;EACA,eAAe,MAAM;EACrB,gBAAgB,IAAI,aAAa;GAC/B,IAAI,QACF;GAEF,IAAI,UAAU,IAAI,EAAE,GAAG;IACrB,KAAK,SAAS,IAAI,QAAQ;IAC1B;GACF;GACA,MAAM,OAAO,YAAY,IAAI,EAAE;GAC/B,IAAI,SAAS,KAAA,GACX,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,SAAS,QAAQ,GAChC,KAAK,KAAK,QAAQ;EAEtB;EACA,UAAU,MAAM,aAAa;GAC3B,IAAI,QACF;GAEF,MAAM,OAAO;GACb,IAAI;GACJ,OAAO,IAAI,SAAe,YAAY;IACpC,UAAU;GACZ,CAAC;GACD,CAAM,YAAY;IAChB,MAAM;IACN,IAAI;KACF,IAAI,QACF;KAEF,MAAM,QAAQ,MAAM,OAAO,QAAQ,IAAI;KACvC,IAAI,QACF;KAEF,IAAI,KAAK,IAAI,MAAM,EAAE,GAAG;MACtB,UAAU,KAAK,EAAE;MACjB;KACF;KACA,KAAK,IAAI,MAAM,EAAE;KACjB,IAAI,KAAK,YAAY,MAAM,OAAO,GAChC,KAAK,OAAO,MAAM,QAAQ;KAE5B,UAAU,KAAK,EAAE;KACjB,MAAM,UAAU;MAAE;MAAM;MAAO;KAAS,CAAC;IAC3C,QAAQ,CAER,UAAU;KACR,UAAU;IACZ;GACF,EAAA,CAAG;EACL;CACF,CACF;CAEA,OAAO,EACL,QAAQ,WAAoB;EAC1B,WAAW;EACX,MAAM,MAAM,MAAM;CACpB,EACF;AACF;;;;AClRA,MAAa,gBAAgB;CAC3B,IAAI;CACJ,MAAM;CACN,MAAM;AACR;;AAqLA,IAAa,cAAb,cAAiC,WAAW;CAC1C,OAAgB;AAClB;;;;AC/LA,SAAgB,eACd,QACA,SACA,eACa;CACb,MAAM,SAAS,QAAQ,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC;CAEjD,MAAM,WADgB,OAAO,MAAM,MAAM,EAAE,cAAc,KAAA,CAC5B,IAAI,cAAc,IAAI,KAAA;CACnD,MAAM,OAAoB,CAAC;CAC3B,KAAK,MAAM,KAAK,QAAQ;EACtB,KAAK,MAAM,CAAC,KAAK,QAAQ,EAAE,UACzB,KAAK,KAAK;GAAE,MAAM,CAAC,GAAG;GAAG,SAAS,CAAC,GAAG;EAAE,CAAC;EAE3C,IAAI,EAAE,cAAc,KAAA,GAAW;GAC7B,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,YAAY,2CAA2C;GAEnE,KAAK,KAAK;IAAE,MAAM;IAAU,SAAS,CAAC,EAAE,SAAS;GAAE,CAAC;EACtD;CACF;CACA,OAAO;AACT;AAEA,eAAsB,YACpB,MACA,QACA,SACA,eACA,MAKkB;CAClB,OAAO,YAAY,MAAM,eAAe,QAAQ,SAAS,aAAa,GAAG;EACvE,WAAW,MAAM;EACjB,QAAQ,MAAM;EACd,SAAS,MAAM;CACjB,CAAC;AACH;AAEA,SAAgB,gBACd,MACA,QACA,SACA,eACA,MACsC;CACtC,MAAM,OAAO,eAAe,QAAQ,SAAS,aAAa;CAC1D,IAAI,KAAK,WAAW,GAAG;EACrB,qBAAqB,KAAK,SAAS,CAAC;EACpC,OAAO,EACL,aAAa,CAEb,EACF;CACF;CACA,OAAO,MAAM,MAAM,MAAM,IAAI;AAC/B;;;ACxCA,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAEhC,SAAS,UAAU,KAAsC;CACvD,OAAO,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC;AACzB;AAEA,SAAS,eAA4B;CACnC,OAAO;EACL,OAAO,CAAC;EACR,QAAQ,CAAC;EACT,MAAM,CAAC;EACP,UAAU,CAAC;EACX,cAAc,CAAC;EACf,iBAAiB,CAAC;CACpB;AACF;AAEA,SAAS,iBAAiB,MAAmB,OAAiC;CAC5E,MAAM,eAAe;EAAE,GAAG,KAAK;EAAc,GAAG,MAAM;CAAa;CACnE,MAAM,kBAAkB;EAAE,GAAG,KAAK;EAAiB,GAAG,MAAM;CAAgB;CAC5E,OAAO;EACL,OAAO,UAAU,CAAC,GAAG,KAAK,OAAO,GAAG,MAAM,KAAK,CAAC;EAChD,QAAQ,UAAU,CAAC,GAAG,KAAK,QAAQ,GAAG,MAAM,MAAM,CAAC;EACnD,MAAM,UAAU,CAAC,GAAG,KAAK,MAAM,GAAG,MAAM,IAAI,CAAC;EAC7C,UAAU,UAAU,CAAC,GAAG,KAAK,UAAU,GAAG,MAAM,QAAQ,CAAC;EACzD;EACA;CACF;AACF;;;;;;AAOA,eAAsB,YACpB,MACA,KACA,QACA,MACsB;CACtB,KAAK,YAAY;CACjB,KAAK,eAAe,MAAM,MAAM;CAChC,MAAM,YAAY,MAAM,aAAa,cAAc;CACnD,MAAM,QAAQ,mBAAmB,MAAM;CACvC,MAAM,QAAQ,MAAM,KAAK,QAAQ,gBAAgB,KAAK;CACtD,MAAM,UAAmC,iBAAiB,KAAK;CAE/D,MAAM,EAAE,MAAM,SAAS,OAAM,MADT,KAAK,KAAK,YAAY,KAAK,EAAE,QAAQ,MAAM,OAAO,CAAC,EAAA,CACpC,aAAa,OAAO,SAAS;EAC9D,WAAW,MAAM;EACjB,QAAQ,MAAM;CAChB,CAAC;CAED,MAAM,UAAuB;EAC3B,OAAO;EACP,QAAQ;EACR,MAAM,CAAC;EACP,UAAU,CAAC;EACX,cAAc,CAAC;EACf,iBAAiB,CAAC;CACpB;CAEA,IAAI,MAAM,WAAW,MACnB,OAAO;CAGT,KAAK,cAAc,cAAc,MAAM,cAAc,cAAc,SAAS,KAAK,SAAS,GAAG;EAC3F,MAAM,QAAQ,MAAM,KAAK,QAAQ,MAAM,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;EACtD,MAAM,YAAY,IAAI,IAAI,MAAM,KAAK,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;EACjE,KAAK,MAAM,MAAM,MACf,IAAI,CAAC,UAAU,IAAI,EAAE,GACnB,QAAQ,aAAa,MAAM;EAG/B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,yBAAyB;GAC9D,MAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,uBAAuB;GAGxD,MAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,UAAU;IACzB,IAAI;KACF,MAAM,UAAU,MAAM,KAAK,KAAK,QAAQ,CAAC,GAAG,GAAG,OAAO,EACpD,WAAW,MAAM,UACnB,CAAC;KAED,IADW,QAAQ,MAAM,MAAM,EAAE,QAAQ,OAAO,IAC3C,GACH,QAAQ,KAAK,KAAK,MAAM,EAAE;UAE1B,QAAQ,aAAa,MAAM,MACzB,QAAQ,EAAE,EAAE,SAAS,QAAQ,EAAE,EAAE,QAAQ,WAAW;IAE1D,SAAS,OAAO;KACd,QAAQ,aAAa,MAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IACxF;GACF,CAAC,CACH;EACF;CACF;CAEA,KAAK,cAAc,cAAc,QAAQ,cAAc,cAAc,SAAS,KAAK,SAAS,GAAG;EAC7F,MAAM,gBAAgB,KAAK,YAAY,MAAM,OAAO;EACpD,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,eAAe;GACnD,MAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,aAAa;GAC7C,KAAK,eAAe,MAAM,MAAM;GAEhC,MAAM,2BAAW,IAAI,IAAsB;GAG3C,MAAM,SAAS,MAAM,KAAK,KAAK,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,GAAG;IAC5D,WAAW,MAAM;IACjB,QAAQ,MAAM;IACd,SAAS,iBACJ,OAAO,aAAa;KACnB,MAAM,OAAO,SAAS,IAAI,MAAM,EAAE;KAClC,IAAI,SAAS,KAAA,GACX,SAAS,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC;UAC5B,IAAI,CAAC,KAAK,SAAS,QAAQ,GAChC,KAAK,KAAK,QAAQ;IAEtB,IACA,KAAA;GACN,CAAC;GACD,IAAI,CAAC,eAAe;IAClB,KAAK,MAAM,SAAS,QAClB,QAAQ,SAAS,KAAK,MAAM,EAAE;IAEhC;GACF;GACA,MAAM,aAAa,UAAuB;IACxC,MAAM,OAAO,SAAS,IAAI,MAAM,EAAE,KAAK,CAAC;IACxC,KAAK,OAAO,OAAO,KAAK,IAAI,EAAE,SAAS,MAAM,CAAC;IAC9C,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC,GAC5B,KAAK,SAAS,MAAM,IAAI,GAAG;GAE/B;GACA,IAAI,CAAC,KAAK,eAAe;IACvB,KAAK,MAAM,SAAS,QAAQ;KAC1B,UAAU,KAAK;KACf,QAAQ,SAAS,KAAK,MAAM,EAAE;IAChC;IACA;GACF;GAGA,IAAI;GACJ,IAAI;IAGF,UAAU,MAAM,KAAK,QAAQ,QAAQ,MAAM;GAC7C,SAAS,OAAO;IACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IACrE,KAAK,MAAM,SAAS,QAClB,QAAQ,gBAAgB,MAAM,MAAM;IAEtC;GACF;GACA,KAAK,MAAM,CAAC,GAAG,UAAU,OAAO,QAAQ,GAAG;IACzC,IAAI,QAAQ,OAAO,cAAc,QAAQ,OAAO,WAC9C;IAEF,UAAU,KAAK;IACf,QAAQ,SAAS,KAAK,MAAM,EAAE;GAChC;EACF;CACF;CAEA,OAAO;AACT;;;;;;AAOA,eAAsB,KACpB,MACA,QACA,MACsB;CACtB,KAAK,YAAY;CACjB,MAAM,OAAO,KAAK,cAAc,MAAM,SAAS,CAAC,GAAG,KAAK,MAAM,IAAI,KAAA,CAAS;CAC3E,MAAM,UAAU,MAAM,QAAQ,WAC5B,KAAK,IAAI,OAAO,QAAQ,YAAY,MAAM,KAAK,QAAQ,IAAI,CAAC,CAC9D;CACA,IAAI,SAAS,aAAa;CAC1B,IAAI,YAAY;CAChB,IAAI;CACJ,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,WAAW,aAAa;EACjC,aAAa;EACb,SAAS,iBAAiB,QAAQ,OAAO,KAAK;CAChD,OACE,mBAAmB,OAAO;CAG9B,IAAI,KAAK,SAAS,KAAK,cAAc,GACnC,MAAM;CAER,OAAO;AACT;;;;AC/KA,IAAa,SAAb,MAAa,OAAO;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,YAAY;CACZ;CACA,gBAAkC,CAAC;CACnC;CAEA,YAAY,OAAsB,CAAC,GAAG;EACpC,KAAK,UAAU,KAAK;EACpB,KAAK,UAAU,CAAC;EAChB,KAAK,MAAM,OAAO,KAAK,UAAU,CAAC,GAAG;GACnC,MAAM,MAAM,aAAa,GAAG;GAC5B,IAAI,CAAC,KAAK,QAAQ,SAAS,GAAG,GAC5B,KAAK,QAAQ,KAAK,GAAG;EAEzB;EACA,KAAK,SAAS,KAAK,UAAU,IAAI,OAAO;EACxC,KAAK,UAAU,KAAK,WAAW,IAAI,iBAAiB;EACpD,KAAK,QAAQ,KAAK,SAAS,IAAI,mBAAmB;EAClD,KAAK,iBAAiB,KAAK,iBAAiB;EAC5C,KAAK,iBAAiB,KAAK;EAC3B,KAAK,OAAO,IAAI,KAAK;GACnB,yBAAyB,KAAK;GAC9B,aAAa,KAAK;GAClB,YAAY,KAAK;GACjB,gBAAgB,KAAK;GACrB,eAAe,KAAK;GACpB,kBAAkB,KAAK;GACvB,kBAAkB,KAAK;GACvB,iBAAiB,KAAK,mBAAmB;GACzC,eAAe,KAAK;GACpB,qBAAqB,KAAK;GAC1B,eAAe,KAAK;GACpB,WAAW,KAAK;GAChB,YAAY,KAAK;GAIjB,mBACG,KAAK,iBAAiB,aACb,OAAO,aAAa;IACxB,MAAM,SAAS,KAAK;IACpB,IAAI,CAAC,QACH,MAAM,IAAI,cAAc,+BAA+B;IAEzD,MAAM,KAAK,MAAM,OAAO,aAAa;IACrC,OAAO,OAAO,UAAU;KAAE,GAAG;KAAU,QAAQ;IAAG,CAAC;GACrD,IACA,KAAA;EACR,CAAC;EACD,KAAK,UAAU,cAAc;GAC3B,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,OAAO,KAAK;GACZ,SAAS,OAAO,aAAa,KAAK,QAAQ,OAAO,QAAQ;EAC3D,CAAC;CACH;CAEA,OAAO,UAAyB;EAC9B,OAAO,IAAI,eAAe,SAAS,IAAI,OAAO,IAAI,CAAC;CACrD;CAEA,IAAI,SAAkC;EACpC,OAAO,KAAK;CACd;CAEA,IAAI,SAAgC;EAClC,OAAO,KAAK;CACd;CAEA,IAAI,aAAsB;EACxB,OAAO,KAAK;CACd;CAEA,UAAU,QAAuC;EAC/C,KAAK,UAAU;EAEf,KAAK,KAAK,UAAU;CACtB;CAEA,SAAS,KAAmB;EAC1B,MAAM,aAAa,aAAa,GAAG;EACnC,IAAI,CAAC,KAAK,QAAQ,SAAS,UAAU,GAAG;GACtC,KAAK,QAAQ,KAAK,UAAU;GAC5B,KAAK,QAAQ,SAAS,UAAU;EAClC;CACF;CAEA,YAAY,KAAmB;EAC7B,MAAM,aAAa,aAAa,GAAG;EACnC,KAAK,UAAU,KAAK,QAAQ,QAAQ,MAAM,MAAM,UAAU;EAC1D,KAAK,QAAQ,YAAY,UAAU;EACnC,KAAK,KAAK,MAAM,CAAC,UAAU,CAAC;CAC9B;;CAGA,MAAM,QAAQ,MAAgD;EAC5D,KAAK,aAAa;EAClB,MAAM,QAAQ,WACZ,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,KAAK,YAAY,KAAK,EAAE,QAAQ,MAAM,OAAO,CAAC,CAAC,CACtF;CACF;CAEA,MAAM,WAA0B;EAC9B,KAAK,YAAY;EACjB,OAAO,KAAK,cAAc,KAAA,GAExB,MAAM,KAAK;EAEb,KAAK,KAAK,MAAM;CAClB;CAEA,eAAqB;EACnB,IAAI,KAAK,WACP,MAAM,IAAI,YAAY,qBAAqB;CAE/C;CAEA,eAAe,MAA2B;EACxC,MAAM,OAAO,QAAQ,KAAK;EAC1B,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,YAAY,sBAAsB;EAE9C,OAAO;CACT;CAEA,aAAa,MAAyB;EACpC,OAAO,SAAS;CAClB;;CAGA,QAAQ,OAAc,UAAyB;EAC7C,KAAK,QAAQ,OAAO,QAAQ;CAC9B;;CAGA,WAAW,QAAoC;EAC7C,MAAM,uBAAO,IAAI,IAAY;EAC7B,KAAK,MAAM,SAAS,QAAQ;GAC1B,IAAI,KAAK,IAAI,MAAM,EAAE,GACnB;GAEF,KAAK,IAAI,MAAM,EAAE;GACjB,KAAK,QAAQ,KAAK;EACpB;CACF;;;;;;;CAQA,QAAQ,OAAc,UAAmB,MAAoD;EAC3F,KAAK,MAAM,IAAI,OAAO,QAAQ;EAC9B,IAAI,MAAM,SAAS,OACjB,KAAK,YAAY,KAAK;EAExB,IAAI,MAAM,YAAY,SAAS,CAAC,KAAK,gBACnC;EAEF,KAAK,cAAc,KAAK,KAAK;EAC7B,KAAK,UAAU;CACjB;;CAGA,UAAU,IAAY,UAAwB;EAC5C,KAAK,MAAM,SAAS,IAAI,QAAQ;CAClC;CAEA,YAAY,OAAoB;EAC9B,KAAK,OAAO,OAAO,KAAK;CAC1B;CAEA,YAAkB;EAChB,IAAI,KAAK,WACP;EAEF,KAAK,YAAY,KAAK,WAAW;CACnC;CAEA,MAAM,aAA4B;EAChC,IAAI;GACF,MAAM,IAAI,SAAe,YAAY;IACnC,eAAe,OAAO;GACxB,CAAC;GACD,OAAO,KAAK,cAAc,SAAS,GAAG;IACpC,MAAM,QAAQ,KAAK,cAAc,OAAO,CAAC;IACzC,IAAI;KAEF,MAAM,KAAK,QAAQ,QAAQ,KAAK;IAClC,SAAS,OAAO;KACd,mBAAmB,KAAK,iBAAiB,eAAe,KAAK,CAAC,CAAC;IACjE;GACF;EACF,UAAU;GACR,KAAK,YAAY,KAAA;GACjB,IAAI,KAAK,cAAc,SAAS,GAC9B,KAAK,UAAU;EAEnB;CACF;;;;;CAMA,MAAM,cACJ,SACA,MACe;EACf,KAAK,aAAa;EAClB,MAAM,QAAQ,IACZ,QAAQ,IAAI,OAAO,OAAO;GACxB,MAAM,QAAQ,MAAM,UAAU,OAAO,UAAU;GAC/C,MAAM,CAAC,WAAW,UAAU,MAAM,QAAQ,IAAI,CAC5C,KAAK,QAAQ,UAAU,IAAI;IAAE,OAAO,MAAM;IAAO;GAAM,CAAC,GACxD,KAAK,QAAQ,YAAY,IAAI;IAAE,OAAO,MAAM;IAAO;GAAM,CAAC,CAC5D,CAAC;GACD,IAAI,UAAU,OACZ,KAAK,QAAQ,UAAU,KAAK;GAE9B,IAAI,OAAO,OACT,KAAK,QAAQ,OAAO,KAAK;EAE7B,CAAC,CACH;CACF;;;;;CAMA,OAAO,MAKQ;EACb,KAAK,aAAa;EAClB,OAAO,iBAAiB;GACtB,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,SAAS,KAAK;GACd,iBAAiB,KAAK;GACtB,SAAS,KAAK;GACd,OAAO,KAAK;GACZ,SAAS,KAAK;GACd,oBAAoB,KAAK;GACzB,UAAU,OAAO,aAAa,KAAK,QAAQ,OAAO,QAAQ;GAC1D,OAAO,OAAO,aAAa,KAAK,QAAQ,OAAO,UAAU;IAAE,SAAS;IAAO,MAAM;GAAM,CAAC;GACxF,WAAW,OAAO,WAAW;IAC3B,IAAI,CAAC,KAAK,gBAAgB;KACxB,KAAK,MAAM,SAAS,QAClB,KAAK,QAAQ,OAAO,KAAA,GAAW,EAAE,SAAS,MAAM,CAAC;KAEnD,OAAO,CAAC;IACV;IACA,MAAM,UAAU,MAAM,KAAK,QAAQ,QAAQ,MAAM;IACjD,MAAM,UAAmB,CAAC;IAC1B,KAAK,MAAM,CAAC,GAAG,UAAU,OAAO,QAAQ,GAAG;KACzC,MAAM,SAAS,QAAQ;KACvB,IAAI,WAAW,cAAc,WAAW,eAAe,WAAW,WAChE;KAEF,KAAK,QAAQ,OAAO,KAAA,GAAW,EAAE,SAAS,MAAM,CAAC;KACjD,QAAQ,KAAK,KAAK;IACpB;IACA,OAAO;GACT;GACA,SAAS,OAAO,YAAY,KAAK,cAAc,OAAO;EACxD,CAAC;CACH;CAEA,MAAM,eAAgC;EACpC,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,YAAY,sBAAsB;EAE9C,OAAO,KAAK,QAAQ,aAAa;CACnC;CAEA,MAAM,UAAU,UAAyC;EACvD,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,YAAY,sBAAsB;EAE9C,OAAO,KAAK,QAAQ,UAAU,QAAQ;CACxC;CAEA,MAAM,iBAAiB,SAAuC;EAC5D,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,YAAY,sBAAsB;EAE9C,OAAO,QAAQ,KAAK,KAAK,OAAO;CAClC;CAEA,MAAM,aAAa,UAAyC;EAC1D,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,YAAY,sBAAsB;EAE9C,MAAM,SAAS,MAAM,KAAK,QAAQ,aAAa;EAC/C,OAAO,KAAK,QAAQ,UAAU;GAAE,GAAG;GAAU;EAAO,CAAC;CACvD;;;;;;CAOA,MAAM,QACJ,gBACA,MAC8B;EAC9B,KAAK,aAAa;EAClB,MAAM,QACJ,0BAA0B,eACtB,MAAM,KAAK,iBAAiB,cAAc,IAC1C;EAEN,IAAI,SAAS,MAAM;EACnB,IAAI,CAAC,UAAU,eAAe,MAAM,IAAI,GACtC,SAAS,eAAe,KAAK,QAAQ,KAAK;OACrC,IAAI,CAAC,UAAU,MAAM,WAAW,MAAM;GAC3C,MAAM,OAAiB,CAAC;GACxB,MAAM,OAAO,SAAgC;IAC3C,KAAK,MAAM,OAAO,MAChB,IAAI,CAAC,KAAK,SAAS,GAAG,GACpB,KAAK,KAAK,GAAG;GAGnB;GACA,IAAI,KAAK,OAAO,aAAa,MAAM,MAAM,CAAC;GAC1C,KAAK,MAAM,OAAO,MAAM,MACtB,IAAI,IAAI,OAAO,OAAO,IAAI,OAAO,KAAA,GAC/B,IAAI,KAAK,OAAO,YAAY,IAAI,EAAE,CAAC;GAGvC,IAAI,YAAY;GAChB,KAAK,MAAM,OAAO,MAAM,MAAM;IAC5B,IAAI,aAAa,GACf;IAEF,IAAK,IAAI,OAAO,OAAO,IAAI,OAAO,OAAQ,IAAI,OAAO,KAAA,GACnD;IAEF,IAAI;KACF,MAAM,MAAM,aAAa,IAAI,EAAE;KAC/B,IAAI,CAAC,KAAK,SAAS,GAAG,GAAG;MACvB,KAAK,KAAK,GAAG;MACb,aAAa;KACf;IACF,QAAQ,CAER;GACF;GACA,IAAI,KAAK,SAAS,GAChB,SAAS;EAEb;EACA,MAAM,UAAU,MAAM,KAAK,KAAK,QAAQ,KAAK,eAAe,MAAM,GAAG,OAAO,EAC1E,WAAW,MAAM,UACnB,CAAC;EAGD,IADc,QAAQ,MAAM,MAAM,EAAE,QAAQ,OAAO,IAC3C,KAAK,KAAK,aAAa,MAAM,OAAO,GAC1C,KAAK,QAAQ,KAAK;EAEpB,OAAO;CACT;;;;;CAMA,MAAM,YAAY,QAA2B,MAA6C;EACxF,KAAK,aAAa;EAClB,MAAM,UAAU,oBAAoB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC;EAC7E,MAAM,gBAAgB,KAAK,aAAa,MAAM,OAAO;EACrD,MAAM,aAAsB,CAAC;EAE7B,IAAI,MAAM,eAAe,MAGvB,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,QAAQ,MAAM,OAAO;GAC9C,KAAK,MAAM,KAAK,OAAO;IACrB,WAAW,KAAK,CAAC;IACjB,IAAI,eACF,KAAK,QAAQ,GAAG,KAAA,GAAW;KAAE,SAAS;KAAO,MAAM;IAAM,CAAC;GAE9D;EACF,SAAS,OAAO;GACd,mBAAmB,KAAK,iBAAiB,eAAe,KAAK,CAAC,CAAC;EACjE;EAKF,MAAM,WAAW,OAAc,aAAqB;GAClD,IAAI,eACF,KAAK,QAAQ,OAAO,UAAU;IAAE,SAAS;IAAO,MAAM;GAAM,CAAC;GAE/D,MAAM,UAAU,OAAO,QAAQ;EACjC;EAEA,MAAM,QACJ,MAAM,WAAW,QAAQ,KAAK,WAAW,KAAA,IACrC,MAAM,KAAK,KAAK,MAAM,KAAK,eAAe,MAAM,MAAM,GAAG,SAAS;GAChE,WAAW,MAAM;GACjB,QAAQ,MAAM;GACd;EACF,CAAC,IACD,MAAM,YAAY,KAAK,MAAM,KAAK,QAAQ,eAAe,KAAK,eAAe,GAAG;GAC9E,WAAW,MAAM;GACjB,QAAQ,MAAM;GACd;EACF,CAAC;EACP,KAAK,MAAM,KAAK,OAAO;GACrB,WAAW,KAAK,CAAC;GACjB,IAAI,eACF,KAAK,QAAQ,CAAC;EAElB;EAKA,MAAM,MAAM,IAAI,YAAY;EAC5B,MAAM,4BAAY,IAAI,IAAmB;EACzC,MAAM,SACJ,MAAM,eAAe,OAAO,CAAC,GAAG,KAAK,MAAM,MAAM,OAAO,GAAG,GAAG,UAAU,IAAI;EAC9E,KAAK,MAAM,KAAK,QACd,IAAI,IAAI,IAAI,CAAC,MAAM,eAAe,aAAa,SAAS,CAAC,GACvD,UAAU,IAAI,EAAE,IAAI,CAAC;EAGzB,OAAO,aAAa,CAAC,GAAG,IAAI,MAAM,OAAO,GAAG,GAAG,UAAU,OAAO,CAAC,CAAC;CACpE;;CAGA,MAAM,WAAW,QAA6C;EAC5D,KAAK,aAAa;EAClB,MAAM,UAAU,oBAAoB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC;EAC7E,OAAO,KAAK,QAAQ,MAAM,OAAO;CACnC;CAEA,UACE,QACA,MACsC;EACtC,KAAK,aAAa;EAClB,MAAM,UAAU,oBAAoB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC;EAC7E,MAAM,gBAAgB,KAAK,aAAa,MAAM,OAAO;EAErD,MAAM,aAAa,OAAc,aAAqB;GACpD,IAAI,eACF,KAAK,QAAQ,OAAO,QAAQ;GAE9B,MAAM,UAAU,OAAO,QAAQ;EACjC;EAEA,MAAM,gBAAgB,IAAY,aAAqB;GACrD,IAAI,eACF,KAAK,UAAU,IAAI,QAAQ;GAE7B,MAAM,gBAAgB,IAAI,QAAQ;EACpC;EAEA,IAAI,MAAM,WAAW,QAAQ,KAAK,WAAW,KAAA,GAC3C,OAAO,KAAK,KAAK,UAAU,KAAK,eAAe,MAAM,MAAM,GAAG,SAAS;GACrE,SAAS;GACT,eAAe;GACf,QAAQ,MAAM;GACd,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,IAAI,MAAM;GACV,eAAe,MAAM;EACvB,CAAC;EAGH,OAAO,gBAAgB,KAAK,MAAM,KAAK,QAAQ,eAAe,KAAK,eAAe,GAAG;GACnF,SAAS;GACT,eAAe;GACf,QAAQ,MAAM;GACd,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,eAAe,MAAM;EACvB,CAAC;CACH;CAEA,sBAAmC;EACjC,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,YAAY,sBAAsB;EAE9C,OAAO,mBAAmB,KAAK,OAAO;CACxC;CAEA,gBAAgB,QAA4B;EAC1C,eAAe,MAAM;CACvB;CAEA,UAAkB;EAChB,OAAO;GACL,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,eAAe,OAAO,YAAY,KAAK,cAAc,OAAO;GAC5D,SAAS,OAAO,aAAa,KAAK,QAAQ,OAAO,QAAQ;GACzD,WAAW,IAAI,aAAa,KAAK,UAAU,IAAI,QAAQ;GACvD,mBAAmB,KAAK,aAAa;GACrC,0BAA0B,KAAK,oBAAoB;GACnD,iBAAiB,WAAW,KAAK,gBAAgB,MAAM;GACvD,cAAc,SAAS,KAAK,aAAa,IAAI;GAC7C,SAAS,OAAO,gBAAgB,SAAS,KAAK,QAAQ,gBAAgB,IAAI;EAC5E;CACF;CAEA,YAAsB;EACpB,OAAO;GACL,MAAM,KAAK;GACX,SAAS,KAAK;GACd,eAAe,KAAK;GACpB,mBAAmB,KAAK,aAAa;GACrC,iBAAiB,WAAW,KAAK,gBAAgB,MAAM;GACvD,cAAc,SAAS,KAAK,aAAa,IAAI;GAC7C,SAAS,OAAO,UAAU,SAAS,KAAK,QAAQ,OAAO,UAAU,IAAI;GACrE,WAAW,IAAI,aAAa,KAAK,UAAU,IAAI,QAAQ;GACvD,gBAAgB,SAAS,KAAK,eAAe,IAAI;EACnD;CACF;;CAGA,MAAM,YACJ,QACA,MAC8B;EAC9B,OAAO,YAAY,KAAK,QAAQ,GAAG,QAAQ,IAAI;CACjD;CAEA,MAAM,mBACJ,YACA,SACA,MACmC;EACnC,OAAO,mBAAmB,KAAK,QAAQ,GAAG,YAAY,SAAS,IAAI;CACrE;CAEA,MAAM,qBACJ,MACmC;EACnC,OAAO,qBAAqB,KAAK,QAAQ,GAAG,IAAI;CAClD;CAEA,MAAM,yBACJ,MAC+C;EAC/C,OAAO,yBAAyB,KAAK,QAAQ,GAAG,IAAI;CACtD;;;;;;CAOA,MAAM,YACJ,KACA,QACA,MACsB;EACtB,OAAO,YAAY,KAAK,UAAU,GAAG,KAAK,QAAQ,IAAI;CACxD;;;;;;CAOA,MAAM,KAAK,QAAgB,MAA0C;EACnE,OAAO,KAAK,KAAK,UAAU,GAAG,QAAQ,IAAI;CAC5C;AACF"}
|
package/dist/client.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as FetchEventsOptions, c as PublishOptions, d as SubscribeOptions, f as SubscribePrivateMessagesOptions, g as SyncSummary, h as SyncOptions, i as ClientOptions, l as ReceivedPrivateMessage, m as SyncDirectionName, n as ClientBuilder, o as FetchPrivateMessagesOptions, p as SyncDirection, r as ClientError, s as PrivateMessageSendResult, t as Client, u as SendPrivateMessageOptions } from "./index-B425CAcQ.mjs";
|
|
2
2
|
export { Client, ClientBuilder, ClientError, type ClientOptions, type FetchEventsOptions, type FetchPrivateMessagesOptions, type PrivateMessageSendResult, type PublishOptions, type ReceivedPrivateMessage, type SendPrivateMessageOptions, type SubscribeOptions, type SubscribePrivateMessagesOptions, SyncDirection, type SyncDirectionName, type SyncOptions, type SyncSummary };
|
package/dist/client.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as ClientBuilder, n as ClientError, r as SyncDirection, t as Client } from "./client-
|
|
1
|
+
import { i as ClientBuilder, n as ClientError, r as SyncDirection, t as Client } from "./client-BWsX9Cv1.mjs";
|
|
2
2
|
export { Client, ClientBuilder, ClientError, SyncDirection };
|
package/dist/core.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { a as getPublicKey, c as verifyEvent, i as finalizeEvent, n as PublicKey, o as publicKeyFromHex, r as SecretKey, s as signEvent, t as Keys } from "./key-
|
|
3
|
-
import { n as ProfileMetadata, t as EventBuilder } from "./builder-
|
|
4
|
-
import { a as
|
|
5
|
-
import { a as assertSubscriptionId, c as encodeRelayMessage, d as parseRelayMessage, i as SubscriptionId, l as mergeCountHll, n as CountResult, o as createSubscriptionId, r as RelayMessage, s as encodeClientMessage, t as ClientMessage, u as parseClientMessage } from "./message-
|
|
6
|
-
import { a as NostrError, i as MessageError, n as EventValidationError, o as UrlError, r as HexError, s as WasmVerifyPoisonedError, t as CryptoError } from "./error-
|
|
7
|
-
import {
|
|
8
|
-
export { type ClientMessage, type CountResult, CryptoError, EVENT_ID_BYTES, type Event, type EventAddress, EventBuilder, type EventTemplate, EventValidationError, type Filter, HexError, Keys, Kind, type KindClassification, type KindName, type KnownKind, MessageError, NostrError, PUBLIC_KEY_BYTES, type ProfileMetadata, type PublicKey, type RelayMessage, SECRET_KEY_BYTES, SIGNATURE_BYTES, SUBSCRIPTION_ID_MAX_CHARS, SecretKey, type SubscriptionId, Tag, type TagInput, type UnsignedEvent, UrlError, WasmVerifyPoisonedError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind,
|
|
1
|
+
import { C as parseEventAddress, S as isTag, T as tagValue, _ as Tag, a as isMarkedFailed, b as formatEventAddress, c as markUnverified, d as signedMatchesUnsigned, f as sortEvents, g as EventAddress, h as validateSignedEvent, i as getEventHash, l as markVerified, m as validateEvent, n as EventTemplate, o as isReplaceableWinner, p as sortedEvents, r as UnsignedEvent, s as itemCompare, t as Event, u as serializeEvent, v as TagInput, w as tagName, x as getDTag, y as eventAddress } from "./event-fU3Y01PR.mjs";
|
|
2
|
+
import { a as getPublicKey, c as verifyEvent, i as finalizeEvent, n as PublicKey, o as publicKeyFromHex, r as SecretKey, s as signEvent, t as Keys } from "./key-BlsYhN1V.mjs";
|
|
3
|
+
import { n as ProfileMetadata, t as EventBuilder } from "./builder-BWn55Paf.mjs";
|
|
4
|
+
import { a as getFilterLimit, c as mergeFilters, i as filterFingerprint, n as canonicalizeFilter, o as matchFilter, r as canonicalizeFilters, s as matchFilters, t as Filter } from "./filter-C0IMByE3.mjs";
|
|
5
|
+
import { a as assertSubscriptionId, c as encodeRelayMessage, d as parseRelayMessage, i as SubscriptionId, l as mergeCountHll, n as CountResult, o as createSubscriptionId, r as RelayMessage, s as encodeClientMessage, t as ClientMessage, u as parseClientMessage } from "./message-iGPIqnn0.mjs";
|
|
6
|
+
import { a as NostrError, i as MessageError, n as EventValidationError, o as UrlError, r as HexError, s as WasmVerifyPoisonedError, t as CryptoError } from "./error-CR8Urc84.mjs";
|
|
7
|
+
import { _ as EVENT_ID_BYTES, a as classifyKind, b as SIGNATURE_BYTES, c as isRegularKind, d as assertSecretKeyBytes, f as bytesToHex, g as normalizeURL, h as isHex64, i as KnownKind, l as isReplaceableKind, m as isHex32, n as KindClassification, o as isAddressableKind, p as hexToBytes, r as KindName, s as isEphemeralKind, t as Kind, u as assertHex32, v as PUBLIC_KEY_BYTES, x as SUBSCRIPTION_ID_MAX_CHARS, y as SECRET_KEY_BYTES } from "./index-Boe8FshM.mjs";
|
|
8
|
+
export { type ClientMessage, type CountResult, CryptoError, EVENT_ID_BYTES, type Event, type EventAddress, EventBuilder, type EventTemplate, EventValidationError, type Filter, HexError, Keys, Kind, type KindClassification, type KindName, type KnownKind, MessageError, NostrError, PUBLIC_KEY_BYTES, type ProfileMetadata, type PublicKey, type RelayMessage, SECRET_KEY_BYTES, SIGNATURE_BYTES, SUBSCRIPTION_ID_MAX_CHARS, SecretKey, type SubscriptionId, Tag, type TagInput, type UnsignedEvent, UrlError, WasmVerifyPoisonedError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, markUnverified, markVerified, matchFilter, matchFilters, mergeCountHll, mergeFilters, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, validateEvent, validateSignedEvent, verifyEvent };
|
package/dist/core.mjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import { a as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { t as
|
|
7
|
-
import { a as
|
|
8
|
-
|
|
9
|
-
export { CryptoError, EVENT_ID_BYTES, EventBuilder, EventValidationError, HexError, Keys, Kind, MessageError, NostrError, PUBLIC_KEY_BYTES, SECRET_KEY_BYTES, SIGNATURE_BYTES, SUBSCRIPTION_ID_MAX_CHARS, SecretKey, Tag, UrlError, WasmVerifyPoisonedError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, cloneFilter, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isMarkedVerified, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, markUnverified, markVerified, matchFilter, matchFilters, mergeCountHll, mergeFilters, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, utf8Decoder, utf8Encoder, validateEvent, validateSignedEvent, verifyEvent };
|
|
1
|
+
import { C as SUBSCRIPTION_ID_MAX_CHARS, S as SIGNATURE_BYTES, _ as UrlError, a as hexToBytes, b as PUBLIC_KEY_BYTES, f as CryptoError, g as NostrError, h as MessageError, i as bytesToHex, l as normalizeURL, m as HexError, n as assertHex32, o as isHex32, p as EventValidationError, r as assertSecretKeyBytes, s as isHex64, v as WasmVerifyPoisonedError, x as SECRET_KEY_BYTES, y as EVENT_ID_BYTES } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { a as isRegularKind, i as isEphemeralKind, n as classifyKind, o as isReplaceableKind, r as isAddressableKind, t as Kind } from "./kind-Cxwhhkx8.mjs";
|
|
3
|
+
import { S as tagValue, _ as formatEventAddress, a as isReplaceableWinner, b as parseEventAddress, c as markVerified, d as sortEvents, f as sortedEvents, g as eventAddress, h as Tag, l as serializeEvent, m as validateSignedEvent, n as getEventHash, o as itemCompare, p as validateEvent, r as isMarkedFailed, s as markUnverified, u as signedMatchesUnsigned, v as getDTag, x as tagName, y as isTag } from "./event-D8Nfoh4K.mjs";
|
|
4
|
+
import { a as publicKeyFromHex, i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as verifyEvent, t as Keys } from "./key-Bbtys6o7.mjs";
|
|
5
|
+
import { t as EventBuilder } from "./builder-CyrGKRVP.mjs";
|
|
6
|
+
import { a as matchFilter, i as getFilterLimit, n as canonicalizeFilters, o as matchFilters, r as filterFingerprint, s as mergeFilters, t as canonicalizeFilter } from "./filter-BQl3GlHt.mjs";
|
|
7
|
+
import { a as mergeCountHll, i as encodeRelayMessage, n as createSubscriptionId, o as parseClientMessage, r as encodeClientMessage, s as parseRelayMessage, t as assertSubscriptionId } from "./message-DcY6Fi9o.mjs";
|
|
8
|
+
export { CryptoError, EVENT_ID_BYTES, EventBuilder, EventValidationError, HexError, Keys, Kind, MessageError, NostrError, PUBLIC_KEY_BYTES, SECRET_KEY_BYTES, SIGNATURE_BYTES, SUBSCRIPTION_ID_MAX_CHARS, SecretKey, Tag, UrlError, WasmVerifyPoisonedError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, markUnverified, markVerified, matchFilter, matchFilters, mergeCountHll, mergeFilters, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, validateEvent, validateSignedEvent, verifyEvent };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { a as NostrError } from "./error-CR8Urc84.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
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { StorageError as t };
|
|
9
|
+
//# sourceMappingURL=error-BW7re1UN.d.mts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { g as NostrError } from "./util-LfQirgDk.mjs";
|
|
2
|
+
//#region src/signer/error.ts
|
|
3
|
+
/**
|
|
4
|
+
* Thrown by a lazy NIP-42 AUTH sign function when no signer is configured at challenge time.
|
|
5
|
+
* {@link import("../relay/relay.ts").Relay} catches it and ignores the challenge: no AUTH frame is
|
|
6
|
+
* sent and the connection stays open.
|
|
7
|
+
*/
|
|
8
|
+
var NoSignerError = class extends NostrError {
|
|
9
|
+
name = "NoSignerError";
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { NoSignerError as t };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=error-B__OMBRY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-B__OMBRY.mjs","names":[],"sources":["../src/signer/error.ts"],"sourcesContent":["import { NostrError } from \"../core/error.ts\";\n\n/**\n * Thrown by a lazy NIP-42 AUTH sign function when no signer is configured at challenge time.\n * {@link import(\"../relay/relay.ts\").Relay} catches it and ignores the challenge: no AUTH frame is\n * sent and the connection stays open.\n */\nexport class NoSignerError extends NostrError {\n override name = \"NoSignerError\";\n}\n"],"mappings":";;;;;;;AAOA,IAAa,gBAAb,cAAmC,WAAW;CAC5C,OAAgB;AAClB"}
|
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
//#region src/core/error.d.ts
|
|
2
2
|
/** Base error for all @qntx/nostr failures. */
|
|
3
3
|
declare class NostrError extends Error {
|
|
4
|
-
|
|
4
|
+
name: string;
|
|
5
5
|
}
|
|
6
6
|
/** Invalid hex encoding or length. */
|
|
7
|
-
declare class HexError extends NostrError {
|
|
7
|
+
declare class HexError extends NostrError {
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
8
10
|
/** Invalid URL / relay URL. */
|
|
9
|
-
declare class UrlError extends NostrError {
|
|
11
|
+
declare class UrlError extends NostrError {
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
10
14
|
/** Event shape / wire validation failure. */
|
|
11
|
-
declare class EventValidationError extends NostrError {
|
|
15
|
+
declare class EventValidationError extends NostrError {
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
12
18
|
/** Cryptographic operation failure (keys, signatures). */
|
|
13
|
-
declare class CryptoError extends NostrError {
|
|
19
|
+
declare class CryptoError extends NostrError {
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
14
22
|
/** Message parse / encode failure. */
|
|
15
|
-
declare class MessageError extends NostrError {
|
|
23
|
+
declare class MessageError extends NostrError {
|
|
24
|
+
name: string;
|
|
25
|
+
}
|
|
16
26
|
/** Wasm verify instance aborted; later verifies on that instance fail. */
|
|
17
|
-
declare class WasmVerifyPoisonedError extends NostrError {
|
|
27
|
+
declare class WasmVerifyPoisonedError extends NostrError {
|
|
28
|
+
name: string;
|
|
29
|
+
}
|
|
18
30
|
//#endregion
|
|
19
31
|
export { NostrError as a, MessageError as i, EventValidationError as n, UrlError as o, HexError as r, WasmVerifyPoisonedError as s, CryptoError as t };
|
|
20
|
-
//# sourceMappingURL=error-
|
|
32
|
+
//# sourceMappingURL=error-CR8Urc84.d.mts.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { g as NostrError } from "./util-LfQirgDk.mjs";
|
|
2
2
|
//#region src/storage/error.ts
|
|
3
3
|
/** Event-store I/O failure. Message must not include event content. */
|
|
4
|
-
var StorageError = class extends NostrError {
|
|
4
|
+
var StorageError = class extends NostrError {
|
|
5
|
+
name = "StorageError";
|
|
6
|
+
};
|
|
5
7
|
function toStorageError(err) {
|
|
6
8
|
if (err instanceof StorageError) return err;
|
|
7
9
|
if (err instanceof Error) return new StorageError(err.message, { cause: err });
|
|
@@ -10,4 +12,4 @@ function toStorageError(err) {
|
|
|
10
12
|
//#endregion
|
|
11
13
|
export { toStorageError as n, StorageError as t };
|
|
12
14
|
|
|
13
|
-
//# sourceMappingURL=error-
|
|
15
|
+
//# sourceMappingURL=error-DrEIM7FO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-DrEIM7FO.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 override name = \"StorageError\";\n}\n\nexport function toStorageError(err: unknown): StorageError {\n if (err instanceof StorageError) {\n return err;\n }\n if (err instanceof Error) {\n return new StorageError(err.message, { cause: err });\n }\n return new StorageError(String(err));\n}\n"],"mappings":";;;AAGA,IAAa,eAAb,cAAkC,WAAW;CAC3C,OAAgB;AAClB;AAEA,SAAgB,eAAe,KAA4B;CACzD,IAAI,eAAe,cACjB,OAAO;CAET,IAAI,eAAe,OACjB,OAAO,IAAI,aAAa,IAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAErD,OAAO,IAAI,aAAa,OAAO,GAAG,CAAC;AACrC"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { o as isReplaceableKind, r as isAddressableKind } from "./kind-BLl4cLOc.mjs";
|
|
1
|
+
import { c as isRecord, d as utf8Encoder, i as bytesToHex, o as isHex32, p as EventValidationError, s as isHex64 } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { o as isReplaceableKind, r as isAddressableKind } from "./kind-Cxwhhkx8.mjs";
|
|
4
3
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
5
4
|
//#region src/core/tag.ts
|
|
5
|
+
/** Type guard: a non-empty array of strings. */
|
|
6
6
|
function isTag(value) {
|
|
7
7
|
if (!Array.isArray(value) || value.length === 0) return false;
|
|
8
8
|
for (const item of value) if (typeof item !== "string") return false;
|
|
9
9
|
return true;
|
|
10
10
|
}
|
|
11
|
+
/** First element of a tag (its name). */
|
|
11
12
|
function tagName(tag) {
|
|
12
|
-
return tag[0];
|
|
13
|
+
return tag[0] ?? "";
|
|
13
14
|
}
|
|
15
|
+
/** Second element of a tag (its primary value), or undefined for a bare name tag. */
|
|
14
16
|
function tagValue(tag) {
|
|
15
17
|
return tag[1];
|
|
16
18
|
}
|
|
@@ -56,25 +58,26 @@ function getDTag(tags) {
|
|
|
56
58
|
/** Parse a NIP-01 addressable/replaceable coordinate. */
|
|
57
59
|
function parseEventAddress(value) {
|
|
58
60
|
const first = value.indexOf(":");
|
|
59
|
-
if (first <= 0) return
|
|
61
|
+
if (first <= 0) return;
|
|
60
62
|
const second = value.indexOf(":", first + 1);
|
|
61
|
-
if (second
|
|
63
|
+
if (second === -1) return;
|
|
62
64
|
const kind = Number(value.slice(0, first));
|
|
63
|
-
if (!Number.isInteger(kind) || kind < 0 || kind > 65535) return
|
|
65
|
+
if (!Number.isInteger(kind) || kind < 0 || kind > 65535) return;
|
|
64
66
|
const pubkey = value.slice(first + 1, second).toLowerCase();
|
|
65
|
-
if (!isHex32(pubkey)) return
|
|
67
|
+
if (!isHex32(pubkey)) return;
|
|
66
68
|
return {
|
|
67
69
|
kind,
|
|
68
70
|
pubkey,
|
|
69
71
|
identifier: value.slice(second + 1)
|
|
70
72
|
};
|
|
71
73
|
}
|
|
74
|
+
/** Format an address as a `kind:pubkey:dTag` coordinate string. */
|
|
72
75
|
function formatEventAddress(kind, pubkey, identifier = "") {
|
|
73
76
|
return `${kind}:${pubkey.toLowerCase()}:${identifier}`;
|
|
74
77
|
}
|
|
75
78
|
/**
|
|
76
|
-
* Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events.
|
|
77
|
-
*
|
|
79
|
+
* Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events. Undefined
|
|
80
|
+
* for regular/ephemeral kinds.
|
|
78
81
|
*/
|
|
79
82
|
function eventAddress(event) {
|
|
80
83
|
if (isAddressableKind(event.kind)) return formatEventAddress(event.kind, event.pubkey, getDTag(event.tags) ?? "");
|
|
@@ -100,35 +103,34 @@ function isMarkedVerified(event) {
|
|
|
100
103
|
function isMarkedFailed(event) {
|
|
101
104
|
return failedEvents.has(event);
|
|
102
105
|
}
|
|
103
|
-
const isRecord = (obj) => typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
|
104
106
|
/** Structural validation of an unsigned event (no crypto). */
|
|
105
107
|
function validateEvent(event) {
|
|
106
108
|
if (!isRecord(event)) return false;
|
|
107
|
-
if (typeof event
|
|
108
|
-
if (typeof event
|
|
109
|
-
if (typeof event
|
|
110
|
-
if (typeof event
|
|
111
|
-
if (!Array.isArray(event
|
|
112
|
-
for (const tag of event
|
|
109
|
+
if (typeof event["kind"] !== "number" || !Number.isInteger(event["kind"]) || event["kind"] < 0 || event["kind"] > 65535) return false;
|
|
110
|
+
if (typeof event["content"] !== "string") return false;
|
|
111
|
+
if (typeof event["created_at"] !== "number" || !Number.isInteger(event["created_at"])) return false;
|
|
112
|
+
if (typeof event["pubkey"] !== "string" || !isHex32(event["pubkey"])) return false;
|
|
113
|
+
if (!Array.isArray(event["tags"])) return false;
|
|
114
|
+
for (const tag of event["tags"]) if (!isTag(tag)) return false;
|
|
113
115
|
return true;
|
|
114
116
|
}
|
|
115
117
|
/** Structural validation of a full event including id and sig hex shape. */
|
|
116
118
|
function validateSignedEvent(event) {
|
|
117
119
|
if (!validateEvent(event)) return false;
|
|
118
120
|
const e = event;
|
|
119
|
-
if (typeof e
|
|
120
|
-
if (typeof e
|
|
121
|
+
if (typeof e["id"] !== "string" || !isHex32(e["id"])) return false;
|
|
122
|
+
if (typeof e["sig"] !== "string" || !isHex64(e["sig"])) return false;
|
|
121
123
|
return true;
|
|
122
124
|
}
|
|
123
125
|
/**
|
|
124
|
-
* Canonical NIP-01 serialization used for hashing:
|
|
125
|
-
*
|
|
126
|
+
* Canonical NIP-01 serialization used for hashing: JSON array `[0, pubkey, created_at, kind, tags,
|
|
127
|
+
* content]` with no extra whitespace.
|
|
126
128
|
*/
|
|
127
129
|
function serializeEvent(event) {
|
|
128
130
|
if (!validateEvent(event)) throw new EventValidationError("cannot serialize event with invalid shape");
|
|
129
131
|
return JSON.stringify([
|
|
130
132
|
0,
|
|
131
|
-
event.pubkey
|
|
133
|
+
event.pubkey,
|
|
132
134
|
event.created_at,
|
|
133
135
|
event.kind,
|
|
134
136
|
event.tags,
|
|
@@ -140,24 +142,30 @@ function getEventHash(event) {
|
|
|
140
142
|
const serialized = serializeEvent(event);
|
|
141
143
|
return bytesToHex(sha256(utf8Encoder.encode(serialized)));
|
|
142
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* NIP-01 newest-first order: `created_at` descending, then `id` in plain code-unit order (ids are
|
|
147
|
+
* canonical lowercase hex, so `<` is lexical order).
|
|
148
|
+
*/
|
|
143
149
|
function compareEventsDesc(a, b) {
|
|
144
150
|
if (a.created_at !== b.created_at) return b.created_at - a.created_at;
|
|
145
|
-
|
|
151
|
+
if (a.id < b.id) return -1;
|
|
152
|
+
if (a.id > b.id) return 1;
|
|
153
|
+
return 0;
|
|
146
154
|
}
|
|
147
155
|
/**
|
|
148
|
-
* Sort events reverse-chronologically by `created_at`, then by `id` lexicographically.
|
|
149
|
-
*
|
|
156
|
+
* Sort events reverse-chronologically by `created_at`, then by `id` lexicographically. Mutates and
|
|
157
|
+
* returns the array.
|
|
150
158
|
*/
|
|
151
159
|
function sortEvents(events) {
|
|
152
160
|
return events.sort(compareEventsDesc);
|
|
153
161
|
}
|
|
154
162
|
/** Non-mutating sort; returns a new array. */
|
|
155
163
|
function sortedEvents(events) {
|
|
156
|
-
return events.
|
|
164
|
+
return [...events].sort(compareEventsDesc);
|
|
157
165
|
}
|
|
158
166
|
/**
|
|
159
|
-
* Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`).
|
|
160
|
-
*
|
|
167
|
+
* Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`). Time axis is
|
|
168
|
+
* opposite {@link sortEvents}; id tie-break is the same direction.
|
|
161
169
|
*/
|
|
162
170
|
function itemCompare(a, b) {
|
|
163
171
|
if (a.created_at !== b.created_at) return a.created_at - b.created_at;
|
|
@@ -166,8 +174,8 @@ function itemCompare(a, b) {
|
|
|
166
174
|
return 0;
|
|
167
175
|
}
|
|
168
176
|
/**
|
|
169
|
-
* NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp
|
|
170
|
-
*
|
|
177
|
+
* NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp and
|
|
178
|
+
* lexicographically lower `id`.
|
|
171
179
|
*/
|
|
172
180
|
function isReplaceableWinner(candidate, incumbent) {
|
|
173
181
|
if (candidate.created_at !== incumbent.created_at) return candidate.created_at > incumbent.created_at;
|
|
@@ -183,6 +191,6 @@ function signedMatchesUnsigned(signed, unsigned) {
|
|
|
183
191
|
return true;
|
|
184
192
|
}
|
|
185
193
|
//#endregion
|
|
186
|
-
export {
|
|
194
|
+
export { tagValue as S, formatEventAddress as _, isReplaceableWinner as a, parseEventAddress as b, markVerified as c, sortEvents as d, sortedEvents as f, eventAddress as g, Tag as h, isMarkedVerified as i, serializeEvent as l, validateSignedEvent as m, getEventHash as n, itemCompare as o, validateEvent as p, isMarkedFailed as r, markUnverified as s, compareEventsDesc as t, signedMatchesUnsigned as u, getDTag as v, tagName as x, isTag as y };
|
|
187
195
|
|
|
188
|
-
//# sourceMappingURL=event-
|
|
196
|
+
//# sourceMappingURL=event-D8Nfoh4K.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-D8Nfoh4K.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 = ReadonlyArray<string>;\n\n/** Mutable tag builder input. */\nexport type TagInput = string[];\n\n/** Type guard: a non-empty array of strings. */\nexport function isTag(value: unknown): value is Tag {\n if (!Array.isArray(value) || value.length === 0) {\n return false;\n }\n for (const item of value) {\n if (typeof item !== \"string\") {\n return false;\n }\n }\n return true;\n}\n\n/** First element of a tag (its name). */\nexport function tagName(tag: Tag): string {\n return tag[0] ?? \"\";\n}\n\n/** Second element of a tag (its primary value), or undefined for a bare name tag. */\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) {\n t.push(relay);\n }\n if (marker !== undefined) {\n t.push(marker);\n }\n if (pubkey !== undefined) {\n t.push(pubkey.toLowerCase());\n }\n return t;\n },\n p(pubkey: string, relay?: string, petname?: string): Tag {\n const t: string[] = [\"p\", pubkey.toLowerCase()];\n if (relay !== undefined) {\n t.push(relay);\n }\n if (petname !== undefined) {\n t.push(petname);\n }\n return t;\n },\n a(coordinate: string, relay?: string): Tag {\n const t: string[] = [\"a\", coordinate];\n if (relay !== undefined) {\n t.push(relay);\n }\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) {\n t.push(marker);\n }\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: ReadonlyArray<Tag>): string | undefined {\n for (const tag of tags) {\n if (tag[0] === \"d\" && tag[1] !== undefined) {\n return tag[1];\n }\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) {\n return undefined;\n }\n const second = value.indexOf(\":\", first + 1);\n if (second === -1) {\n return undefined;\n }\n const kind = Number(value.slice(0, first));\n if (!Number.isInteger(kind) || kind < 0 || kind > 65535) {\n return undefined;\n }\n const pubkey = value.slice(first + 1, second).toLowerCase();\n if (!isHex32(pubkey)) {\n return undefined;\n }\n return { kind, pubkey, identifier: value.slice(second + 1) };\n}\n\n/** Format an address as a `kind:pubkey:dTag` coordinate string. */\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. Undefined\n * for regular/ephemeral kinds.\n */\nexport function eventAddress(event: {\n kind: number;\n pubkey: string;\n tags: ReadonlyArray<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 { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { EventValidationError } from \"./error.ts\";\nimport type { Tag } from \"./tag.ts\";\nimport { isTag } from \"./tag.ts\";\nimport { isHex32, isHex64, isRecord, utf8Encoder, bytesToHex } from \"./util.ts\";\n\n/** Wire event template before pubkey/id/sig. */\nexport type EventTemplate = {\n readonly kind: number;\n readonly tags: ReadonlyArray<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). Fields are readonly at the type level;\n * 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<Event>();\n\n/** Cache of events known to fail verification. */\nconst failedEvents = new WeakSet<Event>();\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\n/** Structural validation of an unsigned event (no crypto). */\nexport function validateEvent(event: unknown): event is UnsignedEvent {\n if (!isRecord(event)) {\n return false;\n }\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\") {\n return false;\n }\n if (typeof event[\"created_at\"] !== \"number\" || !Number.isInteger(event[\"created_at\"])) {\n return false;\n }\n if (typeof event[\"pubkey\"] !== \"string\" || !isHex32(event[\"pubkey\"])) {\n return false;\n }\n if (!Array.isArray(event[\"tags\"])) {\n return false;\n }\n for (const tag of event[\"tags\"]) {\n if (!isTag(tag)) {\n return false;\n }\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)) {\n return false;\n }\n const e = event as Record<string, unknown>;\n if (typeof e[\"id\"] !== \"string\" || !isHex32(e[\"id\"])) {\n return false;\n }\n if (typeof e[\"sig\"] !== \"string\" || !isHex64(e[\"sig\"])) {\n return false;\n }\n return true;\n}\n\n/**\n * Canonical NIP-01 serialization used for hashing: JSON array `[0, pubkey, created_at, kind, tags,\n * 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([0, event.pubkey, event.created_at, event.kind, event.tags, event.content]);\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\n/**\n * NIP-01 newest-first order: `created_at` descending, then `id` in plain code-unit order (ids are\n * canonical lowercase hex, so `<` is lexical order).\n */\nexport function compareEventsDesc(\n a: { id: string; created_at: number },\n b: { id: string; created_at: number },\n): number {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at;\n }\n if (a.id < b.id) {\n return -1;\n }\n if (a.id > b.id) {\n return 1;\n }\n return 0;\n}\n\n/**\n * Sort events reverse-chronologically by `created_at`, then by `id` lexicographically. Mutates and\n * 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: ReadonlyArray<Event>): Event[] {\n return [...events].sort(compareEventsDesc);\n}\n\n/**\n * Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`). Time axis is\n * 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) {\n return a.created_at - b.created_at;\n }\n if (a.id < b.id) {\n return -1;\n }\n if (a.id > b.id) {\n return 1;\n }\n return 0;\n}\n\n/**\n * NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp and\n * 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) {\n return false;\n }\n if (signed.content !== unsigned.content) {\n return false;\n }\n if (signed.created_at !== unsigned.created_at) {\n return false;\n }\n if (JSON.stringify(signed.tags) !== JSON.stringify(unsigned.tags)) {\n return false;\n }\n if (unsigned.pubkey && signed.pubkey.toLowerCase() !== unsigned.pubkey.toLowerCase()) {\n return false;\n }\n return true;\n}\n"],"mappings":"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"}
|