@qntx/nostr 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/{builder-GBddxj8i.d.mts → builder-C72nJITG.d.mts} +2 -2
  2. package/dist/{builder-BQbFDO6S.mjs → builder-CGgM_QHT.mjs} +5 -5
  3. package/dist/{builder-BQbFDO6S.mjs.map → builder-CGgM_QHT.mjs.map} +1 -1
  4. package/dist/{client-CTmp5w84.mjs → client-COkEihj_.mjs} +87 -79
  5. package/dist/client-COkEihj_.mjs.map +1 -0
  6. package/dist/client.d.mts +1 -1
  7. package/dist/client.mjs +1 -1
  8. package/dist/core.d.mts +7 -7
  9. package/dist/core.mjs +9 -9
  10. package/dist/{emitter-DkCY6NkU.mjs → emitter-u4kJqQDk.mjs} +2 -2
  11. package/dist/{emitter-DkCY6NkU.mjs.map → emitter-u4kJqQDk.mjs.map} +1 -1
  12. package/dist/{error-BquXDmIN.d.mts → error-BPqAU5RB.d.mts} +2 -6
  13. package/dist/{error-BD_0QFKT.d.mts → error-BjSUsx6M.d.mts} +2 -2
  14. package/dist/{error-UHkqzWL7.mjs → error-Dyb89ahb.mjs} +7 -3
  15. package/dist/error-Dyb89ahb.mjs.map +1 -0
  16. package/dist/{error-DH4guike.mjs → error-QyECUDIp.mjs} +2 -2
  17. package/dist/{error-DH4guike.mjs.map → error-QyECUDIp.mjs.map} +1 -1
  18. package/dist/{event-B3ua2_oL.mjs → event-DvM1f03b.mjs} +7 -3
  19. package/dist/event-DvM1f03b.mjs.map +1 -0
  20. package/dist/{filter-B16P33dz.mjs → filter-3jOh4uLN.mjs} +50 -20
  21. package/dist/filter-3jOh4uLN.mjs.map +1 -0
  22. package/dist/{filter-PG7r79rt.d.mts → filter-oYG2zjJ3.d.mts} +6 -2
  23. package/dist/{gossip-BTMdlUI7.d.mts → gossip-BvCItMVZ.d.mts} +3 -3
  24. package/dist/{gossip-K_JIexQs.mjs → gossip-CRyhK6E6.mjs} +4 -4
  25. package/dist/{gossip-K_JIexQs.mjs.map → gossip-CRyhK6E6.mjs.map} +1 -1
  26. package/dist/gossip.d.mts +1 -1
  27. package/dist/gossip.mjs +1 -1
  28. package/dist/http-CuazNRIP.mjs.map +1 -1
  29. package/dist/{index-DD0Ywpay.d.mts → index-B2JlP2Jf.d.mts} +9 -9
  30. package/dist/{index-BP94lABY.d.mts → index-DCobP2Jj.d.mts} +10 -10
  31. package/dist/{index-Hp26bgYG.d.mts → index-Dpj_MUxb.d.mts} +8 -5
  32. package/dist/{index-rKcmI6ex.d.mts → index-DzHmhHqD.d.mts} +3 -3
  33. package/dist/{index-N7HUGgwo.d.mts → index-YID-zPDF.d.mts} +58 -8
  34. package/dist/{index-CSsnE32i.d.mts → index-muydfuYD.d.mts} +21 -21
  35. package/dist/index.d.mts +19 -20
  36. package/dist/index.mjs +20 -20
  37. package/dist/{key-k8LDEPZh.mjs → key-D_oEutQ6.mjs} +32 -9
  38. package/dist/key-D_oEutQ6.mjs.map +1 -0
  39. package/dist/{key-CyKN1RTi.d.mts → key-DojW2QZl.d.mts} +14 -4
  40. package/dist/{kind-D8fENiiL.mjs → kind-I2Tvbe82.mjs} +6 -5
  41. package/dist/kind-I2Tvbe82.mjs.map +1 -0
  42. package/dist/{loaders-Dp2nXEFk.mjs → loaders-BRh2riV9.mjs} +17 -16
  43. package/dist/loaders-BRh2riV9.mjs.map +1 -0
  44. package/dist/loaders.d.mts +2 -2
  45. package/dist/loaders.mjs +1 -1
  46. package/dist/{memory-VyPnOBU3.mjs → memory-D_GdEQYG.mjs} +2 -2
  47. package/dist/memory-D_GdEQYG.mjs.map +1 -0
  48. package/dist/memory-index-3GSrPIWj.mjs +671 -0
  49. package/dist/memory-index-3GSrPIWj.mjs.map +1 -0
  50. package/dist/{message-pYfVKxPn.mjs → message-BMfreCQc.mjs} +6 -6
  51. package/dist/message-BMfreCQc.mjs.map +1 -0
  52. package/dist/{nip17-B7MI82Iq.d.mts → nip17-BZvFQLcs.d.mts} +5 -5
  53. package/dist/{nip19-DpPN17bY.d.mts → nip19-D4RKn6GC.d.mts} +2 -2
  54. package/dist/{nip46-BHaxC9TZ.d.mts → nip46-i8L8_nIm.d.mts} +2 -2
  55. package/dist/{nip51-O_vhOiK2.d.mts → nip51-C_kTYcud.d.mts} +2 -2
  56. package/dist/{nip59-CdDoJptA.d.mts → nip59-DfJ6Moeu.d.mts} +15 -7
  57. package/dist/{nip65-BL79HI8N.d.mts → nip65-CPNE0SV0.d.mts} +2 -2
  58. package/dist/{nip77-wHA_nEV5.d.mts → nip77-DhpoL7d8.d.mts} +2 -2
  59. package/dist/nips/blossom.d.mts +2 -2
  60. package/dist/nips/blossom.mjs +3 -3
  61. package/dist/nips/blossom.mjs.map +1 -1
  62. package/dist/nips/nip04.d.mts +11 -4
  63. package/dist/nips/nip04.mjs +44 -21
  64. package/dist/nips/nip04.mjs.map +1 -1
  65. package/dist/nips/nip05.d.mts +6 -3
  66. package/dist/nips/nip05.mjs +6 -3
  67. package/dist/nips/nip05.mjs.map +1 -1
  68. package/dist/nips/nip10.d.mts +2 -2
  69. package/dist/nips/nip10.mjs +4 -4
  70. package/dist/nips/nip11.d.mts +1 -1
  71. package/dist/nips/nip11.mjs +1 -1
  72. package/dist/nips/nip13.d.mts +1 -1
  73. package/dist/nips/nip13.mjs +1 -1
  74. package/dist/nips/nip13.mjs.map +1 -1
  75. package/dist/nips/nip17.d.mts +1 -1
  76. package/dist/nips/nip17.mjs +5 -5
  77. package/dist/nips/nip17.mjs.map +1 -1
  78. package/dist/nips/nip19.d.mts +1 -1
  79. package/dist/nips/nip19.mjs +2 -2
  80. package/dist/nips/nip19.mjs.map +1 -1
  81. package/dist/nips/nip21.d.mts +6 -3
  82. package/dist/nips/nip21.mjs +8 -5
  83. package/dist/nips/nip21.mjs.map +1 -1
  84. package/dist/nips/nip27.d.mts +1 -1
  85. package/dist/nips/nip27.mjs +15 -9
  86. package/dist/nips/nip27.mjs.map +1 -1
  87. package/dist/nips/nip42.mjs +2 -2
  88. package/dist/nips/nip44.d.mts +5 -0
  89. package/dist/nips/nip44.mjs +10 -3
  90. package/dist/nips/nip44.mjs.map +1 -1
  91. package/dist/nips/nip46.d.mts +1 -1
  92. package/dist/nips/nip46.mjs +9 -7
  93. package/dist/nips/nip46.mjs.map +1 -1
  94. package/dist/nips/nip49.d.mts +8 -2
  95. package/dist/nips/nip49.mjs +17 -3
  96. package/dist/nips/nip49.mjs.map +1 -1
  97. package/dist/nips/nip51.d.mts +1 -1
  98. package/dist/nips/nip51.mjs +5 -5
  99. package/dist/nips/nip51.mjs.map +1 -1
  100. package/dist/nips/nip57.mjs +6 -5
  101. package/dist/nips/nip57.mjs.map +1 -1
  102. package/dist/nips/nip59.d.mts +1 -1
  103. package/dist/nips/nip59.mjs +51 -23
  104. package/dist/nips/nip59.mjs.map +1 -1
  105. package/dist/nips/nip65.d.mts +1 -1
  106. package/dist/nips/nip65.mjs +3 -3
  107. package/dist/nips/nip77.d.mts +1 -1
  108. package/dist/nips/nip77.mjs +1 -1
  109. package/dist/nips/nip77.mjs.map +1 -1
  110. package/dist/nips/nip98.d.mts +1 -1
  111. package/dist/nips/nip98.mjs +18 -7
  112. package/dist/nips/nip98.mjs.map +1 -1
  113. package/dist/{pool-DUuYJ0x4.d.mts → pool-MehgIIzm.d.mts} +20 -16
  114. package/dist/{pool-BMUsw2un.mjs → pool-lMT_mvzn.mjs} +25 -25
  115. package/dist/pool-lMT_mvzn.mjs.map +1 -0
  116. package/dist/{put-DRmV1wHD.mjs → put-BEM5j8xK.mjs} +5 -5
  117. package/dist/{put-DRmV1wHD.mjs.map → put-BEM5j8xK.mjs.map} +1 -1
  118. package/dist/{reactive-jyKrA9ej.d.mts → reactive-B7lPFgTS.d.mts} +3 -3
  119. package/dist/{reactive--pDpLt2H.mjs → reactive-DFHY-f00.mjs} +24 -9
  120. package/dist/reactive-DFHY-f00.mjs.map +1 -0
  121. package/dist/{relay-DXtwUEdX.mjs → relay-DIR77xQ2.mjs} +102 -89
  122. package/dist/relay-DIR77xQ2.mjs.map +1 -0
  123. package/dist/relay.d.mts +5 -5
  124. package/dist/relay.mjs +3 -3
  125. package/dist/{report-CHld4uWj.mjs → report-D2BM5dgn.mjs} +2 -2
  126. package/dist/{report-CHld4uWj.mjs.map → report-D2BM5dgn.mjs.map} +1 -1
  127. package/dist/{signer-CWtxpOxc.mjs → signer-DJcmC4nA.mjs} +176 -17
  128. package/dist/signer-DJcmC4nA.mjs.map +1 -0
  129. package/dist/signer.d.mts +2 -2
  130. package/dist/signer.mjs +3 -3
  131. package/dist/{storage-B5Wdt_Mn.mjs → storage-n2BE1bdY.mjs} +108 -179
  132. package/dist/storage-n2BE1bdY.mjs.map +1 -0
  133. package/dist/storage.d.mts +3 -3
  134. package/dist/storage.mjs +4 -4
  135. package/dist/store.d.mts +1 -1
  136. package/dist/store.mjs +1 -1
  137. package/dist/testing.d.mts +4 -4
  138. package/dist/testing.mjs +35 -10
  139. package/dist/testing.mjs.map +1 -1
  140. package/dist/{types-CqhnT-Mx.d.mts → types-DiVVyf1e.d.mts} +2 -2
  141. package/dist/{util-DDpPkiED.mjs → util-DfsyJ9nz.mjs} +30 -10
  142. package/dist/util-DfsyJ9nz.mjs.map +1 -0
  143. package/dist/{verifier-CjH1vnP2.mjs → verifier-DEHUy4AD.mjs} +3 -3
  144. package/dist/{verifier-CjH1vnP2.mjs.map → verifier-DEHUy4AD.mjs.map} +1 -1
  145. package/dist/{verifier-Cl24c9ph.d.mts → verifier-DhAbqVJF.d.mts} +2 -2
  146. package/dist/{websocket-CmeqvAkp.d.mts → websocket-DaCvJkF9.d.mts} +2 -5
  147. package/package.json +4 -3
  148. package/dist/client-CTmp5w84.mjs.map +0 -1
  149. package/dist/error-UHkqzWL7.mjs.map +0 -1
  150. package/dist/event-B3ua2_oL.mjs.map +0 -1
  151. package/dist/filter-B16P33dz.mjs.map +0 -1
  152. package/dist/key-k8LDEPZh.mjs.map +0 -1
  153. package/dist/kind-D8fENiiL.mjs.map +0 -1
  154. package/dist/loaders-Dp2nXEFk.mjs.map +0 -1
  155. package/dist/memory-VyPnOBU3.mjs.map +0 -1
  156. package/dist/memory-index-Bhwe0ZdG.mjs +0 -374
  157. package/dist/memory-index-Bhwe0ZdG.mjs.map +0 -1
  158. package/dist/message-pYfVKxPn.mjs.map +0 -1
  159. package/dist/pool-BMUsw2un.mjs.map +0 -1
  160. package/dist/reactive--pDpLt2H.mjs.map +0 -1
  161. package/dist/relay-DXtwUEdX.mjs.map +0 -1
  162. package/dist/signer-CWtxpOxc.mjs.map +0 -1
  163. package/dist/storage-B5Wdt_Mn.mjs.map +0 -1
  164. package/dist/util-DDpPkiED.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { h as Tag, n as EventTemplate, r as UnsignedEvent, t as Event } from "./event-j3BwI5dF.mjs";
2
- import { i as SecretKeyInput, t as Keys } from "./key-CyKN1RTi.mjs";
2
+ import { i as SecretKeyInput, t as Keys } from "./key-DojW2QZl.mjs";
3
3
  //#region src/core/builder.d.ts
4
4
  /** Profile metadata JSON (kind 0 content). NIP-05 is not verified here. */
5
5
  type ProfileMetadata = {
@@ -69,4 +69,4 @@ declare class EventBuilder {
69
69
  }
70
70
  //#endregion
71
71
  export { ProfileMetadata as n, EventBuilder as t };
72
- //# sourceMappingURL=builder-GBddxj8i.d.mts.map
72
+ //# sourceMappingURL=builder-C72nJITG.d.mts.map
@@ -1,7 +1,7 @@
1
- import { d as normalizeURL, f as nowSeconds, g as EventValidationError } from "./util-DDpPkiED.mjs";
2
- import { o as isReplaceableKind, r as isAddressableKind, t as Kind } from "./kind-D8fENiiL.mjs";
3
- import { S as parseEventAddress, b as getDTag, g as Tag, y as formatEventAddress } from "./event-B3ua2_oL.mjs";
4
- import { r as finalizeEvent } from "./key-k8LDEPZh.mjs";
1
+ import { f as normalizeURL, p as nowSeconds, v as EventValidationError } from "./util-DfsyJ9nz.mjs";
2
+ import { o as isReplaceableKind, r as isAddressableKind, t as Kind } from "./kind-I2Tvbe82.mjs";
3
+ import { S as parseEventAddress, b as getDTag, g as Tag, y as formatEventAddress } from "./event-DvM1f03b.mjs";
4
+ import { r as finalizeEvent } from "./key-D_oEutQ6.mjs";
5
5
  //#region src/core/builder.ts
6
6
  /** NIP-18 e third entry MUST be a relay URL; empty string is not one. */
7
7
  function requireRelayUrl(relayHint) {
@@ -181,4 +181,4 @@ var EventBuilder = class EventBuilder {
181
181
  //#endregion
182
182
  export { EventBuilder as t };
183
183
 
184
- //# sourceMappingURL=builder-BQbFDO6S.mjs.map
184
+ //# sourceMappingURL=builder-CGgM_QHT.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder-BQbFDO6S.mjs","names":[],"sources":["../src/core/builder.ts"],"sourcesContent":["import { EventValidationError } from \"./error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"./event.ts\";\nimport { finalizeEvent } from \"./key.ts\";\nimport type { Keys, SecretKeyInput } from \"./key.ts\";\nimport { Kind, isAddressableKind, isReplaceableKind } from \"./kind.ts\";\nimport { Tag, formatEventAddress, getDTag, parseEventAddress } from \"./tag.ts\";\nimport { normalizeURL, nowSeconds } from \"./util.ts\";\nimport type { Mutable } from \"./util.ts\";\n\n/** NIP-18 e third entry MUST be a relay URL; empty string is not one. */\nfunction requireRelayUrl(relayHint: string | undefined): string {\n if (relayHint === undefined || relayHint === \"\") {\n throw new EventValidationError(\"relayHint must be a relay URL\");\n }\n return normalizeURL(relayHint);\n}\n\n/** Profile metadata JSON (kind 0 content). NIP-05 is not verified here. */\nexport type ProfileMetadata = {\n readonly name?: string | undefined;\n readonly display_name?: string | undefined;\n readonly about?: string | undefined;\n readonly picture?: string | undefined;\n readonly banner?: string | undefined;\n readonly website?: string | undefined;\n readonly nip05?: string | undefined;\n readonly lud06?: string | undefined;\n readonly lud16?: string | undefined;\n};\n\n/** ProfileMetadata keys in declaration order (NIP-01 kind 0 content). */\nconst PROFILE_METADATA_KEYS = [\n \"name\",\n \"display_name\",\n \"about\",\n \"picture\",\n \"banner\",\n \"website\",\n \"nip05\",\n \"lud06\",\n \"lud16\",\n] as const satisfies ReadonlyArray<keyof ProfileMetadata>;\n\n/**\n * Fluent builder for event templates. Decouples intent (kind/content/tags) from signing (Keys /\n * NostrSigner).\n */\nexport class EventBuilder {\n #kind: number;\n #content: string;\n readonly #tags: Tag[] = [];\n #createdAt: number | undefined;\n\n constructor(kind: number, content = \"\") {\n this.#kind = kind;\n this.#content = content;\n }\n\n static textNote(content: string): EventBuilder {\n return new EventBuilder(Kind.TextNote, content);\n }\n\n static metadata(meta: ProfileMetadata): EventBuilder {\n // Emit keys in the ProfileMetadata declaration order so the content is\n // stable regardless of the caller's object insertion order (NIP-01; the\n // Rust EventBuilder::metadata matches byte-for-byte).\n const ordered: Mutable<ProfileMetadata> = {};\n for (const key of PROFILE_METADATA_KEYS) {\n const value = meta[key];\n if (value !== undefined) {\n ordered[key] = value;\n }\n }\n return new EventBuilder(Kind.Metadata, JSON.stringify(ordered));\n }\n\n static contacts(pubkeys: ReadonlyArray<string>): EventBuilder {\n const b = new EventBuilder(Kind.Contacts, \"\");\n for (const pk of pubkeys) {\n b.#tags.push(Tag.p(pk));\n }\n return b;\n }\n\n /**\n * Kind-5 deletion. Each target is a bare event id string (or `{ id, kind }`), or `{ address }`\n * for a `kind:pubkey:d` coordinate. Known kinds are emitted as deduped `k` tags (NIP-09 SHOULD).\n */\n static deletion(\n targets: ReadonlyArray<string | { id: string; kind?: number } | { address: string }>,\n reason = \"\",\n ): EventBuilder {\n const b = new EventBuilder(Kind.EventDeletion, reason);\n const kinds = new Set<number>();\n for (const target of targets) {\n if (typeof target === \"string\") {\n b.#tags.push(Tag.e(target));\n continue;\n }\n if (\"address\" in target) {\n const parsed = parseEventAddress(target.address);\n if (parsed) {\n kinds.add(parsed.kind);\n }\n b.#tags.push(Tag.a(target.address));\n continue;\n }\n b.#tags.push(Tag.e(target.id));\n if (target.kind !== undefined) {\n kinds.add(target.kind);\n }\n }\n for (const kind of kinds) {\n b.#tags.push(Tag.k(kind));\n }\n return b;\n }\n\n static reaction(target: Event, content = \"+\", opts?: { relayHint?: string }): EventBuilder {\n const hint = opts?.relayHint === undefined ? undefined : requireRelayUrl(opts.relayHint);\n let coord: string | undefined;\n if (isAddressableKind(target.kind)) {\n const d = getDTag(target.tags);\n if (d === undefined) {\n throw new EventValidationError(\"addressable event is missing d tag\");\n }\n coord = formatEventAddress(target.kind, target.pubkey, d);\n }\n\n const b = new EventBuilder(Kind.Reaction, content);\n // NIP-25 e is [e, id, relay, pubkey]; Tag.e third arg is a NIP-10 marker.\n b.#tags.push([\"e\", target.id.toLowerCase(), hint ?? \"\", target.pubkey.toLowerCase()]);\n b.#tags.push(Tag.p(target.pubkey, hint));\n b.#tags.push([\"k\", String(target.kind)]);\n if (coord !== undefined) {\n b.#tags.push(Tag.a(coord, hint));\n }\n return b;\n }\n\n static repost(target: Event, opts: { relayHint: string }): EventBuilder {\n if (target.kind !== Kind.TextNote) {\n throw new EventValidationError(\"non-kind-1 uses EventBuilder.genericRepost\");\n }\n const hint = requireRelayUrl(opts.relayHint);\n const content = target.tags.some((tag) => tag[0] === \"-\") ? \"\" : JSON.stringify(target);\n const b = new EventBuilder(Kind.Repost, content);\n b.#tags.push(Tag.e(target.id, hint));\n b.#tags.push(Tag.p(target.pubkey));\n return b;\n }\n\n static genericRepost(target: Event, opts: { relayHint: string; pPubkey?: string }): EventBuilder {\n if (target.kind === Kind.TextNote) {\n throw new EventValidationError(\"kind 1 uses EventBuilder.repost\");\n }\n const hint = requireRelayUrl(opts.relayHint);\n const replaceable = isReplaceableKind(target.kind);\n const addressable = isAddressableKind(target.kind);\n const d = getDTag(target.tags);\n if (addressable && d === undefined) {\n throw new EventValidationError(\"addressable event is missing d tag\");\n }\n\n const protectedTag = target.tags.some((tag) => tag[0] === \"-\");\n const content = protectedTag || replaceable || addressable ? \"\" : JSON.stringify(target);\n const b = new EventBuilder(Kind.GenericRepost, content);\n b.#tags.push(Tag.e(target.id, hint));\n b.#tags.push(Tag.p(opts.pPubkey ?? target.pubkey));\n b.#tags.push(Tag.k(target.kind));\n if (replaceable || addressable) {\n b.#tags.push(Tag.a(formatEventAddress(target.kind, target.pubkey, d ?? \"\")));\n }\n return b;\n }\n\n kind(kind: number): this {\n this.#kind = kind;\n return this;\n }\n\n content(content: string): this {\n this.#content = content;\n return this;\n }\n\n tag(tag: Tag): this {\n this.#tags.push(tag);\n return this;\n }\n\n tags(tags: Iterable<Tag>): this {\n for (const t of tags) {\n this.#tags.push(t);\n }\n return this;\n }\n\n createdAt(ts: number): this {\n this.#createdAt = ts;\n return this;\n }\n\n get currentKind(): number {\n return this.#kind;\n }\n\n get currentContent(): string {\n return this.#content;\n }\n\n get currentTags(): ReadonlyArray<Tag> {\n return this.#tags;\n }\n\n get currentCreatedAt(): number | undefined {\n return this.#createdAt;\n }\n\n /** Snapshot as EventTemplate (uses wall clock if created_at unset). */\n toTemplate(): EventTemplate {\n return {\n kind: this.#kind,\n content: this.#content,\n tags: [...this.#tags],\n created_at: this.#createdAt ?? nowSeconds(),\n };\n }\n\n /** Build unsigned event with the given pubkey. */\n buildUnsigned(pubkey: string): UnsignedEvent {\n const template = this.toTemplate();\n return {\n ...template,\n pubkey: pubkey.toLowerCase(),\n };\n }\n\n /** Sign with local Keys (synchronous). */\n signWithKeys(keys: Keys | SecretKeyInput): Event {\n return finalizeEvent(this.toTemplate(), keys);\n }\n\n /**\n * Sign via any NostrSigner-shaped object. Accepts a structural type so core does not depend on\n * the signer module.\n */\n async sign(signer: {\n getPublicKey: () => Promise<string>;\n signEvent: (unsigned: UnsignedEvent) => Promise<Event>;\n }): Promise<Event> {\n const pubkey = await signer.getPublicKey();\n return signer.signEvent(this.buildUnsigned(pubkey));\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder-CGgM_QHT.mjs","names":[],"sources":["../src/core/builder.ts"],"sourcesContent":["import { EventValidationError } from \"./error.ts\";\nimport type { Event, EventTemplate, UnsignedEvent } from \"./event.ts\";\nimport { finalizeEvent } from \"./key.ts\";\nimport type { Keys, SecretKeyInput } from \"./key.ts\";\nimport { Kind, isAddressableKind, isReplaceableKind } from \"./kind.ts\";\nimport { Tag, formatEventAddress, getDTag, parseEventAddress } from \"./tag.ts\";\nimport { normalizeURL, nowSeconds } from \"./util.ts\";\nimport type { Mutable } from \"./util.ts\";\n\n/** NIP-18 e third entry MUST be a relay URL; empty string is not one. */\nfunction requireRelayUrl(relayHint: string | undefined): string {\n if (relayHint === undefined || relayHint === \"\") {\n throw new EventValidationError(\"relayHint must be a relay URL\");\n }\n return normalizeURL(relayHint);\n}\n\n/** Profile metadata JSON (kind 0 content). NIP-05 is not verified here. */\nexport type ProfileMetadata = {\n readonly name?: string | undefined;\n readonly display_name?: string | undefined;\n readonly about?: string | undefined;\n readonly picture?: string | undefined;\n readonly banner?: string | undefined;\n readonly website?: string | undefined;\n readonly nip05?: string | undefined;\n readonly lud06?: string | undefined;\n readonly lud16?: string | undefined;\n};\n\n/** ProfileMetadata keys in declaration order (NIP-01 kind 0 content). */\nconst PROFILE_METADATA_KEYS = [\n \"name\",\n \"display_name\",\n \"about\",\n \"picture\",\n \"banner\",\n \"website\",\n \"nip05\",\n \"lud06\",\n \"lud16\",\n] as const satisfies ReadonlyArray<keyof ProfileMetadata>;\n\n/**\n * Fluent builder for event templates. Decouples intent (kind/content/tags) from signing (Keys /\n * NostrSigner).\n */\nexport class EventBuilder {\n #kind: number;\n #content: string;\n readonly #tags: Tag[] = [];\n #createdAt: number | undefined;\n\n constructor(kind: number, content = \"\") {\n this.#kind = kind;\n this.#content = content;\n }\n\n static textNote(content: string): EventBuilder {\n return new EventBuilder(Kind.TextNote, content);\n }\n\n static metadata(meta: ProfileMetadata): EventBuilder {\n // Emit keys in the ProfileMetadata declaration order so the content is\n // stable regardless of the caller's object insertion order (NIP-01; the\n // Rust EventBuilder::metadata matches byte-for-byte).\n const ordered: Mutable<ProfileMetadata> = {};\n for (const key of PROFILE_METADATA_KEYS) {\n const value = meta[key];\n if (value !== undefined) {\n ordered[key] = value;\n }\n }\n return new EventBuilder(Kind.Metadata, JSON.stringify(ordered));\n }\n\n static contacts(pubkeys: ReadonlyArray<string>): EventBuilder {\n const b = new EventBuilder(Kind.Contacts, \"\");\n for (const pk of pubkeys) {\n b.#tags.push(Tag.p(pk));\n }\n return b;\n }\n\n /**\n * Kind-5 deletion. Each target is a bare event id string (or `{ id, kind }`), or `{ address }`\n * for a `kind:pubkey:d` coordinate. Known kinds are emitted as deduped `k` tags (NIP-09 SHOULD).\n */\n static deletion(\n targets: ReadonlyArray<string | { id: string; kind?: number } | { address: string }>,\n reason = \"\",\n ): EventBuilder {\n const b = new EventBuilder(Kind.EventDeletion, reason);\n const kinds = new Set<number>();\n for (const target of targets) {\n if (typeof target === \"string\") {\n b.#tags.push(Tag.e(target));\n continue;\n }\n if (\"address\" in target) {\n const parsed = parseEventAddress(target.address);\n if (parsed) {\n kinds.add(parsed.kind);\n }\n b.#tags.push(Tag.a(target.address));\n continue;\n }\n b.#tags.push(Tag.e(target.id));\n if (target.kind !== undefined) {\n kinds.add(target.kind);\n }\n }\n for (const kind of kinds) {\n b.#tags.push(Tag.k(kind));\n }\n return b;\n }\n\n static reaction(target: Event, content = \"+\", opts?: { relayHint?: string }): EventBuilder {\n const hint = opts?.relayHint === undefined ? undefined : requireRelayUrl(opts.relayHint);\n let coord: string | undefined;\n if (isAddressableKind(target.kind)) {\n const d = getDTag(target.tags);\n if (d === undefined) {\n throw new EventValidationError(\"addressable event is missing d tag\");\n }\n coord = formatEventAddress(target.kind, target.pubkey, d);\n }\n\n const b = new EventBuilder(Kind.Reaction, content);\n // NIP-25 e is [e, id, relay, pubkey]; Tag.e third arg is a NIP-10 marker.\n b.#tags.push([\"e\", target.id.toLowerCase(), hint ?? \"\", target.pubkey.toLowerCase()]);\n b.#tags.push(Tag.p(target.pubkey, hint));\n b.#tags.push([\"k\", String(target.kind)]);\n if (coord !== undefined) {\n b.#tags.push(Tag.a(coord, hint));\n }\n return b;\n }\n\n static repost(target: Event, opts: { relayHint: string }): EventBuilder {\n if (target.kind !== Kind.TextNote) {\n throw new EventValidationError(\"non-kind-1 uses EventBuilder.genericRepost\");\n }\n const hint = requireRelayUrl(opts.relayHint);\n const content = target.tags.some((tag) => tag[0] === \"-\") ? \"\" : JSON.stringify(target);\n const b = new EventBuilder(Kind.Repost, content);\n b.#tags.push(Tag.e(target.id, hint));\n b.#tags.push(Tag.p(target.pubkey));\n return b;\n }\n\n static genericRepost(target: Event, opts: { relayHint: string; pPubkey?: string }): EventBuilder {\n if (target.kind === Kind.TextNote) {\n throw new EventValidationError(\"kind 1 uses EventBuilder.repost\");\n }\n const hint = requireRelayUrl(opts.relayHint);\n const replaceable = isReplaceableKind(target.kind);\n const addressable = isAddressableKind(target.kind);\n const d = getDTag(target.tags);\n if (addressable && d === undefined) {\n throw new EventValidationError(\"addressable event is missing d tag\");\n }\n\n const protectedTag = target.tags.some((tag) => tag[0] === \"-\");\n const content = protectedTag || replaceable || addressable ? \"\" : JSON.stringify(target);\n const b = new EventBuilder(Kind.GenericRepost, content);\n b.#tags.push(Tag.e(target.id, hint));\n b.#tags.push(Tag.p(opts.pPubkey ?? target.pubkey));\n b.#tags.push(Tag.k(target.kind));\n if (replaceable || addressable) {\n b.#tags.push(Tag.a(formatEventAddress(target.kind, target.pubkey, d ?? \"\")));\n }\n return b;\n }\n\n kind(kind: number): this {\n this.#kind = kind;\n return this;\n }\n\n content(content: string): this {\n this.#content = content;\n return this;\n }\n\n tag(tag: Tag): this {\n this.#tags.push(tag);\n return this;\n }\n\n tags(tags: Iterable<Tag>): this {\n for (const t of tags) {\n this.#tags.push(t);\n }\n return this;\n }\n\n createdAt(ts: number): this {\n this.#createdAt = ts;\n return this;\n }\n\n get currentKind(): number {\n return this.#kind;\n }\n\n get currentContent(): string {\n return this.#content;\n }\n\n get currentTags(): ReadonlyArray<Tag> {\n return this.#tags;\n }\n\n get currentCreatedAt(): number | undefined {\n return this.#createdAt;\n }\n\n /** Snapshot as EventTemplate (uses wall clock if created_at unset). */\n toTemplate(): EventTemplate {\n return {\n kind: this.#kind,\n content: this.#content,\n tags: [...this.#tags],\n created_at: this.#createdAt ?? nowSeconds(),\n };\n }\n\n /** Build unsigned event with the given pubkey. */\n buildUnsigned(pubkey: string): UnsignedEvent {\n const template = this.toTemplate();\n return {\n ...template,\n pubkey: pubkey.toLowerCase(),\n };\n }\n\n /** Sign with local Keys (synchronous). */\n signWithKeys(keys: Keys | SecretKeyInput): Event {\n return finalizeEvent(this.toTemplate(), keys);\n }\n\n /**\n * Sign via any NostrSigner-shaped object. Accepts a structural type so core does not depend on\n * the signer module.\n */\n async sign(signer: {\n getPublicKey: () => Promise<string>;\n signEvent: (unsigned: UnsignedEvent) => Promise<Event>;\n }): Promise<Event> {\n const pubkey = await signer.getPublicKey();\n return signer.signEvent(this.buildUnsigned(pubkey));\n }\n}\n"],"mappings":"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"}
@@ -1,22 +1,22 @@
1
- import { C as toError, S as errorMessage, d as normalizeURL, g as EventValidationError, y as NostrError } from "./util-DDpPkiED.mjs";
2
- import { t as Kind } from "./kind-D8fENiiL.mjs";
3
- import { o as itemCompare, p as sortedEvents } from "./event-B3ua2_oL.mjs";
4
- import { n as verifyEvent } from "./verifier-CjH1vnP2.mjs";
5
- import { t as EventBuilder } from "./builder-BQbFDO6S.mjs";
6
- import { n as canonicalizeFilters, o as matchFilters, t as canonicalizeFilter } from "./filter-B16P33dz.mjs";
7
- import { t as NoSignerError } from "./error-UHkqzWL7.mjs";
1
+ import { C as errorMessage, f as normalizeURL, v as EventValidationError, w as toError, x as NostrError } from "./util-DfsyJ9nz.mjs";
2
+ import { t as Kind } from "./kind-I2Tvbe82.mjs";
3
+ import { o as itemCompare, p as sortedEvents } from "./event-DvM1f03b.mjs";
4
+ import { n as verifyEvent } from "./verifier-DEHUy4AD.mjs";
5
+ import { t as EventBuilder } from "./builder-CGgM_QHT.mjs";
6
+ import { n as canonicalizeFilters, s as matchFilters, t as canonicalizeFilter } from "./filter-3jOh4uLN.mjs";
7
+ import { t as NoSignerError } from "./error-Dyb89ahb.mjs";
8
8
  import { i as throwIfAborted, n as onAbort } from "./abort-DBq2STPj.mjs";
9
- import { n as fanIn, r as fetchRouted, t as Pool } from "./pool-BMUsw2un.mjs";
10
- import { t as Emitter } from "./emitter-DkCY6NkU.mjs";
9
+ import { n as fanIn, r as fetchRouted, t as Pool } from "./pool-lMT_mvzn.mjs";
10
+ import { t as Emitter } from "./emitter-u4kJqQDk.mjs";
11
11
  import { storageFromItems } from "./nips/nip77.mjs";
12
12
  import { isGiftWrapKind, requireNip59Crypto, unwrap } from "./nips/nip59.mjs";
13
13
  import { Nip17Error, buildChatMessageRumor, dmRelayListEventBuilder, normalizeRecipients, requireDmRelays, wrapDirectMessage } from "./nips/nip17.mjs";
14
- import { t as Gossip } from "./gossip-K_JIexQs.mjs";
15
- import { r as OutboxFeed, t as createLoaders } from "./loaders-Dp2nXEFk.mjs";
16
- import { n as toStorageError } from "./error-DH4guike.mjs";
17
- import { t as MemoryIndex } from "./memory-index-Bhwe0ZdG.mjs";
18
- import { t as MemoryEventStore } from "./memory-VyPnOBU3.mjs";
19
- import { t as ReactiveEventStore } from "./reactive--pDpLt2H.mjs";
14
+ import { t as Gossip } from "./gossip-CRyhK6E6.mjs";
15
+ import { r as OutboxFeed, t as createLoaders } from "./loaders-BRh2riV9.mjs";
16
+ import { n as toStorageError } from "./error-QyECUDIp.mjs";
17
+ import { t as MemoryIndex } from "./memory-index-3GSrPIWj.mjs";
18
+ import { t as MemoryEventStore } from "./memory-D_GdEQYG.mjs";
19
+ import { t as ReactiveEventStore } from "./reactive-DFHY-f00.mjs";
20
20
  import { t as SerialQueue } from "./serial-Bzpw-xz3.mjs";
21
21
  //#region src/client/dm.ts
22
22
  function giftWrapRelays(gossip, event) {
@@ -84,7 +84,7 @@ async function fetchPrivateMessages(deps, opts) {
84
84
  }], {
85
85
  timeoutMs: opts?.timeoutMs,
86
86
  signal: opts?.signal,
87
- onevent: (event, relayUrl) => {
87
+ onEvent: (event, relayUrl) => {
88
88
  let set = urls.get(event.id);
89
89
  if (!set) urls.set(event.id, set = /* @__PURE__ */ new Set());
90
90
  set.add(relayUrl);
@@ -136,51 +136,59 @@ async function subscribePrivateMessages(deps, opts) {
136
136
  };
137
137
  if (opts?.signal?.aborted === true) markClosed();
138
138
  else disposeAbort = onAbort(opts?.signal, markClosed);
139
- const inner = deps.pool.subscribe(relays, [{
140
- kinds: [Kind.GiftWrap, Kind.GiftWrapEphemeral],
141
- "#p": [self],
142
- since: opts?.since
143
- }], {
144
- signal: opts?.signal,
145
- oneose: opts?.oneose,
146
- onclose: (reason) => {
147
- markClosed();
148
- opts?.onclose?.(reason);
149
- },
150
- eoseTimeoutMs: opts?.eoseTimeoutMs,
151
- receivedEvent: (id, relayUrl) => {
152
- if (closed) return;
153
- if (processed.has(id)) {
154
- deps.markSeen(id, relayUrl);
155
- return;
156
- }
157
- const list = pendingUrls.get(id);
158
- if (list === void 0) pendingUrls.set(id, [relayUrl]);
159
- else if (!list.includes(relayUrl)) list.push(relayUrl);
160
- },
161
- onevent: (wrap, relayUrl) => {
162
- if (closed) return;
163
- queue.run(async () => {
164
- try {
165
- if (closed) return;
166
- const rumor = await unwrap(crypto, wrap);
167
- if (closed) return;
168
- if (seen.has(rumor.id)) {
139
+ let inner;
140
+ try {
141
+ inner = deps.pool.subscribe(relays, [{
142
+ kinds: [Kind.GiftWrap, Kind.GiftWrapEphemeral],
143
+ "#p": [self],
144
+ since: opts?.since
145
+ }], {
146
+ signal: opts?.signal,
147
+ onEose: opts?.onEose,
148
+ onClose: (reason) => {
149
+ markClosed();
150
+ opts?.onClose?.(reason);
151
+ },
152
+ eoseTimeoutMs: opts?.eoseTimeoutMs,
153
+ onEventSeen: (id, relayUrl) => {
154
+ if (closed) return;
155
+ if (processed.has(id)) {
156
+ deps.markSeen(id, relayUrl);
157
+ return;
158
+ }
159
+ const list = pendingUrls.get(id);
160
+ if (list === void 0) pendingUrls.set(id, [relayUrl]);
161
+ else if (!list.includes(relayUrl)) list.push(relayUrl);
162
+ },
163
+ onEvent: (wrap, relayUrl) => {
164
+ if (closed) return;
165
+ queue.run(async () => {
166
+ try {
167
+ if (closed) return;
168
+ const rumor = await unwrap(crypto, wrap);
169
+ if (closed) return;
170
+ if (seen.has(rumor.id)) {
171
+ flushSeen(wrap.id);
172
+ return;
173
+ }
174
+ seen.add(rumor.id);
175
+ if (opts?.observe !== false) deps.ingest(wrap, relayUrl);
176
+ flushSeen(wrap.id);
177
+ opts?.onEvent?.({
178
+ wrap,
179
+ rumor,
180
+ relayUrl
181
+ });
182
+ } catch {
169
183
  flushSeen(wrap.id);
170
- return;
171
184
  }
172
- seen.add(rumor.id);
173
- if (opts?.observe !== false) deps.ingest(wrap, relayUrl);
174
- flushSeen(wrap.id);
175
- opts?.onevent?.({
176
- wrap,
177
- rumor,
178
- relayUrl
179
- });
180
- } catch {}
181
- });
182
- }
183
- });
185
+ });
186
+ }
187
+ });
188
+ } catch (error) {
189
+ markClosed();
190
+ throw error;
191
+ }
184
192
  return { close: (reason) => {
185
193
  markClosed();
186
194
  inner.close(reason);
@@ -224,13 +232,13 @@ async function fetchGossip(pool, gossip, filters, defaultRelays, opts) {
224
232
  return fetchRouted(pool, jobsForFilters(gossip, filters, defaultRelays), {
225
233
  timeoutMs: opts?.timeoutMs,
226
234
  signal: opts?.signal,
227
- onevent: opts?.onevent
235
+ onEvent: opts?.onEvent
228
236
  });
229
237
  }
230
238
  function subscribeGossip(pool, gossip, filters, defaultRelays, opts) {
231
239
  const jobs = jobsForFilters(gossip, filters, defaultRelays);
232
240
  if (jobs.length === 0) {
233
- queueMicrotask(() => opts.oneose?.());
241
+ queueMicrotask(() => opts.onEose?.());
234
242
  return { close: () => {} };
235
243
  }
236
244
  return fanIn(pool, jobs, opts);
@@ -328,7 +336,7 @@ async function syncToRelay(deps, url, filter, opts) {
328
336
  const events = await deps.pool.fetch([url], [{ ids: batch }], {
329
337
  timeoutMs: opts?.timeoutMs,
330
338
  signal: opts?.signal,
331
- onevent: shouldObserve ? (event, relayUrl) => {
339
+ onEvent: shouldObserve ? (event, relayUrl) => {
332
340
  const urls = urlsById.get(event.id);
333
341
  if (urls === void 0) urlsById.set(event.id, [relayUrl]);
334
342
  else if (!urls.includes(relayUrl)) urls.push(relayUrl);
@@ -498,8 +506,8 @@ var Client = class {
498
506
  }
499
507
  async shutdown() {
500
508
  this.#shutdown = true;
501
- while (this.#flushing !== void 0) await this.#flushing;
502
509
  this.pool.close();
510
+ while (this.#flushing !== void 0) await this.#flushing;
503
511
  }
504
512
  /**
505
513
  * Listen for a client event. Multiple listeners per type are allowed and fire in registration
@@ -557,7 +565,7 @@ var Client = class {
557
565
  this.#queuePersist(event);
558
566
  }
559
567
  #queuePersist(event) {
560
- if (!this.#persistEvents) return;
568
+ if (!this.#persistEvents || this.#shutdown) return;
561
569
  this.#persistQueue.push(event);
562
570
  this.#armFlush();
563
571
  }
@@ -719,7 +727,7 @@ var Client = class {
719
727
  this.#events.emit("storageerror", toStorageError(error));
720
728
  }
721
729
  const seenIds = /* @__PURE__ */ new Set();
722
- const onevent = (event, relayUrl) => {
730
+ const onEvent = (event, relayUrl) => {
723
731
  if (shouldObserve) {
724
732
  if (seenIds.has(event.id)) this.index.markSeen(event.id, relayUrl);
725
733
  else {
@@ -727,16 +735,16 @@ var Client = class {
727
735
  this.index.add(event, relayUrl);
728
736
  }
729
737
  }
730
- opts?.onevent?.(event, relayUrl);
738
+ opts?.onEvent?.(event, relayUrl);
731
739
  };
732
740
  const batch = opts?.gossip !== true || opts.relays !== void 0 ? await this.pool.fetch(this.#defaultRelays(opts?.relays), filters, {
733
741
  timeoutMs: opts?.timeoutMs,
734
742
  signal: opts?.signal,
735
- onevent
743
+ onEvent
736
744
  }) : await fetchGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {
737
745
  timeoutMs: opts?.timeoutMs,
738
746
  signal: opts?.signal,
739
- onevent
747
+ onEvent
740
748
  });
741
749
  for (const e of batch) {
742
750
  candidates.push(e);
@@ -789,26 +797,26 @@ var Client = class {
789
797
  const shouldObserve = opts?.observe !== false;
790
798
  const wrapEvent = (event, relayUrl) => {
791
799
  if (shouldObserve) this.observe(event, relayUrl);
792
- opts?.onevent?.(event, relayUrl);
800
+ opts?.onEvent?.(event, relayUrl);
793
801
  };
794
802
  const wrapReceived = (id, relayUrl) => {
795
803
  if (shouldObserve) this.index.markSeen(id, relayUrl);
796
- opts?.receivedEvent?.(id, relayUrl);
804
+ opts?.onEventSeen?.(id, relayUrl);
797
805
  };
798
806
  if (opts?.gossip !== true || opts.relays !== void 0) return this.pool.subscribe(this.#defaultRelays(opts?.relays), filters, {
799
- onevent: wrapEvent,
800
- receivedEvent: wrapReceived,
801
- oneose: opts?.oneose,
802
- onclose: opts?.onclose,
807
+ onEvent: wrapEvent,
808
+ onEventSeen: wrapReceived,
809
+ onEose: opts?.onEose,
810
+ onClose: opts?.onClose,
803
811
  signal: opts?.signal,
804
812
  id: opts?.id,
805
813
  eoseTimeoutMs: opts?.eoseTimeoutMs
806
814
  });
807
815
  return subscribeGossip(this.pool, this.gossip, filters, () => this.#defaultRelays(), {
808
- onevent: wrapEvent,
809
- receivedEvent: wrapReceived,
810
- oneose: opts?.oneose,
811
- onclose: opts?.onclose,
816
+ onEvent: wrapEvent,
817
+ onEventSeen: wrapReceived,
818
+ onEose: opts?.onEose,
819
+ onClose: opts?.onClose,
812
820
  signal: opts?.signal,
813
821
  eoseTimeoutMs: opts?.eoseTimeoutMs
814
822
  });
@@ -849,4 +857,4 @@ var Client = class {
849
857
  //#endregion
850
858
  export { ClientError as n, SyncDirection as r, Client as t };
851
859
 
852
- //# sourceMappingURL=client-CTmp5w84.mjs.map
860
+ //# sourceMappingURL=client-COkEihj_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-COkEihj_.mjs","names":[],"sources":["../src/client/dm.ts","../src/client/types.ts","../src/client/gossip-io.ts","../src/client/sync.ts","../src/client/client.ts"],"sourcesContent":["import { onAbort, throwIfAborted } from \"../core/abort.ts\";\nimport 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 { SerialQueue } from \"../core/serial.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 { Closer } from \"../relay/subscription.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 publish: (\n eventOrBuilder: Event | EventBuilder,\n opts?: PublishOptions,\n ) => Promise<PoolPublishResult[]>;\n};\n\nexport function giftWrapRelays(gossip: Gossip, event: Event): ReadonlyArray<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 expiration: opts?.expiration,\n ephemeral: opts?.ephemeral,\n });\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.status === \"ok\") && opts?.observe !== false) {\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 throwIfAborted(opts?.signal);\n await deps.hydrateGossip([self]);\n 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 eslint/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 (opts?.observe !== false) {\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<Closer> {\n deps.assertAlive();\n const crypto = deps.requireNip59Crypto();\n const self = await crypto.getPublicKey();\n throwIfAborted(opts?.signal);\n await deps.hydrateGossip([self]);\n 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 const queue = new SerialQueue();\n let closed = false;\n let disposeAbort: (() => void) | undefined;\n const markClosed = (): void => {\n closed = true;\n disposeAbort?.();\n };\n if (opts?.signal?.aborted === true) {\n markClosed();\n } else {\n disposeAbort = onAbort(opts?.signal, markClosed);\n }\n\n let inner: Closer;\n try {\n 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 onEventSeen: (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 void queue.run(async () => {\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 (opts?.observe !== false) {\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\n // throws, and still mark the wrap processed so its buffered relay\n // receipts flush instead of accumulating in pendingUrls forever.\n flushSeen(wrap.id);\n }\n });\n },\n },\n );\n } catch (error) {\n // A synchronous subscribe throw must not leave the abort listener armed.\n markClosed();\n throw error;\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 { PoolOptions, PoolPublishResult } from \"../relay/pool.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> | undefined;\n direction?: SyncDirectionName | undefined;\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 | undefined;\n signal?: AbortSignal | undefined;\n dryRun?: boolean | undefined;\n /** When false, skip observe/storage on downloaded events. Default true. */\n observe?: boolean | undefined;\n};\n\n/** Outcome of a {@link Client.sync} run: ids compared, sent, received, and failures. */\nexport type SyncSummary = {\n readonly local: ReadonlyArray<string>;\n readonly remote: ReadonlyArray<string>;\n readonly sent: ReadonlyArray<string>;\n readonly received: ReadonlyArray<string>;\n /** Publish failures by event id: relay messages or thrown-error text. */\n readonly sendFailures: Readonly<Record<string, string>>;\n /** PutMany throws by event id. */\n readonly persistFailures: Readonly<Record<string, Error>>;\n};\n\n/**\n * Options for the {@link Client} constructor. Pool fields are forwarded to {@link Pool}; the\n * client-only fields are documented here.\n */\nexport type ClientOptions = Omit<PoolOptions, \"automaticallyAuth\"> & {\n signer?: NostrSigner | undefined;\n relays?: ReadonlyArray<string> | undefined;\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 | undefined;\n gossip?: Gossip | undefined;\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 | undefined;\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 | undefined;\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 | undefined;\n};\n\n/** Typed event payloads for {@link Client.on}. */\nexport type ClientEventMap = {\n /**\n * Storage I/O failures: live `putMany` flush and `fetchEvents({ localFirst: true })` query. Those\n * paths do not throw.\n */\n storageerror: StorageError;\n};\n\nexport type FetchEventsOptions = {\n relays?: ReadonlyArray<string> | undefined;\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n gossip?: boolean | undefined;\n /** When true, query local storage first and merge with network results. Defaults to false. */\n localFirst?: boolean | undefined;\n /** When false, skip writing fetched events to storage/observe. Default true. */\n observe?: boolean | undefined;\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) | undefined;\n};\n\n/** Options for {@link Client.fetchEach}: one-shot per-relay fetch, no gossip routing. */\nexport type FetchEachOptions = {\n relays?: ReadonlyArray<string> | undefined;\n timeoutMs?: number | undefined;\n signal?: AbortSignal | undefined;\n /** When false, skip writing fetched events to storage/observe. Default true. */\n observe?: boolean | undefined;\n};\n\nexport type SubscribeOptions = {\n relays?: ReadonlyArray<string> | undefined;\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) | undefined;\n /** Every receipt from every relay, including duplicates skipped by dedupe. */\n onEventSeen?: ((id: string, relayUrl: string) => void) | undefined;\n onEose?: (() => void) | undefined;\n onClose?: ((reason: string) => void) | undefined;\n signal?: AbortSignal | undefined;\n id?: string | undefined;\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 | undefined;\n /** Fan out REQs via NIP-65 gossip routes when available. */\n gossip?: boolean | undefined;\n /** When false, skip writing received events to storage/observe. Default true. */\n observe?: boolean | undefined;\n};\n\nexport type PublishOptions = {\n relays?: ReadonlyArray<string> | undefined;\n timeoutMs?: number | undefined;\n gossip?: boolean | undefined;\n /** When false, skip writing the published event to storage/observe. Default true. */\n observe?: boolean | undefined;\n};\n\n/** Options for sending a NIP-17 private message. */\nexport type SendPrivateMessageOptions = {\n readonly subject?: string | undefined;\n readonly replyTo?: ReplyTo | undefined;\n readonly created_at?: number | undefined;\n readonly timeoutMs?: number | undefined;\n readonly observe?: boolean | undefined;\n /** NIP-17 disappearing-message expiry (unix seconds) on the seal and the gift wrap. */\n readonly expiration?: number | undefined;\n /** Wrap in the ephemeral kind 21059 (relays MUST NOT store). */\n readonly ephemeral?: boolean | undefined;\n};\n\n/** Result of sending a NIP-17 DM: the rumor plus per-recipient wrap publish results. */\nexport type PrivateMessageSendResult = {\n readonly rumor: Rumor;\n readonly wraps: ReadonlyArray<{\n readonly recipient: string;\n readonly wrap: Event;\n readonly results: ReadonlyArray<PoolPublishResult>;\n }>;\n};\n\n/** An unwrapped NIP-17 private message: the received gift wrap and its inner rumor. */\nexport type ReceivedPrivateMessage = {\n readonly wrap: Event;\n readonly rumor: Rumor;\n /** Normalized URL of the relay that delivered the wrap, when known. */\n readonly relayUrl?: string | undefined;\n};\n\n/** Options for fetching NIP-17 private-message history. */\nexport type FetchPrivateMessagesOptions = {\n readonly since?: number | undefined;\n readonly until?: number | undefined;\n readonly timeoutMs?: number | undefined;\n readonly signal?: AbortSignal | undefined;\n readonly observe?: boolean | undefined;\n};\n\n/** Options for a live NIP-17 private-message subscription. */\nexport type SubscribePrivateMessagesOptions = {\n readonly since?: number | undefined;\n readonly onEvent?: ((msg: ReceivedPrivateMessage) => void) | undefined;\n readonly onEose?: (() => void) | undefined;\n readonly onClose?: ((reason: string) => void) | undefined;\n readonly signal?: AbortSignal | undefined;\n readonly eoseTimeoutMs?: number | undefined;\n readonly observe?: boolean | undefined;\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 type { Closer } from \"../relay/subscription.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: ReadonlyArray<Filter>,\n defaultRelays: () => ReadonlyArray<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: ReadonlyArray<Filter>,\n defaultRelays: () => ReadonlyArray<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: ReadonlyArray<Filter>,\n defaultRelays: () => ReadonlyArray<string>,\n opts: FanInOptions,\n): Closer {\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 { throwIfAborted } from \"../core/abort.ts\";\nimport { errorMessage, toError } from \"../core/error.ts\";\nimport 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 /**\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?: ReadonlyArray<string>) => ReadonlyArray<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 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 sent: string[] = [];\n const received: string[] = [];\n const sendFailures: Record<string, string> = {};\n const persistFailures: Record<string, Error> = {};\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 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 eslint/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.status === \"ok\");\n if (ok) {\n sent.push(event.id);\n } else {\n const [first] = results;\n sendFailures[event.id] =\n first === undefined\n ? \"publish failed\"\n : first.status === \"failed\"\n ? errorMessage(first.error)\n : first.message;\n }\n } catch (error) {\n sendFailures[event.id] = errorMessage(error);\n }\n }),\n );\n }\n }\n\n if ((direction === SyncDirection.Down || direction === SyncDirection.Both) && need.length > 0) {\n const shouldObserve = opts?.observe !== false;\n for (let i = 0; i < need.length; i += SYNC_ID_BATCH) {\n const batch = need.slice(i, i + SYNC_ID_BATCH);\n 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 eslint/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 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 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 eslint/no-await-in-loop\n results = await deps.storage.putMany(events);\n } catch (error) {\n const thrown = toError(error);\n for (const event of events) {\n persistFailures[event.id] = thrown;\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 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);\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 { EventBuilder } from \"../core/builder.ts\";\nimport { Emitter } from \"../core/emitter.ts\";\nimport { EventValidationError } from \"../core/error.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 { normalizeURL } from \"../core/util.ts\";\nimport { verifyEvent } from \"../core/verifier.ts\";\nimport { Gossip } from \"../gossip/index.ts\";\nimport { createLoaders, OutboxFeed } from \"../loaders/index.ts\";\nimport type { Loaders } 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 { PoolFetchResult, PoolPublishResult } from \"../relay/pool.ts\";\nimport type { Closer } from \"../relay/subscription.ts\";\nimport { NoSignerError } from \"../signer/error.ts\";\nimport type { NostrSigner } from \"../signer/types.ts\";\nimport { toStorageError } 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 {\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 ClientEventMap,\n ClientOptions,\n FetchEachOptions,\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\nfunction isFilterList(filter: Filter | ReadonlyArray<Filter>): filter is ReadonlyArray<Filter> {\n return Array.isArray(filter);\n}\n\nfunction toFilterList(filter: Filter | ReadonlyArray<Filter>): Filter[] {\n return canonicalizeFilters(isFilterList(filter) ? filter : [filter]);\n}\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 #signer: NostrSigner | undefined;\n #relays: string[];\n #shutdown = false;\n readonly #persistEvents: boolean;\n readonly #persistQueue: Event[] = [];\n #flushing: Promise<void> | undefined;\n readonly #events = new Emitter<ClientEventMap>();\n readonly #dmDeps: DmDeps;\n readonly #syncDeps: SyncDeps;\n\n constructor(opts: ClientOptions = {}) {\n const { signer, relays, automaticAuth, gossip, storage, index, persistEvents, ...poolOptions } =\n opts;\n this.#signer = signer;\n this.#relays = [];\n for (const raw of relays ?? []) {\n const url = normalizeURL(raw);\n if (!this.#relays.includes(url)) {\n this.#relays.push(url);\n }\n }\n this.gossip = gossip ?? new Gossip();\n this.storage = storage ?? new MemoryEventStore();\n this.index = index ?? new ReactiveEventStore();\n this.#persistEvents = persistEvents ?? true;\n this.pool = new Pool({\n ...poolOptions,\n enableReconnect: poolOptions.enableReconnect ?? true,\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 (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 this.#dmDeps = {\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) => {\n this.index.markSeen(id, relayUrl);\n },\n assertAlive: () => this.#assertAlive(),\n requireNip59Crypto: () => this.#requireNip59Crypto(),\n publish: async (eventOrBuilder, opts) => this.publish(eventOrBuilder, opts),\n };\n this.#syncDeps = {\n pool: this.pool,\n storage: this.storage,\n persistEvents: this.#persistEvents,\n assertAlive: () => this.#assertAlive(),\n ingest: (event, relayUrl, opts) => this.#ingest(event, relayUrl, opts),\n markSeen: (id, relayUrl) => {\n this.index.markSeen(id, relayUrl);\n },\n defaultRelays: (urls) => this.#defaultRelays(urls),\n };\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.closeRelays([normalized]);\n }\n\n /** Connect all configured relays (best-effort; failures are ignored). */\n async connect(opts?: { signal?: AbortSignal | undefined }): 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 // Stop inbound events first: a live subscription would otherwise keep\n // refilling the persistence queue and the drain below would never settle.\n this.pool.close();\n while (this.#flushing !== undefined) {\n // oxlint-disable-next-line eslint/no-await-in-loop -- waits for the current flush to settle\n await this.#flushing;\n }\n }\n\n /**\n * Listen for a client event. Multiple listeners per type are allowed and fire in registration\n * order; a throwing listener is reported and does not break the dispatch. Returns an unsubscribe\n * function.\n */\n on<K extends keyof ClientEventMap>(\n type: K,\n listener: (err: ClientEventMap[K]) => void,\n ): () => void {\n return this.#events.on(type, listener);\n }\n\n #assertAlive(): void {\n if (this.#shutdown) {\n throw new ClientError(\"client is shut down\");\n }\n }\n\n #defaultRelays(urls?: ReadonlyArray<string>): ReadonlyArray<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 /**\n * Ingest one inbound event: index (with relay URL) → meta → persistence. The event must carry a\n * valid signature; {@link EventValidationError} is thrown otherwise. Events delivered by relay\n * subscriptions are already verified, so this is a WeakSet cache hit on those paths.\n */\n observe(event: Event, relayUrl?: string): void {\n if (!verifyEvent(event)) {\n throw new EventValidationError(\"observe requires a verified event\");\n }\n this.#ingest(event, relayUrl);\n }\n\n /**\n * Ingest many events (deduped by id, order preserved) as one persist batch. Every event must\n * carry a valid signature — all are verified before anything is ingested, so a batch is\n * all-or-nothing.\n */\n observeAll(events: ReadonlyArray<Event>): void {\n for (const event of events) {\n if (!verifyEvent(event)) {\n throw new EventValidationError(\"observe requires a verified event\");\n }\n }\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.gossip.ingest(event);\n }\n if (opts?.persist !== false) {\n this.#queuePersist(event);\n }\n }\n\n /** Gossip + persistence for an event the index already holds — no redundant `index.add`. */\n #ingestMeta(event: Event): void {\n this.gossip.ingest(event);\n this.#queuePersist(event);\n }\n\n #queuePersist(event: Event): void {\n if (!this.#persistEvents || this.#shutdown) {\n return;\n }\n this.#persistQueue.push(event);\n this.#armFlush();\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 eslint/no-await-in-loop -- queued batches are persisted in order\n await this.storage.putMany(batch);\n } catch (error) {\n this.#events.emit(\"storageerror\", 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 new OutboxFeed({\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 #requireSigner(): NostrSigner {\n const signer = this.#signer;\n if (!signer) {\n throw new ClientError(\"no signer configured\");\n }\n return signer;\n }\n\n async getPublicKey(): Promise<string> {\n return this.#requireSigner().getPublicKey();\n }\n\n async signEvent(unsigned: UnsignedEvent): Promise<Event> {\n return this.#requireSigner().signEvent(unsigned);\n }\n\n async signEventBuilder(builder: EventBuilder): Promise<Event> {\n return builder.sign(this.#requireSigner());\n }\n\n async signTemplate(template: EventTemplate): Promise<Event> {\n const signer = this.#requireSigner();\n const pubkey = await signer.getPublicKey();\n return 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.status === \"ok\");\n if (anyOk && opts?.observe !== false) {\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(\n filter: Filter | ReadonlyArray<Filter>,\n opts?: FetchEventsOptions,\n ): Promise<Event[]> {\n this.#assertAlive();\n const filters = toFilterList(filter);\n const shouldObserve = opts?.observe !== false;\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 this.#events.emit(\"storageerror\", toStorageError(error));\n }\n }\n\n // Every inbound event lands in the index (with its relay URL) before the caller's\n // onEvent runs. `onEvent` fires once per relay delivery, so only the first sighting of\n // an id does a full index put — later relays are recorded via markSeen. The batch loop\n // below adds gossip meta and persistence without re-putting.\n const seenIds = new Set<string>();\n const onEvent = (event: Event, relayUrl: string) => {\n if (shouldObserve) {\n if (seenIds.has(event.id)) {\n this.index.markSeen(event.id, relayUrl);\n } else {\n seenIds.add(event.id);\n this.index.add(event, relayUrl);\n }\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.#ingestMeta(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 /**\n * One-shot fetch with per-relay results: each entry reports its events and end reason (`eose`,\n * `closed`, `timeout`, or `failed` when the relay could not be reached). Events are ingested into\n * the index with each relay's URL in `seenOn` and persisted exactly like {@link fetchEvents}\n * (`observe` defaults to true). No gossip routing and no local merge.\n */\n async fetchEach(\n filter: Filter | ReadonlyArray<Filter>,\n opts?: FetchEachOptions,\n ): Promise<PoolFetchResult[]> {\n this.#assertAlive();\n const filters = toFilterList(filter);\n const results = await this.pool.fetchEach(this.#defaultRelays(opts?.relays), filters, {\n timeoutMs: opts?.timeoutMs,\n signal: opts?.signal,\n });\n if (opts?.observe !== false) {\n const unique: Event[] = [];\n const seen = new Set<string>();\n for (const result of results) {\n for (const event of result.events) {\n if (seen.has(event.id)) {\n this.index.markSeen(event.id, result.url);\n continue;\n }\n seen.add(event.id);\n this.index.add(event, result.url);\n unique.push(event);\n }\n }\n for (const event of unique) {\n this.#ingestMeta(event);\n }\n }\n return results;\n }\n\n /** Query local storage only (no network). */\n async queryLocal(filter: Filter | ReadonlyArray<Filter>): Promise<Event[]> {\n this.#assertAlive();\n const filters = toFilterList(filter);\n return this.storage.query(filters);\n }\n\n subscribe(filter: Filter | ReadonlyArray<Filter>, opts?: SubscribeOptions): Closer {\n this.#assertAlive();\n const filters = toFilterList(filter);\n const shouldObserve = opts?.observe !== false;\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.index.markSeen(id, relayUrl);\n }\n opts?.onEventSeen?.(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 onEventSeen: 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 onEventSeen: wrapReceived,\n onEose: opts?.onEose,\n onClose: opts?.onClose,\n signal: opts?.signal,\n eoseTimeoutMs: opts?.eoseTimeoutMs,\n });\n }\n\n #requireNip59Crypto(): Nip59Crypto {\n return requireNip59Crypto(this.#requireSigner());\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(opts?: SubscribePrivateMessagesOptions): Promise<Closer> {\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":"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"}
package/dist/client.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as SyncSummary, a as FetchEachOptions, c as PrivateMessageSendResult, d as SendPrivateMessageOptions, f as SubscribeOptions, g as SyncOptions, h as SyncDirectionName, i as ClientOptions, l as PublishOptions, m as SyncDirection, n as ClientError, o as FetchEventsOptions, p as SubscribePrivateMessagesOptions, r as ClientEventMap, s as FetchPrivateMessagesOptions, t as Client, u as ReceivedPrivateMessage } from "./index-CSsnE32i.mjs";
1
+ import { _ as SyncSummary, a as FetchEachOptions, c as PrivateMessageSendResult, d as SendPrivateMessageOptions, f as SubscribeOptions, g as SyncOptions, h as SyncDirectionName, i as ClientOptions, l as PublishOptions, m as SyncDirection, n as ClientError, o as FetchEventsOptions, p as SubscribePrivateMessagesOptions, r as ClientEventMap, s as FetchPrivateMessagesOptions, t as Client, u as ReceivedPrivateMessage } from "./index-muydfuYD.mjs";
2
2
  export { Client, ClientError, type ClientEventMap, type ClientOptions, type FetchEachOptions, 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 { n as ClientError, r as SyncDirection, t as Client } from "./client-CTmp5w84.mjs";
1
+ import { n as ClientError, r as SyncDirection, t as Client } from "./client-COkEihj_.mjs";
2
2
  export { Client, ClientError, SyncDirection };
package/dist/core.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { C as tagName, S as parseEventAddress, _ as eventAddress, a as isMarkedFailed, b as getDTag, c as serializeEvent, d as sortedEvents, f as validateEvent, g as TagInput, h as Tag, i as getEventHash, l as signedMatchesUnsigned, m as EventAddress, n as EventTemplate, o as isReplaceableWinner, p as validateSignedEvent, r as UnsignedEvent, s as itemCompare, t as Event, u as sortEvents, v as firstTagValue, w as tagValue, x as isTag, y as formatEventAddress } from "./event-j3BwI5dF.mjs";
2
- import { a as SigningBackend, c as publicKeyFromHex, i as SecretKeyInput, l as signEvent, n as PublicKey, o as finalizeEvent, r as SecretKey, s as getPublicKey, t as Keys, u as toSecretKey } from "./key-CyKN1RTi.mjs";
3
- import { n as ProfileMetadata, t as EventBuilder } from "./builder-GBddxj8i.mjs";
4
- import { a as getFilterLimit, i as filterFingerprint, n as canonicalizeFilter, o as matchFilter, r as canonicalizeFilters, s as matchFilters, t as Filter } from "./filter-PG7r79rt.mjs";
5
- import { a as ClientMessage, c as SubscriptionId, d as encodeClientMessage, f as encodeRelayMessage, h as parseRelayMessage, i as verifyEvent, l as assertSubscriptionId, m as parseClientMessage, n as SerializedEventVerifier, o as CountResult, p as mergeCountHll, r as createEventVerifier, s as RelayMessage, t as EventVerifier, u as createSubscriptionId } from "./verifier-Cl24c9ph.mjs";
6
- import { a as NostrError, i as MessageError, n as EventValidationError, o as UrlError, r as HexError, s as WasmPoisonedError, t as CryptoError } from "./error-BquXDmIN.mjs";
7
- import { S as SUBSCRIPTION_ID_MAX_CHARS, _ as normalizeURL, a as classifyKind, b as SECRET_KEY_BYTES, c as isRegularKind, d as assertSecretKeyBytes, f as bytesToHex, g as normalizeRelayUrls, 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 EVENT_ID_BYTES, x as SIGNATURE_BYTES, y as PUBLIC_KEY_BYTES } from "./index-Hp26bgYG.mjs";
8
- export { type ClientMessage, type CountResult, CryptoError, EVENT_ID_BYTES, type Event, type EventAddress, EventBuilder, type EventTemplate, EventValidationError, type EventVerifier, 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 SecretKeyInput, type SerializedEventVerifier, type SigningBackend, type SubscriptionId, Tag, type TagInput, type UnsignedEvent, UrlError, WasmPoisonedError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, createEventVerifier, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, firstTagValue, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, matchFilter, matchFilters, mergeCountHll, normalizeRelayUrls, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, toSecretKey, validateEvent, validateSignedEvent, verifyEvent };
2
+ import { a as SigningBackend, c as publicKeyFromHex, i as SecretKeyInput, l as signEvent, n as PublicKey, o as finalizeEvent, r as SecretKey, s as getPublicKey, t as Keys, u as toSecretKey } from "./key-DojW2QZl.mjs";
3
+ import { n as ProfileMetadata, t as EventBuilder } from "./builder-C72nJITG.mjs";
4
+ import { a as getFilterLimit, i as filterFingerprint, n as canonicalizeFilter, o as matchFilter, r as canonicalizeFilters, s as matchFilters, t as Filter } from "./filter-oYG2zjJ3.mjs";
5
+ import { a as ClientMessage, c as SubscriptionId, d as encodeClientMessage, f as encodeRelayMessage, h as parseRelayMessage, i as verifyEvent, l as assertSubscriptionId, m as parseClientMessage, n as SerializedEventVerifier, o as CountResult, p as mergeCountHll, r as createEventVerifier, s as RelayMessage, t as EventVerifier, u as createSubscriptionId } from "./verifier-DhAbqVJF.mjs";
6
+ import { a as NostrError, i as MessageError, n as EventValidationError, o as UrlError, r as HexError, t as CryptoError } from "./error-BPqAU5RB.mjs";
7
+ import { C as SUBSCRIPTION_ID_MAX_CHARS, S as SIGNATURE_BYTES, _ as normalizeURL, a as classifyKind, b as PUBLIC_KEY_BYTES, c as isRegularKind, d as assertSecretKeyBytes, f as bytesToHex, g as normalizeRelayUrls, 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 randomBytes, x as SECRET_KEY_BYTES, y as EVENT_ID_BYTES } from "./index-Dpj_MUxb.mjs";
8
+ export { type ClientMessage, type CountResult, CryptoError, EVENT_ID_BYTES, type Event, type EventAddress, EventBuilder, type EventTemplate, EventValidationError, type EventVerifier, 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 SecretKeyInput, type SerializedEventVerifier, type SigningBackend, type SubscriptionId, Tag, type TagInput, type UnsignedEvent, UrlError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, createEventVerifier, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, firstTagValue, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, matchFilter, matchFilters, mergeCountHll, normalizeRelayUrls, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, randomBytes, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, toSecretKey, validateEvent, validateSignedEvent, verifyEvent };
package/dist/core.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { D as SIGNATURE_BYTES, E as SECRET_KEY_BYTES, O as SUBSCRIPTION_ID_MAX_CHARS, T as PUBLIC_KEY_BYTES, _ as HexError, b as UrlError, c as isHex64, d as normalizeURL, g as EventValidationError, h as CryptoError, i as bytesToHex, n as assertHex32, o as hexToBytes, r as assertSecretKeyBytes, s as isHex32, u as normalizeRelayUrls, v as MessageError, w as EVENT_ID_BYTES, x as WasmPoisonedError, y as NostrError } from "./util-DDpPkiED.mjs";
2
- import { a as isRegularKind, i as isEphemeralKind, n as classifyKind, o as isReplaceableKind, r as isAddressableKind, t as Kind } from "./kind-D8fENiiL.mjs";
3
- import { C as tagName, S as parseEventAddress, _ as eventAddress, a as isReplaceableWinner, b as getDTag, d as signedMatchesUnsigned, f as sortEvents, g as Tag, h as validateSignedEvent, l as serializeEvent, m as validateEvent, n as getEventHash, o as itemCompare, p as sortedEvents, r as isMarkedFailed, v as firstTagValue, w as tagValue, x as isTag, y as formatEventAddress } from "./event-B3ua2_oL.mjs";
4
- import { a as publicKeyFromHex, i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as toSecretKey, t as Keys } from "./key-k8LDEPZh.mjs";
5
- import { n as verifyEvent, t as createEventVerifier } from "./verifier-CjH1vnP2.mjs";
6
- import { t as EventBuilder } from "./builder-BQbFDO6S.mjs";
7
- import { a as matchFilter, i as getFilterLimit, n as canonicalizeFilters, o as matchFilters, r as filterFingerprint, t as canonicalizeFilter } from "./filter-B16P33dz.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-pYfVKxPn.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, WasmPoisonedError, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, createEventVerifier, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, firstTagValue, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, matchFilter, matchFilters, mergeCountHll, normalizeRelayUrls, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, toSecretKey, validateEvent, validateSignedEvent, verifyEvent };
1
+ import { D as SECRET_KEY_BYTES, E as PUBLIC_KEY_BYTES, O as SIGNATURE_BYTES, S as UrlError, T as EVENT_ID_BYTES, _ as CryptoError, b as MessageError, c as isHex32, d as normalizeRelayUrls, f as normalizeURL, i as bytesToHex, k as SUBSCRIPTION_ID_MAX_CHARS, l as isHex64, m as randomBytes, n as assertHex32, r as assertSecretKeyBytes, s as hexToBytes, v as EventValidationError, x as NostrError, y as HexError } from "./util-DfsyJ9nz.mjs";
2
+ import { a as isRegularKind, i as isEphemeralKind, n as classifyKind, o as isReplaceableKind, r as isAddressableKind, t as Kind } from "./kind-I2Tvbe82.mjs";
3
+ import { C as tagName, S as parseEventAddress, _ as eventAddress, a as isReplaceableWinner, b as getDTag, d as signedMatchesUnsigned, f as sortEvents, g as Tag, h as validateSignedEvent, l as serializeEvent, m as validateEvent, n as getEventHash, o as itemCompare, p as sortedEvents, r as isMarkedFailed, v as firstTagValue, w as tagValue, x as isTag, y as formatEventAddress } from "./event-DvM1f03b.mjs";
4
+ import { a as publicKeyFromHex, i as getPublicKey, n as SecretKey, o as signEvent, r as finalizeEvent, s as toSecretKey, t as Keys } from "./key-D_oEutQ6.mjs";
5
+ import { n as verifyEvent, t as createEventVerifier } from "./verifier-DEHUy4AD.mjs";
6
+ import { t as EventBuilder } from "./builder-CGgM_QHT.mjs";
7
+ import { a as getFilterLimit, n as canonicalizeFilters, o as matchFilter, r as filterFingerprint, s as matchFilters, t as canonicalizeFilter } from "./filter-3jOh4uLN.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-BMfreCQc.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, assertHex32, assertSecretKeyBytes, assertSubscriptionId, bytesToHex, canonicalizeFilter, canonicalizeFilters, classifyKind, createEventVerifier, createSubscriptionId, encodeClientMessage, encodeRelayMessage, eventAddress, filterFingerprint, finalizeEvent, firstTagValue, formatEventAddress, getDTag, getEventHash, getFilterLimit, getPublicKey, hexToBytes, isAddressableKind, isEphemeralKind, isHex32, isHex64, isMarkedFailed, isRegularKind, isReplaceableKind, isReplaceableWinner, isTag, itemCompare, matchFilter, matchFilters, mergeCountHll, normalizeRelayUrls, normalizeURL, parseClientMessage, parseEventAddress, parseRelayMessage, publicKeyFromHex, randomBytes, serializeEvent, signEvent, signedMatchesUnsigned, sortEvents, sortedEvents, tagName, tagValue, toSecretKey, validateEvent, validateSignedEvent, verifyEvent };
@@ -1,4 +1,4 @@
1
- import { t as invokeSafely } from "./report-CHld4uWj.mjs";
1
+ import { t as invokeSafely } from "./report-D2BM5dgn.mjs";
2
2
  //#region src/core/emitter.ts
3
3
  /**
4
4
  * Typed multi-listener dispatch for long-lived objects: `M` maps each event name to its payload
@@ -29,4 +29,4 @@ var Emitter = class {
29
29
  //#endregion
30
30
  export { Emitter as t };
31
31
 
32
- //# sourceMappingURL=emitter-DkCY6NkU.mjs.map
32
+ //# sourceMappingURL=emitter-u4kJqQDk.mjs.map