@qntx/nostr 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/builder-BphJa-Y-.d.mts +67 -0
  4. package/dist/builder-q0VsvnYE.mjs +158 -0
  5. package/dist/builder-q0VsvnYE.mjs.map +1 -0
  6. package/dist/client-Bd8B1mYm.mjs +835 -0
  7. package/dist/client-Bd8B1mYm.mjs.map +1 -0
  8. package/dist/client.d.mts +2 -0
  9. package/dist/client.mjs +2 -0
  10. package/dist/core.d.mts +8 -0
  11. package/dist/core.mjs +9 -0
  12. package/dist/error-B49rbDzT.d.mts +7 -0
  13. package/dist/error-CwBxle6N.mjs +13 -0
  14. package/dist/error-CwBxle6N.mjs.map +1 -0
  15. package/dist/error-DZEs5OuZ.mjs +24 -0
  16. package/dist/error-DZEs5OuZ.mjs.map +1 -0
  17. package/dist/error-WEFS-R-4.d.mts +20 -0
  18. package/dist/event-B5D2jxt_.d.mts +108 -0
  19. package/dist/event-CzoQEFMF.mjs +188 -0
  20. package/dist/event-CzoQEFMF.mjs.map +1 -0
  21. package/dist/filter-BxwjEkZp.mjs +113 -0
  22. package/dist/filter-BxwjEkZp.mjs.map +1 -0
  23. package/dist/filter-DUEKP3q1.d.mts +40 -0
  24. package/dist/gossip-3xkRRCm_.mjs +220 -0
  25. package/dist/gossip-3xkRRCm_.mjs.map +1 -0
  26. package/dist/gossip-C5RVB1UB.d.mts +71 -0
  27. package/dist/gossip.d.mts +3 -0
  28. package/dist/gossip.mjs +2 -0
  29. package/dist/http-6vevbBlu.d.mts +22 -0
  30. package/dist/http-D2rhokZo.mjs +24 -0
  31. package/dist/http-D2rhokZo.mjs.map +1 -0
  32. package/dist/index-BYMnhRIC.d.mts +161 -0
  33. package/dist/index-C0C4e-Gn.d.mts +55 -0
  34. package/dist/index-CaxrMD1A.d.mts +1 -0
  35. package/dist/index-DaRyjo7O.d.mts +77 -0
  36. package/dist/index-DgOugrpF.d.mts +275 -0
  37. package/dist/index-EwL6fHLo.d.mts +267 -0
  38. package/dist/index-k2YhCgsh.d.mts +57 -0
  39. package/dist/index.d.mts +22 -0
  40. package/dist/index.mjs +23 -0
  41. package/dist/key-BiGxGLhg.d.mts +37 -0
  42. package/dist/key-Dn-aX4x4.mjs +130 -0
  43. package/dist/key-Dn-aX4x4.mjs.map +1 -0
  44. package/dist/kind-BLl4cLOc.mjs +59 -0
  45. package/dist/kind-BLl4cLOc.mjs.map +1 -0
  46. package/dist/loaders-BNQszDAn.mjs +767 -0
  47. package/dist/loaders-BNQszDAn.mjs.map +1 -0
  48. package/dist/loaders.d.mts +3 -0
  49. package/dist/loaders.mjs +2 -0
  50. package/dist/memory-BCmhZPek.mjs +461 -0
  51. package/dist/memory-BCmhZPek.mjs.map +1 -0
  52. package/dist/message-C_Uj-Y-c.mjs +179 -0
  53. package/dist/message-C_Uj-Y-c.mjs.map +1 -0
  54. package/dist/message-DJC-Jz6T.d.mts +32 -0
  55. package/dist/nip17-BWq-Kfq5.d.mts +38 -0
  56. package/dist/nip19-D7905oIv.d.mts +63 -0
  57. package/dist/nip46-C_DoxiS_.d.mts +51 -0
  58. package/dist/nip59-DljW_sYh.d.mts +76 -0
  59. package/dist/nip65-Di5hZRuV.d.mts +21 -0
  60. package/dist/nip77-ByxlgoQO.d.mts +55 -0
  61. package/dist/nips/blossom.d.mts +93 -0
  62. package/dist/nips/blossom.mjs +325 -0
  63. package/dist/nips/blossom.mjs.map +1 -0
  64. package/dist/nips/nip04.d.mts +8 -0
  65. package/dist/nips/nip04.mjs +41 -0
  66. package/dist/nips/nip04.mjs.map +1 -0
  67. package/dist/nips/nip05.d.mts +89 -0
  68. package/dist/nips/nip05.mjs +147 -0
  69. package/dist/nips/nip05.mjs.map +1 -0
  70. package/dist/nips/nip10.d.mts +43 -0
  71. package/dist/nips/nip10.mjs +194 -0
  72. package/dist/nips/nip10.mjs.map +1 -0
  73. package/dist/nips/nip11.d.mts +43 -0
  74. package/dist/nips/nip11.mjs +99 -0
  75. package/dist/nips/nip11.mjs.map +1 -0
  76. package/dist/nips/nip13.d.mts +23 -0
  77. package/dist/nips/nip13.mjs +88 -0
  78. package/dist/nips/nip13.mjs.map +1 -0
  79. package/dist/nips/nip17.d.mts +2 -0
  80. package/dist/nips/nip17.mjs +138 -0
  81. package/dist/nips/nip17.mjs.map +1 -0
  82. package/dist/nips/nip19.d.mts +2 -0
  83. package/dist/nips/nip19.mjs +174 -0
  84. package/dist/nips/nip19.mjs.map +1 -0
  85. package/dist/nips/nip21.d.mts +17 -0
  86. package/dist/nips/nip21.mjs +29 -0
  87. package/dist/nips/nip21.mjs.map +1 -0
  88. package/dist/nips/nip27.d.mts +42 -0
  89. package/dist/nips/nip27.mjs +175 -0
  90. package/dist/nips/nip27.mjs.map +1 -0
  91. package/dist/nips/nip42.d.mts +12 -0
  92. package/dist/nips/nip42.mjs +22 -0
  93. package/dist/nips/nip42.mjs.map +1 -0
  94. package/dist/nips/nip44.d.mts +12 -0
  95. package/dist/nips/nip44.mjs +125 -0
  96. package/dist/nips/nip44.mjs.map +1 -0
  97. package/dist/nips/nip46.d.mts +2 -0
  98. package/dist/nips/nip46.mjs +132 -0
  99. package/dist/nips/nip46.mjs.map +1 -0
  100. package/dist/nips/nip49.d.mts +12 -0
  101. package/dist/nips/nip49.mjs +80 -0
  102. package/dist/nips/nip49.mjs.map +1 -0
  103. package/dist/nips/nip51.d.mts +88 -0
  104. package/dist/nips/nip51.mjs +246 -0
  105. package/dist/nips/nip51.mjs.map +1 -0
  106. package/dist/nips/nip57.d.mts +43 -0
  107. package/dist/nips/nip57.mjs +230 -0
  108. package/dist/nips/nip57.mjs.map +1 -0
  109. package/dist/nips/nip59.d.mts +2 -0
  110. package/dist/nips/nip59.mjs +171 -0
  111. package/dist/nips/nip59.mjs.map +1 -0
  112. package/dist/nips/nip65.d.mts +2 -0
  113. package/dist/nips/nip65.mjs +76 -0
  114. package/dist/nips/nip65.mjs.map +1 -0
  115. package/dist/nips/nip77.d.mts +2 -0
  116. package/dist/nips/nip77.mjs +421 -0
  117. package/dist/nips/nip77.mjs.map +1 -0
  118. package/dist/nips/nip96.d.mts +31 -0
  119. package/dist/nips/nip96.mjs +95 -0
  120. package/dist/nips/nip96.mjs.map +1 -0
  121. package/dist/nips/nip98.d.mts +28 -0
  122. package/dist/nips/nip98.mjs +91 -0
  123. package/dist/nips/nip98.mjs.map +1 -0
  124. package/dist/nostr_crypto_wasm_bg-hi5aXi5P.mjs +4 -0
  125. package/dist/nostr_crypto_wasm_bg.wasm +0 -0
  126. package/dist/pool-C_j1OmBB.mjs +1881 -0
  127. package/dist/pool-C_j1OmBB.mjs.map +1 -0
  128. package/dist/pool-DhRi7l-b.d.mts +297 -0
  129. package/dist/relay.d.mts +4 -0
  130. package/dist/relay.mjs +2 -0
  131. package/dist/signer-CZ6K6FUc.mjs +473 -0
  132. package/dist/signer-CZ6K6FUc.mjs.map +1 -0
  133. package/dist/signer.d.mts +3 -0
  134. package/dist/signer.mjs +2 -0
  135. package/dist/storage-DOy0iLRE.mjs +870 -0
  136. package/dist/storage-DOy0iLRE.mjs.map +1 -0
  137. package/dist/storage.d.mts +4 -0
  138. package/dist/storage.mjs +4 -0
  139. package/dist/types-BzyADqnw.d.mts +19 -0
  140. package/dist/types-Dn24TPFs.d.mts +43 -0
  141. package/dist/util-6tfLQ9JF.mjs +73 -0
  142. package/dist/util-6tfLQ9JF.mjs.map +1 -0
  143. package/dist/wasm.d.mts +19 -0
  144. package/dist/wasm.mjs +237 -0
  145. package/dist/wasm.mjs.map +1 -0
  146. package/package.json +204 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loaders-BNQszDAn.mjs","names":["#events","#relays","#batchLoadFn","#cacheKeyFn","#maxBatchSize","#useCache","#cache","#inflight","#queue","#dispatch","#scheduled","#pool","#gossip","#storage","#discovery","#kinds","#maxRelays","#timeoutMs","#onEvent","#observe","#applySync","#hydrate","#bounds","#authors","#assertOpen","#hydrateBoundsFromStore","#syncFilters","#updateBounds","#persistBounds","#liveCloser","#noteEvent","#closed"],"sources":["../src/loaders/cache.ts","../src/loaders/context.ts","../src/loaders/event.ts","../src/loaders/dataloader.ts","../src/loaders/replaceable.ts","../src/loaders/lists.ts","../src/loaders/profile.ts","../src/loaders/outbox.ts","../src/loaders/index.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner } from \"../core/event.ts\";\n\nexport type ReplaceableKey = {\n kind: number;\n pubkey: string;\n dTag?: string;\n};\n\nfunction keyOf(spec: ReplaceableKey): string {\n return `${spec.kind}:${spec.pubkey.toLowerCase()}:${spec.dTag ?? \"\"}`;\n}\n\n/** In-memory replaceable-event cache used by loaders (no DOM / localStorage). */\nexport class ReplaceableCache {\n #events = new Map<string, { event: Event | null; fetchedAt: number }>();\n\n get(spec: ReplaceableKey): { event: Event | null; fetchedAt: number } | undefined {\n return this.#events.get(keyOf(spec));\n }\n\n set(spec: ReplaceableKey, event: Event | null, fetchedAt = Math.floor(Date.now() / 1000)): void {\n this.#events.set(keyOf(spec), { event, fetchedAt });\n }\n\n /** Keep newer event by created_at. */\n putIfNewer(event: Event, dTag?: string): void {\n const spec: ReplaceableKey = { kind: event.kind, pubkey: event.pubkey, dTag };\n const prev = this.get(spec);\n if (!prev?.event || isReplaceableWinner(event, prev.event)) {\n this.set(spec, event);\n }\n }\n\n clear(spec?: ReplaceableKey): void {\n if (spec) this.#events.delete(keyOf(spec));\n else this.#events.clear();\n }\n\n get size(): number {\n return this.#events.size;\n }\n}\n","import type { Pool } from \"../relay/pool.ts\";\nimport { ReplaceableCache } from \"./cache.ts\";\n\nexport type LoaderContextOptions = {\n pool: Pool;\n /** Fallback / discovery relays when no per-user routing is known. */\n relays: readonly string[];\n cache?: ReplaceableCache;\n /** Max age (seconds) before a cached replaceable is considered stale. Default 2 days. */\n staleAfterSec?: number;\n fetchTimeoutMs?: number;\n};\n\n/**\n * Explicit dependency bag for loaders — never a module-level singleton.\n */\nexport class LoaderContext {\n readonly pool: Pool;\n readonly cache: ReplaceableCache;\n readonly staleAfterSec: number;\n readonly fetchTimeoutMs: number;\n #relays: string[];\n\n constructor(opts: LoaderContextOptions) {\n this.pool = opts.pool;\n this.#relays = [...opts.relays];\n this.cache = opts.cache ?? new ReplaceableCache();\n this.staleAfterSec = opts.staleAfterSec ?? 60 * 60 * 24 * 2;\n this.fetchTimeoutMs = opts.fetchTimeoutMs ?? 4400;\n }\n\n /** Snapshot of discovery/fallback relays. */\n get relays(): readonly string[] {\n return this.#relays;\n }\n\n addRelay(url: string): void {\n if (!this.#relays.includes(url)) this.#relays.push(url);\n }\n\n removeRelay(url: string): void {\n this.#relays = this.#relays.filter((r) => r !== url);\n }\n\n setRelays(urls: readonly string[]): void {\n this.#relays = [...urls];\n }\n\n isFresh(fetchedAt: number, now = Math.floor(Date.now() / 1000)): boolean {\n return now - fetchedAt < this.staleAfterSec;\n }\n}\n","import { isReplaceableWinner, type Event } from \"../core/event.ts\";\nimport { isAddressableKind } from \"../core/kind.ts\";\nimport { isHex32 } from \"../core/util.ts\";\nimport { decode, Nip19Error, type AddressPointer, type EventPointer } from \"../nips/nip19.ts\";\nimport type { LoaderContext } from \"./context.ts\";\n\nexport type EventRef = string | EventPointer | AddressPointer;\n\nfunction dFilter(kind: number, identifier: string): { \"#d\"?: string[] } {\n if (isAddressableKind(kind)) return { \"#d\": [identifier] };\n return {};\n}\n\nfunction parseRef(ref: EventRef): {\n filter: { ids?: string[]; authors?: string[]; kinds?: number[]; \"#d\"?: string[] };\n hints: string[];\n cacheKey: string;\n} {\n if (typeof ref === \"string\") {\n if (isHex32(ref)) {\n return {\n filter: { ids: [ref.toLowerCase()] },\n hints: [],\n cacheKey: `id:${ref.toLowerCase()}`,\n };\n }\n const decoded = decode(ref);\n switch (decoded.type) {\n case \"note\":\n return { filter: { ids: [decoded.data] }, hints: [], cacheKey: `id:${decoded.data}` };\n case \"nevent\":\n return {\n filter: { ids: [decoded.data.id] },\n hints: decoded.data.relays ?? [],\n cacheKey: `id:${decoded.data.id}`,\n };\n case \"naddr\":\n return {\n filter: {\n authors: [decoded.data.pubkey.toLowerCase()],\n kinds: [decoded.data.kind],\n ...dFilter(decoded.data.kind, decoded.data.identifier),\n },\n hints: decoded.data.relays ?? [],\n cacheKey: `addr:${decoded.data.kind}:${decoded.data.pubkey}:${decoded.data.identifier}`,\n };\n default:\n throw new Nip19Error(`cannot load event from ${decoded.type}`);\n }\n }\n if (\"id\" in ref) {\n return {\n filter: { ids: [ref.id.toLowerCase()] },\n hints: ref.relays ?? [],\n cacheKey: `id:${ref.id.toLowerCase()}`,\n };\n }\n return {\n filter: {\n authors: [ref.pubkey.toLowerCase()],\n kinds: [ref.kind],\n ...dFilter(ref.kind, ref.identifier),\n },\n hints: ref.relays ?? [],\n cacheKey: `addr:${ref.kind}:${ref.pubkey}:${ref.identifier}`,\n };\n}\n\nexport function createEventLoader(ctx: LoaderContext) {\n const inflight = new Map<string, Promise<Event | undefined>>();\n const cache = new Map<string, Event | undefined>();\n return {\n load(ref: EventRef): Promise<Event | undefined> {\n const parsed = parseRef(ref);\n if (cache.has(parsed.cacheKey)) return Promise.resolve(cache.get(parsed.cacheKey));\n const hit = inflight.get(parsed.cacheKey);\n if (hit) return hit;\n const p = (async () => {\n const relays = [...new Set([...parsed.hints, ...ctx.relays])];\n if (relays.length === 0) return undefined;\n const events = await ctx.pool.fetch(relays, [parsed.filter], {\n timeoutMs: ctx.fetchTimeoutMs,\n });\n let best: Event | undefined;\n for (const e of events) {\n if (!best || isReplaceableWinner(e, best)) best = e;\n }\n cache.set(parsed.cacheKey, best);\n return best;\n })().finally(() => inflight.delete(parsed.cacheKey));\n inflight.set(parsed.cacheKey, p);\n return p;\n },\n clearAll() {\n inflight.clear();\n cache.clear();\n },\n };\n}\n\nexport type EventLoader = ReturnType<typeof createEventLoader>;\n","import { NostrError } from \"../core/error.ts\";\n\nexport class LoaderError extends NostrError {}\n\n/** Minimal request coalescer. Batches keys within a microtask; no global state. */\nexport type BatchLoadFn<K, V> = (keys: readonly K[]) => Promise<readonly (V | Error)[]>;\n\nexport type DataLoaderOptions<K, C = K> = {\n cacheKeyFn?: (key: K) => C;\n maxBatchSize?: number;\n /** When false, only coalesces in-flight requests (no durable memoization). Default true. */\n cache?: boolean;\n};\n\nexport class DataLoader<K, V, C = K> {\n readonly #batchLoadFn: BatchLoadFn<K, V>;\n readonly #cacheKeyFn: (key: K) => C;\n readonly #maxBatchSize: number;\n readonly #useCache: boolean;\n readonly #cache = new Map<C, Promise<V>>();\n readonly #inflight = new Map<C, Promise<V>>();\n #queue: Array<{\n key: K;\n resolve: (v: V) => void;\n reject: (e: unknown) => void;\n }> = [];\n #scheduled = false;\n\n constructor(batchLoadFn: BatchLoadFn<K, V>, options: DataLoaderOptions<K, C> = {}) {\n this.#batchLoadFn = batchLoadFn;\n this.#cacheKeyFn = options.cacheKeyFn ?? ((k: K) => k as unknown as C);\n this.#maxBatchSize = options.maxBatchSize ?? Infinity;\n this.#useCache = options.cache !== false;\n }\n\n load(key: K): Promise<V> {\n const cacheKey = this.#cacheKeyFn(key);\n if (this.#useCache) {\n const cached = this.#cache.get(cacheKey);\n if (cached) return cached;\n }\n const inflight = this.#inflight.get(cacheKey);\n if (inflight) return inflight;\n\n const promise = new Promise<V>((resolve, reject) => {\n this.#queue.push({ key, resolve, reject });\n if (this.#queue.length >= this.#maxBatchSize) {\n this.#dispatch();\n } else if (!this.#scheduled) {\n this.#scheduled = true;\n queueMicrotask(() => this.#dispatch());\n }\n }).finally(() => {\n this.#inflight.delete(cacheKey);\n });\n\n this.#inflight.set(cacheKey, promise);\n if (this.#useCache) this.#cache.set(cacheKey, promise);\n return promise;\n }\n\n clear(key: K): void {\n this.#cache.delete(this.#cacheKeyFn(key));\n this.#inflight.delete(this.#cacheKeyFn(key));\n }\n\n clearAll(): void {\n this.#cache.clear();\n this.#inflight.clear();\n }\n\n #dispatch(): void {\n this.#scheduled = false;\n const batch = this.#queue.splice(0, this.#maxBatchSize);\n if (batch.length === 0) return;\n\n const keys = batch.map((b) => b.key);\n void this.#batchLoadFn(keys)\n .then((values) => {\n if (values.length !== keys.length) {\n const err = new LoaderError(\n `DataLoader batch function must return array of length ${keys.length}, got ${values.length}`,\n );\n for (const item of batch) item.reject(err);\n return;\n }\n for (let i = 0; i < batch.length; i++) {\n const value = values[i]!;\n if (value instanceof Error) batch[i]!.reject(value);\n else batch[i]!.resolve(value);\n }\n })\n .catch((err) => {\n for (const item of batch) item.reject(err);\n });\n\n if (this.#queue.length > 0) {\n this.#scheduled = true;\n queueMicrotask(() => this.#dispatch());\n }\n }\n}\n","import type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { getDTag } from \"../core/tag.ts\";\nimport { DataLoader } from \"./dataloader.ts\";\nimport type { LoaderContext } from \"./context.ts\";\n\nexport type ReplaceableLoadResult = {\n event: Event | null;\n fresh: boolean;\n};\n\nexport type LoadStyle = \"default\" | \"force\" | \"cache-only\";\n\n/**\n * Batch-fetch replaceable events (kind + authors) via the pool, with cache.\n * Durable cache is ReplaceableCache; DataLoader only coalesces in-flight requests.\n */\nexport function createReplaceableLoader(ctx: LoaderContext, kind: number) {\n type Key = { pubkey: string; hints?: string[] };\n\n const loader = new DataLoader<Key, Event | null, string>(\n async (keys) => {\n const authors = [...new Set(keys.map((k) => k.pubkey))];\n const hintRelays = [...new Set(keys.flatMap((k) => k.hints ?? []).concat(ctx.relays))];\n const filter: Filter = { kinds: [kind], authors };\n const events =\n hintRelays.length > 0\n ? await ctx.pool.fetch(hintRelays, [filter], { timeoutMs: ctx.fetchTimeoutMs })\n : [];\n\n const best = new Map<string, Event>();\n for (const event of events) {\n if (event.kind !== kind) continue;\n const prev = best.get(event.pubkey);\n if (!prev || isReplaceableWinner(event, prev)) best.set(event.pubkey, event);\n }\n\n const now = Math.floor(Date.now() / 1000);\n return keys.map((k) => {\n const event = best.get(k.pubkey) ?? null;\n ctx.cache.set(\n { kind, pubkey: k.pubkey, dTag: event ? (getDTag(event.tags) ?? undefined) : undefined },\n event,\n now,\n );\n return event;\n });\n },\n {\n cache: false,\n cacheKeyFn: (k) => `${kind}:${k.pubkey}:${(k.hints ?? []).join(\",\")}`,\n maxBatchSize: 50,\n },\n );\n\n return {\n async load(\n pubkey: string,\n opts?: { hints?: string[]; style?: LoadStyle },\n ): Promise<ReplaceableLoadResult> {\n const pk = pubkey.toLowerCase();\n const style = opts?.style ?? \"default\";\n const cached = ctx.cache.get({ kind, pubkey: pk });\n\n if (style === \"cache-only\") {\n return { event: cached?.event ?? null, fresh: false };\n }\n if (style === \"default\" && cached && ctx.isFresh(cached.fetchedAt)) {\n return { event: cached.event, fresh: false };\n }\n\n const event = await loader.load({ pubkey: pk, hints: opts?.hints });\n return { event, fresh: true };\n },\n clear(pubkey?: string) {\n if (pubkey) {\n const pk = pubkey.toLowerCase();\n loader.clear({ pubkey: pk });\n ctx.cache.clear({ kind, pubkey: pk });\n } else {\n loader.clearAll();\n }\n },\n };\n}\n","import type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { isHex32, normalizeURL } from \"../core/util.ts\";\nimport { parseDmRelayList } from \"../nips/nip17.ts\";\nimport type { RelayListItem } from \"../nips/nip65.ts\";\nimport { parseRelayList } from \"../nips/nip65.ts\";\nimport type { LoaderContext } from \"./context.ts\";\nimport { createReplaceableLoader, type LoadStyle } from \"./replaceable.ts\";\n\nexport type ListResult<T> = {\n event: Event | null;\n items: T[];\n fresh: boolean;\n};\n\nexport type MutedEntity =\n | { label: \"pubkey\"; value: string }\n | { label: \"thread\"; value: string }\n | { label: \"hashtag\"; value: string }\n | { label: \"word\"; value: string };\n\nfunction fromTags<T>(event: Event | null, map: (tag: readonly string[]) => T | undefined): T[] {\n if (!event) return [];\n const out: T[] = [];\n for (const tag of event.tags) {\n const item = map(tag);\n if (item !== undefined) out.push(item);\n }\n return out;\n}\n\nexport function createListLoaders(ctx: LoaderContext) {\n const followsLoader = createReplaceableLoader(ctx, Kind.Contacts);\n const muteLoader = createReplaceableLoader(ctx, Kind.MuteList);\n const relayListLoader = createReplaceableLoader(ctx, Kind.RelayList);\n const dmRelayListLoader = createReplaceableLoader(ctx, Kind.DirectMessageRelaysList);\n\n return {\n async follows(\n pubkey: string,\n opts?: { hints?: string[]; style?: LoadStyle },\n ): Promise<ListResult<string>> {\n const { event, fresh } = await followsLoader.load(pubkey, opts);\n return {\n event,\n fresh,\n items: fromTags(event, (tag) =>\n tag[0] === \"p\" && tag[1] && isHex32(tag[1]) ? tag[1].toLowerCase() : undefined,\n ),\n };\n },\n\n async muteList(\n pubkey: string,\n opts?: { hints?: string[]; style?: LoadStyle },\n ): Promise<ListResult<MutedEntity>> {\n const { event, fresh } = await muteLoader.load(pubkey, opts);\n return {\n event,\n fresh,\n items: fromTags(event, (tag) => {\n if (!tag[1]) return undefined;\n switch (tag[0]) {\n case \"p\":\n return isHex32(tag[1]) ? { label: \"pubkey\", value: tag[1].toLowerCase() } : undefined;\n case \"e\":\n return isHex32(tag[1]) ? { label: \"thread\", value: tag[1].toLowerCase() } : undefined;\n case \"t\":\n return { label: \"hashtag\", value: tag[1] };\n case \"word\":\n return { label: \"word\", value: tag[1] };\n default:\n return undefined;\n }\n }),\n };\n },\n\n async relayList(\n pubkey: string,\n opts?: { hints?: string[]; style?: LoadStyle },\n ): Promise<ListResult<RelayListItem>> {\n const { event, fresh } = await relayListLoader.load(pubkey, opts);\n let items: RelayListItem[] = [];\n if (event) {\n try {\n items = parseRelayList(event);\n } catch {\n items = [];\n }\n }\n // ensure normalized urls even if parse skipped\n items = items.map((i) => {\n try {\n return { ...i, url: normalizeURL(i.url) };\n } catch {\n return i;\n }\n });\n return { event, fresh, items };\n },\n\n async dmRelayList(\n pubkey: string,\n opts?: { hints?: string[]; style?: LoadStyle },\n ): Promise<ListResult<string>> {\n const { event, fresh } = await dmRelayListLoader.load(pubkey, opts);\n let items: string[] = [];\n if (event) {\n try {\n items = parseDmRelayList(event);\n } catch {\n items = [];\n }\n }\n return { event, fresh, items };\n },\n };\n}\n\nexport type ListLoaders = ReturnType<typeof createListLoaders>;\n","import type { Event } from \"../core/event.ts\";\nimport type { ProfileMetadata } from \"../core/builder.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { npubEncode } from \"../nips/nip19.ts\";\nimport type { LoaderContext } from \"./context.ts\";\nimport { createReplaceableLoader, type LoadStyle } from \"./replaceable.ts\";\n\nexport type NostrUser = {\n pubkey: string;\n npub: string;\n shortName: string;\n image?: string;\n metadata: ProfileMetadata;\n lastUpdated: number;\n event: Event | null;\n fresh: boolean;\n};\n\nexport function bareNostrUser(pubkey: string): NostrUser {\n const pk = pubkey.toLowerCase();\n let npub: string;\n try {\n npub = npubEncode(pk);\n } catch {\n npub = pk;\n }\n return {\n pubkey: pk,\n npub,\n shortName: npub.startsWith(\"npub1\") ? `${npub.slice(0, 8)}…${npub.slice(-4)}` : pk.slice(0, 8),\n metadata: {},\n lastUpdated: 0,\n event: null,\n fresh: false,\n };\n}\n\nfunction parseMetadata(content: string): ProfileMetadata {\n try {\n const obj = JSON.parse(content) as ProfileMetadata;\n return typeof obj === \"object\" && obj !== null ? obj : {};\n } catch {\n return {};\n }\n}\n\nexport function createProfileLoader(ctx: LoaderContext) {\n const loader = createReplaceableLoader(ctx, Kind.Metadata);\n\n return {\n async load(pubkey: string, opts?: { hints?: string[]; style?: LoadStyle }): Promise<NostrUser> {\n const base = bareNostrUser(pubkey);\n const { event, fresh } = await loader.load(pubkey, opts);\n if (!event) return { ...base, fresh };\n\n const metadata = parseMetadata(event.content);\n const display = metadata.display_name || metadata.name;\n return {\n ...base,\n shortName: display || base.shortName,\n image: metadata.picture,\n metadata,\n lastUpdated: event.created_at,\n event,\n fresh,\n };\n },\n };\n}\n\nexport type ProfileLoader = ReturnType<typeof createProfileLoader>;\n","import type { Event } from \"../core/event.ts\";\nimport { NostrError } from \"../core/error.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { sortedEvents } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport type { Gossip } from \"../gossip/gossip.ts\";\nimport type { Pool } from \"../relay/pool.ts\";\nimport { toStorageError } from \"../storage/error.ts\";\nimport type { EventStore, OutboxBound } from \"../storage/types.ts\";\n\nexport type { OutboxBound } from \"../storage/types.ts\";\n\nexport class OutboxError extends NostrError {}\n\nexport type OutboxFeedOptions = {\n pool: Pool;\n gossip: Gossip;\n storage: EventStore;\n /** Fallback relays when an author has no known outbox routes. */\n discoveryRelays: readonly string[];\n authors: readonly string[];\n /** Event kinds to fetch. Default `[Kind.TextNote]`. */\n kinds?: readonly number[];\n /** Max write-relays to use per author. Default 3. */\n maxRelaysPerAuthor?: number;\n fetchTimeoutMs?: number;\n /** Called for live events after observe, and for sync events returned by applySync. */\n onEvent?: (event: Event) => void;\n /** Live ingest (e.g. `client.observe`). StartLive never putManys. */\n observe?: (event: Event) => void;\n /**\n * Sync path only. Awaited. Return events that should advance bounds.\n * Throw → sync throws, bounds unchanged.\n */\n applySync?: (events: readonly Event[]) => Promise<readonly Event[]>;\n /**\n * Load kind:10002 for authors before sync when routes are missing.\n * Requires a relay-list loader.\n */\n hydrate?: (pubkeys: readonly string[]) => Promise<void>;\n};\n\nfunction boundKey(pubkey: string, kind: number): string {\n return `${pubkey.toLowerCase()}:${kind}`;\n}\n\n/** Same skip/dedup as Gossip.setRoutes so prefer can match Client.relays. */\nfunction canonicalRelayUrls(urls: readonly string[]): string[] {\n const out: string[] = [];\n for (const raw of urls) {\n try {\n const url = normalizeURL(raw);\n if (!out.includes(url)) out.push(url);\n } catch {\n // not a relay URL\n }\n }\n return out;\n}\n\n/**\n * Group authors by outbox relay (discovery fallback).\n * `prefer` reorders existing candidates only; it never appends a URL\n * that is not already in the author's outbox or discovery list.\n * Returns Map<relayUrl, authors[]>.\n */\nexport function groupAuthorsByOutboxRelay(\n authors: readonly string[],\n gossip: Gossip,\n discoveryRelays: readonly string[],\n maxRelaysPerAuthor = 3,\n prefer: readonly string[] = [],\n): Map<string, string[]> {\n const leftover = new Set(\n (gossip.route({ authors: authors.map((a) => a.toLowerCase()) }).remainder?.authors ?? []).map(\n (a) => a.toLowerCase(),\n ),\n );\n const preferSet = new Set(canonicalRelayUrls(prefer));\n const discovery = canonicalRelayUrls(discoveryRelays);\n const map = new Map<string, string[]>();\n\n for (const author of authors) {\n const pk = author.toLowerCase();\n const urls = leftover.has(pk) ? discovery : gossip.outboxRelays(pk);\n const preferred: string[] = [];\n const rest: string[] = [];\n for (const url of urls) {\n if (preferSet.has(url)) preferred.push(url);\n else rest.push(url);\n }\n for (const url of preferred.concat(rest).slice(0, maxRelaysPerAuthor)) {\n const list = map.get(url) ?? [];\n if (!list.includes(pk)) list.push(pk);\n map.set(url, list);\n }\n }\n return map;\n}\n\n/**\n * Outbox-model feed: history sync + live subscription for a set of authors,\n * routed via NIP-65 write relays (with discovery fallback).\n */\nexport class OutboxFeed {\n readonly #pool: Pool;\n readonly #gossip: Gossip;\n readonly #storage: EventStore;\n readonly #discovery: string[];\n readonly #kinds: number[];\n readonly #maxRelays: number;\n readonly #timeoutMs: number;\n readonly #onEvent: ((event: Event) => void) | undefined;\n readonly #observe: ((event: Event) => void) | undefined;\n readonly #applySync: ((events: readonly Event[]) => Promise<readonly Event[]>) | undefined;\n readonly #hydrate: ((pubkeys: readonly string[]) => Promise<void>) | undefined;\n readonly #bounds = new Map<string, OutboxBound>();\n #authors: string[];\n #liveCloser: { close: (reason?: string) => void } | undefined;\n #closed = false;\n\n constructor(opts: OutboxFeedOptions) {\n this.#pool = opts.pool;\n this.#gossip = opts.gossip;\n this.#storage = opts.storage;\n this.#discovery = [...opts.discoveryRelays];\n this.#authors = [...new Set(opts.authors.map((a) => a.toLowerCase()))];\n this.#kinds = [...(opts.kinds ?? [Kind.TextNote])];\n this.#maxRelays = opts.maxRelaysPerAuthor ?? 3;\n this.#timeoutMs = opts.fetchTimeoutMs ?? 4400;\n this.#onEvent = opts.onEvent;\n this.#observe = opts.observe;\n this.#applySync = opts.applySync;\n this.#hydrate = opts.hydrate;\n }\n\n get authors(): readonly string[] {\n return this.#authors;\n }\n\n get kinds(): readonly number[] {\n return this.#kinds;\n }\n\n /** Replace the author set (does not auto-restart live). */\n setAuthors(authors: readonly string[]): void {\n this.#authors = [...new Set(authors.map((a) => a.toLowerCase()))];\n }\n\n getBound(pubkey: string, kind: number): OutboxBound | undefined {\n return this.#bounds.get(boundKey(pubkey, kind));\n }\n\n /**\n * Load NIP-65 relay lists for authors that have no outbox routes yet.\n */\n async hydrate(): Promise<void> {\n this.#assertOpen();\n if (!this.#hydrate) return;\n const missing = this.#authors.filter((pk) => this.#gossip.outboxRelays(pk).length === 0);\n if (missing.length === 0) return;\n await this.#hydrate(missing);\n }\n\n /**\n * One-shot history pull. Persistence is `applySync`; bounds move only for events it returns.\n */\n async sync(opts?: {\n limit?: number;\n since?: number;\n until?: number;\n signal?: AbortSignal;\n /** Skip hydrate() even if provided. */\n skipHydrate?: boolean;\n }): Promise<Event[]> {\n this.#assertOpen();\n if (!opts?.skipHydrate) await this.hydrate();\n await this.#hydrateBoundsFromStore();\n\n const byRelay = groupAuthorsByOutboxRelay(\n this.#authors,\n this.#gossip,\n this.#discovery,\n this.#maxRelays,\n this.#pool.connectedUrls(),\n );\n\n if (byRelay.size === 0) return [];\n\n const byId = new Map<string, Event>();\n await Promise.all(\n [...byRelay.entries()].map(async ([url, authors]) => {\n if (opts?.signal?.aborted) return;\n\n const filters = this.#syncFilters(authors, opts);\n try {\n const batch = await this.#pool.fetch([url], filters, {\n timeoutMs: this.#timeoutMs,\n signal: opts?.signal,\n });\n for (const event of batch) byId.set(event.id, event);\n } catch {\n // skip failed relay\n }\n }),\n );\n\n const unique = [...byId.values()];\n if (unique.length === 0) return [];\n\n let applied: readonly Event[] = [];\n if (this.#applySync) {\n try {\n applied = await this.#applySync(unique);\n } catch (err) {\n throw toStorageError(err);\n }\n }\n const dirty = new Set<string>();\n for (const event of applied) {\n this.#updateBounds(event);\n dirty.add(boundKey(event.pubkey, event.kind));\n this.#onEvent?.(event);\n }\n await this.#persistBounds(dirty);\n return sortedEvents(unique);\n }\n\n /**\n * Start a live subscription across outbox relays for the current authors.\n * Closes any previous live subscription.\n */\n startLive(opts?: { signal?: AbortSignal; since?: number }): { close: (reason?: string) => void } {\n this.#assertOpen();\n this.#liveCloser?.close(\"restart\");\n\n const byRelay = groupAuthorsByOutboxRelay(\n this.#authors,\n this.#gossip,\n this.#discovery,\n this.#maxRelays,\n this.#pool.connectedUrls(),\n );\n\n const seen = new Set<string>();\n const closers: Array<{ close: (reason?: string) => void }> = [];\n const since = opts?.since ?? Math.floor(Date.now() / 1000) - 60;\n\n for (const [url, authors] of byRelay) {\n const filter: Filter = {\n authors,\n kinds: this.#kinds,\n since,\n };\n closers.push(\n this.#pool.subscribe([url], [filter], {\n signal: opts?.signal,\n onevent: (event) => {\n if (seen.has(event.id)) return;\n seen.add(event.id);\n this.#noteEvent(event);\n },\n }),\n );\n }\n\n const closer = {\n close: (reason?: string) => {\n for (const c of closers) c.close(reason);\n if (this.#liveCloser === closer) this.#liveCloser = undefined;\n },\n };\n this.#liveCloser = closer;\n return closer;\n }\n\n /** Convenience: hydrate + sync + startLive. */\n async start(opts?: {\n limit?: number;\n signal?: AbortSignal;\n }): Promise<{ close: (reason?: string) => void; events: Event[] }> {\n const events = await this.sync({ limit: opts?.limit, signal: opts?.signal });\n const live = this.startLive({ signal: opts?.signal });\n return { close: (r) => live.close(r), events };\n }\n\n close(): void {\n this.#closed = true;\n this.#liveCloser?.close(\"feed closed\");\n this.#liveCloser = undefined;\n }\n\n #assertOpen(): void {\n if (this.#closed) throw new OutboxError(\"OutboxFeed is closed\");\n }\n\n async #hydrateBoundsFromStore(): Promise<void> {\n await Promise.all(\n this.#authors.flatMap((pk) =>\n this.#kinds.map(async (kind) => {\n const key = boundKey(pk, kind);\n if (this.#bounds.has(key)) return;\n const bound = await this.#storage.getOutboxBound(pk, kind);\n if (!bound) return;\n await this.#storage.setOutboxBound(pk, kind, bound);\n this.#bounds.set(key, { oldest: bound.oldest, newest: bound.newest });\n }),\n ),\n );\n }\n\n #syncFilters(\n authors: string[],\n opts?: { limit?: number; since?: number; until?: number },\n ): Filter[] {\n const base: Filter = {\n kinds: this.#kinds,\n limit: opts?.limit ?? 50,\n ...(opts?.until !== undefined ? { until: opts.until } : {}),\n };\n\n if (opts?.since !== undefined) {\n return [{ ...base, authors, since: opts.since }];\n }\n\n const bounded: string[] = [];\n const unbounded: string[] = [];\n let minBoundedNewest: number | undefined;\n\n for (const pk of authors) {\n let newest: number | undefined;\n let complete = true;\n for (const kind of this.#kinds) {\n const b = this.#bounds.get(boundKey(pk, kind));\n if (!b) {\n complete = false;\n break;\n }\n if (newest === undefined || b.newest < newest) newest = b.newest;\n }\n if (complete && newest !== undefined) {\n bounded.push(pk);\n if (minBoundedNewest === undefined || newest < minBoundedNewest) {\n minBoundedNewest = newest;\n }\n } else {\n unbounded.push(pk);\n }\n }\n\n if (bounded.length === 0 || minBoundedNewest === undefined) {\n return [{ ...base, authors }];\n }\n if (unbounded.length === 0) {\n return [{ ...base, authors, since: Math.max(0, minBoundedNewest - 1) }];\n }\n return [\n { ...base, authors: bounded, since: Math.max(0, minBoundedNewest - 1) },\n { ...base, authors: unbounded },\n ];\n }\n\n #noteEvent(event: Event): void {\n this.#updateBounds(event);\n const bound = this.#bounds.get(boundKey(event.pubkey, event.kind));\n if (bound) {\n void this.#storage\n .setOutboxBound(event.pubkey, event.kind, {\n oldest: bound.oldest,\n newest: bound.newest,\n })\n .catch(() => {});\n }\n this.#observe?.(event);\n this.#onEvent?.(event);\n }\n\n async #persistBounds(keys: Iterable<string>): Promise<void> {\n const writes: Promise<void>[] = [];\n for (const key of keys) {\n const bound = this.#bounds.get(key);\n if (!bound) continue;\n const sep = key.lastIndexOf(\":\");\n writes.push(\n this.#storage.setOutboxBound(key.slice(0, sep), Number(key.slice(sep + 1)), {\n oldest: bound.oldest,\n newest: bound.newest,\n }),\n );\n }\n if (writes.length === 0) return;\n try {\n await Promise.all(writes);\n } catch (err) {\n throw toStorageError(err);\n }\n }\n\n #updateBounds(event: Event): void {\n const key = boundKey(event.pubkey, event.kind);\n const prev = this.#bounds.get(key);\n if (!prev) {\n this.#bounds.set(key, { oldest: event.created_at, newest: event.created_at });\n return;\n }\n if (event.created_at < prev.oldest) prev.oldest = event.created_at;\n if (event.created_at > prev.newest) prev.newest = event.created_at;\n }\n}\n\n/** Factory matching other loaders helpers. */\nexport function createOutboxFeed(opts: OutboxFeedOptions): OutboxFeed {\n return new OutboxFeed(opts);\n}\n","import type { Pool } from \"../relay/pool.ts\";\nimport { LoaderContext } from \"./context.ts\";\nimport { createEventLoader } from \"./event.ts\";\nimport { createListLoaders } from \"./lists.ts\";\nimport { createProfileLoader } from \"./profile.ts\";\nimport type { ReplaceableCache } from \"./cache.ts\";\n\nexport { DataLoader, LoaderError } from \"./dataloader.ts\";\nexport { ReplaceableCache } from \"./cache.ts\";\nexport { LoaderContext, type LoaderContextOptions } from \"./context.ts\";\nexport {\n createReplaceableLoader,\n type LoadStyle,\n type ReplaceableLoadResult,\n} from \"./replaceable.ts\";\nexport { createListLoaders, type ListResult, type ListLoaders, type MutedEntity } from \"./lists.ts\";\nexport {\n createProfileLoader,\n bareNostrUser,\n type NostrUser,\n type ProfileLoader,\n} from \"./profile.ts\";\nexport { createEventLoader, type EventLoader, type EventRef } from \"./event.ts\";\nexport {\n OutboxError,\n OutboxFeed,\n createOutboxFeed,\n groupAuthorsByOutboxRelay,\n type OutboxBound,\n type OutboxFeedOptions,\n} from \"./outbox.ts\";\n\nimport type { ListLoaders } from \"./lists.ts\";\nimport type { ProfileLoader } from \"./profile.ts\";\nimport type { EventLoader } from \"./event.ts\";\n\nexport type Loaders = {\n context: LoaderContext;\n follows: ListLoaders[\"follows\"];\n muteList: ListLoaders[\"muteList\"];\n relayList: ListLoaders[\"relayList\"];\n dmRelayList: ListLoaders[\"dmRelayList\"];\n profile: ProfileLoader[\"load\"];\n event: EventLoader[\"load\"];\n};\n\nexport type CreateLoadersOptions = {\n pool: Pool;\n relays: readonly string[];\n cache?: ReplaceableCache;\n staleAfterSec?: number;\n fetchTimeoutMs?: number;\n};\n\n/** Build an instance-scoped loader suite (no module globals). */\nexport function createLoaders(opts: CreateLoadersOptions): Loaders {\n const context = new LoaderContext(opts);\n const lists = createListLoaders(context);\n const profile = createProfileLoader(context);\n const event = createEventLoader(context);\n return {\n context,\n follows: (pubkey, o) => lists.follows(pubkey, o),\n muteList: (pubkey, o) => lists.muteList(pubkey, o),\n relayList: (pubkey, o) => lists.relayList(pubkey, o),\n dmRelayList: (pubkey, o) => lists.dmRelayList(pubkey, o),\n profile: (pubkey, o) => profile.load(pubkey, o),\n event: (ref) => event.load(ref),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { C as DataLoader, D as ReplaceableCache, E as LoaderContextOptions, S as createReplaceableLoader, T as LoaderContext, _ as ListResult, a as OutboxFeed, b as LoadStyle, c as groupAuthorsByOutboxRelay, d as createEventLoader, f as NostrUser, g as ListLoaders, h as createProfileLoader, i as OutboxError, l as EventLoader, m as bareNostrUser, n as Loaders, o as OutboxFeedOptions, p as ProfileLoader, r as createLoaders, s as createOutboxFeed, t as CreateLoadersOptions, u as EventRef, v as MutedEntity, w as LoaderError, x as ReplaceableLoadResult, y as createListLoaders } from "./index-EwL6fHLo.mjs";
2
+ import { r as OutboxBound } from "./types-Dn24TPFs.mjs";
3
+ export { CreateLoadersOptions, DataLoader, type EventLoader, type EventRef, type ListLoaders, type ListResult, type LoadStyle, LoaderContext, type LoaderContextOptions, LoaderError, Loaders, type MutedEntity, type NostrUser, type OutboxBound, OutboxError, OutboxFeed, type OutboxFeedOptions, type ProfileLoader, ReplaceableCache, type ReplaceableLoadResult, bareNostrUser, createEventLoader, createListLoaders, createLoaders, createOutboxFeed, createProfileLoader, createReplaceableLoader, groupAuthorsByOutboxRelay };
@@ -0,0 +1,2 @@
1
+ import { a as groupAuthorsByOutboxRelay, c as createListLoaders, d as LoaderError, f as createEventLoader, i as createOutboxFeed, l as createReplaceableLoader, m as ReplaceableCache, n as OutboxError, o as bareNostrUser, p as LoaderContext, r as OutboxFeed, s as createProfileLoader, t as createLoaders, u as DataLoader } from "./loaders-BNQszDAn.mjs";
2
+ export { DataLoader, LoaderContext, LoaderError, OutboxError, OutboxFeed, ReplaceableCache, bareNostrUser, createEventLoader, createListLoaders, createLoaders, createOutboxFeed, createProfileLoader, createReplaceableLoader, groupAuthorsByOutboxRelay };
@@ -0,0 +1,461 @@
1
+ import { a as isHex32 } from "./util-6tfLQ9JF.mjs";
2
+ import { i as isEphemeralKind, t as Kind } from "./kind-BLl4cLOc.mjs";
3
+ import { a as itemCompare, h as eventAddress, i as isReplaceableWinner, u as sortEvents, y as parseEventAddress } from "./event-CzoQEFMF.mjs";
4
+ import { o as matchFilter } from "./filter-BxwjEkZp.mjs";
5
+ //#region src/storage/deletion.ts
6
+ /**
7
+ * NIP-09 application plan for a kind 5 event.
8
+ *
9
+ * - `e` tags: delete only when the target exists, is not itself kind 5, and shares pubkey.
10
+ * - Unknown `e` ids are pending until the event arrives (client MUST validate pubkey).
11
+ * - `a` tags: tombstone that coordinate up to this deletion's `created_at` when pubkey matches.
12
+ * - Deleting a deletion request is a no-op.
13
+ */
14
+ function planDeletion(deletion, getById) {
15
+ const pubkey = deletion.pubkey.toLowerCase();
16
+ const removeIds = [];
17
+ const pendingIds = [];
18
+ const coordinates = [];
19
+ const seenIds = /* @__PURE__ */ new Set();
20
+ const seenCoords = /* @__PURE__ */ new Set();
21
+ for (const tag of deletion.tags) {
22
+ if (tag[0] === "e" && tag[1] && isHex32(tag[1])) {
23
+ const id = tag[1].toLowerCase();
24
+ if (seenIds.has(id)) continue;
25
+ seenIds.add(id);
26
+ const existing = getById(id);
27
+ if (!existing) {
28
+ pendingIds.push({
29
+ id,
30
+ pubkey
31
+ });
32
+ continue;
33
+ }
34
+ if (existing.kind === Kind.EventDeletion) continue;
35
+ if (existing.pubkey.toLowerCase() !== pubkey) continue;
36
+ removeIds.push(id);
37
+ continue;
38
+ }
39
+ if (tag[0] === "a" && tag[1]) {
40
+ const coord = parseEventAddress(tag[1]);
41
+ if (!coord || coord.pubkey !== pubkey) continue;
42
+ const key = `${coord.kind}:${coord.pubkey}:${coord.identifier}`;
43
+ if (seenCoords.has(key)) continue;
44
+ seenCoords.add(key);
45
+ coordinates.push({
46
+ key,
47
+ until: deletion.created_at
48
+ });
49
+ }
50
+ }
51
+ return {
52
+ removeIds,
53
+ pendingIds,
54
+ coordinates
55
+ };
56
+ }
57
+ /** In-memory NIP-09 tombstones shared by MemoryEventStore and IndexedDbEventStore. */
58
+ var DeletionState = class {
59
+ ids = /* @__PURE__ */ new Set();
60
+ pending = /* @__PURE__ */ new Map();
61
+ coordinates = /* @__PURE__ */ new Map();
62
+ clear() {
63
+ this.ids.clear();
64
+ this.pending.clear();
65
+ this.coordinates.clear();
66
+ }
67
+ covers(event) {
68
+ if (this.ids.has(event.id)) return true;
69
+ if (event.kind === Kind.EventDeletion) return false;
70
+ const pendingPk = this.pending.get(event.id);
71
+ if (pendingPk && event.pubkey.toLowerCase() === pendingPk) return true;
72
+ const addr = eventAddress(event);
73
+ if (!addr) return false;
74
+ const until = this.coordinates.get(addr);
75
+ return until !== void 0 && event.created_at <= until;
76
+ }
77
+ absorb(plan) {
78
+ for (const id of plan.removeIds) {
79
+ this.ids.add(id);
80
+ this.pending.delete(id);
81
+ }
82
+ for (const p of plan.pendingIds) if (!this.ids.has(p.id)) this.pending.set(p.id, p.pubkey);
83
+ for (const c of plan.coordinates) {
84
+ const prev = this.coordinates.get(c.key) ?? Number.NEGATIVE_INFINITY;
85
+ this.coordinates.set(c.key, Math.max(prev, c.until));
86
+ }
87
+ }
88
+ };
89
+ function coordinateRemovals(coordinates, getCurrent) {
90
+ const ids = [];
91
+ for (const c of coordinates) {
92
+ const current = getCurrent(c.key);
93
+ if (current && current.created_at <= c.until) ids.push(current.id);
94
+ }
95
+ return ids;
96
+ }
97
+ //#endregion
98
+ //#region src/storage/put.ts
99
+ function normalizeEvent(event) {
100
+ const id = event.id.toLowerCase();
101
+ const pubkey = event.pubkey.toLowerCase();
102
+ if (id === event.id && pubkey === event.pubkey) return event;
103
+ return {
104
+ ...event,
105
+ id,
106
+ pubkey
107
+ };
108
+ }
109
+ function outboxBoundKey(pubkey, kind) {
110
+ return `${pubkey.toLowerCase()}:${kind}`;
111
+ }
112
+ function decidePut(raw, lookup) {
113
+ const event = normalizeEvent(raw);
114
+ if (lookup.deletion.ids.has(event.id) || lookup.getById(event.id)) return {
115
+ action: "skip",
116
+ result: "duplicate",
117
+ event
118
+ };
119
+ if (event.kind === Kind.EventDeletion) {
120
+ const plan = planDeletion(event, lookup.getById);
121
+ return {
122
+ action: "delete",
123
+ result: "deleted",
124
+ event,
125
+ plan,
126
+ coordIds: coordinateRemovals(plan.coordinates, lookup.getReplaceable)
127
+ };
128
+ }
129
+ if (lookup.deletion.covers(event)) return {
130
+ action: "tombstone",
131
+ result: "duplicate",
132
+ event
133
+ };
134
+ if (isEphemeralKind(event.kind)) return {
135
+ action: "skip",
136
+ result: "ephemeral",
137
+ event
138
+ };
139
+ const address = eventAddress(event);
140
+ if (address) {
141
+ const prev = lookup.getReplaceable(address);
142
+ if (prev && !isReplaceableWinner(event, prev)) return {
143
+ action: "skip",
144
+ result: "rejected",
145
+ event
146
+ };
147
+ return {
148
+ action: "insert",
149
+ result: prev ? "replaced" : "accepted",
150
+ event,
151
+ address,
152
+ replaceId: prev?.id
153
+ };
154
+ }
155
+ return {
156
+ action: "insert",
157
+ result: "accepted",
158
+ event
159
+ };
160
+ }
161
+ function applyPutMemory(s, d) {
162
+ switch (d.action) {
163
+ case "skip": return d.result;
164
+ case "tombstone":
165
+ s.deletion.ids.add(d.event.id);
166
+ s.deletion.pending.delete(d.event.id);
167
+ return "duplicate";
168
+ case "delete":
169
+ s.deletion.pending.delete(d.event.id);
170
+ s.deletion.absorb(d.plan);
171
+ for (const id of d.plan.removeIds) s.indexRemove(id);
172
+ for (const id of d.coordIds) {
173
+ s.deletion.ids.add(id);
174
+ s.indexRemove(id);
175
+ }
176
+ s.indexInsert(d.event);
177
+ return "deleted";
178
+ case "insert":
179
+ if (d.replaceId) s.indexRemove(d.replaceId);
180
+ s.indexInsert(d.event);
181
+ return d.result;
182
+ }
183
+ }
184
+ //#endregion
185
+ //#region src/storage/memory.ts
186
+ /**
187
+ * In-memory event store with NIP-01 replaceable / addressable / ephemeral
188
+ * handling and NIP-09 deletion (kind 5) application.
189
+ */
190
+ var MemoryEventStore = class {
191
+ #byId = /* @__PURE__ */ new Map();
192
+ #byPubkey = /* @__PURE__ */ new Map();
193
+ #byKind = /* @__PURE__ */ new Map();
194
+ #byKindPubkey = /* @__PURE__ */ new Map();
195
+ #byEpTag = /* @__PURE__ */ new Map();
196
+ #replaceable = /* @__PURE__ */ new Map();
197
+ #deletion = new DeletionState();
198
+ #outboxBounds = /* @__PURE__ */ new Map();
199
+ async put(raw) {
200
+ const lookup = {
201
+ deletion: this.#deletion,
202
+ getById: (id) => this.#byId.get(id),
203
+ getReplaceable: (addr) => {
204
+ const id = this.#replaceable.get(addr);
205
+ const ev = id ? this.#byId.get(id) : void 0;
206
+ return ev ? {
207
+ id: ev.id,
208
+ created_at: ev.created_at
209
+ } : void 0;
210
+ }
211
+ };
212
+ return applyPutMemory({
213
+ deletion: this.#deletion,
214
+ indexInsert: (e) => this.#indexInsert(e),
215
+ indexRemove: (id) => this.#indexRemove(id)
216
+ }, decidePut(raw, lookup));
217
+ }
218
+ /** Sequential `put` in input order. No transaction: a throw leaves earlier events applied. */
219
+ async putMany(events) {
220
+ const results = [];
221
+ for (const event of events) results.push(await this.put(event));
222
+ return results;
223
+ }
224
+ async get(id) {
225
+ const key = id.toLowerCase();
226
+ if (this.#deletion.ids.has(key)) return void 0;
227
+ return this.#byId.get(key);
228
+ }
229
+ async query(filters) {
230
+ const seen = /* @__PURE__ */ new Set();
231
+ const events = [];
232
+ for (const filter of filters) for (const event of this.#matchedEvents(filter)) {
233
+ if (seen.has(event.id)) continue;
234
+ seen.add(event.id);
235
+ events.push(event);
236
+ }
237
+ sortEvents(events);
238
+ return events;
239
+ }
240
+ async count(filters) {
241
+ const seen = /* @__PURE__ */ new Set();
242
+ for (const filter of filters) for (const event of this.#matchedEvents(filter)) seen.add(event.id);
243
+ return seen.size;
244
+ }
245
+ async negentropyItems(filter) {
246
+ if (filter.limit === 0) return [];
247
+ const items = [];
248
+ this.#eachCandidate(filter, (event) => {
249
+ if (this.#deletion.covers(event)) return;
250
+ if (!matchFilter(filter, event)) return;
251
+ items.push({
252
+ id: event.id,
253
+ created_at: event.created_at
254
+ });
255
+ });
256
+ if (filter.limit !== void 0) {
257
+ items.sort(queryItemOrder);
258
+ if (items.length > filter.limit) items.length = filter.limit;
259
+ }
260
+ items.sort(itemCompare);
261
+ return items;
262
+ }
263
+ async remove(ids) {
264
+ let n = 0;
265
+ for (const raw of ids) {
266
+ const id = raw.toLowerCase();
267
+ if (this.#indexRemove(id)) n += 1;
268
+ this.#deletion.ids.add(id);
269
+ this.#deletion.pending.delete(id);
270
+ }
271
+ return n;
272
+ }
273
+ async getOutboxBound(pubkey, kind) {
274
+ const persisted = this.#outboxBounds.get(outboxBoundKey(pubkey, kind));
275
+ if (persisted) return {
276
+ oldest: persisted.oldest,
277
+ newest: persisted.newest
278
+ };
279
+ return this.#deriveOutboxBound(pubkey, kind);
280
+ }
281
+ async setOutboxBound(pubkey, kind, bound) {
282
+ this.#outboxBounds.set(outboxBoundKey(pubkey, kind), {
283
+ oldest: bound.oldest,
284
+ newest: bound.newest
285
+ });
286
+ }
287
+ async clear() {
288
+ this.#byId.clear();
289
+ this.#byPubkey.clear();
290
+ this.#byKind.clear();
291
+ this.#byKindPubkey.clear();
292
+ this.#byEpTag.clear();
293
+ this.#replaceable.clear();
294
+ this.#deletion.clear();
295
+ this.#outboxBounds.clear();
296
+ }
297
+ get size() {
298
+ return this.#byId.size;
299
+ }
300
+ #indexInsert(event) {
301
+ this.#byId.set(event.id, event);
302
+ const pubkey = event.pubkey.toLowerCase();
303
+ addToSet(this.#byPubkey, pubkey, event.id);
304
+ addToSet(this.#byKind, event.kind, event.id);
305
+ addToSet(this.#byKindPubkey, `${event.kind}:${pubkey}`, event.id);
306
+ for (const tag of event.tags) {
307
+ if (tag[0] !== "e" && tag[0] !== "p" || tag[1] === void 0) continue;
308
+ addToSet(this.#byEpTag, `${tag[0]}:${tag[1].toLowerCase()}`, event.id);
309
+ }
310
+ const addr = eventAddress(event);
311
+ if (addr) this.#replaceable.set(addr, event.id);
312
+ }
313
+ #indexRemove(id) {
314
+ const key = id.toLowerCase();
315
+ const event = this.#byId.get(key);
316
+ if (!event) return false;
317
+ this.#byId.delete(key);
318
+ const pubkey = event.pubkey.toLowerCase();
319
+ removeFromSet(this.#byPubkey, pubkey, key);
320
+ removeFromSet(this.#byKind, event.kind, key);
321
+ removeFromSet(this.#byKindPubkey, `${event.kind}:${pubkey}`, key);
322
+ for (const tag of event.tags) {
323
+ if (tag[0] !== "e" && tag[0] !== "p" || tag[1] === void 0) continue;
324
+ removeFromSet(this.#byEpTag, `${tag[0]}:${tag[1].toLowerCase()}`, key);
325
+ }
326
+ const addr = eventAddress(event);
327
+ if (addr && this.#replaceable.get(addr) === key) this.#replaceable.delete(addr);
328
+ return true;
329
+ }
330
+ #matchedEvents(filter) {
331
+ if (filter.limit === 0) return [];
332
+ const matched = [];
333
+ this.#eachCandidate(filter, (event) => {
334
+ if (this.#deletion.covers(event)) return;
335
+ if (!matchFilter(filter, event)) return;
336
+ matched.push(event);
337
+ });
338
+ sortEvents(matched);
339
+ return filter.limit !== void 0 ? matched.slice(0, filter.limit) : matched;
340
+ }
341
+ #deriveOutboxBound(pubkey, kind) {
342
+ const byPk = this.#byPubkey.get(pubkey.toLowerCase());
343
+ const byKind = this.#byKind.get(kind);
344
+ if (!byPk || !byKind) return void 0;
345
+ let oldest;
346
+ let newest;
347
+ for (const id of byPk) {
348
+ if (!byKind.has(id) || this.#deletion.ids.has(id)) continue;
349
+ const event = this.#byId.get(id);
350
+ if (!event || this.#deletion.covers(event)) continue;
351
+ if (oldest === void 0 || event.created_at < oldest) oldest = event.created_at;
352
+ if (newest === void 0 || event.created_at > newest) newest = event.created_at;
353
+ }
354
+ if (oldest === void 0 || newest === void 0) return void 0;
355
+ return {
356
+ oldest,
357
+ newest
358
+ };
359
+ }
360
+ #eachCandidate(filter, visit) {
361
+ if (filter.ids) {
362
+ const seen = /* @__PURE__ */ new Set();
363
+ for (const raw of filter.ids) {
364
+ const event = this.#byId.get(raw.toLowerCase());
365
+ if (!event || seen.has(event.id)) continue;
366
+ seen.add(event.id);
367
+ visit(event);
368
+ }
369
+ return;
370
+ }
371
+ if (filter.authors && filter.kinds) {
372
+ const seen = /* @__PURE__ */ new Set();
373
+ for (const pk of filter.authors) {
374
+ const pubkey = pk.toLowerCase();
375
+ for (const kind of filter.kinds) {
376
+ const ids = this.#byKindPubkey.get(`${kind}:${pubkey}`);
377
+ if (!ids) continue;
378
+ for (const id of ids) {
379
+ if (seen.has(id)) continue;
380
+ seen.add(id);
381
+ const event = this.#byId.get(id);
382
+ if (event) visit(event);
383
+ }
384
+ }
385
+ }
386
+ return;
387
+ }
388
+ if (filter.authors) {
389
+ const seen = /* @__PURE__ */ new Set();
390
+ for (const pk of filter.authors) {
391
+ const byPk = this.#byPubkey.get(pk.toLowerCase());
392
+ if (!byPk) continue;
393
+ for (const id of byPk) {
394
+ if (seen.has(id)) continue;
395
+ seen.add(id);
396
+ const event = this.#byId.get(id);
397
+ if (event) visit(event);
398
+ }
399
+ }
400
+ return;
401
+ }
402
+ if (filter.kinds) {
403
+ const seen = /* @__PURE__ */ new Set();
404
+ for (const kind of filter.kinds) {
405
+ const byKind = this.#byKind.get(kind);
406
+ if (!byKind) continue;
407
+ for (const id of byKind) {
408
+ if (seen.has(id)) continue;
409
+ seen.add(id);
410
+ const event = this.#byId.get(id);
411
+ if (event) visit(event);
412
+ }
413
+ }
414
+ return;
415
+ }
416
+ const eTags = filter["#e"];
417
+ const pTags = filter["#p"];
418
+ if (eTags !== void 0 || pTags !== void 0) {
419
+ const seen = /* @__PURE__ */ new Set();
420
+ visitEpTagIds(this.#byEpTag, this.#byId, "e", eTags, seen, visit);
421
+ visitEpTagIds(this.#byEpTag, this.#byId, "p", pTags, seen, visit);
422
+ return;
423
+ }
424
+ for (const event of this.#byId.values()) visit(event);
425
+ }
426
+ };
427
+ function visitEpTagIds(byEpTag, byId, name, values, seen, visit) {
428
+ if (values === void 0) return;
429
+ for (const value of values) {
430
+ const ids = byEpTag.get(`${name}:${value.toLowerCase()}`);
431
+ if (!ids) continue;
432
+ for (const id of ids) {
433
+ if (seen.has(id)) continue;
434
+ seen.add(id);
435
+ const event = byId.get(id);
436
+ if (event) visit(event);
437
+ }
438
+ }
439
+ }
440
+ function addToSet(map, key, id) {
441
+ let set = map.get(key);
442
+ if (!set) {
443
+ set = /* @__PURE__ */ new Set();
444
+ map.set(key, set);
445
+ }
446
+ set.add(id);
447
+ }
448
+ function removeFromSet(map, key, id) {
449
+ const set = map.get(key);
450
+ if (!set) return;
451
+ set.delete(id);
452
+ if (set.size === 0) map.delete(key);
453
+ }
454
+ function queryItemOrder(a, b) {
455
+ if (a.created_at !== b.created_at) return b.created_at - a.created_at;
456
+ return a.id.localeCompare(b.id);
457
+ }
458
+ //#endregion
459
+ export { DeletionState as a, outboxBoundKey as i, decidePut as n, planDeletion as o, normalizeEvent as r, MemoryEventStore as t };
460
+
461
+ //# sourceMappingURL=memory-BCmhZPek.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-BCmhZPek.mjs","names":["#deletion","#byId","#replaceable","#indexInsert","#indexRemove","#matchedEvents","#eachCandidate","#outboxBounds","#deriveOutboxBound","#byPubkey","#byKind","#byKindPubkey","#byEpTag"],"sources":["../src/storage/deletion.ts","../src/storage/put.ts","../src/storage/memory.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { eventAddress, parseEventAddress } from \"../core/tag.ts\";\nimport { isHex32 } from \"../core/util.ts\";\n\nexport type DeletionPlan = {\n /** Stored events validated as same-pubkey (not kind 5) and to be removed now. */\n removeIds: string[];\n /** Referenced ids not in the store; remember deletion pubkey until the event arrives. */\n pendingIds: Array<{ id: string; pubkey: string }>;\n /** Replaceable/addressable coordinates tombstoned up to `until` (deletion created_at). */\n coordinates: Array<{ key: string; until: number }>;\n};\n\n/**\n * NIP-09 application plan for a kind 5 event.\n *\n * - `e` tags: delete only when the target exists, is not itself kind 5, and shares pubkey.\n * - Unknown `e` ids are pending until the event arrives (client MUST validate pubkey).\n * - `a` tags: tombstone that coordinate up to this deletion's `created_at` when pubkey matches.\n * - Deleting a deletion request is a no-op.\n */\nexport function planDeletion(\n deletion: Pick<Event, \"pubkey\" | \"created_at\" | \"tags\">,\n getById: (id: string) => Pick<Event, \"id\" | \"pubkey\" | \"kind\"> | undefined,\n): DeletionPlan {\n const pubkey = deletion.pubkey.toLowerCase();\n const removeIds: string[] = [];\n const pendingIds: Array<{ id: string; pubkey: string }> = [];\n const coordinates: Array<{ key: string; until: number }> = [];\n const seenIds = new Set<string>();\n const seenCoords = new Set<string>();\n\n for (const tag of deletion.tags) {\n if (tag[0] === \"e\" && tag[1] && isHex32(tag[1])) {\n const id = tag[1].toLowerCase();\n if (seenIds.has(id)) continue;\n seenIds.add(id);\n const existing = getById(id);\n if (!existing) {\n pendingIds.push({ id, pubkey });\n continue;\n }\n if (existing.kind === Kind.EventDeletion) continue;\n if (existing.pubkey.toLowerCase() !== pubkey) continue;\n removeIds.push(id);\n continue;\n }\n\n if (tag[0] === \"a\" && tag[1]) {\n const coord = parseEventAddress(tag[1]);\n if (!coord || coord.pubkey !== pubkey) continue;\n const key = `${coord.kind}:${coord.pubkey}:${coord.identifier}`;\n if (seenCoords.has(key)) continue;\n seenCoords.add(key);\n coordinates.push({ key, until: deletion.created_at });\n }\n }\n\n return { removeIds, pendingIds, coordinates };\n}\n\n/** In-memory NIP-09 tombstones shared by MemoryEventStore and IndexedDbEventStore. */\nexport class DeletionState {\n readonly ids = new Set<string>();\n readonly pending = new Map<string, string>();\n readonly coordinates = new Map<string, number>();\n\n clear(): void {\n this.ids.clear();\n this.pending.clear();\n this.coordinates.clear();\n }\n\n covers(event: Pick<Event, \"id\" | \"pubkey\" | \"kind\" | \"created_at\" | \"tags\">): boolean {\n if (this.ids.has(event.id)) return true;\n if (event.kind === Kind.EventDeletion) return false;\n const pendingPk = this.pending.get(event.id);\n if (pendingPk && event.pubkey.toLowerCase() === pendingPk) return true;\n const addr = eventAddress(event);\n if (!addr) return false;\n const until = this.coordinates.get(addr);\n return until !== undefined && event.created_at <= until;\n }\n\n absorb(plan: DeletionPlan): void {\n for (const id of plan.removeIds) {\n this.ids.add(id);\n this.pending.delete(id);\n }\n for (const p of plan.pendingIds) {\n if (!this.ids.has(p.id)) this.pending.set(p.id, p.pubkey);\n }\n for (const c of plan.coordinates) {\n const prev = this.coordinates.get(c.key) ?? Number.NEGATIVE_INFINITY;\n this.coordinates.set(c.key, Math.max(prev, c.until));\n }\n }\n}\n\nexport function coordinateRemovals(\n coordinates: readonly { key: string; until: number }[],\n getCurrent: (key: string) => Pick<Event, \"id\" | \"created_at\"> | undefined,\n): string[] {\n const ids: string[] = [];\n for (const c of coordinates) {\n const current = getCurrent(c.key);\n if (current && current.created_at <= c.until) ids.push(current.id);\n }\n return ids;\n}\n","import type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner } from \"../core/event.ts\";\nimport { isEphemeralKind, Kind } from \"../core/kind.ts\";\nimport { eventAddress } from \"../core/tag.ts\";\nimport {\n coordinateRemovals,\n planDeletion,\n type DeletionPlan,\n type DeletionState,\n} from \"./deletion.ts\";\nimport type { PutResult } from \"./types.ts\";\n\nexport function normalizeEvent(event: Event): Event {\n const id = event.id.toLowerCase();\n const pubkey = event.pubkey.toLowerCase();\n if (id === event.id && pubkey === event.pubkey) return event;\n return { ...event, id, pubkey };\n}\n\nexport function outboxBoundKey(pubkey: string, kind: number): string {\n return `${pubkey.toLowerCase()}:${kind}`;\n}\n\nexport type PutDecision =\n | { action: \"skip\"; result: \"duplicate\" | \"ephemeral\" | \"rejected\"; event: Event }\n | { action: \"tombstone\"; result: \"duplicate\"; event: Event }\n | { action: \"delete\"; result: \"deleted\"; event: Event; plan: DeletionPlan; coordIds: string[] }\n | {\n action: \"insert\";\n result: \"accepted\" | \"replaced\";\n event: Event;\n address?: string;\n replaceId?: string;\n };\n\nexport type PutLookup = {\n deletion: DeletionState;\n getById: (\n id: string,\n ) => Pick<Event, \"id\" | \"pubkey\" | \"kind\" | \"created_at\" | \"tags\"> | undefined;\n getReplaceable: (address: string) => Pick<Event, \"id\" | \"created_at\"> | undefined;\n};\n\nexport function decidePut(raw: Event, lookup: PutLookup): PutDecision {\n const event = normalizeEvent(raw);\n if (lookup.deletion.ids.has(event.id) || lookup.getById(event.id)) {\n return { action: \"skip\", result: \"duplicate\", event };\n }\n if (event.kind === Kind.EventDeletion) {\n const plan = planDeletion(event, lookup.getById);\n const coordIds = coordinateRemovals(plan.coordinates, lookup.getReplaceable);\n return { action: \"delete\", result: \"deleted\", event, plan, coordIds };\n }\n if (lookup.deletion.covers(event)) return { action: \"tombstone\", result: \"duplicate\", event };\n if (isEphemeralKind(event.kind)) return { action: \"skip\", result: \"ephemeral\", event };\n const address = eventAddress(event);\n if (address) {\n const prev = lookup.getReplaceable(address);\n if (prev && !isReplaceableWinner(event, prev)) {\n return { action: \"skip\", result: \"rejected\", event };\n }\n return {\n action: \"insert\",\n result: prev ? \"replaced\" : \"accepted\",\n event,\n address,\n replaceId: prev?.id,\n };\n }\n return { action: \"insert\", result: \"accepted\", event };\n}\n\nexport function applyPutMemory(\n s: {\n deletion: DeletionState;\n indexInsert(event: Event): void;\n indexRemove(id: string): boolean;\n },\n d: PutDecision,\n): PutResult {\n switch (d.action) {\n case \"skip\":\n return d.result;\n case \"tombstone\":\n s.deletion.ids.add(d.event.id);\n s.deletion.pending.delete(d.event.id);\n return \"duplicate\";\n case \"delete\":\n s.deletion.pending.delete(d.event.id);\n s.deletion.absorb(d.plan);\n for (const id of d.plan.removeIds) s.indexRemove(id);\n for (const id of d.coordIds) {\n s.deletion.ids.add(id);\n s.indexRemove(id);\n }\n s.indexInsert(d.event);\n return \"deleted\";\n case \"insert\":\n if (d.replaceId) s.indexRemove(d.replaceId);\n s.indexInsert(d.event);\n return d.result;\n }\n}\n","import type { Event } from \"../core/event.ts\";\nimport { itemCompare, sortEvents } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { matchFilter } from \"../core/filter.ts\";\nimport { eventAddress } from \"../core/tag.ts\";\nimport { DeletionState } from \"./deletion.ts\";\nimport { applyPutMemory, decidePut, outboxBoundKey, type PutLookup } from \"./put.ts\";\nimport type { EventStore, NegentropyItem, OutboxBound, PutResult } from \"./types.ts\";\n\n/**\n * In-memory event store with NIP-01 replaceable / addressable / ephemeral\n * handling and NIP-09 deletion (kind 5) application.\n */\nexport class MemoryEventStore implements EventStore {\n #byId = new Map<string, Event>();\n #byPubkey = new Map<string, Set<string>>();\n #byKind = new Map<number, Set<string>>();\n #byKindPubkey = new Map<string, Set<string>>(); // `${kind}:${pubkey}` → ids\n #byEpTag = new Map<string, Set<string>>(); // `${\"e\"|\"p\"}:${value.toLowerCase()}` → ids\n #replaceable = new Map<string, string>(); // address -> event id\n #deletion = new DeletionState();\n #outboxBounds = new Map<string, OutboxBound>();\n\n async put(raw: Event): Promise<PutResult> {\n const lookup: PutLookup = {\n deletion: this.#deletion,\n getById: (id) => this.#byId.get(id),\n getReplaceable: (addr) => {\n const id = this.#replaceable.get(addr);\n const ev = id ? this.#byId.get(id) : undefined;\n return ev ? { id: ev.id, created_at: ev.created_at } : undefined;\n },\n };\n return applyPutMemory(\n {\n deletion: this.#deletion,\n indexInsert: (e) => this.#indexInsert(e),\n indexRemove: (id) => this.#indexRemove(id),\n },\n decidePut(raw, lookup),\n );\n }\n\n /** Sequential `put` in input order. No transaction: a throw leaves earlier events applied. */\n async putMany(events: readonly Event[]): Promise<PutResult[]> {\n const results: PutResult[] = [];\n for (const event of events) results.push(await this.put(event));\n return results;\n }\n\n async get(id: string): Promise<Event | undefined> {\n const key = id.toLowerCase();\n if (this.#deletion.ids.has(key)) return undefined;\n return this.#byId.get(key);\n }\n\n async query(filters: Filter[]): Promise<Event[]> {\n const seen = new Set<string>();\n const events: Event[] = [];\n for (const filter of filters) {\n for (const event of this.#matchedEvents(filter)) {\n if (seen.has(event.id)) continue;\n seen.add(event.id);\n events.push(event);\n }\n }\n sortEvents(events);\n return events;\n }\n\n async count(filters: Filter[]): Promise<number> {\n const seen = new Set<string>();\n for (const filter of filters) {\n for (const event of this.#matchedEvents(filter)) seen.add(event.id);\n }\n return seen.size;\n }\n\n async negentropyItems(filter: Filter): Promise<NegentropyItem[]> {\n if (filter.limit === 0) return [];\n const items: NegentropyItem[] = [];\n this.#eachCandidate(filter, (event) => {\n if (this.#deletion.covers(event)) return;\n if (!matchFilter(filter, event)) return;\n items.push({ id: event.id, created_at: event.created_at });\n });\n if (filter.limit !== undefined) {\n items.sort(queryItemOrder);\n if (items.length > filter.limit) items.length = filter.limit;\n }\n items.sort(itemCompare);\n return items;\n }\n\n async remove(ids: string[]): Promise<number> {\n let n = 0;\n for (const raw of ids) {\n const id = raw.toLowerCase();\n if (this.#indexRemove(id)) n += 1;\n this.#deletion.ids.add(id);\n this.#deletion.pending.delete(id);\n }\n return n;\n }\n\n async getOutboxBound(pubkey: string, kind: number): Promise<OutboxBound | undefined> {\n const persisted = this.#outboxBounds.get(outboxBoundKey(pubkey, kind));\n if (persisted) return { oldest: persisted.oldest, newest: persisted.newest };\n return this.#deriveOutboxBound(pubkey, kind);\n }\n\n async setOutboxBound(pubkey: string, kind: number, bound: OutboxBound): Promise<void> {\n this.#outboxBounds.set(outboxBoundKey(pubkey, kind), {\n oldest: bound.oldest,\n newest: bound.newest,\n });\n }\n\n async clear(): Promise<void> {\n this.#byId.clear();\n this.#byPubkey.clear();\n this.#byKind.clear();\n this.#byKindPubkey.clear();\n this.#byEpTag.clear();\n this.#replaceable.clear();\n this.#deletion.clear();\n this.#outboxBounds.clear();\n }\n\n get size(): number {\n return this.#byId.size;\n }\n\n #indexInsert(event: Event): void {\n this.#byId.set(event.id, event);\n const pubkey = event.pubkey.toLowerCase();\n addToSet(this.#byPubkey, pubkey, event.id);\n addToSet(this.#byKind, event.kind, event.id);\n addToSet(this.#byKindPubkey, `${event.kind}:${pubkey}`, event.id);\n for (const tag of event.tags) {\n if ((tag[0] !== \"e\" && tag[0] !== \"p\") || tag[1] === undefined) continue;\n addToSet(this.#byEpTag, `${tag[0]}:${tag[1].toLowerCase()}`, event.id);\n }\n const addr = eventAddress(event);\n if (addr) this.#replaceable.set(addr, event.id);\n }\n\n #indexRemove(id: string): boolean {\n const key = id.toLowerCase();\n const event = this.#byId.get(key);\n if (!event) return false;\n this.#byId.delete(key);\n const pubkey = event.pubkey.toLowerCase();\n removeFromSet(this.#byPubkey, pubkey, key);\n removeFromSet(this.#byKind, event.kind, key);\n removeFromSet(this.#byKindPubkey, `${event.kind}:${pubkey}`, key);\n for (const tag of event.tags) {\n if ((tag[0] !== \"e\" && tag[0] !== \"p\") || tag[1] === undefined) continue;\n removeFromSet(this.#byEpTag, `${tag[0]}:${tag[1].toLowerCase()}`, key);\n }\n const addr = eventAddress(event);\n if (addr && this.#replaceable.get(addr) === key) this.#replaceable.delete(addr);\n return true;\n }\n\n #matchedEvents(filter: Filter): Event[] {\n if (filter.limit === 0) return [];\n const matched: Event[] = [];\n this.#eachCandidate(filter, (event) => {\n if (this.#deletion.covers(event)) return;\n if (!matchFilter(filter, event)) return;\n matched.push(event);\n });\n sortEvents(matched);\n return filter.limit !== undefined ? matched.slice(0, filter.limit) : matched;\n }\n\n #deriveOutboxBound(pubkey: string, kind: number): OutboxBound | undefined {\n const byPk = this.#byPubkey.get(pubkey.toLowerCase());\n const byKind = this.#byKind.get(kind);\n if (!byPk || !byKind) return undefined;\n let oldest: number | undefined;\n let newest: number | undefined;\n for (const id of byPk) {\n if (!byKind.has(id) || this.#deletion.ids.has(id)) continue;\n const event = this.#byId.get(id);\n if (!event || this.#deletion.covers(event)) continue;\n if (oldest === undefined || event.created_at < oldest) oldest = event.created_at;\n if (newest === undefined || event.created_at > newest) newest = event.created_at;\n }\n if (oldest === undefined || newest === undefined) return undefined;\n return { oldest, newest };\n }\n\n #eachCandidate(filter: Filter, visit: (event: Event) => void): void {\n if (filter.ids) {\n const seen = new Set<string>();\n for (const raw of filter.ids) {\n const event = this.#byId.get(raw.toLowerCase());\n if (!event || seen.has(event.id)) continue;\n seen.add(event.id);\n visit(event);\n }\n return;\n }\n\n if (filter.authors && filter.kinds) {\n const seen = new Set<string>();\n for (const pk of filter.authors) {\n const pubkey = pk.toLowerCase();\n for (const kind of filter.kinds) {\n const ids = this.#byKindPubkey.get(`${kind}:${pubkey}`);\n if (!ids) continue;\n for (const id of ids) {\n if (seen.has(id)) continue;\n seen.add(id);\n const event = this.#byId.get(id);\n if (event) visit(event);\n }\n }\n }\n return;\n }\n\n if (filter.authors) {\n const seen = new Set<string>();\n for (const pk of filter.authors) {\n const byPk = this.#byPubkey.get(pk.toLowerCase());\n if (!byPk) continue;\n for (const id of byPk) {\n if (seen.has(id)) continue;\n seen.add(id);\n const event = this.#byId.get(id);\n if (event) visit(event);\n }\n }\n return;\n }\n\n if (filter.kinds) {\n const seen = new Set<string>();\n for (const kind of filter.kinds) {\n const byKind = this.#byKind.get(kind);\n if (!byKind) continue;\n for (const id of byKind) {\n if (seen.has(id)) continue;\n seen.add(id);\n const event = this.#byId.get(id);\n if (event) visit(event);\n }\n }\n return;\n }\n\n const eTags = filter[\"#e\"];\n const pTags = filter[\"#p\"];\n if (eTags !== undefined || pTags !== undefined) {\n const seen = new Set<string>();\n visitEpTagIds(this.#byEpTag, this.#byId, \"e\", eTags, seen, visit);\n visitEpTagIds(this.#byEpTag, this.#byId, \"p\", pTags, seen, visit);\n return;\n }\n\n // #t/#d and other non-e/p tags are not indexed (e/p only). A generic tag\n // store is extra put/remove amp; hashtag-only queries scan #byId.\n for (const event of this.#byId.values()) visit(event);\n }\n}\n\nfunction visitEpTagIds(\n byEpTag: Map<string, Set<string>>,\n byId: Map<string, Event>,\n name: \"e\" | \"p\",\n values: readonly string[] | undefined,\n seen: Set<string>,\n visit: (event: Event) => void,\n): void {\n if (values === undefined) return;\n for (const value of values) {\n const ids = byEpTag.get(`${name}:${value.toLowerCase()}`);\n if (!ids) continue;\n for (const id of ids) {\n if (seen.has(id)) continue;\n seen.add(id);\n const event = byId.get(id);\n if (event) visit(event);\n }\n }\n}\n\nfunction addToSet<K>(map: Map<K, Set<string>>, key: K, id: string): void {\n let set = map.get(key);\n if (!set) {\n set = new Set();\n map.set(key, set);\n }\n set.add(id);\n}\n\nfunction removeFromSet<K>(map: Map<K, Set<string>>, key: K, id: string): void {\n const set = map.get(key);\n if (!set) return;\n set.delete(id);\n if (set.size === 0) map.delete(key);\n}\n\nfunction queryItemOrder(a: NegentropyItem, b: NegentropyItem): number {\n if (a.created_at !== b.created_at) return b.created_at - a.created_at;\n return a.id.localeCompare(b.id);\n}\n"],"mappings":"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"}