@qntx/nostr 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/builder-BphJa-Y-.d.mts +67 -0
  4. package/dist/builder-q0VsvnYE.mjs +158 -0
  5. package/dist/builder-q0VsvnYE.mjs.map +1 -0
  6. package/dist/client-Bd8B1mYm.mjs +835 -0
  7. package/dist/client-Bd8B1mYm.mjs.map +1 -0
  8. package/dist/client.d.mts +2 -0
  9. package/dist/client.mjs +2 -0
  10. package/dist/core.d.mts +8 -0
  11. package/dist/core.mjs +9 -0
  12. package/dist/error-B49rbDzT.d.mts +7 -0
  13. package/dist/error-CwBxle6N.mjs +13 -0
  14. package/dist/error-CwBxle6N.mjs.map +1 -0
  15. package/dist/error-DZEs5OuZ.mjs +24 -0
  16. package/dist/error-DZEs5OuZ.mjs.map +1 -0
  17. package/dist/error-WEFS-R-4.d.mts +20 -0
  18. package/dist/event-B5D2jxt_.d.mts +108 -0
  19. package/dist/event-CzoQEFMF.mjs +188 -0
  20. package/dist/event-CzoQEFMF.mjs.map +1 -0
  21. package/dist/filter-BxwjEkZp.mjs +113 -0
  22. package/dist/filter-BxwjEkZp.mjs.map +1 -0
  23. package/dist/filter-DUEKP3q1.d.mts +40 -0
  24. package/dist/gossip-3xkRRCm_.mjs +220 -0
  25. package/dist/gossip-3xkRRCm_.mjs.map +1 -0
  26. package/dist/gossip-C5RVB1UB.d.mts +71 -0
  27. package/dist/gossip.d.mts +3 -0
  28. package/dist/gossip.mjs +2 -0
  29. package/dist/http-6vevbBlu.d.mts +22 -0
  30. package/dist/http-D2rhokZo.mjs +24 -0
  31. package/dist/http-D2rhokZo.mjs.map +1 -0
  32. package/dist/index-BYMnhRIC.d.mts +161 -0
  33. package/dist/index-C0C4e-Gn.d.mts +55 -0
  34. package/dist/index-CaxrMD1A.d.mts +1 -0
  35. package/dist/index-DaRyjo7O.d.mts +77 -0
  36. package/dist/index-DgOugrpF.d.mts +275 -0
  37. package/dist/index-EwL6fHLo.d.mts +267 -0
  38. package/dist/index-k2YhCgsh.d.mts +57 -0
  39. package/dist/index.d.mts +22 -0
  40. package/dist/index.mjs +23 -0
  41. package/dist/key-BiGxGLhg.d.mts +37 -0
  42. package/dist/key-Dn-aX4x4.mjs +130 -0
  43. package/dist/key-Dn-aX4x4.mjs.map +1 -0
  44. package/dist/kind-BLl4cLOc.mjs +59 -0
  45. package/dist/kind-BLl4cLOc.mjs.map +1 -0
  46. package/dist/loaders-BNQszDAn.mjs +767 -0
  47. package/dist/loaders-BNQszDAn.mjs.map +1 -0
  48. package/dist/loaders.d.mts +3 -0
  49. package/dist/loaders.mjs +2 -0
  50. package/dist/memory-BCmhZPek.mjs +461 -0
  51. package/dist/memory-BCmhZPek.mjs.map +1 -0
  52. package/dist/message-C_Uj-Y-c.mjs +179 -0
  53. package/dist/message-C_Uj-Y-c.mjs.map +1 -0
  54. package/dist/message-DJC-Jz6T.d.mts +32 -0
  55. package/dist/nip17-BWq-Kfq5.d.mts +38 -0
  56. package/dist/nip19-D7905oIv.d.mts +63 -0
  57. package/dist/nip46-C_DoxiS_.d.mts +51 -0
  58. package/dist/nip59-DljW_sYh.d.mts +76 -0
  59. package/dist/nip65-Di5hZRuV.d.mts +21 -0
  60. package/dist/nip77-ByxlgoQO.d.mts +55 -0
  61. package/dist/nips/blossom.d.mts +93 -0
  62. package/dist/nips/blossom.mjs +325 -0
  63. package/dist/nips/blossom.mjs.map +1 -0
  64. package/dist/nips/nip04.d.mts +8 -0
  65. package/dist/nips/nip04.mjs +41 -0
  66. package/dist/nips/nip04.mjs.map +1 -0
  67. package/dist/nips/nip05.d.mts +89 -0
  68. package/dist/nips/nip05.mjs +147 -0
  69. package/dist/nips/nip05.mjs.map +1 -0
  70. package/dist/nips/nip10.d.mts +43 -0
  71. package/dist/nips/nip10.mjs +194 -0
  72. package/dist/nips/nip10.mjs.map +1 -0
  73. package/dist/nips/nip11.d.mts +43 -0
  74. package/dist/nips/nip11.mjs +99 -0
  75. package/dist/nips/nip11.mjs.map +1 -0
  76. package/dist/nips/nip13.d.mts +23 -0
  77. package/dist/nips/nip13.mjs +88 -0
  78. package/dist/nips/nip13.mjs.map +1 -0
  79. package/dist/nips/nip17.d.mts +2 -0
  80. package/dist/nips/nip17.mjs +138 -0
  81. package/dist/nips/nip17.mjs.map +1 -0
  82. package/dist/nips/nip19.d.mts +2 -0
  83. package/dist/nips/nip19.mjs +174 -0
  84. package/dist/nips/nip19.mjs.map +1 -0
  85. package/dist/nips/nip21.d.mts +17 -0
  86. package/dist/nips/nip21.mjs +29 -0
  87. package/dist/nips/nip21.mjs.map +1 -0
  88. package/dist/nips/nip27.d.mts +42 -0
  89. package/dist/nips/nip27.mjs +175 -0
  90. package/dist/nips/nip27.mjs.map +1 -0
  91. package/dist/nips/nip42.d.mts +12 -0
  92. package/dist/nips/nip42.mjs +22 -0
  93. package/dist/nips/nip42.mjs.map +1 -0
  94. package/dist/nips/nip44.d.mts +12 -0
  95. package/dist/nips/nip44.mjs +125 -0
  96. package/dist/nips/nip44.mjs.map +1 -0
  97. package/dist/nips/nip46.d.mts +2 -0
  98. package/dist/nips/nip46.mjs +132 -0
  99. package/dist/nips/nip46.mjs.map +1 -0
  100. package/dist/nips/nip49.d.mts +12 -0
  101. package/dist/nips/nip49.mjs +80 -0
  102. package/dist/nips/nip49.mjs.map +1 -0
  103. package/dist/nips/nip51.d.mts +88 -0
  104. package/dist/nips/nip51.mjs +246 -0
  105. package/dist/nips/nip51.mjs.map +1 -0
  106. package/dist/nips/nip57.d.mts +43 -0
  107. package/dist/nips/nip57.mjs +230 -0
  108. package/dist/nips/nip57.mjs.map +1 -0
  109. package/dist/nips/nip59.d.mts +2 -0
  110. package/dist/nips/nip59.mjs +171 -0
  111. package/dist/nips/nip59.mjs.map +1 -0
  112. package/dist/nips/nip65.d.mts +2 -0
  113. package/dist/nips/nip65.mjs +76 -0
  114. package/dist/nips/nip65.mjs.map +1 -0
  115. package/dist/nips/nip77.d.mts +2 -0
  116. package/dist/nips/nip77.mjs +421 -0
  117. package/dist/nips/nip77.mjs.map +1 -0
  118. package/dist/nips/nip96.d.mts +31 -0
  119. package/dist/nips/nip96.mjs +95 -0
  120. package/dist/nips/nip96.mjs.map +1 -0
  121. package/dist/nips/nip98.d.mts +28 -0
  122. package/dist/nips/nip98.mjs +91 -0
  123. package/dist/nips/nip98.mjs.map +1 -0
  124. package/dist/nostr_crypto_wasm_bg-hi5aXi5P.mjs +4 -0
  125. package/dist/nostr_crypto_wasm_bg.wasm +0 -0
  126. package/dist/pool-C_j1OmBB.mjs +1881 -0
  127. package/dist/pool-C_j1OmBB.mjs.map +1 -0
  128. package/dist/pool-DhRi7l-b.d.mts +297 -0
  129. package/dist/relay.d.mts +4 -0
  130. package/dist/relay.mjs +2 -0
  131. package/dist/signer-CZ6K6FUc.mjs +473 -0
  132. package/dist/signer-CZ6K6FUc.mjs.map +1 -0
  133. package/dist/signer.d.mts +3 -0
  134. package/dist/signer.mjs +2 -0
  135. package/dist/storage-DOy0iLRE.mjs +870 -0
  136. package/dist/storage-DOy0iLRE.mjs.map +1 -0
  137. package/dist/storage.d.mts +4 -0
  138. package/dist/storage.mjs +4 -0
  139. package/dist/types-BzyADqnw.d.mts +19 -0
  140. package/dist/types-Dn24TPFs.d.mts +43 -0
  141. package/dist/util-6tfLQ9JF.mjs +73 -0
  142. package/dist/util-6tfLQ9JF.mjs.map +1 -0
  143. package/dist/wasm.d.mts +19 -0
  144. package/dist/wasm.mjs +237 -0
  145. package/dist/wasm.mjs.map +1 -0
  146. package/package.json +204 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-Bd8B1mYm.mjs","names":["#opts","#signer","#relays","#persistEvents","#shutdown","#assertAlive","#flushing","#ingestMeta","#persistQueue","#armFlush","#flushLoop","#defaultRelays","#wantObserve","#requireNip59Crypto","#throwIfAborted","#dmDeps","#syncDeps"],"sources":["../src/client/builder.ts","../src/client/dm.ts","../src/client/gossip-io.ts","../src/client/types.ts","../src/client/sync.ts","../src/client/client.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { WebSocketConstructor } from \"../relay/websocket.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport type { StorageError } from \"../storage/error.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport { Client } from \"./client.ts\";\nimport type { ClientOptions } from \"./types.ts\";\n\n/** Fluent constructor for {@link Client}. */\nexport class ClientBuilder {\n #opts: ClientOptions = {};\n\n signer(signer: NostrSigner): this {\n this.#opts = { ...this.#opts, signer };\n return this;\n }\n\n relays(urls: readonly string[]): this {\n this.#opts = { ...this.#opts, relays: [...urls] };\n return this;\n }\n\n addRelay(url: string): this {\n this.#opts = { ...this.#opts, relays: [...(this.#opts.relays ?? []), url] };\n return this;\n }\n\n websocketImplementation(impl: WebSocketConstructor): this {\n this.#opts = { ...this.#opts, websocketImplementation: impl };\n return this;\n }\n\n verifyEvent(fn: (event: Event) => boolean): this {\n this.#opts = { ...this.#opts, verifyEvent: fn };\n return this;\n }\n\n connectTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, connectTimeoutMs: ms };\n return this;\n }\n\n publishTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, publishTimeoutMs: ms };\n return this;\n }\n\n automaticAuth(enabled: boolean): this {\n this.#opts = { ...this.#opts, automaticAuth: enabled };\n return this;\n }\n\n enableReconnect(enabled: boolean): this {\n this.#opts = { ...this.#opts, enableReconnect: enabled };\n return this;\n }\n\n enablePing(enabled: boolean): this {\n this.#opts = { ...this.#opts, enablePing: enabled };\n return this;\n }\n\n pingIntervalMs(ms: number): this {\n this.#opts = { ...this.#opts, pingIntervalMs: ms };\n return this;\n }\n\n pingTimeoutMs(ms: number): this {\n this.#opts = { ...this.#opts, pingTimeoutMs: ms };\n return this;\n }\n\n /**\n * Local event store. Defaults to {@link MemoryEventStore}.\n * Browser apps that want persistence must pass {@link IndexedDbEventStore} and `await open()`.\n */\n storage(store: EventStore): this {\n this.#opts = { ...this.#opts, storage: store };\n return this;\n }\n\n /** When false, Client will not auto-write events to storage. Default true. */\n persistEvents(enabled: boolean): this {\n this.#opts = { ...this.#opts, persistEvents: enabled };\n return this;\n }\n\n gossip(gossip: Gossip): this {\n this.#opts = { ...this.#opts, gossip };\n return this;\n }\n\n onstorageerror(fn: (err: StorageError) => void): this {\n this.#opts = { ...this.#opts, onstorageerror: fn };\n return this;\n }\n\n build(): Client {\n return new Client(this.#opts);\n }\n}\n","import type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { EventBuilder } from \"../core/builder.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { Pool, PoolPublishResult } from \"../relay/pool.ts\";\nimport {\n Nip17Error,\n buildChatMessageRumor,\n dmRelayListEventBuilder,\n normalizeRecipients,\n requireDmRelays,\n wrapDirectMessage,\n type Recipient,\n} from \"../nips/nip17.ts\";\nimport { unwrap, type Nip59Crypto } from \"../nips/nip59.ts\";\nimport type {\n FetchPrivateMessagesOptions,\n PrivateMessageSendResult,\n PublishOptions,\n ReceivedPrivateMessage,\n SendPrivateMessageOptions,\n SubscribePrivateMessagesOptions,\n} from \"./types.ts\";\n\nexport type DmDeps = {\n pool: Pool;\n gossip: Gossip;\n hydrateGossip: (pubkeys: readonly string[]) => Promise<void>;\n observe: (event: Event) => void;\n assertAlive: () => void;\n requireNip59Crypto: () => Nip59Crypto;\n throwIfAborted: (signal?: AbortSignal) => void;\n wantObserve: (flag?: boolean) => boolean;\n publish: (\n eventOrBuilder: Event | EventBuilder,\n opts?: PublishOptions,\n ) => Promise<PoolPublishResult[]>;\n};\n\nexport function giftWrapRelays(gossip: Gossip, event: Event): string[] {\n const targets: string[] = [];\n for (const tag of event.tags) {\n if (tag[0] === \"p\" && tag[1]) targets.push(tag[1].toLowerCase());\n }\n if (targets.length === 0) {\n throw new Nip17Error(\"gift wrap has no p-tag recipient\");\n }\n if (targets.length !== 1) {\n throw new Nip17Error(\"gift wrap must have exactly one p-tag recipient\");\n }\n const relays = gossip.dmRelays(targets[0]!);\n if (relays.length === 0) {\n throw new Nip17Error(\"no kind 10050 in gossip; use sendPrivateMessage or pass relays\");\n }\n return relays;\n}\n\nexport async function setDmRelays(\n deps: DmDeps,\n relays: readonly string[],\n opts?: PublishOptions,\n): Promise<PoolPublishResult[]> {\n return deps.publish(dmRelayListEventBuilder(relays), { gossip: true, ...opts });\n}\n\nexport async function sendPrivateMessage(\n deps: DmDeps,\n recipients: string | Recipient | readonly (string | Recipient)[],\n content: string,\n opts?: SendPrivateMessageOptions,\n): Promise<PrivateMessageSendResult> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const sender = await crypto.getPublicKey();\n const list = normalizeRecipients(recipients);\n if (list.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n\n const targets = new Set<string>([sender.toLowerCase(), ...list.map((r) => r.pubkey)]);\n await deps.hydrateGossip([...targets]);\n for (const pk of targets) {\n requireDmRelays(pk, deps.gossip.dmRelays(pk));\n }\n\n const rumor = buildChatMessageRumor(sender, list, content, {\n created_at: opts?.created_at,\n subject: opts?.subject,\n replyTo: opts?.replyTo,\n });\n const wraps = await wrapDirectMessage(crypto, list, rumor);\n const sent = await Promise.all(\n wraps.map(async ({ recipient, wrap }) => {\n const relays = requireDmRelays(recipient, deps.gossip.dmRelays(recipient));\n const results = await deps.pool.publish(relays, wrap, { timeoutMs: opts?.timeoutMs });\n if (results.some((r) => r.result?.ok) && deps.wantObserve(opts?.observe)) {\n deps.observe(wrap);\n }\n return { recipient, wrap, results };\n }),\n );\n return { rumor, wraps: sent };\n}\n\nexport async function fetchPrivateMessages(\n deps: DmDeps,\n opts?: FetchPrivateMessagesOptions,\n): Promise<ReceivedPrivateMessage[]> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const self = await crypto.getPublicKey();\n deps.throwIfAborted(opts?.signal);\n await deps.hydrateGossip([self]);\n deps.throwIfAborted(opts?.signal);\n const relays = requireDmRelays(self, deps.gossip.dmRelays(self));\n const events = await deps.pool.fetch(\n relays,\n [\n {\n kinds: [Kind.GiftWrap],\n \"#p\": [self],\n since: opts?.since,\n until: opts?.until,\n },\n ],\n { timeoutMs: opts?.timeoutMs, signal: opts?.signal },\n );\n\n const byRumor = new Map<string, ReceivedPrivateMessage>();\n for (const wrap of events) {\n try {\n const rumor = await unwrap(crypto, wrap);\n if (deps.wantObserve(opts?.observe)) deps.observe(wrap);\n byRumor.set(rumor.id, { wrap, rumor });\n } catch {\n // junk / forgery / key mismatch — not stored\n }\n }\n\n return [...byRumor.values()].sort((a, b) => {\n if (a.rumor.created_at !== b.rumor.created_at) {\n return a.rumor.created_at - b.rumor.created_at;\n }\n return a.rumor.id.localeCompare(b.rumor.id);\n });\n}\n\nexport async function subscribePrivateMessages(\n deps: DmDeps,\n opts?: SubscribePrivateMessagesOptions,\n): Promise<{ close: (reason?: string) => void }> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const self = await crypto.getPublicKey();\n deps.throwIfAborted(opts?.signal);\n await deps.hydrateGossip([self]);\n deps.throwIfAborted(opts?.signal);\n const relays = requireDmRelays(self, deps.gossip.dmRelays(self));\n\n const seen = new Set<string>();\n let tail = Promise.resolve();\n let closed = false;\n const markClosed = (): void => {\n closed = true;\n };\n if (opts?.signal?.aborted) markClosed();\n else opts?.signal?.addEventListener(\"abort\", markClosed, { once: true });\n\n const inner = deps.pool.subscribe(\n relays,\n // 21059 is ephemeral (relays MUST NOT store); live inbox has to REQ it.\n [{ kinds: [Kind.GiftWrap, Kind.GiftWrapEphemeral], \"#p\": [self], since: opts?.since }],\n {\n signal: opts?.signal,\n oneose: opts?.oneose,\n onclose: (reason) => {\n markClosed();\n opts?.onclose?.(reason);\n },\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n onevent: (wrap) => {\n if (closed) return;\n tail = tail\n .then(async () => {\n if (closed) return;\n try {\n const rumor = await unwrap(crypto, wrap);\n if (closed) return;\n if (seen.has(rumor.id)) return;\n seen.add(rumor.id);\n if (deps.wantObserve(opts?.observe)) deps.observe(wrap);\n opts?.onevent?.({ wrap, rumor });\n } catch {\n // junk / forgery — not stored\n }\n })\n .catch(() => {\n // keep the queue alive if a handler throws\n });\n },\n },\n );\n\n return {\n close: (reason?: string) => {\n markClosed();\n inner.close(reason);\n },\n };\n}\n","import type { Event } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport { fanIn, fetchRouted, type FanInOptions, type RoutedJob } from \"../relay/fan-in.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\n\n/** Remainder is one job on defaults; throw before any REQ when defaults are empty. */\nexport function jobsForFilters(\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n): RoutedJob[] {\n const routed = filters.map((f) => gossip.route(f));\n const needsDefaults = routed.some((r) => r.remainder !== undefined);\n const defaults = needsDefaults ? defaultRelays() : undefined;\n const jobs: RoutedJob[] = [];\n for (const r of routed) {\n for (const [url, sub] of r.perRelay) jobs.push({ urls: [url], filters: [sub] });\n if (r.remainder) jobs.push({ urls: defaults!, filters: [r.remainder] });\n }\n return jobs;\n}\n\nexport function fetchGossip(\n pool: Pool,\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n opts?: { timeoutMs?: number; signal?: AbortSignal },\n): Promise<Event[]> {\n return fetchRouted(pool, jobsForFilters(gossip, filters, defaultRelays), {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n}\n\nexport function subscribeGossip(\n pool: Pool,\n gossip: Gossip,\n filters: Filter[],\n defaultRelays: () => string[],\n opts: FanInOptions,\n): { close: (reason?: string) => void } {\n const jobs = jobsForFilters(gossip, filters, defaultRelays);\n if (jobs.length === 0) {\n queueMicrotask(() => opts.oneose?.());\n return { close: () => {} };\n }\n return fanIn(pool, jobs, opts);\n}\n","import { NostrError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { PoolPublishResult } from \"../relay/pool.ts\";\nimport type { WebSocketConstructor } from \"../relay/websocket.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport type { StorageError } from \"../storage/error.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport type { ReplyTo } from \"../nips/nip17.ts\";\nimport type { Rumor } from \"../nips/nip59.ts\";\n\nexport const SyncDirection = {\n Up: \"up\",\n Down: \"down\",\n Both: \"both\",\n} as const;\n\nexport type SyncDirectionName = (typeof SyncDirection)[keyof typeof SyncDirection];\n\nexport type SyncOptions = {\n relays?: readonly string[];\n direction?: SyncDirectionName;\n /**\n * Wall-clock deadline for the Negentropy reconciliation session\n * (`NEG-OPEN` through `NEG-CLOSE`), in milliseconds.\n * One clock for the whole session — not reset per `NEG-MSG`.\n * Default: the relay `publishTimeoutMs`.\n * Upload/download phases reuse this value as their per-call timeout.\n */\n timeoutMs?: number;\n signal?: AbortSignal;\n dryRun?: boolean;\n /** When false, skip observe/storage on downloaded events. Default true. */\n observe?: boolean;\n};\n\nexport type SyncSummary = {\n local: string[];\n remote: string[];\n sent: string[];\n received: string[];\n sendFailures: Record<string, string>;\n persistFailures: Record<string, string>;\n};\n\nexport type ClientOptions = {\n signer?: NostrSigner;\n relays?: readonly string[];\n websocketImplementation?: WebSocketConstructor;\n /** Injected EVENT verifier. Default is core BIP-340. */\n verifyEvent?: (event: Event) => boolean;\n connectTimeoutMs?: number;\n publishTimeoutMs?: number;\n /** When true (default if signer present), answer NIP-42 AUTH automatically. */\n automaticAuth?: boolean;\n /** When true (default), relays reconnect with backoff after disconnect. */\n enableReconnect?: boolean;\n /** Keepalive ping. Default false. */\n enablePing?: boolean;\n pingIntervalMs?: number;\n pingTimeoutMs?: number;\n gossip?: Gossip;\n /**\n * Local event store. Defaults to {@link MemoryEventStore}.\n * Browser apps that want persistence must pass {@link IndexedDbEventStore} and `await open()`.\n */\n storage?: EventStore;\n /**\n * When true (default), every ingested event is written to storage.\n * Set false to disable automatic persistence while keeping the store for manual use.\n */\n persistEvents?: boolean;\n /**\n * Storage I/O failures: live `putMany` flush and `fetchEvents({ localFirst: true })` query.\n * Those paths do not throw.\n */\n onstorageerror?: (err: StorageError) => void;\n};\n\nexport type FetchEventsOptions = {\n relays?: string[];\n timeoutMs?: number;\n signal?: AbortSignal;\n gossip?: boolean;\n /**\n * When true, query local storage first and merge with network results.\n * Defaults to false.\n */\n localFirst?: boolean;\n /** When false, skip writing fetched events to storage/observe. Default true. */\n observe?: boolean;\n};\n\nexport type SubscribeOptions = {\n relays?: string[];\n onevent?: (event: Event) => void;\n oneose?: () => void;\n onclose?: (reason: string) => void;\n signal?: AbortSignal;\n id?: string;\n /**\n * If set, fire `oneose` once after this many ms if not all relays have EOSEd.\n * Does not close the subscription.\n */\n eoseTimeoutMs?: number;\n /** Fan out REQs via NIP-65 gossip routes when available. */\n gossip?: boolean;\n /** When false, skip writing received events to storage/observe. Default true. */\n observe?: boolean;\n};\n\nexport type PublishOptions = {\n relays?: string[];\n timeoutMs?: number;\n gossip?: boolean;\n /** When false, skip writing the published event to storage/observe. Default true. */\n observe?: boolean;\n};\n\nexport type SendPrivateMessageOptions = {\n readonly subject?: string;\n readonly replyTo?: ReplyTo;\n readonly created_at?: number;\n readonly timeoutMs?: number;\n readonly observe?: boolean;\n};\n\nexport type PrivateMessageSendResult = {\n rumor: Rumor;\n wraps: ReadonlyArray<{\n recipient: string;\n wrap: Event;\n results: PoolPublishResult[];\n }>;\n};\n\nexport type ReceivedPrivateMessage = {\n wrap: Event;\n rumor: Rumor;\n};\n\nexport type FetchPrivateMessagesOptions = {\n readonly since?: number;\n readonly until?: number;\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n readonly observe?: boolean;\n};\n\nexport type SubscribePrivateMessagesOptions = {\n readonly since?: number;\n readonly onevent?: (msg: ReceivedPrivateMessage) => void;\n readonly oneose?: () => void;\n readonly onclose?: (reason: string) => void;\n readonly signal?: AbortSignal;\n readonly eoseTimeoutMs?: number;\n readonly observe?: boolean;\n};\n\n/** Client lifecycle, configuration, or abort failure (not cryptographic). */\nexport class ClientError extends NostrError {}\n","import type { Event } from \"../core/event.ts\";\nimport { canonicalizeFilter, type Filter } from \"../core/filter.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\nimport type { EventStore, PutResult } from \"../storage/types.ts\";\nimport { storageFromItems, type NegentropyStorageVector } from \"../nips/nip77.ts\";\nimport { SyncDirection, type SyncOptions, type SyncSummary } from \"./types.ts\";\n\nexport type SyncDeps = {\n pool: Pool;\n storage: EventStore;\n persistEvents: boolean;\n assertAlive: () => void;\n throwIfAborted: (signal?: AbortSignal) => void;\n wantObserve: (flag?: boolean) => boolean;\n ingestMeta: (event: Event) => void;\n defaultRelays: (urls?: string[]) => string[];\n};\n\nconst SYNC_ID_BATCH = 100;\nconst SYNC_UPLOAD_CONCURRENCY = 8;\n\nfunction uniqueIds(ids: readonly string[]): string[] {\n return [...new Set(ids)];\n}\n\nfunction emptySummary(): SyncSummary {\n return {\n local: [],\n remote: [],\n sent: [],\n received: [],\n sendFailures: {},\n persistFailures: {},\n };\n}\n\nfunction mergeSyncSummary(into: SyncSummary, other: SyncSummary): SyncSummary {\n const sendFailures = { ...into.sendFailures, ...other.sendFailures };\n const persistFailures = { ...into.persistFailures, ...other.persistFailures };\n return {\n local: uniqueIds([...into.local, ...other.local]),\n remote: uniqueIds([...into.remote, ...other.remote]),\n sent: uniqueIds([...into.sent, ...other.sent]),\n received: uniqueIds([...into.received, ...other.received]),\n sendFailures,\n persistFailures,\n };\n}\n\n/**\n * NIP-77 sync against one relay: reconcile, then optionally upload\n * local-only events and/or download remote-only events.\n * `observe: false` skips putMany and ingestMeta; received ids are still listed.\n * `persistEvents: false` skips putMany, still ingestMeta when observe is on.\n */\nexport async function syncToRelay(\n deps: SyncDeps,\n url: string,\n filter: Filter,\n opts?: Omit<SyncOptions, \"relays\">,\n): Promise<SyncSummary> {\n deps.assertAlive();\n deps.throwIfAborted(opts?.signal);\n const direction = opts?.direction ?? SyncDirection.Down;\n filter = canonicalizeFilter(filter);\n const items = await deps.storage.negentropyItems(filter);\n const storage: NegentropyStorageVector = storageFromItems(items);\n const relay = await deps.pool.ensureRelay(url, { signal: opts?.signal });\n const { have, need } = await relay.negReconcile(filter, storage, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n\n const summary: SyncSummary = {\n local: have,\n remote: need,\n sent: [],\n received: [],\n sendFailures: {},\n persistFailures: {},\n };\n\n if (opts?.dryRun) return summary;\n\n if (direction === SyncDirection.Up || direction === SyncDirection.Both) {\n if (have.length > 0) {\n const found = await deps.storage.query([{ ids: have }]);\n const foundById = new Map(found.map((event) => [event.id, event]));\n for (const id of have) {\n if (!foundById.has(id)) {\n summary.sendFailures[id] = \"event not found in local store\";\n }\n }\n for (let i = 0; i < found.length; i += SYNC_UPLOAD_CONCURRENCY) {\n const chunk = found.slice(i, i + SYNC_UPLOAD_CONCURRENCY);\n await Promise.all(\n chunk.map(async (event) => {\n try {\n const results = await deps.pool.publish([url], event, {\n timeoutMs: opts?.timeoutMs,\n });\n const ok = results.some((r) => r.result?.ok);\n if (ok) summary.sent.push(event.id);\n else {\n summary.sendFailures[event.id] =\n results[0]?.error ?? results[0]?.result?.message ?? \"publish failed\";\n }\n } catch (error) {\n summary.sendFailures[event.id] =\n error instanceof Error ? error.message : String(error);\n }\n }),\n );\n }\n }\n }\n\n if ((direction === SyncDirection.Down || direction === SyncDirection.Both) && need.length > 0) {\n const shouldObserve = deps.wantObserve(opts?.observe);\n for (let i = 0; i < need.length; i += SYNC_ID_BATCH) {\n const batch = need.slice(i, i + SYNC_ID_BATCH);\n deps.throwIfAborted(opts?.signal);\n const events = await deps.pool.fetch([url], [{ ids: batch }], {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n if (!shouldObserve) {\n for (const event of events) summary.received.push(event.id);\n continue;\n }\n if (!deps.persistEvents) {\n for (const event of events) {\n deps.ingestMeta(event);\n summary.received.push(event.id);\n }\n continue;\n }\n let results: PutResult[];\n try {\n results = await deps.storage.putMany(events);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n for (const event of events) summary.persistFailures[event.id] = message;\n break;\n }\n for (let j = 0; j < events.length; j++) {\n const event = events[j]!;\n if (results[j] === \"rejected\") continue;\n deps.ingestMeta(event);\n summary.received.push(event.id);\n }\n }\n }\n\n return summary;\n}\n\n/**\n * NIP-77 sync against the given relays (or Client default relays).\n * Independent sessions run in parallel. Fulfilled summaries are merged;\n * if every relay rejects, throws the first rejection in URL order.\n */\nexport async function sync(\n deps: SyncDeps,\n filter: Filter,\n opts?: SyncOptions,\n): Promise<SyncSummary> {\n deps.assertAlive();\n const urls = deps.defaultRelays(opts?.relays ? [...opts.relays] : undefined);\n const results = await Promise.allSettled(urls.map((url) => syncToRelay(deps, url, filter, opts)));\n let merged = emptySummary();\n let fulfilled = 0;\n let firstRejection: unknown;\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n fulfilled += 1;\n merged = mergeSyncSummary(merged, result.value);\n } else {\n firstRejection ??= result.reason;\n }\n }\n if (urls.length > 0 && fulfilled === 0) throw firstRejection;\n return merged;\n}\n","import { EventBuilder } from \"../core/builder.ts\";\nimport { sortedEvents, type Event, type EventTemplate, type UnsignedEvent } from \"../core/event.ts\";\nimport { canonicalizeFilters, type Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { Gossip } from \"../gossip/index.ts\";\nimport {\n createLoaders,\n createOutboxFeed,\n type Loaders,\n type OutboxFeed,\n} from \"../loaders/index.ts\";\nimport type { Recipient } from \"../nips/nip17.ts\";\nimport { isGiftWrapKind, requireNip59Crypto, type Nip59Crypto } from \"../nips/nip59.ts\";\nimport { Pool, type PoolPublishResult } from \"../relay/pool.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport { toStorageError, type StorageError } from \"../storage/error.ts\";\nimport { MemoryEventStore } from \"../storage/memory.ts\";\nimport type { EventStore } from \"../storage/types.ts\";\nimport { ClientBuilder } from \"./builder.ts\";\nimport {\n fetchPrivateMessages,\n giftWrapRelays,\n sendPrivateMessage,\n setDmRelays,\n subscribePrivateMessages,\n type DmDeps,\n} from \"./dm.ts\";\nimport { fetchGossip, subscribeGossip } from \"./gossip-io.ts\";\nimport { sync, syncToRelay, type SyncDeps } from \"./sync.ts\";\nimport {\n ClientError,\n type ClientOptions,\n type FetchEventsOptions,\n type FetchPrivateMessagesOptions,\n type PrivateMessageSendResult,\n type PublishOptions,\n type ReceivedPrivateMessage,\n type SendPrivateMessageOptions,\n type SubscribeOptions,\n type SubscribePrivateMessagesOptions,\n type SyncOptions,\n type SyncSummary,\n} from \"./types.ts\";\n\n/**\n * Layer-5 facade: signer + default relays + pool + loaders + gossip + event store.\n */\nexport class Client {\n readonly pool: Pool;\n readonly loaders: Loaders;\n readonly gossip: Gossip;\n readonly storage: EventStore;\n onstorageerror: ((err: StorageError) => void) | null;\n #signer: NostrSigner | undefined;\n #relays: string[];\n #shutdown = false;\n #persistEvents: boolean;\n #persistQueue: Event[] = [];\n #flushing: Promise<void> | undefined;\n\n constructor(opts: ClientOptions = {}) {\n this.#signer = opts.signer;\n this.#relays = [...(opts.relays ?? [])];\n this.gossip = opts.gossip ?? new Gossip();\n this.storage = opts.storage ?? new MemoryEventStore();\n this.#persistEvents = opts.persistEvents ?? true;\n this.onstorageerror = opts.onstorageerror ?? null;\n const autoAuth = opts.automaticAuth ?? Boolean(opts.signer);\n this.pool = new Pool({\n websocketImplementation: opts.websocketImplementation,\n verifyEvent: opts.verifyEvent,\n enablePing: opts.enablePing,\n pingIntervalMs: opts.pingIntervalMs,\n pingTimeoutMs: opts.pingTimeoutMs,\n connectTimeoutMs: opts.connectTimeoutMs,\n publishTimeoutMs: opts.publishTimeoutMs,\n enableReconnect: opts.enableReconnect ?? true,\n automaticallyAuth: autoAuth\n ? () => {\n const signer = this.#signer;\n if (!signer) return null;\n return async (template) => {\n const pk = await signer.getPublicKey();\n return signer.signEvent({ ...template, pubkey: pk });\n };\n }\n : undefined,\n });\n this.loaders = createLoaders({\n pool: this.pool,\n relays: this.#relays,\n });\n }\n\n static builder(): ClientBuilder {\n return new ClientBuilder();\n }\n\n get signer(): NostrSigner | undefined {\n return this.#signer;\n }\n\n get relays(): readonly string[] {\n return this.#relays;\n }\n\n get isShutdown(): boolean {\n return this.#shutdown;\n }\n\n setSigner(signer: NostrSigner): void {\n this.#signer = signer;\n }\n\n addRelay(url: string): void {\n if (!this.#relays.includes(url)) {\n this.#relays.push(url);\n this.loaders.context.addRelay(url);\n }\n }\n\n removeRelay(url: string): void {\n this.#relays = this.#relays.filter((r) => r !== url);\n this.loaders.context.removeRelay(url);\n this.pool.close([url]);\n }\n\n /** Connect all configured relays (best-effort; failures are ignored). */\n async connect(opts?: { signal?: AbortSignal }): Promise<void> {\n this.#assertAlive();\n await Promise.allSettled(\n this.#relays.map((url) => this.pool.ensureRelay(url, { signal: opts?.signal })),\n );\n }\n\n async shutdown(): Promise<void> {\n this.#shutdown = true;\n while (this.#flushing) await this.#flushing;\n this.pool.close();\n this.loaders.context.cache.clear();\n }\n\n #assertAlive(): void {\n if (this.#shutdown) throw new ClientError(\"client is shut down\");\n }\n\n #defaultRelays(urls?: string[]): string[] {\n const list = urls ?? this.#relays;\n if (list.length === 0) throw new ClientError(\"no relays configured\");\n return list;\n }\n\n #wantObserve(flag?: boolean): boolean {\n return flag !== false;\n }\n\n /**\n * Unified ingest pipeline: gossip + replaceable loader cache immediately;\n * storage writes are coalesced into a single-flight `putMany`.\n */\n observe(event: Event): void {\n this.#ingestMeta(event);\n if (!this.#persistEvents) return;\n this.#persistQueue.push(event);\n this.#armFlush();\n }\n\n /** Observe many events (deduped by id, order preserved) as one persist batch. */\n observeAll(events: readonly Event[]): void {\n const seen = new Set<string>();\n for (const event of events) {\n if (seen.has(event.id)) continue;\n seen.add(event.id);\n this.#ingestMeta(event);\n if (this.#persistEvents) this.#persistQueue.push(event);\n }\n if (this.#persistEvents && this.#persistQueue.length > 0) this.#armFlush();\n }\n\n #ingestMeta(event: Event): void {\n this.gossip.ingest(event);\n if (\n event.kind === Kind.Metadata ||\n event.kind === Kind.Contacts ||\n event.kind === Kind.MuteList ||\n event.kind === Kind.RelayList ||\n event.kind === Kind.DirectMessageRelaysList\n ) {\n this.loaders.context.cache.putIfNewer(event);\n }\n }\n\n #armFlush(): void {\n if (this.#flushing) return;\n this.#flushing = this.#flushLoop();\n }\n\n async #flushLoop(): Promise<void> {\n try {\n await new Promise<void>((resolve) => {\n queueMicrotask(resolve);\n });\n while (this.#persistQueue.length > 0) {\n const batch = this.#persistQueue.splice(0);\n try {\n await this.storage.putMany(batch);\n } catch (err) {\n this.onstorageerror?.(toStorageError(err));\n }\n }\n } finally {\n this.#flushing = undefined;\n if (this.#persistQueue.length > 0) this.#armFlush();\n }\n }\n\n /**\n * Explicitly load kind:10002 and kind:10050 lists for pubkeys and feed gossip.\n * Does not background-fetch unknown authors on every subscribe (predictable DX).\n */\n async hydrateGossip(\n pubkeys: readonly string[],\n opts?: { hints?: string[]; force?: boolean },\n ): Promise<void> {\n this.#assertAlive();\n await Promise.all(\n pubkeys.map(async (pk) => {\n const style = opts?.force ? \"force\" : \"default\";\n const [relayList, dmList] = await Promise.all([\n this.loaders.relayList(pk, { hints: opts?.hints, style }),\n this.loaders.dmRelayList(pk, { hints: opts?.hints, style }),\n ]);\n if (relayList.event) this.observe(relayList.event);\n if (dmList.event) this.observe(dmList.event);\n }),\n );\n }\n\n /**\n * Create an outbox-model feed for the given authors (NIP-65 write relays).\n * Live events go through {@link observe}; sync persists via applySync.\n */\n outbox(opts: {\n authors: readonly string[];\n kinds?: readonly number[];\n onEvent?: (event: Event) => void;\n maxRelaysPerAuthor?: number;\n }): OutboxFeed {\n this.#assertAlive();\n return createOutboxFeed({\n pool: this.pool,\n gossip: this.gossip,\n storage: this.storage,\n discoveryRelays: this.#relays,\n authors: opts.authors,\n kinds: opts.kinds,\n onEvent: opts.onEvent,\n maxRelaysPerAuthor: opts.maxRelaysPerAuthor,\n observe: (event) => this.observe(event),\n applySync: async (events) => {\n if (!this.#persistEvents) {\n for (const event of events) this.#ingestMeta(event);\n return [];\n }\n const results = await this.storage.putMany(events);\n const applied: Event[] = [];\n for (let i = 0; i < events.length; i++) {\n if (results[i] === \"rejected\" || results[i] === \"ephemeral\") continue;\n this.#ingestMeta(events[i]!);\n applied.push(events[i]!);\n }\n return applied;\n },\n hydrate: (pubkeys) => this.hydrateGossip(pubkeys),\n });\n }\n\n async getPublicKey(): Promise<string> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return this.#signer.getPublicKey();\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return this.#signer.signEvent(unsigned);\n }\n\n async signEventBuilder(builder: EventBuilder): Promise<Event> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return builder.sign(this.#signer);\n }\n\n async signTemplate(template: EventTemplate): Promise<Event> {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n const pubkey = await this.#signer.getPublicKey();\n return this.#signer.signEvent({ ...template, pubkey });\n }\n\n /**\n * Sign (if builder) and publish to relays.\n * With `gossip: true`, prefers the author's NIP-65 outbox relays, tagged `p`\n * inboxes, and up to 5 `e`/`a` tag relay hints when known.\n * On any successful OK, observes the event into storage/gossip.\n */\n async publish(\n eventOrBuilder: Event | EventBuilder,\n opts?: PublishOptions,\n ): Promise<PoolPublishResult[]> {\n this.#assertAlive();\n const event =\n eventOrBuilder instanceof EventBuilder\n ? await this.signEventBuilder(eventOrBuilder)\n : eventOrBuilder;\n\n let relays = opts?.relays;\n if (!relays && isGiftWrapKind(event.kind)) {\n relays = giftWrapRelays(this.gossip, event);\n } else if (!relays && opts?.gossip) {\n const urls: string[] = [];\n const add = (list: readonly string[]) => {\n for (const url of list) {\n if (!urls.includes(url)) urls.push(url);\n }\n };\n add(this.gossip.outboxRelays(event.pubkey));\n for (const tag of event.tags) {\n if (tag[0] === \"p\" && tag[1]) add(this.gossip.inboxRelays(tag[1]));\n }\n let hintCount = 0;\n for (const tag of event.tags) {\n if (hintCount >= 5) break;\n if ((tag[0] !== \"e\" && tag[0] !== \"a\") || !tag[2]) continue;\n try {\n const url = normalizeURL(tag[2]);\n if (!urls.includes(url)) {\n urls.push(url);\n hintCount += 1;\n }\n } catch {\n // not a relay URL\n }\n }\n if (urls.length > 0) relays = urls;\n }\n const results = await this.pool.publish(this.#defaultRelays(relays), event, {\n timeoutMs: opts?.timeoutMs,\n });\n\n const anyOk = results.some((r) => r.result?.ok);\n if (anyOk && this.#wantObserve(opts?.observe)) {\n this.observe(event);\n }\n return results;\n }\n\n /**\n * Fetch events. With `gossip: true`, routes filters by NIP-65 when possible.\n * With `localFirst: true`, merges storage hits with network results.\n */\n async fetchEvents(filter: Filter | Filter[], opts?: FetchEventsOptions): Promise<Event[]> {\n this.#assertAlive();\n const filters = canonicalizeFilters(Array.isArray(filter) ? filter : [filter]);\n const shouldObserve = this.#wantObserve(opts?.observe);\n const byId = new Map<string, Event>();\n\n if (opts?.localFirst) {\n try {\n const local = await this.storage.query(filters);\n for (const e of local) byId.set(e.id, e);\n } catch (err) {\n this.onstorageerror?.(toStorageError(err));\n }\n }\n\n const ingest = (events: Event[]) => {\n for (const e of events) {\n byId.set(e.id, e);\n if (shouldObserve) this.observe(e);\n }\n };\n\n if (!opts?.gossip || opts.relays) {\n ingest(\n await this.pool.fetch(this.#defaultRelays(opts?.relays), filters, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n }),\n );\n return sortedEvents([...byId.values()]);\n }\n\n ingest(\n await fetchGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n }),\n );\n return sortedEvents([...byId.values()]);\n }\n\n /**\n * Query local storage only (no network).\n */\n async queryLocal(filter: Filter | Filter[]): Promise<Event[]> {\n this.#assertAlive();\n const filters = canonicalizeFilters(Array.isArray(filter) ? filter : [filter]);\n return this.storage.query(filters);\n }\n\n subscribe(\n filter: Filter | Filter[],\n opts?: SubscribeOptions,\n ): { close: (reason?: string) => void } {\n this.#assertAlive();\n const filters = canonicalizeFilters(Array.isArray(filter) ? filter : [filter]);\n const shouldObserve = this.#wantObserve(opts?.observe);\n\n const wrapEvent = (event: Event) => {\n if (shouldObserve) this.observe(event);\n opts?.onevent?.(event);\n };\n\n if (!opts?.gossip || opts.relays) {\n return this.pool.subscribe(this.#defaultRelays(opts?.relays), filters, {\n onevent: wrapEvent,\n oneose: opts?.oneose,\n onclose: opts?.onclose,\n signal: opts?.signal,\n id: opts?.id,\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n });\n }\n\n return subscribeGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {\n onevent: wrapEvent,\n oneose: opts?.oneose,\n onclose: opts?.onclose,\n signal: opts?.signal,\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n });\n }\n\n #requireNip59Crypto(): Nip59Crypto {\n if (!this.#signer) throw new ClientError(\"no signer configured\");\n return requireNip59Crypto(this.#signer);\n }\n\n #throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return;\n if (signal.reason instanceof Error) throw signal.reason;\n throw new ClientError(\"aborted\");\n }\n\n #dmDeps(): DmDeps {\n return {\n pool: this.pool,\n gossip: this.gossip,\n hydrateGossip: (pubkeys) => this.hydrateGossip(pubkeys),\n observe: (event) => this.observe(event),\n assertAlive: () => this.#assertAlive(),\n requireNip59Crypto: () => this.#requireNip59Crypto(),\n throwIfAborted: (signal) => this.#throwIfAborted(signal),\n wantObserve: (flag) => this.#wantObserve(flag),\n publish: (eventOrBuilder, opts) => this.publish(eventOrBuilder, opts),\n };\n }\n\n #syncDeps(): SyncDeps {\n return {\n pool: this.pool,\n storage: this.storage,\n persistEvents: this.#persistEvents,\n assertAlive: () => this.#assertAlive(),\n throwIfAborted: (signal) => this.#throwIfAborted(signal),\n wantObserve: (flag) => this.#wantObserve(flag),\n ingestMeta: (event) => this.#ingestMeta(event),\n defaultRelays: (urls) => this.#defaultRelays(urls),\n };\n }\n\n /** Publish a kind:10050 NIP-17 DM relay list (`relay` tags). Not kind 10002. */\n async setDmRelays(\n relays: readonly string[],\n opts?: PublishOptions,\n ): Promise<PoolPublishResult[]> {\n return setDmRelays(this.#dmDeps(), relays, opts);\n }\n\n async sendPrivateMessage(\n recipients: string | Recipient | readonly (string | Recipient)[],\n content: string,\n opts?: SendPrivateMessageOptions,\n ): Promise<PrivateMessageSendResult> {\n return sendPrivateMessage(this.#dmDeps(), recipients, content, opts);\n }\n\n async fetchPrivateMessages(\n opts?: FetchPrivateMessagesOptions,\n ): Promise<ReceivedPrivateMessage[]> {\n return fetchPrivateMessages(this.#dmDeps(), opts);\n }\n\n async subscribePrivateMessages(\n opts?: SubscribePrivateMessagesOptions,\n ): Promise<{ close: (reason?: string) => void }> {\n return subscribePrivateMessages(this.#dmDeps(), opts);\n }\n\n /**\n * NIP-77 sync against one relay: reconcile, then optionally upload\n * local-only events and/or download remote-only events.\n * `observe: false` skips putMany and ingestMeta; received ids are still listed.\n * `persistEvents: false` skips putMany, still ingestMeta when observe is on.\n */\n async syncToRelay(\n url: string,\n filter: Filter,\n opts?: Omit<SyncOptions, \"relays\">,\n ): Promise<SyncSummary> {\n return syncToRelay(this.#syncDeps(), url, filter, opts);\n }\n\n /**\n * NIP-77 sync against the given relays (or Client default relays).\n * Independent sessions run in parallel. Fulfilled summaries are merged;\n * if every relay rejects, throws the first rejection in URL order.\n */\n async sync(filter: Filter, opts?: SyncOptions): Promise<SyncSummary> {\n return sync(this.#syncDeps(), filter, opts);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { a as FetchPrivateMessagesOptions, c as ReceivedPrivateMessage, d as SubscribePrivateMessagesOptions, f as SyncDirection, g as ClientBuilder, h as SyncSummary, i as FetchEventsOptions, l as SendPrivateMessageOptions, m as SyncOptions, n as ClientError, o as PrivateMessageSendResult, p as SyncDirectionName, r as ClientOptions, s as PublishOptions, t as Client, u as SubscribeOptions } from "./index-DgOugrpF.mjs";
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 };
@@ -0,0 +1,2 @@
1
+ import { i as ClientBuilder, n as ClientError, r as SyncDirection, t as Client } from "./client-Bd8B1mYm.mjs";
2
+ export { Client, ClientBuilder, ClientError, SyncDirection };
@@ -0,0 +1,8 @@
1
+ import { C as isTag, E as tagValue, S as getDTag, T as tagName, _ as EventAddress, a as isMarkedFailed, b as eventAddress, c as itemCompare, d as serializeEvent, f as signedMatchesUnsigned, g as validateSignedEvent, h as validateEvent, i as getEventHash, l as markUnverified, m as sortedEvents, n as EventTemplate, o as isMarkedVerified, p as sortEvents, r as UnsignedEvent, s as isReplaceableWinner, t as Event, u as markVerified, v as Tag, w as parseEventAddress, x as formatEventAddress, y as TagInput } from "./event-B5D2jxt_.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-BiGxGLhg.mjs";
3
+ import { n as ProfileMetadata, t as EventBuilder } from "./builder-BphJa-Y-.mjs";
4
+ import { a as filterFingerprint, c as matchFilters, i as cloneFilter, l as mergeFilters, n as canonicalizeFilter, o as getFilterLimit, r as canonicalizeFilters, s as matchFilter, t as Filter } from "./filter-DUEKP3q1.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-DJC-Jz6T.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-WEFS-R-4.mjs";
7
+ import { C as SUBSCRIPTION_ID_MAX_CHARS, S as SIGNATURE_BYTES, _ as utf8Decoder, a as classifyKind, b as PUBLIC_KEY_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 utf8Encoder, x as SECRET_KEY_BYTES, y as EVENT_ID_BYTES } from "./index-DaRyjo7O.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, 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 };
package/dist/core.mjs ADDED
@@ -0,0 +1,9 @@
1
+ import { a as isHex32, c as utf8Decoder, d as PUBLIC_KEY_BYTES, f as SECRET_KEY_BYTES, i as hexToBytes, l as utf8Encoder, m as SUBSCRIPTION_ID_MAX_CHARS, n as assertSecretKeyBytes, o as isHex64, p as SIGNATURE_BYTES, r as bytesToHex, s as normalizeURL, t as assertHex32, u as EVENT_ID_BYTES } from "./util-6tfLQ9JF.mjs";
2
+ import { a as NostrError, i as MessageError, n as EventValidationError, o as UrlError, r as HexError, s as WasmVerifyPoisonedError, t as CryptoError } from "./error-DZEs5OuZ.mjs";
3
+ import { a as isRegularKind, i as isEphemeralKind, n as classifyKind, o as isReplaceableKind, r as isAddressableKind, t as Kind } from "./kind-BLl4cLOc.mjs";
4
+ import { _ as getDTag, a as itemCompare, b as tagName, c as serializeEvent, d as sortedEvents, f as validateEvent, g as formatEventAddress, h as eventAddress, i as isReplaceableWinner, l as signedMatchesUnsigned, m as Tag, n as isMarkedFailed, o as markUnverified, p as validateSignedEvent, r as isMarkedVerified, s as markVerified, t as getEventHash, u as sortEvents, v as isTag, x as tagValue, y as parseEventAddress } from "./event-CzoQEFMF.mjs";
5
+ import { a as publicKeyFromHex, i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as verifyEvent, t as Keys } from "./key-Dn-aX4x4.mjs";
6
+ import { t as EventBuilder } from "./builder-q0VsvnYE.mjs";
7
+ import { a as getFilterLimit, c as mergeFilters, i as filterFingerprint, n as canonicalizeFilters, o as matchFilter, r as cloneFilter, s as matchFilters, t as canonicalizeFilter } from "./filter-BxwjEkZp.mjs";
8
+ import { a as mergeCountHll, i as encodeRelayMessage, n as createSubscriptionId, o as parseClientMessage, r as encodeClientMessage, s as parseRelayMessage, t as assertSubscriptionId } from "./message-C_Uj-Y-c.mjs";
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 };
@@ -0,0 +1,7 @@
1
+ import { a as NostrError } from "./error-WEFS-R-4.mjs";
2
+ //#region src/storage/error.d.ts
3
+ /** Event-store I/O failure. Message must not include event content. */
4
+ declare class StorageError extends NostrError {}
5
+ //#endregion
6
+ export { StorageError as t };
7
+ //# sourceMappingURL=error-B49rbDzT.d.mts.map
@@ -0,0 +1,13 @@
1
+ import { a as NostrError } from "./error-DZEs5OuZ.mjs";
2
+ //#region src/storage/error.ts
3
+ /** Event-store I/O failure. Message must not include event content. */
4
+ var StorageError = class extends NostrError {};
5
+ function toStorageError(err) {
6
+ if (err instanceof StorageError) return err;
7
+ if (err instanceof Error) return new StorageError(err.message, { cause: err });
8
+ return new StorageError(String(err));
9
+ }
10
+ //#endregion
11
+ export { toStorageError as n, StorageError as t };
12
+
13
+ //# sourceMappingURL=error-CwBxle6N.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-CwBxle6N.mjs","names":[],"sources":["../src/storage/error.ts"],"sourcesContent":["import { NostrError } from \"../core/error.ts\";\n\n/** Event-store I/O failure. Message must not include event content. */\nexport class StorageError extends NostrError {}\n\nexport function toStorageError(err: unknown): StorageError {\n if (err instanceof StorageError) return err;\n if (err instanceof Error) return new StorageError(err.message, { cause: err });\n return new StorageError(String(err));\n}\n"],"mappings":";;;AAGA,IAAa,eAAb,cAAkC,WAAW,CAAC;AAE9C,SAAgB,eAAe,KAA4B;CACzD,IAAI,eAAe,cAAc,OAAO;CACxC,IAAI,eAAe,OAAO,OAAO,IAAI,aAAa,IAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7E,OAAO,IAAI,aAAa,OAAO,GAAG,CAAC;AACrC"}
@@ -0,0 +1,24 @@
1
+ //#region src/core/error.ts
2
+ /** Base error for all @qntx/nostr failures. */
3
+ var NostrError = class extends Error {
4
+ constructor(message, options) {
5
+ super(message, options);
6
+ this.name = new.target.name;
7
+ }
8
+ };
9
+ /** Invalid hex encoding or length. */
10
+ var HexError = class extends NostrError {};
11
+ /** Invalid URL / relay URL. */
12
+ var UrlError = class extends NostrError {};
13
+ /** Event shape / wire validation failure. */
14
+ var EventValidationError = class extends NostrError {};
15
+ /** Cryptographic operation failure (keys, signatures). */
16
+ var CryptoError = class extends NostrError {};
17
+ /** Message parse / encode failure. */
18
+ var MessageError = class extends NostrError {};
19
+ /** Wasm verify instance aborted; later verifies on that instance fail. */
20
+ var WasmVerifyPoisonedError = class extends NostrError {};
21
+ //#endregion
22
+ export { NostrError as a, MessageError as i, EventValidationError as n, UrlError as o, HexError as r, WasmVerifyPoisonedError as s, CryptoError as t };
23
+
24
+ //# sourceMappingURL=error-DZEs5OuZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-DZEs5OuZ.mjs","names":[],"sources":["../src/core/error.ts"],"sourcesContent":["/** Base error for all @qntx/nostr failures. */\nexport class NostrError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\n/** Invalid hex encoding or length. */\nexport class HexError extends NostrError {}\n\n/** Invalid URL / relay URL. */\nexport class UrlError extends NostrError {}\n\n/** Event shape / wire validation failure. */\nexport class EventValidationError extends NostrError {}\n\n/** Cryptographic operation failure (keys, signatures). */\nexport class CryptoError extends NostrError {}\n\n/** Message parse / encode failure. */\nexport class MessageError extends NostrError {}\n\n/** Wasm verify instance aborted; later verifies on that instance fail. */\nexport class WasmVerifyPoisonedError extends NostrError {}\n"],"mappings":";;AACA,IAAa,aAAb,cAAgC,MAAM;CACpC,YAAY,SAAiB,SAAwB;EACnD,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO,WAAW;CACzB;AACF;;AAGA,IAAa,WAAb,cAA8B,WAAW,CAAC;;AAG1C,IAAa,WAAb,cAA8B,WAAW,CAAC;;AAG1C,IAAa,uBAAb,cAA0C,WAAW,CAAC;;AAGtD,IAAa,cAAb,cAAiC,WAAW,CAAC;;AAG7C,IAAa,eAAb,cAAkC,WAAW,CAAC;;AAG9C,IAAa,0BAAb,cAA6C,WAAW,CAAC"}
@@ -0,0 +1,20 @@
1
+ //#region src/core/error.d.ts
2
+ /** Base error for all @qntx/nostr failures. */
3
+ declare class NostrError extends Error {
4
+ constructor(message: string, options?: ErrorOptions);
5
+ }
6
+ /** Invalid hex encoding or length. */
7
+ declare class HexError extends NostrError {}
8
+ /** Invalid URL / relay URL. */
9
+ declare class UrlError extends NostrError {}
10
+ /** Event shape / wire validation failure. */
11
+ declare class EventValidationError extends NostrError {}
12
+ /** Cryptographic operation failure (keys, signatures). */
13
+ declare class CryptoError extends NostrError {}
14
+ /** Message parse / encode failure. */
15
+ declare class MessageError extends NostrError {}
16
+ /** Wasm verify instance aborted; later verifies on that instance fail. */
17
+ declare class WasmVerifyPoisonedError extends NostrError {}
18
+ //#endregion
19
+ 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-WEFS-R-4.d.mts.map
@@ -0,0 +1,108 @@
1
+ //#region src/core/tag.d.ts
2
+ /** A NIP-01 tag: first element is the name, rest are values. */
3
+ type Tag = readonly string[];
4
+ /** Mutable tag builder input. */
5
+ type TagInput = string[];
6
+ declare function isTag(value: unknown): value is Tag;
7
+ declare function tagName(tag: Tag): string;
8
+ declare function tagValue(tag: Tag): string | undefined;
9
+ /** Construct common tags. */
10
+ declare const Tag: {
11
+ readonly e: (id: string, relay?: string, marker?: string, pubkey?: string) => Tag;
12
+ readonly p: (pubkey: string, relay?: string, petname?: string) => Tag;
13
+ readonly a: (coordinate: string, relay?: string) => Tag;
14
+ readonly d: (identifier: string) => Tag;
15
+ readonly t: (hashtag: string) => Tag;
16
+ readonly r: (url: string, marker?: string) => Tag;
17
+ readonly k: (kind: number | string) => Tag;
18
+ };
19
+ /** First `d` tag value on an event, if any. */
20
+ declare function getDTag(tags: readonly Tag[]): string | undefined;
21
+ /** NIP-01 `a` tag: `kind:pubkey:identifier` (identifier may be empty and may contain extra colons). */
22
+ type EventAddress = {
23
+ kind: number;
24
+ pubkey: string;
25
+ identifier: string;
26
+ };
27
+ /** Parse a NIP-01 addressable/replaceable coordinate. */
28
+ declare function parseEventAddress(value: string): EventAddress | undefined;
29
+ declare function formatEventAddress(kind: number, pubkey: string, identifier?: string): string;
30
+ /**
31
+ * Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events.
32
+ * Undefined for regular/ephemeral kinds.
33
+ */
34
+ declare function eventAddress(event: {
35
+ kind: number;
36
+ pubkey: string;
37
+ tags: readonly Tag[];
38
+ }): string | undefined;
39
+ //#endregion
40
+ //#region src/core/event.d.ts
41
+ /** Wire event template before pubkey/id/sig. */
42
+ type EventTemplate = {
43
+ readonly kind: number;
44
+ readonly tags: readonly Tag[];
45
+ readonly content: string;
46
+ readonly created_at: number;
47
+ };
48
+ /** Event with pubkey, ready to hash and sign. */
49
+ type UnsignedEvent = EventTemplate & {
50
+ readonly pubkey: string;
51
+ };
52
+ /**
53
+ * Fully formed NIP-01 event (JSON-friendly plain object).
54
+ * Fields are readonly at the type level; wire interop remains plain JSON.
55
+ */
56
+ type Event = UnsignedEvent & {
57
+ readonly id: string;
58
+ readonly sig: string;
59
+ };
60
+ declare function markVerified(event: Event): void;
61
+ declare function markUnverified(event: Event): void;
62
+ declare function isMarkedVerified(event: Event): boolean;
63
+ declare function isMarkedFailed(event: Event): boolean;
64
+ /** Structural validation of an unsigned event (no crypto). */
65
+ declare function validateEvent(event: unknown): event is UnsignedEvent;
66
+ /** Structural validation of a full event including id and sig hex shape. */
67
+ declare function validateSignedEvent(event: unknown): event is Event;
68
+ /**
69
+ * Canonical NIP-01 serialization used for hashing:
70
+ * JSON array `[0, pubkey, created_at, kind, tags, content]` with no extra whitespace.
71
+ */
72
+ declare function serializeEvent(event: UnsignedEvent): string;
73
+ /** SHA-256 of the canonical serialization, lowercase hex. */
74
+ declare function getEventHash(event: UnsignedEvent): string;
75
+ /**
76
+ * Sort events reverse-chronologically by `created_at`, then by `id` lexicographically.
77
+ * Mutates and returns the array.
78
+ */
79
+ declare function sortEvents(events: Event[]): Event[];
80
+ /** Non-mutating sort; returns a new array. */
81
+ declare function sortedEvents(events: readonly Event[]): Event[];
82
+ /**
83
+ * Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`).
84
+ * Time axis is opposite {@link sortEvents}; id tie-break is the same direction.
85
+ */
86
+ declare function itemCompare(a: {
87
+ id: string;
88
+ created_at: number;
89
+ }, b: {
90
+ id: string;
91
+ created_at: number;
92
+ }): number;
93
+ /**
94
+ * NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp
95
+ * and lexicographically lower `id`.
96
+ */
97
+ declare function isReplaceableWinner(candidate: {
98
+ created_at: number;
99
+ id: string;
100
+ }, incumbent: {
101
+ created_at: number;
102
+ id: string;
103
+ }): boolean;
104
+ /** True when a signed event is the signed form of `unsigned` (kind/tags/content/time/pubkey). */
105
+ declare function signedMatchesUnsigned(signed: Event, unsigned: UnsignedEvent): boolean;
106
+ //#endregion
107
+ export { isTag as C, tagValue as E, getDTag as S, tagName as T, EventAddress as _, isMarkedFailed as a, eventAddress as b, itemCompare as c, serializeEvent as d, signedMatchesUnsigned as f, validateSignedEvent as g, validateEvent as h, getEventHash as i, markUnverified as l, sortedEvents as m, EventTemplate as n, isMarkedVerified as o, sortEvents as p, UnsignedEvent as r, isReplaceableWinner as s, Event as t, markVerified as u, Tag as v, parseEventAddress as w, formatEventAddress as x, TagInput as y };
108
+ //# sourceMappingURL=event-B5D2jxt_.d.mts.map
@@ -0,0 +1,188 @@
1
+ import { a as isHex32, l as utf8Encoder, o as isHex64, r as bytesToHex } from "./util-6tfLQ9JF.mjs";
2
+ import { n as EventValidationError } from "./error-DZEs5OuZ.mjs";
3
+ import { o as isReplaceableKind, r as isAddressableKind } from "./kind-BLl4cLOc.mjs";
4
+ import { sha256 } from "@noble/hashes/sha2.js";
5
+ //#region src/core/tag.ts
6
+ function isTag(value) {
7
+ if (!Array.isArray(value) || value.length === 0) return false;
8
+ for (const item of value) if (typeof item !== "string") return false;
9
+ return true;
10
+ }
11
+ function tagName(tag) {
12
+ return tag[0];
13
+ }
14
+ function tagValue(tag) {
15
+ return tag[1];
16
+ }
17
+ /** Construct common tags. */
18
+ const Tag = {
19
+ e(id, relay, marker, pubkey) {
20
+ const t = ["e", id.toLowerCase()];
21
+ if (relay !== void 0) t.push(relay);
22
+ if (marker !== void 0) t.push(marker);
23
+ if (pubkey !== void 0) t.push(pubkey.toLowerCase());
24
+ return t;
25
+ },
26
+ p(pubkey, relay, petname) {
27
+ const t = ["p", pubkey.toLowerCase()];
28
+ if (relay !== void 0) t.push(relay);
29
+ if (petname !== void 0) t.push(petname);
30
+ return t;
31
+ },
32
+ a(coordinate, relay) {
33
+ const t = ["a", coordinate];
34
+ if (relay !== void 0) t.push(relay);
35
+ return t;
36
+ },
37
+ d(identifier) {
38
+ return ["d", identifier];
39
+ },
40
+ t(hashtag) {
41
+ return ["t", hashtag];
42
+ },
43
+ r(url, marker) {
44
+ const t = ["r", url];
45
+ if (marker !== void 0) t.push(marker);
46
+ return t;
47
+ },
48
+ k(kind) {
49
+ return ["k", String(kind)];
50
+ }
51
+ };
52
+ /** First `d` tag value on an event, if any. */
53
+ function getDTag(tags) {
54
+ for (const tag of tags) if (tag[0] === "d" && tag[1] !== void 0) return tag[1];
55
+ }
56
+ /** Parse a NIP-01 addressable/replaceable coordinate. */
57
+ function parseEventAddress(value) {
58
+ const first = value.indexOf(":");
59
+ if (first <= 0) return void 0;
60
+ const second = value.indexOf(":", first + 1);
61
+ if (second < 0) return void 0;
62
+ const kind = Number(value.slice(0, first));
63
+ if (!Number.isInteger(kind) || kind < 0 || kind > 65535) return void 0;
64
+ const pubkey = value.slice(first + 1, second).toLowerCase();
65
+ if (!isHex32(pubkey)) return void 0;
66
+ return {
67
+ kind,
68
+ pubkey,
69
+ identifier: value.slice(second + 1)
70
+ };
71
+ }
72
+ function formatEventAddress(kind, pubkey, identifier = "") {
73
+ return `${kind}:${pubkey.toLowerCase()}:${identifier}`;
74
+ }
75
+ /**
76
+ * Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events.
77
+ * Undefined for regular/ephemeral kinds.
78
+ */
79
+ function eventAddress(event) {
80
+ if (isAddressableKind(event.kind)) return formatEventAddress(event.kind, event.pubkey, getDTag(event.tags) ?? "");
81
+ if (isReplaceableKind(event.kind)) return formatEventAddress(event.kind, event.pubkey, "");
82
+ }
83
+ //#endregion
84
+ //#region src/core/event.ts
85
+ /** Cache of events whose signatures have been verified successfully. */
86
+ const verifiedEvents = /* @__PURE__ */ new WeakSet();
87
+ /** Cache of events known to fail verification. */
88
+ const failedEvents = /* @__PURE__ */ new WeakSet();
89
+ function markVerified(event) {
90
+ verifiedEvents.add(event);
91
+ failedEvents.delete(event);
92
+ }
93
+ function markUnverified(event) {
94
+ failedEvents.add(event);
95
+ verifiedEvents.delete(event);
96
+ }
97
+ function isMarkedVerified(event) {
98
+ return verifiedEvents.has(event);
99
+ }
100
+ function isMarkedFailed(event) {
101
+ return failedEvents.has(event);
102
+ }
103
+ const isRecord = (obj) => typeof obj === "object" && obj !== null && !Array.isArray(obj);
104
+ /** Structural validation of an unsigned event (no crypto). */
105
+ function validateEvent(event) {
106
+ if (!isRecord(event)) return false;
107
+ if (typeof event.kind !== "number" || !Number.isInteger(event.kind) || event.kind < 0 || event.kind > 65535) return false;
108
+ if (typeof event.content !== "string") return false;
109
+ if (typeof event.created_at !== "number" || !Number.isInteger(event.created_at)) return false;
110
+ if (typeof event.pubkey !== "string" || !isHex32(event.pubkey)) return false;
111
+ if (!Array.isArray(event.tags)) return false;
112
+ for (const tag of event.tags) if (!isTag(tag)) return false;
113
+ return true;
114
+ }
115
+ /** Structural validation of a full event including id and sig hex shape. */
116
+ function validateSignedEvent(event) {
117
+ if (!validateEvent(event)) return false;
118
+ const e = event;
119
+ if (typeof e.id !== "string" || !isHex32(e.id)) return false;
120
+ if (typeof e.sig !== "string" || !isHex64(e.sig)) return false;
121
+ return true;
122
+ }
123
+ /**
124
+ * Canonical NIP-01 serialization used for hashing:
125
+ * JSON array `[0, pubkey, created_at, kind, tags, content]` with no extra whitespace.
126
+ */
127
+ function serializeEvent(event) {
128
+ if (!validateEvent(event)) throw new EventValidationError("cannot serialize event with invalid shape");
129
+ return JSON.stringify([
130
+ 0,
131
+ event.pubkey.toLowerCase(),
132
+ event.created_at,
133
+ event.kind,
134
+ event.tags,
135
+ event.content
136
+ ]);
137
+ }
138
+ /** SHA-256 of the canonical serialization, lowercase hex. */
139
+ function getEventHash(event) {
140
+ const serialized = serializeEvent(event);
141
+ return bytesToHex(sha256(utf8Encoder.encode(serialized)));
142
+ }
143
+ function compareEventsDesc(a, b) {
144
+ if (a.created_at !== b.created_at) return b.created_at - a.created_at;
145
+ return a.id.localeCompare(b.id);
146
+ }
147
+ /**
148
+ * Sort events reverse-chronologically by `created_at`, then by `id` lexicographically.
149
+ * Mutates and returns the array.
150
+ */
151
+ function sortEvents(events) {
152
+ return events.sort(compareEventsDesc);
153
+ }
154
+ /** Non-mutating sort; returns a new array. */
155
+ function sortedEvents(events) {
156
+ return events.slice().sort(compareEventsDesc);
157
+ }
158
+ /**
159
+ * Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`).
160
+ * Time axis is opposite {@link sortEvents}; id tie-break is the same direction.
161
+ */
162
+ function itemCompare(a, b) {
163
+ if (a.created_at !== b.created_at) return a.created_at - b.created_at;
164
+ if (a.id < b.id) return -1;
165
+ if (a.id > b.id) return 1;
166
+ return 0;
167
+ }
168
+ /**
169
+ * NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp
170
+ * and lexicographically lower `id`.
171
+ */
172
+ function isReplaceableWinner(candidate, incumbent) {
173
+ if (candidate.created_at !== incumbent.created_at) return candidate.created_at > incumbent.created_at;
174
+ return candidate.id < incumbent.id;
175
+ }
176
+ /** True when a signed event is the signed form of `unsigned` (kind/tags/content/time/pubkey). */
177
+ function signedMatchesUnsigned(signed, unsigned) {
178
+ if (signed.kind !== unsigned.kind) return false;
179
+ if (signed.content !== unsigned.content) return false;
180
+ if (signed.created_at !== unsigned.created_at) return false;
181
+ if (JSON.stringify(signed.tags) !== JSON.stringify(unsigned.tags)) return false;
182
+ if (unsigned.pubkey && signed.pubkey.toLowerCase() !== unsigned.pubkey.toLowerCase()) return false;
183
+ return true;
184
+ }
185
+ //#endregion
186
+ export { getDTag as _, itemCompare as a, tagName as b, serializeEvent as c, sortedEvents as d, validateEvent as f, formatEventAddress as g, eventAddress as h, isReplaceableWinner as i, signedMatchesUnsigned as l, Tag as m, isMarkedFailed as n, markUnverified as o, validateSignedEvent as p, isMarkedVerified as r, markVerified as s, getEventHash as t, sortEvents as u, isTag as v, tagValue as x, parseEventAddress as y };
187
+
188
+ //# sourceMappingURL=event-CzoQEFMF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-CzoQEFMF.mjs","names":[],"sources":["../src/core/tag.ts","../src/core/event.ts"],"sourcesContent":["import { isAddressableKind, isReplaceableKind } from \"./kind.ts\";\nimport { isHex32 } from \"./util.ts\";\n\n/** A NIP-01 tag: first element is the name, rest are values. */\nexport type Tag = readonly string[];\n\n/** Mutable tag builder input. */\nexport type TagInput = string[];\n\nexport function isTag(value: unknown): value is Tag {\n if (!Array.isArray(value) || value.length === 0) return false;\n for (const item of value) {\n if (typeof item !== \"string\") return false;\n }\n return true;\n}\n\nexport function tagName(tag: Tag): string {\n return tag[0];\n}\n\nexport function tagValue(tag: Tag): string | undefined {\n return tag[1];\n}\n\n/** Construct common tags. */\nexport const Tag = {\n e(id: string, relay?: string, marker?: string, pubkey?: string): Tag {\n const t: string[] = [\"e\", id.toLowerCase()];\n if (relay !== undefined) t.push(relay);\n if (marker !== undefined) t.push(marker);\n if (pubkey !== undefined) t.push(pubkey.toLowerCase());\n return t;\n },\n p(pubkey: string, relay?: string, petname?: string): Tag {\n const t: string[] = [\"p\", pubkey.toLowerCase()];\n if (relay !== undefined) t.push(relay);\n if (petname !== undefined) t.push(petname);\n return t;\n },\n a(coordinate: string, relay?: string): Tag {\n const t: string[] = [\"a\", coordinate];\n if (relay !== undefined) t.push(relay);\n return t;\n },\n d(identifier: string): Tag {\n return [\"d\", identifier];\n },\n t(hashtag: string): Tag {\n return [\"t\", hashtag];\n },\n r(url: string, marker?: string): Tag {\n const t: string[] = [\"r\", url];\n if (marker !== undefined) t.push(marker);\n return t;\n },\n k(kind: number | string): Tag {\n return [\"k\", String(kind)];\n },\n} as const;\n\n/** First `d` tag value on an event, if any. */\nexport function getDTag(tags: readonly Tag[]): string | undefined {\n for (const tag of tags) {\n if (tag[0] === \"d\" && tag[1] !== undefined) return tag[1];\n }\n return undefined;\n}\n\n/** NIP-01 `a` tag: `kind:pubkey:identifier` (identifier may be empty and may contain extra colons). */\nexport type EventAddress = {\n kind: number;\n pubkey: string;\n identifier: string;\n};\n\n/** Parse a NIP-01 addressable/replaceable coordinate. */\nexport function parseEventAddress(value: string): EventAddress | undefined {\n const first = value.indexOf(\":\");\n if (first <= 0) return undefined;\n const second = value.indexOf(\":\", first + 1);\n if (second < 0) return undefined;\n const kind = Number(value.slice(0, first));\n if (!Number.isInteger(kind) || kind < 0 || kind > 65535) return undefined;\n const pubkey = value.slice(first + 1, second).toLowerCase();\n if (!isHex32(pubkey)) return undefined;\n return { kind, pubkey, identifier: value.slice(second + 1) };\n}\n\nexport function formatEventAddress(kind: number, pubkey: string, identifier = \"\"): string {\n return `${kind}:${pubkey.toLowerCase()}:${identifier}`;\n}\n\n/**\n * Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events.\n * Undefined for regular/ephemeral kinds.\n */\nexport function eventAddress(event: {\n kind: number;\n pubkey: string;\n tags: readonly Tag[];\n}): string | undefined {\n if (isAddressableKind(event.kind)) {\n return formatEventAddress(event.kind, event.pubkey, getDTag(event.tags) ?? \"\");\n }\n if (isReplaceableKind(event.kind)) {\n return formatEventAddress(event.kind, event.pubkey, \"\");\n }\n return undefined;\n}\n","import { EventValidationError } from \"./error.ts\";\nimport { isHex32, isHex64, utf8Encoder } from \"./util.ts\";\nimport type { Tag } from \"./tag.ts\";\nimport { isTag } from \"./tag.ts\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { bytesToHex } from \"./util.ts\";\n\n/** Wire event template before pubkey/id/sig. */\nexport type EventTemplate = {\n readonly kind: number;\n readonly tags: readonly Tag[];\n readonly content: string;\n readonly created_at: number;\n};\n\n/** Event with pubkey, ready to hash and sign. */\nexport type UnsignedEvent = EventTemplate & {\n readonly pubkey: string;\n};\n\n/**\n * Fully formed NIP-01 event (JSON-friendly plain object).\n * Fields are readonly at the type level; wire interop remains plain JSON.\n */\nexport type Event = UnsignedEvent & {\n readonly id: string;\n readonly sig: string;\n};\n\n/** Cache of events whose signatures have been verified successfully. */\nconst verifiedEvents = new WeakSet<object>();\n\n/** Cache of events known to fail verification. */\nconst failedEvents = new WeakSet<object>();\n\nexport function markVerified(event: Event): void {\n verifiedEvents.add(event);\n failedEvents.delete(event);\n}\n\nexport function markUnverified(event: Event): void {\n failedEvents.add(event);\n verifiedEvents.delete(event);\n}\n\nexport function isMarkedVerified(event: Event): boolean {\n return verifiedEvents.has(event);\n}\n\nexport function isMarkedFailed(event: Event): boolean {\n return failedEvents.has(event);\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> =>\n typeof obj === \"object\" && obj !== null && !Array.isArray(obj);\n\n/** Structural validation of an unsigned event (no crypto). */\nexport function validateEvent(event: unknown): event is UnsignedEvent {\n if (!isRecord(event)) return false;\n if (\n typeof event.kind !== \"number\" ||\n !Number.isInteger(event.kind) ||\n event.kind < 0 ||\n event.kind > 65535\n ) {\n return false;\n }\n if (typeof event.content !== \"string\") return false;\n if (typeof event.created_at !== \"number\" || !Number.isInteger(event.created_at)) return false;\n if (typeof event.pubkey !== \"string\" || !isHex32(event.pubkey)) return false;\n if (!Array.isArray(event.tags)) return false;\n for (const tag of event.tags) {\n if (!isTag(tag)) return false;\n }\n return true;\n}\n\n/** Structural validation of a full event including id and sig hex shape. */\nexport function validateSignedEvent(event: unknown): event is Event {\n if (!validateEvent(event)) return false;\n const e = event as Record<string, unknown>;\n if (typeof e.id !== \"string\" || !isHex32(e.id)) return false;\n if (typeof e.sig !== \"string\" || !isHex64(e.sig)) return false;\n return true;\n}\n\n/**\n * Canonical NIP-01 serialization used for hashing:\n * JSON array `[0, pubkey, created_at, kind, tags, content]` with no extra whitespace.\n */\nexport function serializeEvent(event: UnsignedEvent): string {\n if (!validateEvent(event)) {\n throw new EventValidationError(\"cannot serialize event with invalid shape\");\n }\n return JSON.stringify([\n 0,\n event.pubkey.toLowerCase(),\n event.created_at,\n event.kind,\n event.tags,\n event.content,\n ]);\n}\n\n/** SHA-256 of the canonical serialization, lowercase hex. */\nexport function getEventHash(event: UnsignedEvent): string {\n const serialized = serializeEvent(event);\n return bytesToHex(sha256(utf8Encoder.encode(serialized)));\n}\n\nfunction compareEventsDesc(a: Event, b: Event): number {\n if (a.created_at !== b.created_at) return b.created_at - a.created_at;\n return a.id.localeCompare(b.id);\n}\n\n/**\n * Sort events reverse-chronologically by `created_at`, then by `id` lexicographically.\n * Mutates and returns the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort(compareEventsDesc);\n}\n\n/** Non-mutating sort; returns a new array. */\nexport function sortedEvents(events: readonly Event[]): Event[] {\n return events.slice().sort(compareEventsDesc);\n}\n\n/**\n * Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`).\n * Time axis is opposite {@link sortEvents}; id tie-break is the same direction.\n */\nexport function itemCompare(\n a: { id: string; created_at: number },\n b: { id: string; created_at: number },\n): number {\n if (a.created_at !== b.created_at) return a.created_at - b.created_at;\n if (a.id < b.id) return -1;\n if (a.id > b.id) return 1;\n return 0;\n}\n\n/**\n * NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp\n * and lexicographically lower `id`.\n */\nexport function isReplaceableWinner(\n candidate: { created_at: number; id: string },\n incumbent: { created_at: number; id: string },\n): boolean {\n if (candidate.created_at !== incumbent.created_at) {\n return candidate.created_at > incumbent.created_at;\n }\n return candidate.id < incumbent.id;\n}\n\n/** True when a signed event is the signed form of `unsigned` (kind/tags/content/time/pubkey). */\nexport function signedMatchesUnsigned(signed: Event, unsigned: UnsignedEvent): boolean {\n if (signed.kind !== unsigned.kind) return false;\n if (signed.content !== unsigned.content) return false;\n if (signed.created_at !== unsigned.created_at) return false;\n if (JSON.stringify(signed.tags) !== JSON.stringify(unsigned.tags)) return false;\n if (unsigned.pubkey && signed.pubkey.toLowerCase() !== unsigned.pubkey.toLowerCase()) {\n return false;\n }\n return true;\n}\n"],"mappings":"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"}