@powerhousedao/reactor 6.2.3-dev.44 → 6.2.3-dev.45

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.
@@ -1 +1 @@
1
- {"version":3,"file":"document-indexer-BRT2a1uw.js","names":["uuidv4","uuidv4"],"sources":["../src/catch-up/scheduler.ts","../src/catch-up/types.ts","../src/catch-up/contiguous-cursor.ts","../src/read-models/base-read-model.ts","../src/read-models/coordinator.ts","../src/read-models/names.ts","../src/read-models/document-view.ts","../src/shared/consistency-tracker.ts","../src/shared/collect-all-pages.ts","../src/storage/kysely/document-indexer.ts"],"sourcesContent":["import type { ILogger } from \"document-model\";\nimport type { IOperationIndex } from \"../cache/operation-index-types.js\";\nimport type { WatermarkSession } from \"./settled-watermark.js\";\nimport type {\n CatchUpConfig,\n CatchUpConsumerStatus,\n CatchUpStatus,\n CatchUpThread,\n ICatchUp,\n ICatchUpConsumer,\n ISettledWatermark,\n SweepBlockedAt,\n SweepResult,\n} from \"./types.js\";\n\ntype ConsumerEntry = {\n consumer: ICatchUpConsumer;\n thread: CatchUpThread;\n blockedAt?: SweepBlockedAt;\n lastAdvanceUtcMs: number;\n warnedHeld: boolean;\n};\n\nexport type CatchUpSchedulerHooks = {\n /** Called for every sweep that moved, replayed or failed. */\n onSwept: (result: SweepResult, thread: CatchUpThread) => void;\n /** Names the sessions holding the watermark, for the stall warning. */\n describeSessions: (xids: readonly string[]) => Promise<WatermarkSession[]>;\n};\n\nconst noHooks: CatchUpSchedulerHooks = {\n onSwept: () => {},\n describeSessions: () => Promise.resolve([]),\n};\n\ntype PresentPage = { bound: number; present: number[] };\n\ntype ConsumerSource = {\n consumers: () => readonly ICatchUpConsumer[];\n thread: CatchUpThread;\n};\n\nexport function isCatchUpConsumer(value: unknown): value is ICatchUpConsumer {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as Partial<ICatchUpConsumer>;\n return (\n typeof candidate.sweep === \"function\" &&\n typeof candidate.consumerId === \"string\" &&\n typeof candidate.appliedThrough === \"number\"\n );\n}\n\n/** Periodically sweeps every consumer up to the settled watermark. */\nexport class CatchUpScheduler implements ICatchUp {\n private readonly fixed: ConsumerEntry[] = [];\n private readonly sources: ConsumerSource[] = [];\n private readonly sourced = new Map<ICatchUpConsumer, ConsumerEntry>();\n private timer: ReturnType<typeof setInterval> | undefined;\n private running: Promise<SweepResult[]> | undefined;\n private started = false;\n private stopped = false;\n private warnedStallSince: number | undefined;\n private readonly statusSources: Array<() => CatchUpConsumerStatus[]> = [];\n\n constructor(\n private readonly watermark: ISettledWatermark,\n private readonly operationIndex: IOperationIndex,\n private readonly config: CatchUpConfig,\n private readonly logger: ILogger,\n private readonly hooks: CatchUpSchedulerHooks = noHooks,\n ) {}\n\n get settledWatermark(): ISettledWatermark {\n return this.watermark;\n }\n\n addConsumer(consumer: ICatchUpConsumer, thread: CatchUpThread): void {\n if (this.fixed.some((entry) => entry.consumer === consumer)) return;\n this.fixed.push({\n consumer,\n thread,\n lastAdvanceUtcMs: Date.now(),\n warnedHeld: false,\n });\n this.ensureTimer();\n }\n\n /** Consumers read on every tick, so models registered later are swept too. */\n addSource(\n consumers: () => readonly ICatchUpConsumer[],\n thread: CatchUpThread,\n ): void {\n this.sources.push({ consumers, thread });\n this.ensureTimer();\n }\n\n /** Consumers another thread sweeps, reported in status(). */\n addStatusSource(source: () => CatchUpConsumerStatus[]): void {\n this.statusSources.push(source);\n }\n\n start(): void {\n this.started = true;\n this.ensureTimer();\n }\n\n async stop(): Promise<void> {\n this.stopped = true;\n if (this.timer !== undefined) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n if (this.running !== undefined) {\n await this.running.catch(() => []);\n }\n }\n\n async sweepNow(): Promise<SweepResult[]> {\n if (this.running !== undefined) {\n await this.running.catch(() => []);\n }\n return this.run();\n }\n\n status(): CatchUpStatus {\n return {\n watermark: this.watermark.status(),\n consumers: this.entries()\n .map((entry): CatchUpConsumerStatus => ({\n consumerId: entry.consumer.consumerId,\n thread: entry.thread,\n appliedThrough: entry.consumer.appliedThrough,\n trackedAbove: entry.consumer.trackedAbove,\n ...(entry.blockedAt !== undefined\n ? { blockedAt: entry.blockedAt }\n : {}),\n lastAdvanceUtcMs: entry.lastAdvanceUtcMs,\n }))\n .concat(this.statusSources.flatMap((source) => source())),\n };\n }\n\n private ensureTimer(): void {\n if (!this.started || this.stopped || this.timer !== undefined) return;\n if (this.fixed.length === 0 && this.sources.length === 0) return;\n\n const timer = setInterval(() => {\n if (this.running !== undefined) return;\n void this.run().catch((error: unknown) => {\n this.logger.error(\"catch-up tick failed: @error\", error);\n });\n }, this.config.intervalMs);\n if (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n this.timer = timer;\n }\n\n private run(): Promise<SweepResult[]> {\n const run = this.tick().finally(() => {\n if (this.running === run) this.running = undefined;\n });\n this.running = run;\n return run;\n }\n\n private async tick(): Promise<SweepResult[]> {\n const settled = await this.watermark.refresh();\n await this.warnIfWatermarkHeld();\n const entries = this.entries();\n if (entries.length === 0) return [];\n\n let lowest = Number.POSITIVE_INFINITY;\n for (const entry of entries) {\n lowest = Math.min(lowest, entry.consumer.appliedThrough);\n }\n const shared = await this.readPage(lowest, settled);\n\n const results: SweepResult[] = [];\n for (const entry of entries) {\n if (this.stopped) break;\n const result = await this.sweepOne(entry, shared, settled);\n if (result !== undefined) results.push(result);\n }\n return results;\n }\n\n private entries(): ConsumerEntry[] {\n const entries = [...this.fixed];\n const seen = new Set(entries.map((entry) => entry.consumer));\n for (const source of this.sources) {\n for (const consumer of source.consumers()) {\n if (seen.has(consumer)) continue;\n seen.add(consumer);\n let entry = this.sourced.get(consumer);\n if (entry === undefined) {\n entry = {\n consumer,\n thread: source.thread,\n lastAdvanceUtcMs: Date.now(),\n warnedHeld: false,\n };\n this.sourced.set(consumer, entry);\n }\n entries.push(entry);\n }\n }\n return entries;\n }\n\n private async sweepOne(\n entry: ConsumerEntry,\n shared: PresentPage,\n settled: number,\n ): Promise<SweepResult | undefined> {\n const applied = entry.consumer.appliedThrough;\n let page = shared;\n if (applied >= shared.bound && shared.bound < settled) {\n try {\n page = await this.readPage(applied, settled);\n } catch (error) {\n this.logger.error(\n \"@consumer catch-up could not read present ordinals: @error\",\n entry.consumer.consumerId,\n error,\n );\n return undefined;\n }\n }\n\n let result: SweepResult;\n try {\n result = await entry.consumer.sweep(page.bound, page.present);\n } catch (error) {\n this.logger.error(\n \"@consumer catch-up sweep failed: @error\",\n entry.consumer.consumerId,\n error,\n );\n return undefined;\n }\n\n if (result.to > result.from) {\n entry.lastAdvanceUtcMs = Date.now();\n entry.warnedHeld = false;\n }\n entry.blockedAt = result.blockedAt;\n this.warnIfConsumerHeld(entry, settled);\n if (\n result.to > result.from ||\n result.replayed > 0 ||\n result.blockedAt !== undefined\n ) {\n this.hooks.onSwept(result, entry.thread);\n }\n return result;\n }\n\n private async warnIfWatermarkHeld(): Promise<void> {\n const status = this.watermark.status();\n const since = status.stalledSinceUtcMs;\n if (since === undefined) {\n this.warnedStallSince = undefined;\n return;\n }\n const heldMs = Date.now() - since;\n if (heldMs < this.config.stuckWarnMs || this.warnedStallSince === since) {\n return;\n }\n this.warnedStallSince = since;\n const sessions: WatermarkSession[] = await this.hooks\n .describeSessions(status.waitingOn)\n .catch(() => []);\n this.logger.warn(\n \"settled watermark held at @settled (head @head) for @ms ms, waiting on xid @xids: @sessions\",\n status.settledThrough,\n status.head,\n heldMs,\n status.waitingOn.join(\", \"),\n sessions\n .map(\n (session) =>\n `pid ${session.pid} ${session.applicationName} ${session.state} since ${session.xactStart ?? \"?\"}`,\n )\n .join(\"; \"),\n );\n }\n\n private warnIfConsumerHeld(entry: ConsumerEntry, settled: number): void {\n const applied = entry.consumer.appliedThrough;\n if (applied >= settled || entry.warnedHeld) return;\n const heldMs = Date.now() - entry.lastAdvanceUtcMs;\n if (heldMs < this.config.stuckWarnMs) return;\n entry.warnedHeld = true;\n this.logger.warn(\n \"@consumer cursor held at @applied for @ms ms (settled @settled)\",\n entry.consumer.consumerId,\n applied,\n heldMs,\n settled,\n );\n }\n\n private async readPage(after: number, settled: number): Promise<PresentPage> {\n const limit = this.config.sweepPageSize;\n const present = await this.operationIndex.getOrdinalsInRange(\n after,\n settled,\n limit,\n );\n const bound =\n present.length >= limit ? present[present.length - 1]! : settled;\n return { bound, present };\n }\n}\n","import type { Unsubscribe } from \"../events/types.js\";\n\nexport type WatermarkStatus = {\n head: number;\n settledThrough: number;\n waitingOn: string[];\n stalledSinceUtcMs?: number;\n};\n\nexport interface ISettledWatermark {\n /** Every ordinal at or below this is visible or will never exist. */\n readonly settledThrough: number;\n /** Probes, coalesced with one in flight; resolves with settledThrough. */\n refresh(signal?: AbortSignal): Promise<number>;\n onAdvance(listener: (settledThrough: number) => void): Unsubscribe;\n status(): WatermarkStatus;\n}\n\nexport type SweepBlockedAt = {\n ordinal: number;\n documentId: string;\n scope: string;\n branch: string;\n type: string;\n error: string;\n};\n\nexport type SweepResult = {\n consumerId: string;\n from: number;\n to: number;\n durationMs: number;\n /** Late operations applied. */\n replayed: number;\n /** Later operations of their streams applied again. */\n reapplied: number;\n blockedAt?: SweepBlockedAt;\n};\n\nexport interface ICatchUpConsumer {\n readonly consumerId: string;\n readonly appliedThrough: number;\n /** Ordinals above the cursor this consumer holds in memory. */\n readonly trackedAbove: number;\n sweep(\n settledThrough: number,\n present: readonly number[],\n signal?: AbortSignal,\n ): Promise<SweepResult>;\n}\n\nexport type CatchUpThread = \"host\" | \"projection\";\n\nexport type CatchUpConsumerStatus = {\n consumerId: string;\n thread: CatchUpThread;\n appliedThrough: number;\n trackedAbove: number;\n blockedAt?: SweepBlockedAt;\n lastAdvanceUtcMs: number;\n};\n\nexport type CatchUpStatus = {\n watermark: WatermarkStatus;\n consumers: CatchUpConsumerStatus[];\n};\n\nexport type CatchUpConfig = {\n intervalMs: number;\n stuckWarnMs: number;\n maxTrackedAboveCursor: number;\n /** Present ordinals read per tick. */\n sweepPageSize: number;\n};\n\nexport const defaultCatchUpConfig: CatchUpConfig = {\n intervalMs: 2000,\n stuckWarnMs: 60_000,\n maxTrackedAboveCursor: 100_000,\n sweepPageSize: 10_000,\n};\n\n/** The catch-up surface a reactor module exposes. */\nexport interface ICatchUp {\n status(): CatchUpStatus;\n sweepNow(): Promise<SweepResult[]>;\n}\n","/** In memory, per consumer; tracks ordinals above appliedThrough only. */\nexport class ContiguousCursor {\n private claimed = new Set<number>();\n private applied = new Set<number>();\n\n constructor(\n private through: number,\n private limit: number,\n ) {}\n\n setLimit(limit: number): void {\n this.limit = limit;\n }\n\n /** Every present ordinal at or below this has been applied. */\n get appliedThrough(): number {\n return this.through;\n }\n\n get trackedAbove(): number {\n return this.claimed.size + this.applied.size;\n }\n\n /** Ordinals the caller must apply; the rest are already covered. */\n claim(ordinals: Iterable<number>): Set<number> {\n const mine = new Set<number>();\n for (const ordinal of ordinals) {\n if (ordinal <= this.through) continue;\n if (this.claimed.has(ordinal) || this.applied.has(ordinal)) continue;\n this.claimed.add(ordinal);\n mine.add(ordinal);\n }\n return mine;\n }\n\n /** Releases claims; committed ones join the applied set. */\n settle(ordinals: Iterable<number>, committed: boolean): void {\n for (const ordinal of ordinals) {\n if (!this.claimed.delete(ordinal)) continue;\n if (committed && ordinal > this.through) this.applied.add(ordinal);\n }\n }\n\n /** Past the limit, clears the applied set; the next sweep re-applies it. */\n enforceLimit(): void {\n if (this.claimed.size + this.applied.size > this.limit) {\n this.applied.clear();\n }\n }\n\n /** Present ordinals above the cursor that no path has claimed or applied. */\n missing(present: readonly number[]): number[] {\n return present.filter(\n (ordinal) =>\n ordinal > this.through &&\n !this.claimed.has(ordinal) &&\n !this.applied.has(ordinal),\n );\n }\n\n /** `settled`, held below the lowest claimed or unapplied ordinal. */\n target(settled: number, present: readonly number[]): number {\n let to = settled;\n for (const ordinal of this.claimed) {\n if (ordinal <= to) to = ordinal - 1;\n }\n for (const ordinal of present) {\n if (ordinal <= this.through || ordinal > to) continue;\n if (!this.applied.has(ordinal)) to = ordinal - 1;\n }\n return Math.max(to, this.through);\n }\n\n advance(to: number): void {\n if (to <= this.through) return;\n this.through = to;\n for (const ordinal of this.applied) {\n if (ordinal <= to) this.applied.delete(ordinal);\n }\n for (const ordinal of this.claimed) {\n if (ordinal <= to) this.claimed.delete(ordinal);\n }\n }\n}\n","import {\n isPurgeMarker,\n type OperationWithContext,\n} from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport type { IOperationIndex } from \"../cache/operation-index-types.js\";\nimport type { IWriteCache } from \"../cache/write/interfaces.js\";\nimport { ContiguousCursor } from \"../catch-up/contiguous-cursor.js\";\nimport {\n createKyselyWatermarkProbe,\n SettledWatermark,\n} from \"../catch-up/settled-watermark.js\";\nimport {\n defaultCatchUpConfig,\n type ICatchUpConsumer,\n type ISettledWatermark,\n type SweepBlockedAt,\n type SweepResult,\n} from \"../catch-up/types.js\";\nimport type { Unsubscribe } from \"../events/types.js\";\nimport type { IConsistencyTracker } from \"../shared/consistency-tracker.js\";\nimport { DocumentNotFoundError } from \"../shared/errors.js\";\nimport type {\n ConsistencyCoordinate,\n ConsistencyToken,\n} from \"../shared/types.js\";\nimport { yieldToMain } from \"../shared/utils.js\";\nimport {\n acquirePurgeLocks,\n findPurged,\n} from \"../storage/kysely/document-purges.js\";\nimport type { Database as StorageDatabase } from \"../storage/kysely/types.js\";\nimport type { IReadModel, IReadModelReservation } from \"./interfaces.js\";\nimport type { DocumentViewDatabase } from \"./types.js\";\n\n/** Bounds on an indexing pass: one transaction, and the stall between yields. */\nexport type ReadModelIndexingConfig = {\n /** Maximum operations committed in a single transaction. */\n commitChunkSize: number;\n /** Maximum elapsed milliseconds before yielding between chunks. */\n yieldDeadlineMs: number;\n};\n\n/** Small enough that a chunk's transaction rarely outlasts the yield deadline. */\nexport const DEFAULT_COMMIT_CHUNK_SIZE = 50;\n\n/** Matches the executor's own default, so both paths yield on the same cadence. */\nexport const DEFAULT_READ_MODEL_YIELD_DEADLINE_MS = 50;\n\nexport const defaultReadModelIndexingConfig: ReadModelIndexingConfig = {\n commitChunkSize: DEFAULT_COMMIT_CHUNK_SIZE,\n yieldDeadlineMs: DEFAULT_READ_MODEL_YIELD_DEADLINE_MS,\n};\n\n/** For read models whose callers can observe where a batch was split. */\nexport const unchunkedReadModelIndexingConfig: ReadModelIndexingConfig = {\n commitChunkSize: Number.MAX_SAFE_INTEGER,\n yieldDeadlineMs: DEFAULT_READ_MODEL_YIELD_DEADLINE_MS,\n};\n\n/**\n * Keeps the chunk size at one operation or more: a chunk of zero or less never\n * advances the indexing loop, so the pass would spin without ever resolving.\n */\nfunction normalizeIndexingConfig(\n config: ReadModelIndexingConfig,\n): ReadModelIndexingConfig {\n if (Number.isNaN(config.commitChunkSize)) {\n return { ...config, commitChunkSize: DEFAULT_COMMIT_CHUNK_SIZE };\n }\n\n return {\n ...config,\n commitChunkSize: Math.max(\n 1,\n Math.min(Math.floor(config.commitChunkSize), Number.MAX_SAFE_INTEGER),\n ),\n };\n}\n\nexport type PurgeFence =\n /** Commits in a purge-locked trx; see commitsInFenceTransaction. */\n | \"locked\"\n /** Drops tombstoned ids only, for rows that live on another database handle. */\n | \"skip\"\n /** No fence: ProcessorManager, and commits that open their own trx on this.db. */\n | \"none\";\n\nexport type BaseReadModelConfig = {\n readModelId: string;\n /** Rebuilds resultingState for boot replay and sweeps. */\n rebuildStateOnInit: boolean;\n /** Defaults to {@link defaultReadModelIndexingConfig}. */\n indexing?: ReadModelIndexingConfig;\n /** Where a first registration starts; defaults to \"beginning\". */\n startFrom?: \"beginning\" | \"head\";\n /** Re-applies the rest of a late operation's stream; defaults to true. */\n replayStreamSuffix?: boolean;\n /** Defaults to \"locked\"; see {@link PurgeFence} for the opt-outs. */\n purgeFence?: PurgeFence;\n};\n\ntype StreamGroup = {\n documentId: string;\n scope: string;\n branch: string;\n lowest: number;\n late: OperationWithContext[];\n};\n\nfunction ordinalOf(item: OperationWithContext): number {\n return item.context.ordinal;\n}\n\nfunction isTracked(ordinal: number): boolean {\n return Number.isFinite(ordinal) && ordinal > 0;\n}\n\nfunction streamKeyOf(stream: {\n documentId: string;\n scope: string;\n branch: string;\n}): string {\n return `${stream.documentId}\\u0000${stream.scope}\\u0000${stream.branch}`;\n}\n\nfunction groupByStream(items: OperationWithContext[]): StreamGroup[] {\n const groups = new Map<string, StreamGroup>();\n for (const item of items) {\n const { documentId, scope, branch } = item.context;\n const key = streamKeyOf(item.context);\n let group = groups.get(key);\n if (group === undefined) {\n group = { documentId, scope, branch, lowest: ordinalOf(item), late: [] };\n groups.set(key, group);\n }\n group.lowest = Math.min(group.lowest, ordinalOf(item));\n group.late.push(item);\n }\n return [...groups.values()].sort((a, b) => a.lowest - b.lowest);\n}\n\nfunction mergeByOrdinal(\n ...lists: OperationWithContext[][]\n): OperationWithContext[] {\n const byOrdinal = new Map<number, OperationWithContext>();\n for (const list of lists) {\n for (const item of list) byOrdinal.set(ordinalOf(item), item);\n }\n return [...byOrdinal.values()].sort((a, b) => ordinalOf(a) - ordinalOf(b));\n}\n\n/** The ids whose purge an operation's rows must not outlive. */\nfunction purgeFenceIds(items: OperationWithContext[]): string[] {\n const ids = new Set<string>();\n for (const { operation, context } of items) {\n ids.add(context.documentId);\n if (operation.action.type !== \"ADD_RELATIONSHIP\") continue;\n const input = operation.action.input as {\n sourceId?: unknown;\n targetId?: unknown;\n };\n if (typeof input.sourceId === \"string\") ids.add(input.sourceId);\n if (typeof input.targetId === \"string\") ids.add(input.targetId);\n }\n return [...ids].sort();\n}\n\nfunction dropPurged(\n items: OperationWithContext[],\n purged: Set<string>,\n): OperationWithContext[] {\n if (purged.size === 0) return items;\n return items.filter(\n (item) =>\n isPurgeMarker(item.operation) || !purged.has(item.context.documentId),\n );\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** A read model whose cursor only sweeps and boot replay advance. */\nexport class BaseReadModel implements IReadModel, ICatchUpConsumer {\n readonly name: string;\n\n private readonly indexing: ReadModelIndexingConfig;\n private readonly catchUpLogger: ILogger;\n private cursor: ContiguousCursor;\n private persisted = 0;\n private watermark: ISettledWatermark | undefined;\n private maxTrackedAboveCursor = defaultCatchUpConfig.maxTrackedAboveCursor;\n private loggedFailure: number | undefined;\n private failedItem: OperationWithContext | undefined;\n private initialized = false;\n private readonly liveInFlight = new Map<string, Set<number>>();\n private readonly sweptListeners = new Set<\n (coordinates: ConsistencyCoordinate[]) => void\n >();\n\n constructor(\n protected db: Kysely<DocumentViewDatabase>,\n protected operationIndex: IOperationIndex,\n protected writeCache: IWriteCache,\n protected consistencyTracker: IConsistencyTracker,\n protected config: BaseReadModelConfig,\n ) {\n this.name = config.readModelId;\n this.catchUpLogger = childLogger([\n \"reactor\",\n \"read-model\",\n config.readModelId,\n ]);\n this.indexing = normalizeIndexingConfig(\n config.indexing ?? defaultReadModelIndexingConfig,\n );\n this.cursor = new ContiguousCursor(0, this.maxTrackedAboveCursor);\n // A locked commit through this.db deadlocks single-connection PGlite.\n if (\n (config.purgeFence ?? \"locked\") === \"locked\" &&\n this.commitOperations !== BaseReadModel.prototype.commitOperations &&\n !(this.constructor as typeof BaseReadModel).commitsInFenceTransaction\n ) {\n throw new Error(\n `Read model ${config.readModelId}: purgeFence \"locked\" commits in a ` +\n \"transaction its commitOperations must write through. Write \" +\n \"through the trx argument and set static commitsInFenceTransaction \" +\n 'to true, or set purgeFence \"skip\" (rows on another handle) or ' +\n '\"none\" (no rows here, or its own transaction).',\n );\n }\n }\n\n /** Set by a subclass whose commitOperations writes through its trx argument. */\n static readonly commitsInFenceTransaction: boolean = false;\n\n get consumerId(): string {\n return this.config.readModelId;\n }\n\n get appliedThrough(): number {\n return this.cursor.appliedThrough;\n }\n\n get trackedAbove(): number {\n return this.cursor.trackedAbove;\n }\n\n /** Shares a thread's watermark; otherwise boot probes through this db. */\n attachCatchUp(\n watermark: ISettledWatermark,\n maxTrackedAboveCursor: number,\n ): void {\n this.watermark = watermark;\n this.maxTrackedAboveCursor = maxTrackedAboveCursor;\n this.cursor.setLimit(maxTrackedAboveCursor);\n }\n\n /** Notified with the coordinates each sweep applied. */\n onSwept(\n listener: (coordinates: ConsistencyCoordinate[]) => void,\n ): Unsubscribe {\n this.sweptListeners.add(listener);\n return () => {\n this.sweptListeners.delete(listener);\n };\n }\n\n /** A chunk that throws ends the replay; sweeps continue from below it. */\n async init(): Promise<void> {\n // A repeat init replays from where this process is, keeping what it applied.\n if (this.initialized) {\n await this.replayFromCursor();\n return;\n }\n let stored = await this.loadState();\n\n if (stored === undefined) {\n if (this.config.startFrom === \"head\") {\n const watermark = this.settledWatermark();\n const settled = await watermark.refresh();\n // The head, not settledThrough: any open write elsewhere holds that at 0.\n const head = Math.max(settled, watermark.status().head);\n await this.initializeState(head);\n this.resetCursor(head);\n this.initialized = true;\n return;\n }\n await this.initializeState(0);\n stored = 0;\n }\n\n this.resetCursor(stored);\n this.initialized = true;\n await this.replayFromCursor();\n }\n\n /** The live path: never moves the cursor. */\n indexOperations(items: OperationWithContext[]): Promise<void> {\n if (items.length === 0) return Promise.resolve();\n return this.reserveOperations(items).apply();\n }\n\n /** Holds a queued batch as live, so a sweep neither takes nor passes it. */\n reserveOperations(items: OperationWithContext[]): IReadModelReservation {\n const cursor = this.cursor;\n const owned = this.claimLive(items);\n const unmark = this.markLive(owned);\n let done = false;\n return {\n apply: () => {\n if (done) return Promise.resolve();\n done = true;\n // A cursor reset since the claim dropped it.\n if (cursor !== this.cursor) {\n unmark();\n return this.indexOperations(items);\n }\n if (owned.length === 0) {\n unmark();\n return Promise.resolve();\n }\n return this.applyChunked(owned, unmark);\n },\n release: () => {\n if (done) return;\n done = true;\n cursor.settle(owned.map(ordinalOf), false);\n unmark();\n },\n };\n }\n\n async sweep(\n settledThrough: number,\n present: readonly number[],\n signal?: AbortSignal,\n ): Promise<SweepResult> {\n const startedAt = performance.now();\n const from = this.cursor.appliedThrough;\n const range = present.filter(\n (ordinal) => ordinal > from && ordinal <= settledThrough,\n );\n const mine = this.cursor.claim(this.cursor.missing(range));\n\n let replayed = 0;\n let reapplied = 0;\n let blockedAt: SweepBlockedAt | undefined;\n\n if (mine.size > 0) {\n let late: OperationWithContext[];\n try {\n late = await this.operationIndex.getByOrdinals([...mine], signal);\n } catch (error) {\n this.cursor.settle(mine, false);\n throw error;\n }\n\n const found = new Set(late.map(ordinalOf));\n this.cursor.settle(\n [...mine].filter((ordinal) => !found.has(ordinal)),\n true,\n );\n\n for (const group of groupByStream(late)) {\n const outcome = await this.sweepStream(group, signal);\n replayed += outcome.replayed;\n reapplied += outcome.reapplied;\n blockedAt ??= outcome.blockedAt;\n }\n\n if (replayed > 0) {\n this.catchUpLogger.warn(\n \"@consumer applied @n operations its live path never received: ordinals @first..@last\",\n this.consumerId,\n replayed,\n Math.min(...found),\n Math.max(...found),\n );\n }\n }\n\n const to = this.cursor.target(settledThrough, range);\n if (to > from) {\n await this.moveCursor(to);\n }\n this.cursor.enforceLimit();\n\n return {\n consumerId: this.consumerId,\n from,\n to: this.cursor.appliedThrough,\n durationMs: performance.now() - startedAt,\n replayed,\n reapplied,\n ...(blockedAt !== undefined ? { blockedAt } : {}),\n };\n }\n\n /**\n * Waits for the read model to reach the specified consistency level.\n */\n async waitForConsistency(\n token: ConsistencyToken,\n timeoutMs?: number,\n signal?: AbortSignal,\n ): Promise<void> {\n if (token.coordinates.length === 0) {\n return;\n }\n await this.consistencyTracker.waitFor(token.coordinates, timeoutMs, signal);\n }\n\n /** The cursor, for subclasses: every present ordinal at or below it is applied. */\n protected get lastOrdinal(): number {\n return this.cursor.appliedThrough;\n }\n\n /** Called after the cursor advances. */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected onCursorAdvanced(appliedThrough: number): void {}\n\n /** Writes through `trx` when given: the purge fence's transaction. */\n protected async commitOperations(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n items: OperationWithContext[],\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n trx?: Transaction<DocumentViewDatabase>,\n ): Promise<void> {}\n\n /** The handle document_purges is read through; `db` may be the fence trx. */\n protected purgeLookup(db: Kysely<any>): Kysely<any> {\n return db;\n }\n\n /** False when the batch writes no rows, so the fence opens no transaction. */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected writesRows(items: OperationWithContext[]): boolean {\n return true;\n }\n\n /** Every delivery commits through here. */\n protected async commitFenced(items: OperationWithContext[]): Promise<void> {\n const fence = this.config.purgeFence ?? \"locked\";\n if (fence === \"none\") {\n await this.commitOperations(items);\n return;\n }\n if (items.length === 0 || !this.writesRows(items)) {\n if (items.length > 0) await this.commitOperations(items);\n return;\n }\n\n const ids = purgeFenceIds(items);\n if (fence === \"skip\") {\n const live = dropPurged(\n items,\n await findPurged(this.purgeLookup(this.db), ids),\n );\n if (live.length > 0) await this.commitOperations(live);\n return;\n }\n\n await this.db.transaction().execute(async (trx) => {\n await acquirePurgeLocks(trx, ids, \"shared\");\n const live = dropPurged(\n items,\n await findPurged(this.purgeLookup(trx), ids),\n );\n if (live.length > 0) await this.commitOperations(live, trx);\n });\n }\n\n /** Rebuilds resultingState as the executor writes it: scopes plus header. */\n protected async rebuildStateForOperations(\n operations: OperationWithContext[],\n ): Promise<OperationWithContext[]> {\n const result: OperationWithContext[] = [];\n\n for (const op of operations) {\n const { documentId, scope, branch } = op.context;\n const targetRevision = op.operation.index;\n\n const document = await this.writeCache.getState(\n documentId,\n scope,\n branch,\n targetRevision,\n );\n\n result.push({\n operation: op.operation,\n context: {\n ...op.context,\n resultingState: JSON.stringify({\n ...document.state,\n header: document.header,\n }),\n },\n });\n }\n\n return result;\n }\n\n /**\n * Loads the last processed ordinal from the ViewState table.\n * Returns undefined if no state exists for this read model.\n */\n protected async loadState(): Promise<number | undefined> {\n const row = await this.db\n .selectFrom(\"ViewState\")\n .select(\"lastOrdinal\")\n .where(\"readModelId\", \"=\", this.config.readModelId)\n .executeTakeFirst();\n\n return row?.lastOrdinal;\n }\n\n /**\n * Initializes the ViewState row for this read model.\n */\n protected async initializeState(lastOrdinal = 0): Promise<void> {\n await this.db\n .insertInto(\"ViewState\")\n .values({\n readModelId: this.config.readModelId,\n lastOrdinal,\n })\n .onConflict((oc) => oc.column(\"readModelId\").doNothing())\n .execute();\n }\n\n /**\n * Updates the consistency tracker with the processed operations.\n */\n protected updateConsistencyTracker(items: OperationWithContext[]): void {\n this.consistencyTracker.update(this.coordinatesOf(items));\n }\n\n private coordinatesOf(\n items: OperationWithContext[],\n ): ConsistencyCoordinate[] {\n const coordinates: ConsistencyCoordinate[] = [];\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n coordinates.push({\n documentId: item.context.documentId,\n scope: item.context.scope,\n branch: item.context.branch,\n operationIndex: item.operation.index,\n });\n }\n return coordinates;\n }\n\n private settledWatermark(): ISettledWatermark {\n this.watermark ??= new SettledWatermark(\n createKyselyWatermarkProbe(this.db as unknown as Kysely<StorageDatabase>),\n this.catchUpLogger,\n );\n return this.watermark;\n }\n\n private resetCursor(appliedThrough: number): void {\n this.cursor = new ContiguousCursor(\n appliedThrough,\n this.maxTrackedAboveCursor,\n );\n this.persisted = appliedThrough;\n }\n\n /** Items this pass must apply; untracked ordinals always apply. */\n private claimLive(items: OperationWithContext[]): OperationWithContext[] {\n const mine = this.cursor.claim(items.map(ordinalOf));\n return items.filter((item) => {\n const ordinal = ordinalOf(item);\n return !isTracked(ordinal) || mine.has(ordinal);\n });\n }\n\n /** Marks items in flight on their streams; returns the release. */\n private markLive(items: OperationWithContext[]): () => void {\n const keys = new Set<string>();\n for (const item of items) {\n if (!isTracked(ordinalOf(item))) continue;\n const key = streamKeyOf(item.context);\n let ordinals = this.liveInFlight.get(key);\n if (ordinals === undefined) {\n ordinals = new Set();\n this.liveInFlight.set(key, ordinals);\n }\n ordinals.add(ordinalOf(item));\n keys.add(key);\n }\n return () => {\n for (const item of items) {\n this.liveInFlight\n .get(streamKeyOf(item.context))\n ?.delete(ordinalOf(item));\n }\n for (const key of keys) {\n if (this.liveInFlight.get(key)?.size === 0)\n this.liveInFlight.delete(key);\n }\n };\n }\n\n /** True while a live pass applies an earlier operation of the stream. */\n private liveBelow(group: StreamGroup): boolean {\n const ordinals = this.liveInFlight.get(streamKeyOf(group));\n if (ordinals === undefined) return false;\n for (const ordinal of ordinals) {\n if (ordinal < group.lowest) return true;\n }\n return false;\n }\n\n /** Commits in chunks, yielding with no transaction open. */\n private async applyChunked(\n items: OperationWithContext[],\n release = this.markLive(items),\n ): Promise<void> {\n try {\n const { commitChunkSize, yieldDeadlineMs } = this.indexing;\n let lastYield = performance.now();\n let committed = 0;\n\n for (let start = 0; start < items.length; start += commitChunkSize) {\n if (start > 0 && performance.now() - lastYield > yieldDeadlineMs) {\n await yieldToMain();\n lastYield = performance.now();\n }\n\n const chunk = items.slice(start, start + commitChunkSize);\n\n try {\n await this.commitFenced(chunk);\n } catch (error) {\n this.failedItem = chunk[0];\n const prefix = items.slice(0, committed);\n this.cursor.settle(prefix.map(ordinalOf), true);\n this.cursor.settle(items.slice(committed).map(ordinalOf), false);\n if (prefix.length > 0) this.updateConsistencyTracker(prefix);\n throw error;\n }\n\n committed += chunk.length;\n }\n\n this.cursor.settle(items.map(ordinalOf), true);\n this.cursor.enforceLimit();\n this.updateConsistencyTracker(items);\n } finally {\n release();\n }\n }\n\n private async replayFromCursor(): Promise<void> {\n const settledAtBoot = await this.settledAtBoot();\n let page = await this.operationIndex.getSinceOrdinal(\n this.cursor.appliedThrough,\n );\n\n while (page.results.length > 0) {\n const ordinals = page.results.map(ordinalOf);\n const failed = await this.replayPage(page.results);\n\n const pageMax = Math.max(...ordinals);\n const to = this.cursor.target(Math.min(settledAtBoot, pageMax), ordinals);\n if (to > this.cursor.appliedThrough) {\n await this.moveCursor(to);\n }\n\n if (failed || !page.next) break;\n page = await page.next();\n }\n }\n\n /** Without a probe, boot replay applies but leaves the cursor to sweeps. */\n private async settledAtBoot(): Promise<number> {\n try {\n return await this.settledWatermark().refresh();\n } catch (error) {\n this.catchUpLogger.warn(\n \"@consumer could not probe the settled watermark at boot; the cursor waits for a sweep: @error\",\n this.consumerId,\n error,\n );\n return this.cursor.appliedThrough;\n }\n }\n\n /** Returns true when a chunk failed, which ends the replay. */\n private async replayPage(results: OperationWithContext[]): Promise<boolean> {\n const owned = this.claimLive(results);\n if (owned.length === 0) return false;\n const release = this.markLive(owned);\n try {\n return await this.replayOwned(owned);\n } finally {\n release();\n }\n }\n\n private async replayOwned(owned: OperationWithContext[]): Promise<boolean> {\n let rebuilt: { items: OperationWithContext[]; absent: number[] };\n try {\n rebuilt = await this.rebuildIfConfigured(owned);\n } catch (error) {\n this.cursor.settle(owned.map(ordinalOf), false);\n this.block(owned[0]!, error);\n return true;\n }\n this.cursor.settle(rebuilt.absent, true);\n if (rebuilt.items.length === 0) return false;\n\n try {\n await this.applyChunked(rebuilt.items);\n } catch (error) {\n this.block(this.failedItem ?? rebuilt.items[0]!, error);\n return true;\n }\n return false;\n }\n\n private async sweepStream(\n group: StreamGroup,\n signal: AbortSignal | undefined,\n ): Promise<{\n replayed: number;\n reapplied: number;\n blockedAt?: SweepBlockedAt;\n }> {\n const owned = group.late.map(ordinalOf);\n if (this.liveBelow(group)) {\n this.cursor.settle(owned, false);\n return { replayed: 0, reapplied: 0 };\n }\n const ownedSet = new Set(owned);\n\n let items = group.late;\n if (this.config.replayStreamSuffix ?? true) {\n let suffix: OperationWithContext[];\n try {\n suffix = await this.operationIndex.getStreamAfter(\n group,\n group.lowest,\n signal,\n );\n } catch (error) {\n this.cursor.settle(owned, false);\n return {\n replayed: 0,\n reapplied: 0,\n blockedAt: this.block(group.late[0]!, error),\n };\n }\n items = mergeByOrdinal(group.late, suffix);\n }\n\n let rebuilt: { items: OperationWithContext[]; absent: number[] };\n try {\n rebuilt = await this.rebuildIfConfigured(items);\n } catch (error) {\n this.cursor.settle(owned, false);\n return {\n replayed: 0,\n reapplied: 0,\n blockedAt: this.block(items[0]!, error),\n };\n }\n\n try {\n await this.commitFenced(rebuilt.items);\n } catch (error) {\n this.cursor.settle(owned, false);\n return {\n replayed: 0,\n reapplied: 0,\n blockedAt: this.block(rebuilt.items[0] ?? items[0]!, error),\n };\n }\n\n this.cursor.settle(owned, true);\n this.updateConsistencyTracker(rebuilt.items);\n this.notifySwept(rebuilt.items);\n\n let replayed = 0;\n for (const item of rebuilt.items) {\n if (ownedSet.has(ordinalOf(item))) replayed++;\n }\n return { replayed, reapplied: rebuilt.items.length - replayed };\n }\n\n /** A document gone from the write cache, or purged, is absent. */\n private async rebuildIfConfigured(\n items: OperationWithContext[],\n ): Promise<{ items: OperationWithContext[]; absent: number[] }> {\n if (!this.config.rebuildStateOnInit) {\n return { items, absent: [] };\n }\n\n const rebuilt: OperationWithContext[] = [];\n const absent: number[] = [];\n for (const item of items) {\n // The marker has no state to rebuild; its stream has no CREATE_DOCUMENT.\n if (isPurgeMarker(item.operation)) {\n rebuilt.push(item);\n continue;\n }\n let result: OperationWithContext[];\n try {\n result = await this.rebuildStateForOperations([item]);\n } catch (error) {\n if (\n !DocumentNotFoundError.isError(error) &&\n !(await this.isPurged(item.context.documentId))\n ) {\n throw error;\n }\n this.catchUpLogger.warn(\n \"@consumer dropped ordinal @ordinal: document @documentId is gone\",\n this.consumerId,\n ordinalOf(item),\n item.context.documentId,\n );\n absent.push(ordinalOf(item));\n continue;\n }\n rebuilt.push(...result);\n }\n return { items: rebuilt, absent };\n }\n\n /** A failed lookup is no answer: the caller's own error stands. */\n private async isPurged(documentId: string): Promise<boolean> {\n try {\n return (await findPurged(this.purgeLookup(this.db), [documentId])).has(\n documentId,\n );\n } catch {\n return false;\n }\n }\n\n private block(item: OperationWithContext, error: unknown): SweepBlockedAt {\n const blockedAt: SweepBlockedAt = {\n ordinal: ordinalOf(item),\n documentId: item.context.documentId,\n scope: item.context.scope,\n branch: item.context.branch,\n type: item.operation.action.type,\n error: errorMessage(error),\n };\n if (this.loggedFailure !== blockedAt.ordinal) {\n this.loggedFailure = blockedAt.ordinal;\n this.catchUpLogger.error(\n \"@consumer cursor held at @applied: ordinal @ordinal (@documentId/@scope/@branch, @type) failed: @error\",\n this.consumerId,\n this.cursor.appliedThrough,\n blockedAt.ordinal,\n blockedAt.documentId,\n blockedAt.scope,\n blockedAt.branch,\n blockedAt.type,\n blockedAt.error,\n );\n }\n return blockedAt;\n }\n\n private notifySwept(items: OperationWithContext[]): void {\n if (this.sweptListeners.size === 0 || items.length === 0) return;\n const coordinates = this.coordinatesOf(items);\n for (const listener of this.sweptListeners) {\n listener(coordinates);\n }\n }\n\n /** Compare-and-set against the value this process last wrote. */\n private async moveCursor(to: number): Promise<void> {\n if (to <= this.persisted) {\n this.advanceCursor(to);\n return;\n }\n\n const expected = this.persisted;\n const result = await this.db\n .updateTable(\"ViewState\")\n .set({ lastOrdinal: to, lastOperationTimestamp: new Date() })\n .where(\"readModelId\", \"=\", this.config.readModelId)\n .where(\"lastOrdinal\", \"=\", expected)\n .executeTakeFirst();\n\n if (Number(result.numUpdatedRows) > 0) {\n this.persisted = to;\n this.advanceCursor(to);\n return;\n }\n\n const stored = await this.loadState();\n if (stored === undefined) {\n await this.initializeState(0);\n this.lowered(0);\n return;\n }\n if (stored < this.cursor.appliedThrough) {\n this.lowered(stored);\n return;\n }\n this.persisted = stored;\n this.advanceCursor(Math.min(to, stored));\n }\n\n private advanceCursor(to: number): void {\n const before = this.cursor.appliedThrough;\n this.cursor.advance(to);\n if (this.cursor.appliedThrough > before) {\n this.onCursorAdvanced(this.cursor.appliedThrough);\n }\n }\n\n private lowered(to: number): void {\n this.catchUpLogger.info(\n \"@consumer cursor lowered externally from @old to @new; replaying\",\n this.consumerId,\n this.cursor.appliedThrough,\n to,\n );\n this.resetCursor(to);\n }\n}\n","import type { OperationWithContext } from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport type { IEventBus } from \"../events/interfaces.js\";\nimport {\n ReactorEventTypes,\n type JobReadReadyEvent,\n type JobWriteReadyEvent,\n type ReadModelBatchCompletedEvent,\n type ReadModelIndexedEvent,\n type ReadModelIndexingStage,\n type Unsubscribe,\n} from \"../events/types.js\";\nimport type {\n ILiveReadModelCoordinator,\n IReadModel,\n IReadModelReservation,\n ReadModelRegistrationStage,\n} from \"./interfaces.js\";\n\nexport type BatchReservations = Map<IReadModel, IReadModelReservation>;\n\n/** Claims a batch for every model that supports it, as the batch queues. */\nexport function reserveBatch(\n readModels: readonly IReadModel[],\n operations: OperationWithContext[],\n logger: ILogger,\n): BatchReservations {\n const reservations: BatchReservations = new Map();\n for (const readModel of readModels) {\n if (readModel.reserveOperations === undefined) continue;\n try {\n reservations.set(readModel, readModel.reserveOperations(operations));\n } catch (error) {\n logger.error(\n \"Read model @name could not reserve a batch: @Error\",\n readModel.name,\n error,\n );\n }\n }\n return reservations;\n}\n\n/** Applies the model's reservation, or indexes a model registered since. */\nexport function indexReserved(\n readModel: IReadModel,\n operations: OperationWithContext[],\n reservations: BatchReservations,\n): Promise<void> {\n const reservation = reservations.get(readModel);\n return reservation\n ? reservation.apply()\n : readModel.indexOperations(operations);\n}\n\n/** Frees every claim a run did not apply, so a sweep can take it. */\nexport function releaseBatch(reservations: BatchReservations): void {\n for (const reservation of reservations.values()) reservation.release();\n}\n\n/**\n * Coordinates read model synchronization by listening to operation write events\n * and updating all registered read models on per-`documentId:scope:branch`\n * serial chains. Cross-key projection runs in parallel; same-key projection is\n * serialized so the executor can return to dispatch without holding ordering\n * implicitly.\n */\nexport class ReadModelCoordinator implements ILiveReadModelCoordinator {\n private unsubscribe?: Unsubscribe;\n private isRunning = false;\n private readonly chains = new Map<string, Promise<void>>();\n private readonly logger: ILogger;\n\n readonly readModels: IReadModel[];\n\n constructor(\n private eventBus: IEventBus,\n public readonly preReady: IReadModel[],\n public readonly postReady: IReadModel[],\n ) {\n this.readModels = [...preReady, ...postReady];\n this.logger = childLogger([\"reactor\", \"read-model-coordinator\"]);\n }\n\n start(): void {\n if (this.isRunning) {\n return;\n }\n\n this.unsubscribe = this.eventBus.subscribe(\n ReactorEventTypes.JOB_WRITE_READY,\n (type, event: JobWriteReadyEvent) => {\n return this.handleWriteReady(event);\n },\n );\n\n this.isRunning = true;\n }\n\n stop(): void {\n if (!this.isRunning) {\n return;\n }\n\n if (this.unsubscribe) {\n this.unsubscribe();\n this.unsubscribe = undefined;\n }\n\n this.isRunning = false;\n }\n\n /**\n * Resolves when every per-queueKey projection chain has flushed. Intended\n * for test fixtures and explicit shutdown; production callers use\n * consistency tokens instead.\n */\n async drain(): Promise<void> {\n while (this.chains.size > 0) {\n const pending = Array.from(this.chains.values());\n await Promise.allSettled(pending);\n }\n }\n\n getChainDepth(): number {\n return this.chains.size;\n }\n\n indexedReadModels(): readonly IReadModel[] {\n return [...this.preReady, ...this.postReady];\n }\n\n addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void {\n if (this.readModels.some(({ name }) => name === readModel.name)) {\n throw new Error(`Read model \"${readModel.name}\" is already registered`);\n }\n\n if (stage === \"pre_ready\") {\n this.preReady.push(readModel);\n } else {\n this.postReady.push(readModel);\n }\n this.readModels.push(readModel);\n }\n\n private handleWriteReady(event: JobWriteReadyEvent): void {\n if (event.operations.length === 0) {\n void this.emitEmptyReadReady(event);\n return;\n }\n\n const enqueuedAt = performance.now();\n const key = this.queueKeyFor(event);\n const reservations = reserveBatch(\n this.readModels,\n event.operations,\n this.logger,\n );\n const run = () => this.runChain(event, enqueuedAt, reservations);\n const previous = this.chains.get(key) ?? Promise.resolve();\n const current = previous.then(run, run);\n\n this.chains.set(key, current);\n void current.finally(() => {\n if (this.chains.get(key) === current) {\n this.chains.delete(key);\n }\n });\n }\n\n private async emitEmptyReadReady(event: JobWriteReadyEvent): Promise<void> {\n const readyEvent: JobReadReadyEvent = {\n jobId: event.jobId,\n operations: event.operations,\n };\n try {\n await this.eventBus.emit(ReactorEventTypes.JOB_READ_READY, readyEvent);\n } catch (error) {\n this.logger.error(\n \"JOB_READ_READY emit failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n this.emitBatchCompleted({\n jobId: event.jobId,\n batchSize: 0,\n chainWaitDurationMs: 0,\n preReadyDurationMs: 0,\n emitDurationMs: 0,\n postReadyDurationMs: 0,\n });\n }\n\n private async runChain(\n event: JobWriteReadyEvent,\n enqueuedAt: number,\n reservations: BatchReservations,\n ): Promise<void> {\n try {\n await this.runBatch(event, enqueuedAt, reservations);\n } finally {\n releaseBatch(reservations);\n }\n }\n\n private async runBatch(\n event: JobWriteReadyEvent,\n enqueuedAt: number,\n reservations: BatchReservations,\n ): Promise<void> {\n const chainStartedAt = performance.now();\n const chainWaitDurationMs = chainStartedAt - enqueuedAt;\n\n const preReadyStart = performance.now();\n try {\n await Promise.all(\n this.preReady.map((readModel) =>\n this.indexWithTiming(readModel, \"pre_ready\", event, reservations),\n ),\n );\n } catch (error) {\n this.logger.error(\n \"Pre-ready read model indexing failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n const preReadyDurationMs = performance.now() - preReadyStart;\n\n const readyEvent: JobReadReadyEvent = {\n jobId: event.jobId,\n operations: event.operations,\n };\n const emitStart = performance.now();\n try {\n await this.eventBus.emit(ReactorEventTypes.JOB_READ_READY, readyEvent);\n } catch (error) {\n this.logger.error(\n \"JOB_READ_READY emit failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n const emitDurationMs = performance.now() - emitStart;\n\n const postReadyStart = performance.now();\n try {\n await Promise.all(\n this.postReady.map((readModel) =>\n this.indexWithTiming(readModel, \"post_ready\", event, reservations),\n ),\n );\n } catch (error) {\n this.logger.error(\n \"Post-ready read model indexing failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n const postReadyDurationMs = performance.now() - postReadyStart;\n\n this.emitBatchCompleted({\n jobId: event.jobId,\n batchSize: event.operations.length,\n chainWaitDurationMs,\n preReadyDurationMs,\n emitDurationMs,\n postReadyDurationMs,\n });\n }\n\n private async indexWithTiming(\n readModel: IReadModel,\n stage: ReadModelIndexingStage,\n event: JobWriteReadyEvent,\n reservations: BatchReservations,\n ): Promise<void> {\n const start = performance.now();\n let success = false;\n try {\n await indexReserved(readModel, event.operations, reservations);\n success = true;\n } finally {\n this.emitReadModelIndexed({\n jobId: event.jobId,\n readModelName: readModel.name,\n stage,\n durationMs: performance.now() - start,\n operationCount: event.operations.length,\n success,\n });\n }\n }\n\n private emitReadModelIndexed(payload: ReadModelIndexedEvent): void {\n void this.eventBus\n .emit(ReactorEventTypes.READMODEL_INDEXED, payload)\n .catch((err: unknown) =>\n this.logger.error(\n \"READMODEL_INDEXED emit failed for job @jobId: @Error\",\n { jobId: payload.jobId },\n err,\n ),\n );\n }\n\n private emitBatchCompleted(payload: ReadModelBatchCompletedEvent): void {\n void this.eventBus\n .emit(ReactorEventTypes.READMODEL_BATCH_COMPLETED, payload)\n .catch((err: unknown) =>\n this.logger.error(\n \"READMODEL_BATCH_COMPLETED emit failed for job @jobId: @Error\",\n { jobId: payload.jobId },\n err,\n ),\n );\n }\n\n private queueKeyFor(event: JobWriteReadyEvent): string {\n const ctx = event.operations[0]!.context;\n return `${ctx.documentId}:${ctx.scope}:${ctx.branch}`;\n }\n}\n","import type { IDocumentIndexer, IDocumentView } from \"../storage/interfaces.js\";\n\n/** `getReadModel` name of the document view; see {@link ReactorReadModels}. */\nexport const DOCUMENT_VIEW_READ_MODEL = \"document-view\";\n/** `getReadModel` name of the document indexer; see {@link ReactorReadModels}. */\nexport const DOCUMENT_INDEXER_READ_MODEL = \"document-indexer\";\n\n/**\n * Read models the reactor registers on every host, keyed by the name passed to\n * `IProcessorHostModule.getReadModel`. Each entry says what the model holds\n * and when a processor should reach for it instead of the reactor client.\n */\nexport interface ReactorReadModels {\n /**\n * Materialized document snapshots — header plus per-scope state — kept\n * current as operations are indexed, so reads never replay operations.\n *\n * Reach for it to read a document's current state from inside a\n * processor: `get` / `getMany` by id, `getByIdOrSlug`, `findByType`,\n * `exists`, and `resolveSlug` / `resolveIdOrSlug`. Every query takes an\n * optional `ConsistencyToken` (from a job result) for read-after-write.\n * Unlike `client.get`, results are the raw snapshot — scopes are not\n * filtered to what the caller may read.\n */\n [DOCUMENT_VIEW_READ_MODEL]: IDocumentView;\n\n /**\n * Directed graph of document relationships, built from ADD_RELATIONSHIP /\n * REMOVE_RELATIONSHIP operations. Edges carry a `relationshipType`;\n * parent/child links (drive → document, folder → file) use `\"child\"`.\n *\n * Reach for it to navigate structure rather than content: `getOutgoing` /\n * `getIncoming` neighbours, `hasRelationship`, `findPath`, and\n * `findAncestors` (e.g. which drive(s) contain a document). Snapshots of\n * the documents themselves come from the document view.\n */\n [DOCUMENT_INDEXER_READ_MODEL]: IDocumentIndexer;\n}\n","import type {\n OperationWithContext,\n PHAuthState,\n PHDocument,\n PHDocumentHeader,\n} from \"@powerhousedao/shared/document-model\";\nimport {\n createAuthState,\n isDenied,\n isPurgeMarker,\n} from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { IOperationIndex } from \"../cache/operation-index-types.js\";\nimport type { IWriteCache } from \"../cache/write/interfaces.js\";\nimport type { IConsistencyTracker } from \"../shared/consistency-tracker.js\";\nimport { DocumentNotFoundError } from \"../shared/errors.js\";\nimport { DOCUMENT_VIEW_READ_MODEL } from \"./names.js\";\nimport type {\n ConsistencyToken,\n PagedResults,\n PagingOptions,\n} from \"../shared/types.js\";\nimport {\n DocumentExistence,\n type DocumentRevisions,\n type IDocumentView,\n type IOperationStore,\n type ViewFilter,\n} from \"../storage/interfaces.js\";\nimport type { Database as StorageDatabase } from \"../storage/kysely/types.js\";\nimport {\n BaseReadModel,\n defaultReadModelIndexingConfig,\n type ReadModelIndexingConfig,\n} from \"./base-read-model.js\";\nimport type {\n DocumentViewDatabase,\n InsertableDocumentSnapshot,\n} from \"./types.js\";\n\ntype Database = StorageDatabase & DocumentViewDatabase;\n\n/**\n * What a single-document read of a deleted document returns. A listing omits a\n * deleted document under either value.\n */\nexport enum DeletedDocumentRead {\n /**\n * The document reads as missing: `get` throws and `resolveIdOrSlug` does not\n * match its id.\n */\n NotFound = \"NotFound\",\n /**\n * The document's state as of the deletion, with `state.document.isDeleted`\n * telling the caller what it holds. Only meaningful with `documentDecisions`,\n * which is what makes deletion positional.\n */\n StateAtDeletion = \"StateAtDeletion\",\n}\n\nexport class KyselyDocumentView extends BaseReadModel implements IDocumentView {\n static override readonly commitsInFenceTransaction = true;\n\n private _db: Kysely<Database>;\n private readonly logger: ILogger = childLogger([\n \"reactor\",\n \"read-model\",\n DOCUMENT_VIEW_READ_MODEL,\n ]);\n\n constructor(\n db: Kysely<Database>,\n private operationStore: IOperationStore,\n operationIndex: IOperationIndex,\n writeCache: IWriteCache,\n consistencyTracker: IConsistencyTracker,\n private readonly deletedDocumentRead: DeletedDocumentRead,\n indexing: ReadModelIndexingConfig = defaultReadModelIndexingConfig,\n ) {\n super(\n db as unknown as Kysely<DocumentViewDatabase>,\n operationIndex,\n writeCache,\n consistencyTracker,\n {\n readModelId: DOCUMENT_VIEW_READ_MODEL,\n rebuildStateOnInit: true,\n indexing,\n replayStreamSuffix: false,\n purgeFence: \"locked\",\n },\n );\n this._db = db;\n }\n\n /**\n * Indexes committed operations into DocumentSnapshot rows. CREATE_DOCUMENT\n * only seeds header/document/auth. UPGRADE_DOCUMENT reindexes every scope\n * present in resultingState when the operation vouches for them — a seed\n * carrying initialState or a migration stamped with the __migrated marker\n * — since the upgrade reducer may have reshaped any of them; upgrades\n * without either fall back to header/document/auth, because their sibling\n * echoes may be stale. All other action types index only header and their\n * own scope.\n *\n * Every row accepts a write only from an operation whose global ordinal is\n * at least the one the row already carries, so an older duplicate from a\n * sweep, boot replay or chunk interleave never rolls a scope back.\n */\n protected override async commitOperations(\n items: OperationWithContext[],\n fenced?: Transaction<DocumentViewDatabase>,\n ): Promise<void> {\n const write = async (trx: Transaction<Database>) => {\n for (const item of items) {\n const { operation, context } = item;\n // Its rows went in the purge transaction; the marker writes none back.\n if (isPurgeMarker(operation)) continue;\n const {\n documentId,\n scope,\n branch,\n documentType,\n resultingState,\n ordinal,\n } = context;\n const { index, hash } = operation;\n\n if (!resultingState) {\n throw new Error(\n `Missing resultingState in context for operation ${operation.id || \"unknown\"}. ` +\n `IDocumentView requires resultingState from upstream - it does not rebuild documents.`,\n );\n }\n\n let fullState: Record<string, unknown>;\n try {\n fullState = JSON.parse(resultingState) as Record<string, unknown>;\n } catch (error) {\n throw new Error(\n `Failed to parse resultingState for operation ${operation.id || \"unknown\"}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n\n const operationType = operation.action.type;\n\n // A refused operation holds its index and changes nothing, so it must\n // not carry its action type's side effects. A refused DELETE_DOCUMENT\n // is the case that matters: taking the branch below would hide the\n // document from every listing and destroy its slug mapping, with\n // nothing in any path to put either back.\n const denied = isDenied(operation);\n\n // Non-header ops carry a denormalized header echo with possibly stale\n // `meta`; only header-scope ops and CREATE/UPGRADE/DELETE may write it.\n const preserveHeaderMeta =\n denied ||\n (operationType !== \"CREATE_DOCUMENT\" &&\n operationType !== \"UPGRADE_DOCUMENT\" &&\n operationType !== \"DELETE_DOCUMENT\" &&\n scope !== \"header\");\n\n if (operationType === \"DELETE_DOCUMENT\" && !denied) {\n const now = new Date();\n await trx\n .updateTable(\"DocumentSnapshot\")\n .set({\n isDeleted: true,\n deletedAt: now,\n lastOperationIndex: index,\n lastOperationHash: hash,\n lastOperationOrdinal: ordinal,\n lastUpdatedAt: now,\n })\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch)\n .where(\"lastOperationOrdinal\", \"<=\", ordinal)\n .execute();\n\n // The content has to say so too, or a caller served the boundary state\n // would get state claiming the document is live.\n const deletedDocumentScope = (\n fullState as Record<string, unknown> | undefined\n )?.document;\n if (deletedDocumentScope !== undefined) {\n await trx\n .updateTable(\"DocumentSnapshot\")\n .set({ content: deletedDocumentScope })\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch)\n .where(\"scope\", \"=\", \"document\")\n .where(\"lastOperationOrdinal\", \"<=\", ordinal)\n .execute();\n }\n\n await trx\n .deleteFrom(\"SlugMapping\")\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch)\n .execute();\n\n continue;\n }\n\n let scopesToIndex: Array<[string, unknown]>;\n\n if (operationType === \"CREATE_DOCUMENT\") {\n scopesToIndex = Object.entries(fullState).filter(\n ([key]) => key === \"header\" || key === \"document\" || key === \"auth\",\n );\n } else if (operationType === \"UPGRADE_DOCUMENT\") {\n // Sibling-scope echoes are only trustworthy when the operation\n // itself defines them: a seed carrying initialState, or a migration\n // whose executor vouched (via the __migrated marker) that it\n // fetched every scope fresh. Upgrades persisted by executors that\n // never fetched sibling scopes echo whatever stale state the write\n // cache held, and indexing those would clobber good snapshots.\n const upgradeInput = operation.action.input as {\n initialState?: unknown;\n };\n const scopesVouchedFor =\n fullState.__migrated === true ||\n upgradeInput.initialState !== undefined;\n delete fullState.__migrated;\n\n scopesToIndex = scopesVouchedFor\n ? Object.entries(fullState)\n : Object.entries(fullState).filter(\n ([key]) =>\n key === \"header\" || key === \"document\" || key === \"auth\",\n );\n } else {\n scopesToIndex = [];\n\n if (fullState.header !== undefined) {\n scopesToIndex.push([\"header\", fullState.header]);\n }\n\n if (fullState[scope] !== undefined) {\n scopesToIndex.push([scope, fullState[scope]]);\n } else {\n // An operation whose resultingState lacks its own scope is never\n // legitimate, and writing {} over the row turns the upstream shape\n // bug into silent data loss that passes every consistency check.\n // Keep the existing snapshot and move past the operation; a throw\n // here would park the cursor for every document behind this one.\n this.logger.warn(\n `refusing to index ${documentId} scope \"${scope}\" at operation ${index}: ` +\n `resultingState carries no \"${scope}\" key; leaving the existing snapshot intact`,\n );\n }\n }\n\n for (const [scopeName, scopeState] of scopesToIndex) {\n // Same rule as the missing-key case above: a scope state that is\n // not an object is malformed input, and substituting {} would write\n // a well-formed empty row that passes every consistency check.\n if (typeof scopeState !== \"object\" || scopeState === null) {\n this.logger.warn(\n `refusing to index ${documentId} scope \"${scopeName}\" at operation ${index}: ` +\n `resultingState carries a non-object \"${scopeName}\" value; leaving the existing snapshot intact`,\n );\n continue;\n }\n\n // The previous `content` is the whole prior scope state - hundreds of\n // kilobytes of jsonb on a large drive - and only the header-meta\n // carry-over below reads it. Selecting it unconditionally made every\n // write pay to decompress and ship a copy of the state it was about\n // to overwrite.\n const needsExistingContent =\n scopeName === \"header\" && preserveHeaderMeta;\n\n const existingSnapshot = await trx\n .selectFrom(\"DocumentSnapshot\")\n .select([\n \"slug\",\n \"name\",\n \"isDeleted\",\n \"snapshotVersion\",\n \"lastOperationOrdinal\",\n ])\n .$if(needsExistingContent, (qb) => qb.select(\"content\"))\n .where(\"documentId\", \"=\", documentId)\n .where(\"scope\", \"=\", scopeName)\n .where(\"branch\", \"=\", branch)\n .executeTakeFirst();\n\n // An older operation carries stale state for the whole scope.\n if (\n existingSnapshot !== undefined &&\n existingSnapshot.lastOperationOrdinal > ordinal\n ) {\n continue;\n }\n\n const newState = scopeState as Record<string, unknown>;\n\n let slug: string | null = existingSnapshot?.slug ?? null;\n let name: string | null = existingSnapshot?.name ?? null;\n\n if (scopeName === \"header\") {\n const headerSlug = newState.slug;\n const headerName = newState.name;\n\n if (typeof headerSlug === \"string\") {\n slug = headerSlug;\n }\n if (typeof headerName === \"string\") {\n name = headerName;\n }\n\n if (needsExistingContent && existingSnapshot) {\n const existingHeader = existingSnapshot.content as Record<\n string,\n unknown\n >;\n if (existingHeader && \"meta\" in existingHeader) {\n newState.meta = existingHeader.meta;\n }\n }\n\n // Never for a deleted document. Deleting removes its SlugMapping\n // rows, and resolveIdOrSlug relies on that to keep the slug branch\n // from reaching one: re-inserting here would make the document\n // resolvable by slug again, and the upsert would take the slug from\n // a live document that has since claimed it.\n if (slug && slug !== documentId && !existingSnapshot?.isDeleted) {\n await trx\n .insertInto(\"SlugMapping\")\n .values({\n slug,\n documentId,\n scope: scopeName,\n branch,\n })\n .onConflict((oc) =>\n oc.column(\"slug\").doUpdateSet({\n documentId,\n scope: scopeName,\n branch,\n }),\n )\n .execute();\n }\n }\n\n if (existingSnapshot) {\n await trx\n .updateTable(\"DocumentSnapshot\")\n .set({\n lastOperationIndex: index,\n lastOperationHash: hash,\n lastOperationOrdinal: ordinal,\n lastUpdatedAt: new Date(),\n snapshotVersion: existingSnapshot.snapshotVersion + 1,\n content: newState,\n slug,\n name,\n })\n .where(\"documentId\", \"=\", documentId)\n .where(\"scope\", \"=\", scopeName)\n .where(\"branch\", \"=\", branch)\n // Repeats the guard where the database can enforce it.\n .where(\"lastOperationOrdinal\", \"<=\", ordinal)\n .execute();\n } else {\n const snapshot: InsertableDocumentSnapshot = {\n id: uuidv4(),\n documentId,\n slug,\n name,\n scope: scopeName,\n branch,\n content: newState,\n documentType,\n lastOperationIndex: index,\n lastOperationHash: hash,\n lastOperationOrdinal: ordinal,\n identifiers: null,\n metadata: null,\n deletedAt: null,\n };\n\n await trx.insertInto(\"DocumentSnapshot\").values(snapshot).execute();\n }\n }\n }\n };\n\n if (fenced) {\n await write(fenced as unknown as Transaction<Database>);\n return;\n }\n await this._db.transaction().execute(write);\n }\n\n async exists(\n documentIds: string[],\n existence: DocumentExistence,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<boolean[]> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (documentIds.length === 0) {\n return [];\n }\n\n const existingIds =\n existence === DocumentExistence.IncludingDeleted\n ? await this.idsWithStreams(documentIds, signal)\n : await this.liveIds(documentIds);\n\n return documentIds.map((id) => existingIds.has(id));\n }\n\n async get<TDocument extends PHDocument>(\n documentId: string,\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<TDocument> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n let scopesToQuery: string[];\n if (view?.scopes && view.scopes.length > 0) {\n scopesToQuery = [...new Set([\"header\", \"document\", ...view.scopes])];\n } else {\n scopesToQuery = [];\n }\n\n let query = this._db\n .selectFrom(\"DocumentSnapshot\")\n .selectAll()\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch);\n\n if (this.deletedDocumentRead === DeletedDocumentRead.NotFound) {\n query = query.where(\"isDeleted\", \"=\", false);\n }\n\n if (scopesToQuery.length > 0) {\n query = query.where(\"scope\", \"in\", scopesToQuery);\n }\n\n const snapshots = await query.execute();\n\n if (snapshots.length === 0) {\n throw new DocumentNotFoundError(\n documentId,\n `Document not found: ${documentId}`,\n );\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const headerSnapshot = snapshots.find((s) => s.scope === \"header\");\n if (!headerSnapshot) {\n throw new Error(`Document header not found: ${documentId}`);\n }\n\n const header = headerSnapshot.content as PHDocumentHeader;\n\n const revisions = await this.operationStore.getRevisions(\n documentId,\n branch,\n signal,\n );\n header.revision = revisions.revision;\n header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n\n const state: Record<string, unknown> = {};\n for (const snapshot of snapshots) {\n if (snapshot.scope === \"header\") {\n continue;\n }\n\n // snapshot rows written before PHAuthState had a version carry auth: {}\n state[snapshot.scope] =\n snapshot.scope === \"auth\"\n ? createAuthState(snapshot.content as Partial<PHAuthState>)\n : snapshot.content;\n }\n\n const document: PHDocument = {\n header,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n state: state as any,\n operations: {},\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n initialState: state as any,\n clipboard: [],\n };\n\n return document as TDocument;\n }\n\n async getMany<TDocument extends PHDocument>(\n documentIds: string[],\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<TDocument[]> {\n if (documentIds.length === 0) {\n return [];\n }\n\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n let scopesToQuery: string[];\n if (view?.scopes && view.scopes.length > 0) {\n scopesToQuery = [...new Set([\"header\", \"document\", ...view.scopes])];\n } else {\n scopesToQuery = [];\n }\n\n let query = this._db\n .selectFrom(\"DocumentSnapshot\")\n .selectAll()\n .where(\"documentId\", \"in\", documentIds)\n .where(\"branch\", \"=\", branch)\n .where(\"isDeleted\", \"=\", false);\n\n if (scopesToQuery.length > 0) {\n query = query.where(\"scope\", \"in\", scopesToQuery);\n }\n\n const allSnapshots = await query.execute();\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const snapshotsByDocId = new Map<string, typeof allSnapshots>();\n for (const snapshot of allSnapshots) {\n const existing = snapshotsByDocId.get(snapshot.documentId) || [];\n existing.push(snapshot);\n snapshotsByDocId.set(snapshot.documentId, existing);\n }\n\n const foundDocumentIds = [...snapshotsByDocId.keys()];\n const revisionResults = await Promise.all(\n foundDocumentIds.map((docId) =>\n this.operationStore.getRevisions(docId, branch, signal),\n ),\n );\n\n const revisionsByDocId = new Map<string, DocumentRevisions>();\n for (let i = 0; i < foundDocumentIds.length; i++) {\n revisionsByDocId.set(foundDocumentIds[i], revisionResults[i]);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const documents: TDocument[] = [];\n for (const documentId of documentIds) {\n const snapshots = snapshotsByDocId.get(documentId);\n if (!snapshots || snapshots.length === 0) {\n continue;\n }\n\n const headerSnapshot = snapshots.find((s) => s.scope === \"header\");\n if (!headerSnapshot) {\n continue;\n }\n\n const header = headerSnapshot.content as PHDocumentHeader;\n const revisions = revisionsByDocId.get(documentId);\n if (revisions) {\n header.revision = revisions.revision;\n header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n }\n\n const state: Record<string, unknown> = {};\n for (const snapshot of snapshots) {\n if (snapshot.scope === \"header\") {\n continue;\n }\n // snapshot rows written before PHAuthState had a version carry auth: {}\n state[snapshot.scope] =\n snapshot.scope === \"auth\"\n ? createAuthState(snapshot.content as Partial<PHAuthState>)\n : snapshot.content;\n }\n\n const document: PHDocument = {\n header,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n state: state as any,\n operations: {},\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n initialState: state as any,\n clipboard: [],\n };\n\n documents.push(document as TDocument);\n }\n\n return documents;\n }\n\n async getByIdOrSlug<TDocument extends PHDocument>(\n identifier: string,\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<TDocument> {\n const documentId = await this.resolveIdOrSlug(\n identifier,\n view,\n consistencyToken,\n signal,\n );\n return this.get<TDocument>(documentId, view, undefined, signal);\n }\n\n async findByType(\n type: string,\n view?: ViewFilter,\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<PHDocument>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n const rows = await this._db\n .selectFrom(\"DocumentSnapshot\")\n .select(\"documentId\")\n .select((eb) => eb.fn.max(\"lastUpdatedAt\").as(\"lastUpdatedAt\"))\n .where(\"documentType\", \"=\", type)\n .where(\"branch\", \"=\", branch)\n .where(\"isDeleted\", \"=\", false)\n .groupBy(\"documentId\")\n .orderBy(\"lastUpdatedAt\", \"desc\")\n .orderBy(\"documentId\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const hasMore = rows.length > limit;\n const docsToFetch = rows.slice(0, limit).map((row) => row.documentId);\n\n const documents: PHDocument[] = [];\n for (const documentId of docsToFetch) {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n try {\n const document = await this.get<PHDocument>(\n documentId,\n view,\n undefined,\n signal,\n );\n documents.push(document);\n } catch {\n continue;\n }\n }\n\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: documents,\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.findByType(\n type,\n view,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async resolveSlug(\n slug: string,\n // TODO: this should only be branch\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string | undefined> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n const mapping = await this._db\n .selectFrom(\"SlugMapping\")\n .select(\"documentId\")\n .where(\"slug\", \"=\", slug)\n .where(\"branch\", \"=\", branch)\n .executeTakeFirst();\n\n if (!mapping) {\n return undefined;\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (view?.scopes && view.scopes.length > 0) {\n const scopeCheck = await this._db\n .selectFrom(\"DocumentSnapshot\")\n .select(\"scope\")\n .where(\"documentId\", \"=\", mapping.documentId)\n .where(\"branch\", \"=\", branch)\n .where(\"scope\", \"in\", view.scopes)\n .where(\"isDeleted\", \"=\", false)\n .executeTakeFirst();\n\n if (!scopeCheck) {\n return undefined;\n }\n }\n\n return mapping.documentId;\n }\n\n // TODO: fix\n async resolveSlugs(\n slugs: string[],\n // TODO: this should only be branch\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string[]> {\n const ids = await Promise.all(\n slugs.map((slug) =>\n this.resolveSlug(slug, view, consistencyToken, signal),\n ),\n );\n return ids.filter((id) => id !== undefined) as string[];\n }\n\n async resolveIdOrSlug(\n identifier: string,\n // TODO: this should only be branch\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n // The id branch relaxes with `get`, or resolution throws before it. The slug\n // branch never does: deleting a document removes its SlugMapping rows.\n let idCheckQuery = this._db\n .selectFrom(\"DocumentSnapshot\")\n .select(\"documentId\")\n .where(\"documentId\", \"=\", identifier)\n .where(\"branch\", \"=\", branch);\n\n if (this.deletedDocumentRead === DeletedDocumentRead.NotFound) {\n idCheckQuery = idCheckQuery.where(\"isDeleted\", \"=\", false);\n }\n\n const idCheckPromise = idCheckQuery.executeTakeFirst();\n\n const slugCheckPromise = this._db\n .selectFrom(\"SlugMapping\")\n .select(\"documentId\")\n .where(\"slug\", \"=\", identifier)\n .where(\"branch\", \"=\", branch)\n .executeTakeFirst();\n\n const [idMatch, slugMatch] = await Promise.all([\n idCheckPromise,\n slugCheckPromise,\n ]);\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const idMatchDocId = idMatch?.documentId;\n const slugMatchDocId = slugMatch?.documentId;\n\n if (idMatchDocId && slugMatchDocId && idMatchDocId !== slugMatchDocId) {\n throw new Error(\n `Ambiguous identifier \"${identifier}\": matches both document ID \"${idMatchDocId}\" and slug for document ID \"${slugMatchDocId}\". ` +\n `Please use get() for ID or resolveSlug() + get() for slug to be explicit.`,\n );\n }\n\n const resolvedDocumentId = idMatchDocId || slugMatchDocId;\n\n if (!resolvedDocumentId) {\n throw new DocumentNotFoundError(\n identifier,\n `Document not found: ${identifier}`,\n );\n }\n\n return resolvedDocumentId;\n }\n\n /**\n * Ids that have at least one stream, asked of the operation store rather than\n * of a table, so the answer holds for any store implementation. A deleted\n * document keeps its stream, so this is the id-is-taken answer, and it does\n * not drift when a snapshot row is missing.\n *\n * Asked on main because that is the branch a create writes: the store this\n * question exists to agree with validates the create against main's head.\n */\n private async idsWithStreams(\n documentIds: string[],\n signal?: AbortSignal,\n ): Promise<Set<string>> {\n const unique = [...new Set(documentIds)];\n const revisions = await Promise.all(\n unique.map((documentId) =>\n this.operationStore.getRevisions(documentId, \"main\", signal),\n ),\n );\n\n const taken = new Set<string>();\n for (let i = 0; i < unique.length; i++) {\n if (Object.keys(revisions[i].revision).length > 0) {\n taken.add(unique[i]);\n }\n }\n return taken;\n }\n\n private async liveIds(documentIds: string[]): Promise<Set<string>> {\n const rows = await this._db\n .selectFrom(\"DocumentSnapshot\")\n .select([\"documentId\"])\n .where(\"documentId\", \"in\", documentIds)\n .where(\"isDeleted\", \"=\", false)\n .distinct()\n .execute();\n\n return new Set(rows.map((row) => row.documentId));\n }\n}\n","import type { ConsistencyCoordinate, ConsistencyKey } from \"./types.js\";\n\nexport interface IConsistencyTracker {\n /**\n * Updates the tracker with new operation indexes.\n * When multiple coordinates have the same key, keeps the highest operationIndex.\n * Resolves any pending waiters whose coordinates are now satisfied.\n */\n update(coordinates: ConsistencyCoordinate[]): void;\n\n /**\n * Returns the latest operation index for a given key, or undefined if not tracked.\n */\n getLatest(key: ConsistencyKey): number | undefined;\n\n /**\n * Returns a promise that resolves when all coordinates are satisfied.\n * Rejects if the timeout is reached or the signal is aborted.\n */\n waitFor(\n coordinates: ConsistencyCoordinate[],\n timeoutMs?: number,\n signal?: AbortSignal,\n ): Promise<void>;\n\n /**\n * Returns a serializable snapshot of the current state.\n */\n serialize(): Array<[ConsistencyKey, number]>;\n\n /**\n * Restores state from a serialized snapshot.\n */\n hydrate(entries: Array<[ConsistencyKey, number]>): void;\n}\n\ntype Waiter = {\n coordinates: ConsistencyCoordinate[];\n resolve: () => void;\n reject: (reason: Error) => void;\n signal?: AbortSignal;\n timeoutId?: NodeJS.Timeout;\n};\n\n/**\n * Creates a consistency key from documentId, scope, and branch.\n */\nexport function makeConsistencyKey(\n documentId: string,\n scope: string,\n branch: string,\n): ConsistencyKey {\n return `${documentId}:${scope}:${branch}`;\n}\n\n/**\n * Tracks operation indexes for documents and provides read-after-write consistency guarantees.\n * Maintains an in-memory map of the latest operation index for each (documentId, scope, branch) tuple.\n */\nexport class ConsistencyTracker implements IConsistencyTracker {\n private state = new Map<ConsistencyKey, number>();\n private waiters: Waiter[] = [];\n\n update(coordinates: ConsistencyCoordinate[]): void {\n const deduplicated = this.deduplicateCoordinates(coordinates);\n\n for (let i = 0; i < deduplicated.length; i++) {\n const coord = deduplicated[i]!;\n const key = makeConsistencyKey(\n coord.documentId,\n coord.scope,\n coord.branch,\n );\n const current = this.state.get(key);\n if (current === undefined || coord.operationIndex > current) {\n this.state.set(key, coord.operationIndex);\n }\n }\n\n this.checkWaiters();\n }\n\n getLatest(key: ConsistencyKey): number | undefined {\n return this.state.get(key);\n }\n\n waitFor(\n coordinates: ConsistencyCoordinate[],\n timeoutMs?: number,\n signal?: AbortSignal,\n ): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(new Error(\"Operation aborted\"));\n }\n\n if (this.areCoordinatesSatisfied(coordinates)) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => {\n const waiter: Waiter = {\n coordinates,\n resolve,\n reject,\n signal,\n };\n\n if (timeoutMs !== undefined) {\n waiter.timeoutId = setTimeout(() => {\n this.removeWaiter(waiter);\n reject(new Error(`Consistency wait timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }\n\n if (signal) {\n const abortHandler = () => {\n this.removeWaiter(waiter);\n reject(new Error(\"Operation aborted\"));\n };\n signal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n this.waiters.push(waiter);\n });\n }\n\n serialize(): Array<[ConsistencyKey, number]> {\n return Array.from(this.state.entries());\n }\n\n hydrate(entries: Array<[ConsistencyKey, number]>): void {\n this.state.clear();\n for (const [key, index] of entries) {\n this.state.set(key, index);\n }\n }\n\n private deduplicateCoordinates(\n coordinates: ConsistencyCoordinate[],\n ): ConsistencyCoordinate[] {\n const map = new Map<ConsistencyKey, ConsistencyCoordinate>();\n\n for (let i = 0; i < coordinates.length; i++) {\n const coord = coordinates[i]!;\n const key = makeConsistencyKey(\n coord.documentId,\n coord.scope,\n coord.branch,\n );\n const existing = map.get(key);\n\n if (!existing || coord.operationIndex > existing.operationIndex) {\n map.set(key, coord);\n }\n }\n\n return Array.from(map.values());\n }\n\n private areCoordinatesSatisfied(\n coordinates: ConsistencyCoordinate[],\n ): boolean {\n for (let i = 0; i < coordinates.length; i++) {\n const coord = coordinates[i]!;\n const key = makeConsistencyKey(\n coord.documentId,\n coord.scope,\n coord.branch,\n );\n const latest = this.state.get(key);\n if (latest === undefined || latest < coord.operationIndex) {\n return false;\n }\n }\n return true;\n }\n\n private checkWaiters(): void {\n const satisfiedWaiters: Waiter[] = [];\n const unsatisfiedWaiters: Waiter[] = [];\n\n for (const waiter of this.waiters) {\n if (waiter.signal?.aborted) {\n continue;\n }\n\n if (this.areCoordinatesSatisfied(waiter.coordinates)) {\n satisfiedWaiters.push(waiter);\n } else {\n unsatisfiedWaiters.push(waiter);\n }\n }\n\n this.waiters = unsatisfiedWaiters;\n\n for (const waiter of satisfiedWaiters) {\n if (waiter.timeoutId !== undefined) {\n clearTimeout(waiter.timeoutId);\n }\n waiter.resolve();\n }\n }\n\n private removeWaiter(waiter: Waiter): void {\n const index = this.waiters.indexOf(waiter);\n if (index !== -1) {\n this.waiters.splice(index, 1);\n }\n if (waiter.timeoutId !== undefined) {\n clearTimeout(waiter.timeoutId);\n }\n }\n}\n","import type { PagedResults } from \"./types.js\";\n\n/**\n * Collects all results from a paged result set by following the next() function\n * until all pages have been fetched.\n */\nexport async function collectAllPages<T>(\n firstPage: PagedResults<T>,\n signal?: AbortSignal,\n): Promise<T[]> {\n const allResults: T[] = [...firstPage.results];\n let currentPage = firstPage;\n\n while (currentPage.next) {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n currentPage = await currentPage.next();\n allResults.push(...currentPage.results);\n }\n\n return allResults;\n}\n","import type {\n Operation,\n OperationWithContext,\n} from \"@powerhousedao/shared/document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { IOperationIndex } from \"../../cache/operation-index-types.js\";\nimport type { IWriteCache } from \"../../cache/write/interfaces.js\";\nimport {\n BaseReadModel,\n defaultReadModelIndexingConfig,\n type ReadModelIndexingConfig,\n} from \"../../read-models/base-read-model.js\";\nimport { DOCUMENT_INDEXER_READ_MODEL } from \"../../read-models/names.js\";\nimport type { DocumentViewDatabase } from \"../../read-models/types.js\";\nimport { collectAllPages } from \"../../shared/collect-all-pages.js\";\nimport type { IConsistencyTracker } from \"../../shared/consistency-tracker.js\";\nimport type {\n ConsistencyToken,\n PagedResults,\n PagingOptions,\n} from \"../../shared/types.js\";\nimport type {\n DocumentGraphEdge,\n DocumentRelationship,\n IDocumentGraph,\n IDocumentIndexer,\n} from \"../interfaces.js\";\nimport { findPurged } from \"./document-purges.js\";\nimport type {\n DocumentIndexerDatabase,\n InsertableDocumentRelationship,\n Database as StorageDatabase,\n} from \"./types.js\";\n\nfunction isRelationshipAction(actionType: string): boolean {\n return (\n actionType === \"ADD_RELATIONSHIP\" ||\n actionType === \"REMOVE_RELATIONSHIP\" ||\n actionType === \"UPDATE_RELATIONSHIP\"\n );\n}\n\ntype RelationshipEnds = { sourceId: string; targetId: string };\n\nfunction addRelationshipIds(items: OperationWithContext[]): string[] {\n const ids: string[] = [];\n for (const { operation } of items) {\n if (operation.action.type !== \"ADD_RELATIONSHIP\") continue;\n const { sourceId, targetId } = operation.action.input as RelationshipEnds;\n if (typeof sourceId === \"string\") ids.push(sourceId);\n if (typeof targetId === \"string\") ids.push(targetId);\n }\n return ids;\n}\n\nfunction touchesPurged(operation: Operation, purged: Set<string>): boolean {\n const input = operation.action.input as RelationshipEnds;\n return purged.has(input.sourceId) || purged.has(input.targetId);\n}\n\nexport type IndexerDatabase = StorageDatabase &\n DocumentIndexerDatabase &\n DocumentViewDatabase;\n\nexport class KyselyDocumentIndexer\n extends BaseReadModel\n implements IDocumentIndexer\n{\n static override readonly commitsInFenceTransaction = true;\n\n private _db: Kysely<IndexerDatabase>;\n\n constructor(\n db: Kysely<IndexerDatabase>,\n operationIndex: IOperationIndex,\n writeCache: IWriteCache,\n consistencyTracker: IConsistencyTracker,\n indexing: ReadModelIndexingConfig = defaultReadModelIndexingConfig,\n ) {\n super(\n db as unknown as Kysely<DocumentViewDatabase>,\n operationIndex,\n writeCache,\n consistencyTracker,\n {\n readModelId: DOCUMENT_INDEXER_READ_MODEL,\n rebuildStateOnInit: false,\n indexing,\n purgeFence: \"locked\",\n },\n );\n this._db = db;\n }\n\n protected override writesRows(items: OperationWithContext[]): boolean {\n return items.some((item) =>\n isRelationshipAction(item.operation.action.type),\n );\n }\n\n /** Opens no transaction for a batch carrying no relationship operation. */\n protected override async commitOperations(\n items: OperationWithContext[],\n fenced?: Transaction<DocumentViewDatabase>,\n ): Promise<void> {\n const relationshipOps = items.filter((item) =>\n isRelationshipAction(item.operation.action.type),\n );\n\n if (relationshipOps.length === 0) {\n return;\n }\n\n if (fenced) {\n await this.writeRelationships(\n relationshipOps,\n fenced as unknown as Transaction<IndexerDatabase>,\n );\n return;\n }\n await this._db\n .transaction()\n .execute((trx) => this.writeRelationships(relationshipOps, trx));\n }\n\n private async writeRelationships(\n relationshipOps: OperationWithContext[],\n trx: Transaction<IndexerDatabase>,\n ): Promise<void> {\n const purged = await findPurged(trx, addRelationshipIds(relationshipOps));\n for (const item of relationshipOps) {\n const { operation } = item;\n const actionType = operation.action.type;\n\n if (actionType === \"ADD_RELATIONSHIP\") {\n // Whole: a lone target Document row would outlive the purge.\n if (touchesPurged(operation, purged)) continue;\n await this.handleAddRelationship(trx, operation);\n } else if (actionType === \"REMOVE_RELATIONSHIP\") {\n await this.handleRemoveRelationship(trx, operation);\n } else if (actionType === \"UPDATE_RELATIONSHIP\") {\n await this.handleUpdateRelationship(trx, operation);\n }\n }\n }\n\n async getOutgoing(\n documentId: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where(\"sourceId\", \"=\", documentId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getOutgoing(\n documentId,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async getIncoming(\n documentId: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where(\"targetId\", \"=\", documentId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getIncoming(\n documentId,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async getOrphanedChildren(\n parentIds: string[],\n types?: string[],\n signal?: AbortSignal,\n ): Promise<string[]> {\n if (parentIds.length === 0) {\n return [];\n }\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n let query = this._db\n .selectFrom(\"DocumentRelationship as r\")\n .select(\"r.targetId\")\n .distinct()\n .where(\"r.sourceId\", \"in\", parentIds)\n .where((eb) =>\n eb.not(\n eb.exists(\n eb\n .selectFrom(\"DocumentRelationship as other\")\n .select(\"other.id\")\n .whereRef(\"other.targetId\", \"=\", \"r.targetId\")\n .where(\"other.sourceId\", \"not in\", parentIds),\n ),\n ),\n );\n\n if (types && types.length > 0) {\n query = query.where(\"r.relationshipType\", \"in\", types);\n }\n\n const rows = await query.execute();\n return rows.map((row) => row.targetId);\n }\n\n async hasRelationship(\n sourceId: string,\n targetId: string,\n types?: string[],\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<boolean> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .select(\"id\")\n .where(\"sourceId\", \"=\", sourceId)\n .where(\"targetId\", \"=\", targetId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const result = await query.executeTakeFirst();\n\n return result !== undefined;\n }\n\n async getUndirectedRelationships(\n a: string,\n b: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where((eb) =>\n eb.or([\n eb.and([eb(\"sourceId\", \"=\", a), eb(\"targetId\", \"=\", b)]),\n eb.and([eb(\"sourceId\", \"=\", b), eb(\"targetId\", \"=\", a)]),\n ]),\n );\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getUndirectedRelationships(\n a,\n b,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async getDirectedRelationships(\n sourceId: string,\n targetId: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where(\"sourceId\", \"=\", sourceId)\n .where(\"targetId\", \"=\", targetId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getDirectedRelationships(\n sourceId,\n targetId,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async findPath(\n sourceId: string,\n targetId: string,\n types?: string[],\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string[] | null> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (sourceId === targetId) {\n return [sourceId];\n }\n\n const visited = new Set<string>();\n const queue: Array<{ id: string; path: string[] }> = [\n { id: sourceId, path: [sourceId] },\n ];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current.id === targetId) {\n return current.path;\n }\n\n if (visited.has(current.id)) {\n continue;\n }\n\n visited.add(current.id);\n\n const outgoingPage = await this.getOutgoing(\n current.id,\n types,\n undefined,\n consistencyToken,\n signal,\n );\n const outgoingRelationships = await collectAllPages(outgoingPage, signal);\n\n for (const rel of outgoingRelationships) {\n if (!visited.has(rel.targetId)) {\n queue.push({\n id: rel.targetId,\n path: [...current.path, rel.targetId],\n });\n }\n }\n }\n\n return null;\n }\n\n async findAncestors(\n documentId: string,\n types?: string[],\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<IDocumentGraph> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const nodes = new Set<string>([documentId]);\n const edges: DocumentGraphEdge[] = [];\n const queue: string[] = [documentId];\n const visited = new Set<string>();\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n\n if (visited.has(currentId)) {\n continue;\n }\n\n visited.add(currentId);\n\n const incomingPage = await this.getIncoming(\n currentId,\n types,\n undefined,\n consistencyToken,\n signal,\n );\n const incomingRelationships = await collectAllPages(incomingPage, signal);\n\n for (const rel of incomingRelationships) {\n nodes.add(rel.sourceId);\n edges.push({\n from: rel.sourceId,\n to: rel.targetId,\n type: rel.relationshipType,\n });\n\n if (!visited.has(rel.sourceId)) {\n queue.push(rel.sourceId);\n }\n }\n }\n\n return {\n nodes: Array.from(nodes),\n edges,\n };\n }\n\n async getRelationshipTypes(\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string[]> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const rows = await this._db\n .selectFrom(\"DocumentRelationship\")\n .select(\"relationshipType\")\n .distinct()\n .execute();\n\n return rows.map((row) => row.relationshipType);\n }\n\n private async handleAddRelationship(\n trx: Kysely<IndexerDatabase>,\n operation: Operation,\n ): Promise<void> {\n const input = operation.action.input as {\n sourceId: string;\n targetId: string;\n relationshipType: string;\n metadata?: Record<string, unknown>;\n };\n\n const existingDoc = await trx\n .selectFrom(\"Document\")\n .select(\"id\")\n .where(\"id\", \"=\", input.sourceId)\n .executeTakeFirst();\n\n if (!existingDoc) {\n await trx\n .insertInto(\"Document\")\n .values({\n id: input.sourceId,\n })\n .execute();\n }\n\n const existingTargetDoc = await trx\n .selectFrom(\"Document\")\n .select(\"id\")\n .where(\"id\", \"=\", input.targetId)\n .executeTakeFirst();\n\n if (!existingTargetDoc) {\n await trx\n .insertInto(\"Document\")\n .values({\n id: input.targetId,\n })\n .execute();\n }\n\n const existingRel = await trx\n .selectFrom(\"DocumentRelationship\")\n .select(\"id\")\n .where(\"sourceId\", \"=\", input.sourceId)\n .where(\"targetId\", \"=\", input.targetId)\n .where(\"relationshipType\", \"=\", input.relationshipType)\n .executeTakeFirst();\n\n if (!existingRel) {\n const relationship: InsertableDocumentRelationship = {\n id: uuidv4(),\n sourceId: input.sourceId,\n targetId: input.targetId,\n relationshipType: input.relationshipType,\n metadata: input.metadata || null,\n };\n\n await trx\n .insertInto(\"DocumentRelationship\")\n .values(relationship)\n .execute();\n }\n }\n\n private async handleRemoveRelationship(\n trx: Kysely<IndexerDatabase>,\n operation: Operation,\n ): Promise<void> {\n const input = operation.action.input as {\n sourceId: string;\n targetId: string;\n relationshipType: string;\n };\n\n await trx\n .deleteFrom(\"DocumentRelationship\")\n .where(\"sourceId\", \"=\", input.sourceId)\n .where(\"targetId\", \"=\", input.targetId)\n .where(\"relationshipType\", \"=\", input.relationshipType)\n .execute();\n }\n\n private async handleUpdateRelationship(\n trx: Kysely<IndexerDatabase>,\n operation: Operation,\n ): Promise<void> {\n const input = operation.action.input as {\n sourceId: string;\n targetId: string;\n relationshipType: string;\n metadata: Record<string, unknown> | null;\n };\n\n await trx\n .updateTable(\"DocumentRelationship\")\n .set({\n metadata: input.metadata,\n updatedAt: new Date(),\n })\n .where(\"sourceId\", \"=\", input.sourceId)\n .where(\"targetId\", \"=\", input.targetId)\n .where(\"relationshipType\", \"=\", input.relationshipType)\n .execute();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"document-indexer-lfgXu9ph.js","names":["uuidv4","uuidv4"],"sources":["../src/catch-up/scheduler.ts","../src/catch-up/types.ts","../src/catch-up/contiguous-cursor.ts","../src/read-models/base-read-model.ts","../src/read-models/coordinator.ts","../src/read-models/names.ts","../src/read-models/document-view.ts","../src/shared/consistency-tracker.ts","../src/shared/collect-all-pages.ts","../src/storage/kysely/document-indexer.ts"],"sourcesContent":["import type { ILogger } from \"document-model\";\nimport type { IOperationIndex } from \"../cache/operation-index-types.js\";\nimport type { WatermarkSession } from \"./settled-watermark.js\";\nimport type {\n CatchUpConfig,\n CatchUpConsumerStatus,\n CatchUpStatus,\n CatchUpThread,\n ICatchUp,\n ICatchUpConsumer,\n ISettledWatermark,\n SweepBlockedAt,\n SweepResult,\n} from \"./types.js\";\n\ntype ConsumerEntry = {\n consumer: ICatchUpConsumer;\n thread: CatchUpThread;\n blockedAt?: SweepBlockedAt;\n lastAdvanceUtcMs: number;\n warnedHeld: boolean;\n};\n\nexport type CatchUpSchedulerHooks = {\n /** Called for every sweep that moved, replayed or failed. */\n onSwept: (result: SweepResult, thread: CatchUpThread) => void;\n /** Names the sessions holding the watermark, for the stall warning. */\n describeSessions: (xids: readonly string[]) => Promise<WatermarkSession[]>;\n};\n\nconst noHooks: CatchUpSchedulerHooks = {\n onSwept: () => {},\n describeSessions: () => Promise.resolve([]),\n};\n\ntype PresentPage = { bound: number; present: number[] };\n\ntype ConsumerSource = {\n consumers: () => readonly ICatchUpConsumer[];\n thread: CatchUpThread;\n};\n\nexport function isCatchUpConsumer(value: unknown): value is ICatchUpConsumer {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as Partial<ICatchUpConsumer>;\n return (\n typeof candidate.sweep === \"function\" &&\n typeof candidate.consumerId === \"string\" &&\n typeof candidate.appliedThrough === \"number\"\n );\n}\n\n/** Periodically sweeps every consumer up to the settled watermark. */\nexport class CatchUpScheduler implements ICatchUp {\n private readonly fixed: ConsumerEntry[] = [];\n private readonly sources: ConsumerSource[] = [];\n private readonly sourced = new Map<ICatchUpConsumer, ConsumerEntry>();\n private timer: ReturnType<typeof setInterval> | undefined;\n private running: Promise<SweepResult[]> | undefined;\n private started = false;\n private stopped = false;\n private warnedStallSince: number | undefined;\n private readonly statusSources: Array<() => CatchUpConsumerStatus[]> = [];\n\n constructor(\n private readonly watermark: ISettledWatermark,\n private readonly operationIndex: IOperationIndex,\n private readonly config: CatchUpConfig,\n private readonly logger: ILogger,\n private readonly hooks: CatchUpSchedulerHooks = noHooks,\n ) {}\n\n get settledWatermark(): ISettledWatermark {\n return this.watermark;\n }\n\n addConsumer(consumer: ICatchUpConsumer, thread: CatchUpThread): void {\n if (this.fixed.some((entry) => entry.consumer === consumer)) return;\n this.fixed.push({\n consumer,\n thread,\n lastAdvanceUtcMs: Date.now(),\n warnedHeld: false,\n });\n this.ensureTimer();\n }\n\n /** Consumers read on every tick, so models registered later are swept too. */\n addSource(\n consumers: () => readonly ICatchUpConsumer[],\n thread: CatchUpThread,\n ): void {\n this.sources.push({ consumers, thread });\n this.ensureTimer();\n }\n\n /** Consumers another thread sweeps, reported in status(). */\n addStatusSource(source: () => CatchUpConsumerStatus[]): void {\n this.statusSources.push(source);\n }\n\n start(): void {\n this.started = true;\n this.ensureTimer();\n }\n\n async stop(): Promise<void> {\n this.stopped = true;\n if (this.timer !== undefined) {\n clearInterval(this.timer);\n this.timer = undefined;\n }\n if (this.running !== undefined) {\n await this.running.catch(() => []);\n }\n }\n\n async sweepNow(): Promise<SweepResult[]> {\n if (this.running !== undefined) {\n await this.running.catch(() => []);\n }\n return this.run();\n }\n\n status(): CatchUpStatus {\n return {\n watermark: this.watermark.status(),\n consumers: this.entries()\n .map((entry): CatchUpConsumerStatus => ({\n consumerId: entry.consumer.consumerId,\n thread: entry.thread,\n appliedThrough: entry.consumer.appliedThrough,\n trackedAbove: entry.consumer.trackedAbove,\n ...(entry.blockedAt !== undefined\n ? { blockedAt: entry.blockedAt }\n : {}),\n lastAdvanceUtcMs: entry.lastAdvanceUtcMs,\n }))\n .concat(this.statusSources.flatMap((source) => source())),\n };\n }\n\n private ensureTimer(): void {\n if (!this.started || this.stopped || this.timer !== undefined) return;\n if (this.fixed.length === 0 && this.sources.length === 0) return;\n\n const timer = setInterval(() => {\n if (this.running !== undefined) return;\n void this.run().catch((error: unknown) => {\n this.logger.error(\"catch-up tick failed: @error\", error);\n });\n }, this.config.intervalMs);\n if (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n this.timer = timer;\n }\n\n private run(): Promise<SweepResult[]> {\n const run = this.tick().finally(() => {\n if (this.running === run) this.running = undefined;\n });\n this.running = run;\n return run;\n }\n\n private async tick(): Promise<SweepResult[]> {\n const settled = await this.watermark.refresh();\n await this.warnIfWatermarkHeld();\n const entries = this.entries();\n if (entries.length === 0) return [];\n\n let lowest = Number.POSITIVE_INFINITY;\n for (const entry of entries) {\n lowest = Math.min(lowest, entry.consumer.appliedThrough);\n }\n const shared = await this.readPage(lowest, settled);\n\n const results: SweepResult[] = [];\n for (const entry of entries) {\n if (this.stopped) break;\n const result = await this.sweepOne(entry, shared, settled);\n if (result !== undefined) results.push(result);\n }\n return results;\n }\n\n private entries(): ConsumerEntry[] {\n const entries = [...this.fixed];\n const seen = new Set(entries.map((entry) => entry.consumer));\n for (const source of this.sources) {\n for (const consumer of source.consumers()) {\n if (seen.has(consumer)) continue;\n seen.add(consumer);\n let entry = this.sourced.get(consumer);\n if (entry === undefined) {\n entry = {\n consumer,\n thread: source.thread,\n lastAdvanceUtcMs: Date.now(),\n warnedHeld: false,\n };\n this.sourced.set(consumer, entry);\n }\n entries.push(entry);\n }\n }\n return entries;\n }\n\n private async sweepOne(\n entry: ConsumerEntry,\n shared: PresentPage,\n settled: number,\n ): Promise<SweepResult | undefined> {\n const applied = entry.consumer.appliedThrough;\n let page = shared;\n if (applied >= shared.bound && shared.bound < settled) {\n try {\n page = await this.readPage(applied, settled);\n } catch (error) {\n this.logger.error(\n \"@consumer catch-up could not read present ordinals: @error\",\n entry.consumer.consumerId,\n error,\n );\n return undefined;\n }\n }\n\n let result: SweepResult;\n try {\n result = await entry.consumer.sweep(page.bound, page.present);\n } catch (error) {\n this.logger.error(\n \"@consumer catch-up sweep failed: @error\",\n entry.consumer.consumerId,\n error,\n );\n return undefined;\n }\n\n if (result.to > result.from) {\n entry.lastAdvanceUtcMs = Date.now();\n entry.warnedHeld = false;\n }\n entry.blockedAt = result.blockedAt;\n this.warnIfConsumerHeld(entry, settled);\n if (\n result.to > result.from ||\n result.replayed > 0 ||\n result.blockedAt !== undefined\n ) {\n this.hooks.onSwept(result, entry.thread);\n }\n return result;\n }\n\n private async warnIfWatermarkHeld(): Promise<void> {\n const status = this.watermark.status();\n const since = status.stalledSinceUtcMs;\n if (since === undefined) {\n this.warnedStallSince = undefined;\n return;\n }\n const heldMs = Date.now() - since;\n if (heldMs < this.config.stuckWarnMs || this.warnedStallSince === since) {\n return;\n }\n this.warnedStallSince = since;\n const sessions: WatermarkSession[] = await this.hooks\n .describeSessions(status.waitingOn)\n .catch(() => []);\n this.logger.warn(\n \"settled watermark held at @settled (head @head) for @ms ms, waiting on xid @xids: @sessions\",\n status.settledThrough,\n status.head,\n heldMs,\n status.waitingOn.join(\", \"),\n sessions\n .map(\n (session) =>\n `pid ${session.pid} ${session.applicationName} ${session.state} since ${session.xactStart ?? \"?\"}`,\n )\n .join(\"; \"),\n );\n }\n\n private warnIfConsumerHeld(entry: ConsumerEntry, settled: number): void {\n const applied = entry.consumer.appliedThrough;\n if (applied >= settled || entry.warnedHeld) return;\n const heldMs = Date.now() - entry.lastAdvanceUtcMs;\n if (heldMs < this.config.stuckWarnMs) return;\n entry.warnedHeld = true;\n this.logger.warn(\n \"@consumer cursor held at @applied for @ms ms (settled @settled)\",\n entry.consumer.consumerId,\n applied,\n heldMs,\n settled,\n );\n }\n\n private async readPage(after: number, settled: number): Promise<PresentPage> {\n const limit = this.config.sweepPageSize;\n const present = await this.operationIndex.getOrdinalsInRange(\n after,\n settled,\n limit,\n );\n const bound =\n present.length >= limit ? present[present.length - 1]! : settled;\n return { bound, present };\n }\n}\n","import type { Unsubscribe } from \"../events/types.js\";\n\nexport type WatermarkStatus = {\n head: number;\n settledThrough: number;\n waitingOn: string[];\n stalledSinceUtcMs?: number;\n};\n\nexport interface ISettledWatermark {\n /** Every ordinal at or below this is visible or will never exist. */\n readonly settledThrough: number;\n /** Probes, coalesced with one in flight; resolves with settledThrough. */\n refresh(signal?: AbortSignal): Promise<number>;\n onAdvance(listener: (settledThrough: number) => void): Unsubscribe;\n status(): WatermarkStatus;\n}\n\nexport type SweepBlockedAt = {\n ordinal: number;\n documentId: string;\n scope: string;\n branch: string;\n type: string;\n error: string;\n};\n\nexport type SweepResult = {\n consumerId: string;\n from: number;\n to: number;\n durationMs: number;\n /** Late operations applied. */\n replayed: number;\n /** Later operations of their streams applied again. */\n reapplied: number;\n blockedAt?: SweepBlockedAt;\n};\n\nexport interface ICatchUpConsumer {\n readonly consumerId: string;\n readonly appliedThrough: number;\n /** Ordinals above the cursor this consumer holds in memory. */\n readonly trackedAbove: number;\n sweep(\n settledThrough: number,\n present: readonly number[],\n signal?: AbortSignal,\n ): Promise<SweepResult>;\n}\n\nexport type CatchUpThread = \"host\" | \"projection\";\n\nexport type CatchUpConsumerStatus = {\n consumerId: string;\n thread: CatchUpThread;\n appliedThrough: number;\n trackedAbove: number;\n blockedAt?: SweepBlockedAt;\n lastAdvanceUtcMs: number;\n};\n\nexport type CatchUpStatus = {\n watermark: WatermarkStatus;\n consumers: CatchUpConsumerStatus[];\n};\n\nexport type CatchUpConfig = {\n intervalMs: number;\n stuckWarnMs: number;\n maxTrackedAboveCursor: number;\n /** Present ordinals read per tick. */\n sweepPageSize: number;\n};\n\nexport const defaultCatchUpConfig: CatchUpConfig = {\n intervalMs: 2000,\n stuckWarnMs: 60_000,\n maxTrackedAboveCursor: 100_000,\n sweepPageSize: 10_000,\n};\n\n/** The catch-up surface a reactor module exposes. */\nexport interface ICatchUp {\n status(): CatchUpStatus;\n sweepNow(): Promise<SweepResult[]>;\n}\n","/** In memory, per consumer; tracks ordinals above appliedThrough only. */\nexport class ContiguousCursor {\n private claimed = new Set<number>();\n private applied = new Set<number>();\n\n constructor(\n private through: number,\n private limit: number,\n ) {}\n\n setLimit(limit: number): void {\n this.limit = limit;\n }\n\n /** Every present ordinal at or below this has been applied. */\n get appliedThrough(): number {\n return this.through;\n }\n\n get trackedAbove(): number {\n return this.claimed.size + this.applied.size;\n }\n\n /** Ordinals the caller must apply; the rest are already covered. */\n claim(ordinals: Iterable<number>): Set<number> {\n const mine = new Set<number>();\n for (const ordinal of ordinals) {\n if (ordinal <= this.through) continue;\n if (this.claimed.has(ordinal) || this.applied.has(ordinal)) continue;\n this.claimed.add(ordinal);\n mine.add(ordinal);\n }\n return mine;\n }\n\n /** Releases claims; committed ones join the applied set. */\n settle(ordinals: Iterable<number>, committed: boolean): void {\n for (const ordinal of ordinals) {\n if (!this.claimed.delete(ordinal)) continue;\n if (committed && ordinal > this.through) this.applied.add(ordinal);\n }\n }\n\n /** Past the limit, clears the applied set; the next sweep re-applies it. */\n enforceLimit(): void {\n if (this.claimed.size + this.applied.size > this.limit) {\n this.applied.clear();\n }\n }\n\n /** Present ordinals above the cursor that no path has claimed or applied. */\n missing(present: readonly number[]): number[] {\n return present.filter(\n (ordinal) =>\n ordinal > this.through &&\n !this.claimed.has(ordinal) &&\n !this.applied.has(ordinal),\n );\n }\n\n /** `settled`, held below the lowest claimed or unapplied ordinal. */\n target(settled: number, present: readonly number[]): number {\n let to = settled;\n for (const ordinal of this.claimed) {\n if (ordinal <= to) to = ordinal - 1;\n }\n for (const ordinal of present) {\n if (ordinal <= this.through || ordinal > to) continue;\n if (!this.applied.has(ordinal)) to = ordinal - 1;\n }\n return Math.max(to, this.through);\n }\n\n advance(to: number): void {\n if (to <= this.through) return;\n this.through = to;\n for (const ordinal of this.applied) {\n if (ordinal <= to) this.applied.delete(ordinal);\n }\n for (const ordinal of this.claimed) {\n if (ordinal <= to) this.claimed.delete(ordinal);\n }\n }\n}\n","import {\n isPurgeMarker,\n type OperationWithContext,\n} from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport type { IOperationIndex } from \"../cache/operation-index-types.js\";\nimport type { IWriteCache } from \"../cache/write/interfaces.js\";\nimport { ContiguousCursor } from \"../catch-up/contiguous-cursor.js\";\nimport {\n createKyselyWatermarkProbe,\n SettledWatermark,\n} from \"../catch-up/settled-watermark.js\";\nimport {\n defaultCatchUpConfig,\n type ICatchUpConsumer,\n type ISettledWatermark,\n type SweepBlockedAt,\n type SweepResult,\n} from \"../catch-up/types.js\";\nimport type { Unsubscribe } from \"../events/types.js\";\nimport type { IConsistencyTracker } from \"../shared/consistency-tracker.js\";\nimport { DocumentNotFoundError } from \"../shared/errors.js\";\nimport type {\n ConsistencyCoordinate,\n ConsistencyToken,\n} from \"../shared/types.js\";\nimport { yieldToMain } from \"../shared/utils.js\";\nimport {\n acquirePurgeLocks,\n findPurged,\n} from \"../storage/kysely/document-purges.js\";\nimport type { Database as StorageDatabase } from \"../storage/kysely/types.js\";\nimport type { IReadModel, IReadModelReservation } from \"./interfaces.js\";\nimport type { DocumentViewDatabase } from \"./types.js\";\n\n/** Bounds on an indexing pass: one transaction, and the stall between yields. */\nexport type ReadModelIndexingConfig = {\n /** Maximum operations committed in a single transaction. */\n commitChunkSize: number;\n /** Maximum elapsed milliseconds before yielding between chunks. */\n yieldDeadlineMs: number;\n};\n\n/** Small enough that a chunk's transaction rarely outlasts the yield deadline. */\nexport const DEFAULT_COMMIT_CHUNK_SIZE = 50;\n\n/** Matches the executor's own default, so both paths yield on the same cadence. */\nexport const DEFAULT_READ_MODEL_YIELD_DEADLINE_MS = 50;\n\nexport const defaultReadModelIndexingConfig: ReadModelIndexingConfig = {\n commitChunkSize: DEFAULT_COMMIT_CHUNK_SIZE,\n yieldDeadlineMs: DEFAULT_READ_MODEL_YIELD_DEADLINE_MS,\n};\n\n/** For read models whose callers can observe where a batch was split. */\nexport const unchunkedReadModelIndexingConfig: ReadModelIndexingConfig = {\n commitChunkSize: Number.MAX_SAFE_INTEGER,\n yieldDeadlineMs: DEFAULT_READ_MODEL_YIELD_DEADLINE_MS,\n};\n\n/**\n * Keeps the chunk size at one operation or more: a chunk of zero or less never\n * advances the indexing loop, so the pass would spin without ever resolving.\n */\nfunction normalizeIndexingConfig(\n config: ReadModelIndexingConfig,\n): ReadModelIndexingConfig {\n if (Number.isNaN(config.commitChunkSize)) {\n return { ...config, commitChunkSize: DEFAULT_COMMIT_CHUNK_SIZE };\n }\n\n return {\n ...config,\n commitChunkSize: Math.max(\n 1,\n Math.min(Math.floor(config.commitChunkSize), Number.MAX_SAFE_INTEGER),\n ),\n };\n}\n\nexport type PurgeFence =\n /** Commits in a purge-locked trx; see commitsInFenceTransaction. */\n | \"locked\"\n /** Drops tombstoned ids only, for rows that live on another database handle. */\n | \"skip\"\n /** No fence: ProcessorManager, and commits that open their own trx on this.db. */\n | \"none\";\n\nexport type BaseReadModelConfig = {\n readModelId: string;\n /** Rebuilds resultingState for boot replay and sweeps. */\n rebuildStateOnInit: boolean;\n /** Defaults to {@link defaultReadModelIndexingConfig}. */\n indexing?: ReadModelIndexingConfig;\n /** Where a first registration starts; defaults to \"beginning\". */\n startFrom?: \"beginning\" | \"head\";\n /** Re-applies the rest of a late operation's stream; defaults to true. */\n replayStreamSuffix?: boolean;\n /** Defaults to \"locked\"; see {@link PurgeFence} for the opt-outs. */\n purgeFence?: PurgeFence;\n};\n\ntype StreamGroup = {\n documentId: string;\n scope: string;\n branch: string;\n lowest: number;\n late: OperationWithContext[];\n};\n\nfunction ordinalOf(item: OperationWithContext): number {\n return item.context.ordinal;\n}\n\nfunction isTracked(ordinal: number): boolean {\n return Number.isFinite(ordinal) && ordinal > 0;\n}\n\nfunction streamKeyOf(stream: {\n documentId: string;\n scope: string;\n branch: string;\n}): string {\n return `${stream.documentId}\\u0000${stream.scope}\\u0000${stream.branch}`;\n}\n\nfunction groupByStream(items: OperationWithContext[]): StreamGroup[] {\n const groups = new Map<string, StreamGroup>();\n for (const item of items) {\n const { documentId, scope, branch } = item.context;\n const key = streamKeyOf(item.context);\n let group = groups.get(key);\n if (group === undefined) {\n group = { documentId, scope, branch, lowest: ordinalOf(item), late: [] };\n groups.set(key, group);\n }\n group.lowest = Math.min(group.lowest, ordinalOf(item));\n group.late.push(item);\n }\n return [...groups.values()].sort((a, b) => a.lowest - b.lowest);\n}\n\nfunction mergeByOrdinal(\n ...lists: OperationWithContext[][]\n): OperationWithContext[] {\n const byOrdinal = new Map<number, OperationWithContext>();\n for (const list of lists) {\n for (const item of list) byOrdinal.set(ordinalOf(item), item);\n }\n return [...byOrdinal.values()].sort((a, b) => ordinalOf(a) - ordinalOf(b));\n}\n\n/** The ids whose purge an operation's rows must not outlive. */\nfunction purgeFenceIds(items: OperationWithContext[]): string[] {\n const ids = new Set<string>();\n for (const { operation, context } of items) {\n ids.add(context.documentId);\n if (operation.action.type !== \"ADD_RELATIONSHIP\") continue;\n const input = operation.action.input as {\n sourceId?: unknown;\n targetId?: unknown;\n };\n if (typeof input.sourceId === \"string\") ids.add(input.sourceId);\n if (typeof input.targetId === \"string\") ids.add(input.targetId);\n }\n return [...ids].sort();\n}\n\nfunction dropPurged(\n items: OperationWithContext[],\n purged: Set<string>,\n): OperationWithContext[] {\n if (purged.size === 0) return items;\n return items.filter(\n (item) =>\n isPurgeMarker(item.operation) || !purged.has(item.context.documentId),\n );\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** A read model whose cursor only sweeps and boot replay advance. */\nexport class BaseReadModel implements IReadModel, ICatchUpConsumer {\n readonly name: string;\n\n private readonly indexing: ReadModelIndexingConfig;\n private readonly catchUpLogger: ILogger;\n private cursor: ContiguousCursor;\n private persisted = 0;\n private watermark: ISettledWatermark | undefined;\n private maxTrackedAboveCursor = defaultCatchUpConfig.maxTrackedAboveCursor;\n private loggedFailure: number | undefined;\n private failedItem: OperationWithContext | undefined;\n private initialized = false;\n private readonly liveInFlight = new Map<string, Set<number>>();\n private readonly sweptListeners = new Set<\n (coordinates: ConsistencyCoordinate[]) => void\n >();\n\n constructor(\n protected db: Kysely<DocumentViewDatabase>,\n protected operationIndex: IOperationIndex,\n protected writeCache: IWriteCache,\n protected consistencyTracker: IConsistencyTracker,\n protected config: BaseReadModelConfig,\n ) {\n this.name = config.readModelId;\n this.catchUpLogger = childLogger([\n \"reactor\",\n \"read-model\",\n config.readModelId,\n ]);\n this.indexing = normalizeIndexingConfig(\n config.indexing ?? defaultReadModelIndexingConfig,\n );\n this.cursor = new ContiguousCursor(0, this.maxTrackedAboveCursor);\n // A locked commit through this.db deadlocks single-connection PGlite.\n if (\n (config.purgeFence ?? \"locked\") === \"locked\" &&\n this.commitOperations !== BaseReadModel.prototype.commitOperations &&\n !(this.constructor as typeof BaseReadModel).commitsInFenceTransaction\n ) {\n throw new Error(\n `Read model ${config.readModelId}: purgeFence \"locked\" commits in a ` +\n \"transaction its commitOperations must write through. Write \" +\n \"through the trx argument and set static commitsInFenceTransaction \" +\n 'to true, or set purgeFence \"skip\" (rows on another handle) or ' +\n '\"none\" (no rows here, or its own transaction).',\n );\n }\n }\n\n /** Set by a subclass whose commitOperations writes through its trx argument. */\n static readonly commitsInFenceTransaction: boolean = false;\n\n get consumerId(): string {\n return this.config.readModelId;\n }\n\n get appliedThrough(): number {\n return this.cursor.appliedThrough;\n }\n\n get trackedAbove(): number {\n return this.cursor.trackedAbove;\n }\n\n /** Shares a thread's watermark; otherwise boot probes through this db. */\n attachCatchUp(\n watermark: ISettledWatermark,\n maxTrackedAboveCursor: number,\n ): void {\n this.watermark = watermark;\n this.maxTrackedAboveCursor = maxTrackedAboveCursor;\n this.cursor.setLimit(maxTrackedAboveCursor);\n }\n\n /** Notified with the coordinates each sweep applied. */\n onSwept(\n listener: (coordinates: ConsistencyCoordinate[]) => void,\n ): Unsubscribe {\n this.sweptListeners.add(listener);\n return () => {\n this.sweptListeners.delete(listener);\n };\n }\n\n /** A chunk that throws ends the replay; sweeps continue from below it. */\n async init(): Promise<void> {\n // A repeat init replays from where this process is, keeping what it applied.\n if (this.initialized) {\n await this.replayFromCursor();\n return;\n }\n let stored = await this.loadState();\n\n if (stored === undefined) {\n if (this.config.startFrom === \"head\") {\n const watermark = this.settledWatermark();\n const settled = await watermark.refresh();\n // The head, not settledThrough: any open write elsewhere holds that at 0.\n const head = Math.max(settled, watermark.status().head);\n await this.initializeState(head);\n this.resetCursor(head);\n this.initialized = true;\n return;\n }\n await this.initializeState(0);\n stored = 0;\n }\n\n this.resetCursor(stored);\n this.initialized = true;\n await this.replayFromCursor();\n }\n\n /** The live path: never moves the cursor. */\n indexOperations(items: OperationWithContext[]): Promise<void> {\n if (items.length === 0) return Promise.resolve();\n return this.reserveOperations(items).apply();\n }\n\n /** Holds a queued batch as live, so a sweep neither takes nor passes it. */\n reserveOperations(items: OperationWithContext[]): IReadModelReservation {\n const cursor = this.cursor;\n const owned = this.claimLive(items);\n const unmark = this.markLive(owned);\n let done = false;\n return {\n apply: () => {\n if (done) return Promise.resolve();\n done = true;\n // A cursor reset since the claim dropped it.\n if (cursor !== this.cursor) {\n unmark();\n return this.indexOperations(items);\n }\n if (owned.length === 0) {\n unmark();\n return Promise.resolve();\n }\n return this.applyChunked(owned, unmark);\n },\n release: () => {\n if (done) return;\n done = true;\n cursor.settle(owned.map(ordinalOf), false);\n unmark();\n },\n };\n }\n\n async sweep(\n settledThrough: number,\n present: readonly number[],\n signal?: AbortSignal,\n ): Promise<SweepResult> {\n const startedAt = performance.now();\n const from = this.cursor.appliedThrough;\n const range = present.filter(\n (ordinal) => ordinal > from && ordinal <= settledThrough,\n );\n const mine = this.cursor.claim(this.cursor.missing(range));\n\n let replayed = 0;\n let reapplied = 0;\n let blockedAt: SweepBlockedAt | undefined;\n\n if (mine.size > 0) {\n let late: OperationWithContext[];\n try {\n late = await this.operationIndex.getByOrdinals([...mine], signal);\n } catch (error) {\n this.cursor.settle(mine, false);\n throw error;\n }\n\n const found = new Set(late.map(ordinalOf));\n this.cursor.settle(\n [...mine].filter((ordinal) => !found.has(ordinal)),\n true,\n );\n\n for (const group of groupByStream(late)) {\n const outcome = await this.sweepStream(group, signal);\n replayed += outcome.replayed;\n reapplied += outcome.reapplied;\n blockedAt ??= outcome.blockedAt;\n }\n\n if (replayed > 0) {\n this.catchUpLogger.warn(\n \"@consumer applied @n operations its live path never received: ordinals @first..@last\",\n this.consumerId,\n replayed,\n Math.min(...found),\n Math.max(...found),\n );\n }\n }\n\n const to = this.cursor.target(settledThrough, range);\n if (to > from) {\n await this.moveCursor(to);\n }\n this.cursor.enforceLimit();\n\n return {\n consumerId: this.consumerId,\n from,\n to: this.cursor.appliedThrough,\n durationMs: performance.now() - startedAt,\n replayed,\n reapplied,\n ...(blockedAt !== undefined ? { blockedAt } : {}),\n };\n }\n\n /**\n * Waits for the read model to reach the specified consistency level.\n */\n async waitForConsistency(\n token: ConsistencyToken,\n timeoutMs?: number,\n signal?: AbortSignal,\n ): Promise<void> {\n if (token.coordinates.length === 0) {\n return;\n }\n await this.consistencyTracker.waitFor(token.coordinates, timeoutMs, signal);\n }\n\n /** The cursor, for subclasses: every present ordinal at or below it is applied. */\n protected get lastOrdinal(): number {\n return this.cursor.appliedThrough;\n }\n\n /** Called after the cursor advances. */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected onCursorAdvanced(appliedThrough: number): void {}\n\n /** Writes through `trx` when given: the purge fence's transaction. */\n protected async commitOperations(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n items: OperationWithContext[],\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n trx?: Transaction<DocumentViewDatabase>,\n ): Promise<void> {}\n\n /** The handle document_purges is read through; `db` may be the fence trx. */\n protected purgeLookup(db: Kysely<any>): Kysely<any> {\n return db;\n }\n\n /** False when the batch writes no rows, so the fence opens no transaction. */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected writesRows(items: OperationWithContext[]): boolean {\n return true;\n }\n\n /** Every delivery commits through here. */\n protected async commitFenced(items: OperationWithContext[]): Promise<void> {\n const fence = this.config.purgeFence ?? \"locked\";\n if (fence === \"none\") {\n await this.commitOperations(items);\n return;\n }\n if (items.length === 0 || !this.writesRows(items)) {\n if (items.length > 0) await this.commitOperations(items);\n return;\n }\n\n const ids = purgeFenceIds(items);\n if (fence === \"skip\") {\n const live = dropPurged(\n items,\n await findPurged(this.purgeLookup(this.db), ids),\n );\n if (live.length > 0) await this.commitOperations(live);\n return;\n }\n\n await this.db.transaction().execute(async (trx) => {\n await acquirePurgeLocks(trx, ids, \"shared\");\n const live = dropPurged(\n items,\n await findPurged(this.purgeLookup(trx), ids),\n );\n if (live.length > 0) await this.commitOperations(live, trx);\n });\n }\n\n /** Rebuilds resultingState as the executor writes it: scopes plus header. */\n protected async rebuildStateForOperations(\n operations: OperationWithContext[],\n ): Promise<OperationWithContext[]> {\n const result: OperationWithContext[] = [];\n\n for (const op of operations) {\n const { documentId, scope, branch } = op.context;\n const targetRevision = op.operation.index;\n\n const document = await this.writeCache.getState(\n documentId,\n scope,\n branch,\n targetRevision,\n );\n\n result.push({\n operation: op.operation,\n context: {\n ...op.context,\n resultingState: JSON.stringify({\n ...document.state,\n header: document.header,\n }),\n },\n });\n }\n\n return result;\n }\n\n /**\n * Loads the last processed ordinal from the ViewState table.\n * Returns undefined if no state exists for this read model.\n */\n protected async loadState(): Promise<number | undefined> {\n const row = await this.db\n .selectFrom(\"ViewState\")\n .select(\"lastOrdinal\")\n .where(\"readModelId\", \"=\", this.config.readModelId)\n .executeTakeFirst();\n\n return row?.lastOrdinal;\n }\n\n /**\n * Initializes the ViewState row for this read model.\n */\n protected async initializeState(lastOrdinal = 0): Promise<void> {\n await this.db\n .insertInto(\"ViewState\")\n .values({\n readModelId: this.config.readModelId,\n lastOrdinal,\n })\n .onConflict((oc) => oc.column(\"readModelId\").doNothing())\n .execute();\n }\n\n /**\n * Updates the consistency tracker with the processed operations.\n */\n protected updateConsistencyTracker(items: OperationWithContext[]): void {\n this.consistencyTracker.update(this.coordinatesOf(items));\n }\n\n private coordinatesOf(\n items: OperationWithContext[],\n ): ConsistencyCoordinate[] {\n const coordinates: ConsistencyCoordinate[] = [];\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n coordinates.push({\n documentId: item.context.documentId,\n scope: item.context.scope,\n branch: item.context.branch,\n operationIndex: item.operation.index,\n });\n }\n return coordinates;\n }\n\n private settledWatermark(): ISettledWatermark {\n this.watermark ??= new SettledWatermark(\n createKyselyWatermarkProbe(this.db as unknown as Kysely<StorageDatabase>),\n this.catchUpLogger,\n );\n return this.watermark;\n }\n\n private resetCursor(appliedThrough: number): void {\n this.cursor = new ContiguousCursor(\n appliedThrough,\n this.maxTrackedAboveCursor,\n );\n this.persisted = appliedThrough;\n }\n\n /** Items this pass must apply; untracked ordinals always apply. */\n private claimLive(items: OperationWithContext[]): OperationWithContext[] {\n const mine = this.cursor.claim(items.map(ordinalOf));\n return items.filter((item) => {\n const ordinal = ordinalOf(item);\n return !isTracked(ordinal) || mine.has(ordinal);\n });\n }\n\n /** Marks items in flight on their streams; returns the release. */\n private markLive(items: OperationWithContext[]): () => void {\n const keys = new Set<string>();\n for (const item of items) {\n if (!isTracked(ordinalOf(item))) continue;\n const key = streamKeyOf(item.context);\n let ordinals = this.liveInFlight.get(key);\n if (ordinals === undefined) {\n ordinals = new Set();\n this.liveInFlight.set(key, ordinals);\n }\n ordinals.add(ordinalOf(item));\n keys.add(key);\n }\n return () => {\n for (const item of items) {\n this.liveInFlight\n .get(streamKeyOf(item.context))\n ?.delete(ordinalOf(item));\n }\n for (const key of keys) {\n if (this.liveInFlight.get(key)?.size === 0)\n this.liveInFlight.delete(key);\n }\n };\n }\n\n /** True while a live pass applies an earlier operation of the stream. */\n private liveBelow(group: StreamGroup): boolean {\n const ordinals = this.liveInFlight.get(streamKeyOf(group));\n if (ordinals === undefined) return false;\n for (const ordinal of ordinals) {\n if (ordinal < group.lowest) return true;\n }\n return false;\n }\n\n /** Commits in chunks, yielding with no transaction open. */\n private async applyChunked(\n items: OperationWithContext[],\n release = this.markLive(items),\n ): Promise<void> {\n try {\n const { commitChunkSize, yieldDeadlineMs } = this.indexing;\n let lastYield = performance.now();\n let committed = 0;\n\n for (let start = 0; start < items.length; start += commitChunkSize) {\n if (start > 0 && performance.now() - lastYield > yieldDeadlineMs) {\n await yieldToMain();\n lastYield = performance.now();\n }\n\n const chunk = items.slice(start, start + commitChunkSize);\n\n try {\n await this.commitFenced(chunk);\n } catch (error) {\n this.failedItem = chunk[0];\n const prefix = items.slice(0, committed);\n this.cursor.settle(prefix.map(ordinalOf), true);\n this.cursor.settle(items.slice(committed).map(ordinalOf), false);\n if (prefix.length > 0) this.updateConsistencyTracker(prefix);\n throw error;\n }\n\n committed += chunk.length;\n }\n\n this.cursor.settle(items.map(ordinalOf), true);\n this.cursor.enforceLimit();\n this.updateConsistencyTracker(items);\n } finally {\n release();\n }\n }\n\n private async replayFromCursor(): Promise<void> {\n const settledAtBoot = await this.settledAtBoot();\n let page = await this.operationIndex.getSinceOrdinal(\n this.cursor.appliedThrough,\n );\n\n while (page.results.length > 0) {\n const ordinals = page.results.map(ordinalOf);\n const failed = await this.replayPage(page.results);\n\n const pageMax = Math.max(...ordinals);\n const to = this.cursor.target(Math.min(settledAtBoot, pageMax), ordinals);\n if (to > this.cursor.appliedThrough) {\n await this.moveCursor(to);\n }\n\n if (failed || !page.next) break;\n page = await page.next();\n }\n }\n\n /** Without a probe, boot replay applies but leaves the cursor to sweeps. */\n private async settledAtBoot(): Promise<number> {\n try {\n return await this.settledWatermark().refresh();\n } catch (error) {\n this.catchUpLogger.warn(\n \"@consumer could not probe the settled watermark at boot; the cursor waits for a sweep: @error\",\n this.consumerId,\n error,\n );\n return this.cursor.appliedThrough;\n }\n }\n\n /** Returns true when a chunk failed, which ends the replay. */\n private async replayPage(results: OperationWithContext[]): Promise<boolean> {\n const owned = this.claimLive(results);\n if (owned.length === 0) return false;\n const release = this.markLive(owned);\n try {\n return await this.replayOwned(owned);\n } finally {\n release();\n }\n }\n\n private async replayOwned(owned: OperationWithContext[]): Promise<boolean> {\n let rebuilt: { items: OperationWithContext[]; absent: number[] };\n try {\n rebuilt = await this.rebuildIfConfigured(owned);\n } catch (error) {\n this.cursor.settle(owned.map(ordinalOf), false);\n this.block(owned[0]!, error);\n return true;\n }\n this.cursor.settle(rebuilt.absent, true);\n if (rebuilt.items.length === 0) return false;\n\n try {\n await this.applyChunked(rebuilt.items);\n } catch (error) {\n this.block(this.failedItem ?? rebuilt.items[0]!, error);\n return true;\n }\n return false;\n }\n\n private async sweepStream(\n group: StreamGroup,\n signal: AbortSignal | undefined,\n ): Promise<{\n replayed: number;\n reapplied: number;\n blockedAt?: SweepBlockedAt;\n }> {\n const owned = group.late.map(ordinalOf);\n if (this.liveBelow(group)) {\n this.cursor.settle(owned, false);\n return { replayed: 0, reapplied: 0 };\n }\n const ownedSet = new Set(owned);\n\n let items = group.late;\n if (this.config.replayStreamSuffix ?? true) {\n let suffix: OperationWithContext[];\n try {\n suffix = await this.operationIndex.getStreamAfter(\n group,\n group.lowest,\n signal,\n );\n } catch (error) {\n this.cursor.settle(owned, false);\n return {\n replayed: 0,\n reapplied: 0,\n blockedAt: this.block(group.late[0]!, error),\n };\n }\n items = mergeByOrdinal(group.late, suffix);\n }\n\n let rebuilt: { items: OperationWithContext[]; absent: number[] };\n try {\n rebuilt = await this.rebuildIfConfigured(items);\n } catch (error) {\n this.cursor.settle(owned, false);\n return {\n replayed: 0,\n reapplied: 0,\n blockedAt: this.block(items[0]!, error),\n };\n }\n\n try {\n await this.commitFenced(rebuilt.items);\n } catch (error) {\n this.cursor.settle(owned, false);\n return {\n replayed: 0,\n reapplied: 0,\n blockedAt: this.block(rebuilt.items[0] ?? items[0]!, error),\n };\n }\n\n this.cursor.settle(owned, true);\n this.updateConsistencyTracker(rebuilt.items);\n this.notifySwept(rebuilt.items);\n\n let replayed = 0;\n for (const item of rebuilt.items) {\n if (ownedSet.has(ordinalOf(item))) replayed++;\n }\n return { replayed, reapplied: rebuilt.items.length - replayed };\n }\n\n /** A document gone from the write cache, or purged, is absent. */\n private async rebuildIfConfigured(\n items: OperationWithContext[],\n ): Promise<{ items: OperationWithContext[]; absent: number[] }> {\n if (!this.config.rebuildStateOnInit) {\n return { items, absent: [] };\n }\n\n const rebuilt: OperationWithContext[] = [];\n const absent: number[] = [];\n for (const item of items) {\n // The marker has no state to rebuild; its stream has no CREATE_DOCUMENT.\n if (isPurgeMarker(item.operation)) {\n rebuilt.push(item);\n continue;\n }\n let result: OperationWithContext[];\n try {\n result = await this.rebuildStateForOperations([item]);\n } catch (error) {\n if (\n !DocumentNotFoundError.isError(error) &&\n !(await this.isPurged(item.context.documentId))\n ) {\n throw error;\n }\n this.catchUpLogger.warn(\n \"@consumer dropped ordinal @ordinal: document @documentId is gone\",\n this.consumerId,\n ordinalOf(item),\n item.context.documentId,\n );\n absent.push(ordinalOf(item));\n continue;\n }\n rebuilt.push(...result);\n }\n return { items: rebuilt, absent };\n }\n\n /** A failed lookup is no answer: the caller's own error stands. */\n private async isPurged(documentId: string): Promise<boolean> {\n try {\n return (await findPurged(this.purgeLookup(this.db), [documentId])).has(\n documentId,\n );\n } catch {\n return false;\n }\n }\n\n private block(item: OperationWithContext, error: unknown): SweepBlockedAt {\n const blockedAt: SweepBlockedAt = {\n ordinal: ordinalOf(item),\n documentId: item.context.documentId,\n scope: item.context.scope,\n branch: item.context.branch,\n type: item.operation.action.type,\n error: errorMessage(error),\n };\n if (this.loggedFailure !== blockedAt.ordinal) {\n this.loggedFailure = blockedAt.ordinal;\n this.catchUpLogger.error(\n \"@consumer cursor held at @applied: ordinal @ordinal (@documentId/@scope/@branch, @type) failed: @error\",\n this.consumerId,\n this.cursor.appliedThrough,\n blockedAt.ordinal,\n blockedAt.documentId,\n blockedAt.scope,\n blockedAt.branch,\n blockedAt.type,\n blockedAt.error,\n );\n }\n return blockedAt;\n }\n\n private notifySwept(items: OperationWithContext[]): void {\n if (this.sweptListeners.size === 0 || items.length === 0) return;\n const coordinates = this.coordinatesOf(items);\n for (const listener of this.sweptListeners) {\n listener(coordinates);\n }\n }\n\n /** Compare-and-set against the value this process last wrote. */\n private async moveCursor(to: number): Promise<void> {\n if (to <= this.persisted) {\n this.advanceCursor(to);\n return;\n }\n\n const expected = this.persisted;\n const result = await this.db\n .updateTable(\"ViewState\")\n .set({ lastOrdinal: to, lastOperationTimestamp: new Date() })\n .where(\"readModelId\", \"=\", this.config.readModelId)\n .where(\"lastOrdinal\", \"=\", expected)\n .executeTakeFirst();\n\n if (Number(result.numUpdatedRows) > 0) {\n this.persisted = to;\n this.advanceCursor(to);\n return;\n }\n\n const stored = await this.loadState();\n if (stored === undefined) {\n await this.initializeState(0);\n this.lowered(0);\n return;\n }\n if (stored < this.cursor.appliedThrough) {\n this.lowered(stored);\n return;\n }\n this.persisted = stored;\n this.advanceCursor(Math.min(to, stored));\n }\n\n private advanceCursor(to: number): void {\n const before = this.cursor.appliedThrough;\n this.cursor.advance(to);\n if (this.cursor.appliedThrough > before) {\n this.onCursorAdvanced(this.cursor.appliedThrough);\n }\n }\n\n private lowered(to: number): void {\n this.catchUpLogger.info(\n \"@consumer cursor lowered externally from @old to @new; replaying\",\n this.consumerId,\n this.cursor.appliedThrough,\n to,\n );\n this.resetCursor(to);\n }\n}\n","import type { OperationWithContext } from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport type { IEventBus } from \"../events/interfaces.js\";\nimport {\n ReactorEventTypes,\n type JobReadReadyEvent,\n type JobWriteReadyEvent,\n type ReadModelBatchCompletedEvent,\n type ReadModelIndexedEvent,\n type ReadModelIndexingStage,\n type Unsubscribe,\n} from \"../events/types.js\";\nimport type {\n ILiveReadModelCoordinator,\n IReadModel,\n IReadModelReservation,\n ReadModelRegistrationStage,\n} from \"./interfaces.js\";\n\nexport type BatchReservations = Map<IReadModel, IReadModelReservation>;\n\n/** Claims a batch for every model that supports it, as the batch queues. */\nexport function reserveBatch(\n readModels: readonly IReadModel[],\n operations: OperationWithContext[],\n logger: ILogger,\n): BatchReservations {\n const reservations: BatchReservations = new Map();\n for (const readModel of readModels) {\n if (readModel.reserveOperations === undefined) continue;\n try {\n reservations.set(readModel, readModel.reserveOperations(operations));\n } catch (error) {\n logger.error(\n \"Read model @name could not reserve a batch: @Error\",\n readModel.name,\n error,\n );\n }\n }\n return reservations;\n}\n\n/** Applies the model's reservation, or indexes a model registered since. */\nexport function indexReserved(\n readModel: IReadModel,\n operations: OperationWithContext[],\n reservations: BatchReservations,\n): Promise<void> {\n const reservation = reservations.get(readModel);\n return reservation\n ? reservation.apply()\n : readModel.indexOperations(operations);\n}\n\n/** Frees every claim a run did not apply, so a sweep can take it. */\nexport function releaseBatch(reservations: BatchReservations): void {\n for (const reservation of reservations.values()) reservation.release();\n}\n\n/**\n * Coordinates read model synchronization by listening to operation write events\n * and updating all registered read models on per-`documentId:scope:branch`\n * serial chains. Cross-key projection runs in parallel; same-key projection is\n * serialized so the executor can return to dispatch without holding ordering\n * implicitly.\n */\nexport class ReadModelCoordinator implements ILiveReadModelCoordinator {\n private unsubscribe?: Unsubscribe;\n private isRunning = false;\n private readonly chains = new Map<string, Promise<void>>();\n private readonly logger: ILogger;\n\n readonly readModels: IReadModel[];\n\n constructor(\n private eventBus: IEventBus,\n public readonly preReady: IReadModel[],\n public readonly postReady: IReadModel[],\n ) {\n this.readModels = [...preReady, ...postReady];\n this.logger = childLogger([\"reactor\", \"read-model-coordinator\"]);\n }\n\n start(): void {\n if (this.isRunning) {\n return;\n }\n\n this.unsubscribe = this.eventBus.subscribe(\n ReactorEventTypes.JOB_WRITE_READY,\n (type, event: JobWriteReadyEvent) => {\n return this.handleWriteReady(event);\n },\n );\n\n this.isRunning = true;\n }\n\n stop(): void {\n if (!this.isRunning) {\n return;\n }\n\n if (this.unsubscribe) {\n this.unsubscribe();\n this.unsubscribe = undefined;\n }\n\n this.isRunning = false;\n }\n\n /**\n * Resolves when every per-queueKey projection chain has flushed. Intended\n * for test fixtures and explicit shutdown; production callers use\n * consistency tokens instead.\n */\n async drain(): Promise<void> {\n while (this.chains.size > 0) {\n const pending = Array.from(this.chains.values());\n await Promise.allSettled(pending);\n }\n }\n\n getChainDepth(): number {\n return this.chains.size;\n }\n\n indexedReadModels(): readonly IReadModel[] {\n return [...this.preReady, ...this.postReady];\n }\n\n addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void {\n if (this.readModels.some(({ name }) => name === readModel.name)) {\n throw new Error(`Read model \"${readModel.name}\" is already registered`);\n }\n\n if (stage === \"pre_ready\") {\n this.preReady.push(readModel);\n } else {\n this.postReady.push(readModel);\n }\n this.readModels.push(readModel);\n }\n\n private handleWriteReady(event: JobWriteReadyEvent): void {\n if (event.operations.length === 0) {\n void this.emitEmptyReadReady(event);\n return;\n }\n\n const enqueuedAt = performance.now();\n const key = this.queueKeyFor(event);\n const reservations = reserveBatch(\n this.readModels,\n event.operations,\n this.logger,\n );\n const run = () => this.runChain(event, enqueuedAt, reservations);\n const previous = this.chains.get(key) ?? Promise.resolve();\n const current = previous.then(run, run);\n\n this.chains.set(key, current);\n void current.finally(() => {\n if (this.chains.get(key) === current) {\n this.chains.delete(key);\n }\n });\n }\n\n private async emitEmptyReadReady(event: JobWriteReadyEvent): Promise<void> {\n const readyEvent: JobReadReadyEvent = {\n jobId: event.jobId,\n operations: event.operations,\n };\n try {\n await this.eventBus.emit(ReactorEventTypes.JOB_READ_READY, readyEvent);\n } catch (error) {\n this.logger.error(\n \"JOB_READ_READY emit failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n this.emitBatchCompleted({\n jobId: event.jobId,\n batchSize: 0,\n chainWaitDurationMs: 0,\n preReadyDurationMs: 0,\n emitDurationMs: 0,\n postReadyDurationMs: 0,\n });\n }\n\n private async runChain(\n event: JobWriteReadyEvent,\n enqueuedAt: number,\n reservations: BatchReservations,\n ): Promise<void> {\n try {\n await this.runBatch(event, enqueuedAt, reservations);\n } finally {\n releaseBatch(reservations);\n }\n }\n\n private async runBatch(\n event: JobWriteReadyEvent,\n enqueuedAt: number,\n reservations: BatchReservations,\n ): Promise<void> {\n const chainStartedAt = performance.now();\n const chainWaitDurationMs = chainStartedAt - enqueuedAt;\n\n const preReadyStart = performance.now();\n try {\n await Promise.all(\n this.preReady.map((readModel) =>\n this.indexWithTiming(readModel, \"pre_ready\", event, reservations),\n ),\n );\n } catch (error) {\n this.logger.error(\n \"Pre-ready read model indexing failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n const preReadyDurationMs = performance.now() - preReadyStart;\n\n const readyEvent: JobReadReadyEvent = {\n jobId: event.jobId,\n operations: event.operations,\n };\n const emitStart = performance.now();\n try {\n await this.eventBus.emit(ReactorEventTypes.JOB_READ_READY, readyEvent);\n } catch (error) {\n this.logger.error(\n \"JOB_READ_READY emit failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n const emitDurationMs = performance.now() - emitStart;\n\n const postReadyStart = performance.now();\n try {\n await Promise.all(\n this.postReady.map((readModel) =>\n this.indexWithTiming(readModel, \"post_ready\", event, reservations),\n ),\n );\n } catch (error) {\n this.logger.error(\n \"Post-ready read model indexing failed for job @jobId: @Error\",\n { jobId: event.jobId },\n error,\n );\n }\n const postReadyDurationMs = performance.now() - postReadyStart;\n\n this.emitBatchCompleted({\n jobId: event.jobId,\n batchSize: event.operations.length,\n chainWaitDurationMs,\n preReadyDurationMs,\n emitDurationMs,\n postReadyDurationMs,\n });\n }\n\n private async indexWithTiming(\n readModel: IReadModel,\n stage: ReadModelIndexingStage,\n event: JobWriteReadyEvent,\n reservations: BatchReservations,\n ): Promise<void> {\n const start = performance.now();\n let success = false;\n try {\n await indexReserved(readModel, event.operations, reservations);\n success = true;\n } finally {\n this.emitReadModelIndexed({\n jobId: event.jobId,\n readModelName: readModel.name,\n stage,\n durationMs: performance.now() - start,\n operationCount: event.operations.length,\n success,\n });\n }\n }\n\n private emitReadModelIndexed(payload: ReadModelIndexedEvent): void {\n void this.eventBus\n .emit(ReactorEventTypes.READMODEL_INDEXED, payload)\n .catch((err: unknown) =>\n this.logger.error(\n \"READMODEL_INDEXED emit failed for job @jobId: @Error\",\n { jobId: payload.jobId },\n err,\n ),\n );\n }\n\n private emitBatchCompleted(payload: ReadModelBatchCompletedEvent): void {\n void this.eventBus\n .emit(ReactorEventTypes.READMODEL_BATCH_COMPLETED, payload)\n .catch((err: unknown) =>\n this.logger.error(\n \"READMODEL_BATCH_COMPLETED emit failed for job @jobId: @Error\",\n { jobId: payload.jobId },\n err,\n ),\n );\n }\n\n private queueKeyFor(event: JobWriteReadyEvent): string {\n const ctx = event.operations[0]!.context;\n return `${ctx.documentId}:${ctx.scope}:${ctx.branch}`;\n }\n}\n","import type { IDocumentIndexer, IDocumentView } from \"../storage/interfaces.js\";\n\n/** `getReadModel` name of the document view; see {@link ReactorReadModels}. */\nexport const DOCUMENT_VIEW_READ_MODEL = \"document-view\";\n/** `getReadModel` name of the document indexer; see {@link ReactorReadModels}. */\nexport const DOCUMENT_INDEXER_READ_MODEL = \"document-indexer\";\n\n/**\n * Read models the reactor registers on every host, keyed by the name passed to\n * `IProcessorHostModule.getReadModel`. Each entry says what the model holds\n * and when a processor should reach for it instead of the reactor client.\n */\nexport interface ReactorReadModels {\n /**\n * Materialized document snapshots — header plus per-scope state — kept\n * current as operations are indexed, so reads never replay operations.\n *\n * Reach for it to read a document's current state from inside a\n * processor: `get` / `getMany` by id, `getByIdOrSlug`, `findByType`,\n * `exists`, and `resolveSlug` / `resolveIdOrSlug`. Every query takes an\n * optional `ConsistencyToken` (from a job result) for read-after-write.\n * Unlike `client.get`, results are the raw snapshot — scopes are not\n * filtered to what the caller may read.\n */\n [DOCUMENT_VIEW_READ_MODEL]: IDocumentView;\n\n /**\n * Directed graph of document relationships, built from ADD_RELATIONSHIP /\n * REMOVE_RELATIONSHIP operations. Edges carry a `relationshipType`;\n * parent/child links (drive → document, folder → file) use `\"child\"`.\n *\n * Reach for it to navigate structure rather than content: `getOutgoing` /\n * `getIncoming` neighbours, `hasRelationship`, `findPath`, and\n * `findAncestors` (e.g. which drive(s) contain a document). Snapshots of\n * the documents themselves come from the document view.\n */\n [DOCUMENT_INDEXER_READ_MODEL]: IDocumentIndexer;\n}\n","import type {\n OperationWithContext,\n PHAuthState,\n PHDocument,\n PHDocumentHeader,\n} from \"@powerhousedao/shared/document-model\";\nimport {\n createAuthState,\n isDenied,\n isPurgeMarker,\n} from \"@powerhousedao/shared/document-model\";\nimport { childLogger, type ILogger } from \"document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { IOperationIndex } from \"../cache/operation-index-types.js\";\nimport type { IWriteCache } from \"../cache/write/interfaces.js\";\nimport type { IConsistencyTracker } from \"../shared/consistency-tracker.js\";\nimport { DocumentNotFoundError } from \"../shared/errors.js\";\nimport { DOCUMENT_VIEW_READ_MODEL } from \"./names.js\";\nimport type {\n ConsistencyToken,\n PagedResults,\n PagingOptions,\n} from \"../shared/types.js\";\nimport {\n DocumentExistence,\n type DocumentRevisions,\n type IDocumentView,\n type IOperationStore,\n type ViewFilter,\n} from \"../storage/interfaces.js\";\nimport type { Database as StorageDatabase } from \"../storage/kysely/types.js\";\nimport {\n BaseReadModel,\n defaultReadModelIndexingConfig,\n type ReadModelIndexingConfig,\n} from \"./base-read-model.js\";\nimport type {\n DocumentViewDatabase,\n InsertableDocumentSnapshot,\n} from \"./types.js\";\n\ntype Database = StorageDatabase & DocumentViewDatabase;\n\n/**\n * What a single-document read of a deleted document returns. A listing omits a\n * deleted document under either value.\n */\nexport enum DeletedDocumentRead {\n /**\n * The document reads as missing: `get` throws and `resolveIdOrSlug` does not\n * match its id.\n */\n NotFound = \"NotFound\",\n /**\n * The document's state as of the deletion, with `state.document.isDeleted`\n * telling the caller what it holds. Only meaningful with `documentDecisions`,\n * which is what makes deletion positional.\n */\n StateAtDeletion = \"StateAtDeletion\",\n}\n\nexport class KyselyDocumentView extends BaseReadModel implements IDocumentView {\n static override readonly commitsInFenceTransaction = true;\n\n private _db: Kysely<Database>;\n private readonly logger: ILogger = childLogger([\n \"reactor\",\n \"read-model\",\n DOCUMENT_VIEW_READ_MODEL,\n ]);\n\n constructor(\n db: Kysely<Database>,\n private operationStore: IOperationStore,\n operationIndex: IOperationIndex,\n writeCache: IWriteCache,\n consistencyTracker: IConsistencyTracker,\n private readonly deletedDocumentRead: DeletedDocumentRead,\n indexing: ReadModelIndexingConfig = defaultReadModelIndexingConfig,\n ) {\n super(\n db as unknown as Kysely<DocumentViewDatabase>,\n operationIndex,\n writeCache,\n consistencyTracker,\n {\n readModelId: DOCUMENT_VIEW_READ_MODEL,\n rebuildStateOnInit: true,\n indexing,\n replayStreamSuffix: false,\n purgeFence: \"locked\",\n },\n );\n this._db = db;\n }\n\n /**\n * Indexes committed operations into DocumentSnapshot rows. CREATE_DOCUMENT\n * only seeds header/document/auth. UPGRADE_DOCUMENT reindexes every scope\n * present in resultingState when the operation vouches for them — a seed\n * carrying initialState or a migration stamped with the __migrated marker\n * — since the upgrade reducer may have reshaped any of them; upgrades\n * without either fall back to header/document/auth, because their sibling\n * echoes may be stale. All other action types index only header and their\n * own scope.\n *\n * Every row accepts a write only from an operation whose global ordinal is\n * at least the one the row already carries, so an older duplicate from a\n * sweep, boot replay or chunk interleave never rolls a scope back.\n */\n protected override async commitOperations(\n items: OperationWithContext[],\n fenced?: Transaction<DocumentViewDatabase>,\n ): Promise<void> {\n const write = async (trx: Transaction<Database>) => {\n for (const item of items) {\n const { operation, context } = item;\n // Its rows went in the purge transaction; the marker writes none back.\n if (isPurgeMarker(operation)) continue;\n const {\n documentId,\n scope,\n branch,\n documentType,\n resultingState,\n ordinal,\n } = context;\n const { index, hash } = operation;\n\n if (!resultingState) {\n throw new Error(\n `Missing resultingState in context for operation ${operation.id || \"unknown\"}. ` +\n `IDocumentView requires resultingState from upstream - it does not rebuild documents.`,\n );\n }\n\n let fullState: Record<string, unknown>;\n try {\n fullState = JSON.parse(resultingState) as Record<string, unknown>;\n } catch (error) {\n throw new Error(\n `Failed to parse resultingState for operation ${operation.id || \"unknown\"}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n\n const operationType = operation.action.type;\n\n // A refused operation holds its index and changes nothing, so it must\n // not carry its action type's side effects. A refused DELETE_DOCUMENT\n // is the case that matters: taking the branch below would hide the\n // document from every listing and destroy its slug mapping, with\n // nothing in any path to put either back.\n const denied = isDenied(operation);\n\n // Non-header ops carry a denormalized header echo with possibly stale\n // `meta`; only header-scope ops and CREATE/UPGRADE/DELETE may write it.\n const preserveHeaderMeta =\n denied ||\n (operationType !== \"CREATE_DOCUMENT\" &&\n operationType !== \"UPGRADE_DOCUMENT\" &&\n operationType !== \"DELETE_DOCUMENT\" &&\n scope !== \"header\");\n\n if (operationType === \"DELETE_DOCUMENT\" && !denied) {\n const now = new Date();\n await trx\n .updateTable(\"DocumentSnapshot\")\n .set({\n isDeleted: true,\n deletedAt: now,\n lastOperationIndex: index,\n lastOperationHash: hash,\n lastOperationOrdinal: ordinal,\n lastUpdatedAt: now,\n })\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch)\n .where(\"lastOperationOrdinal\", \"<=\", ordinal)\n .execute();\n\n // The content has to say so too, or a caller served the boundary state\n // would get state claiming the document is live.\n const deletedDocumentScope = (\n fullState as Record<string, unknown> | undefined\n )?.document;\n if (deletedDocumentScope !== undefined) {\n await trx\n .updateTable(\"DocumentSnapshot\")\n .set({ content: deletedDocumentScope })\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch)\n .where(\"scope\", \"=\", \"document\")\n .where(\"lastOperationOrdinal\", \"<=\", ordinal)\n .execute();\n }\n\n await trx\n .deleteFrom(\"SlugMapping\")\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch)\n .execute();\n\n continue;\n }\n\n let scopesToIndex: Array<[string, unknown]>;\n\n if (operationType === \"CREATE_DOCUMENT\") {\n scopesToIndex = Object.entries(fullState).filter(\n ([key]) => key === \"header\" || key === \"document\" || key === \"auth\",\n );\n } else if (operationType === \"UPGRADE_DOCUMENT\") {\n // Sibling-scope echoes are only trustworthy when the operation\n // itself defines them: a seed carrying initialState, or a migration\n // whose executor vouched (via the __migrated marker) that it\n // fetched every scope fresh. Upgrades persisted by executors that\n // never fetched sibling scopes echo whatever stale state the write\n // cache held, and indexing those would clobber good snapshots.\n const upgradeInput = operation.action.input as {\n initialState?: unknown;\n };\n const scopesVouchedFor =\n fullState.__migrated === true ||\n upgradeInput.initialState !== undefined;\n delete fullState.__migrated;\n\n scopesToIndex = scopesVouchedFor\n ? Object.entries(fullState)\n : Object.entries(fullState).filter(\n ([key]) =>\n key === \"header\" || key === \"document\" || key === \"auth\",\n );\n } else {\n scopesToIndex = [];\n\n if (fullState.header !== undefined) {\n scopesToIndex.push([\"header\", fullState.header]);\n }\n\n if (fullState[scope] !== undefined) {\n scopesToIndex.push([scope, fullState[scope]]);\n } else {\n // An operation whose resultingState lacks its own scope is never\n // legitimate, and writing {} over the row turns the upstream shape\n // bug into silent data loss that passes every consistency check.\n // Keep the existing snapshot and move past the operation; a throw\n // here would park the cursor for every document behind this one.\n this.logger.warn(\n `refusing to index ${documentId} scope \"${scope}\" at operation ${index}: ` +\n `resultingState carries no \"${scope}\" key; leaving the existing snapshot intact`,\n );\n }\n }\n\n for (const [scopeName, scopeState] of scopesToIndex) {\n // Same rule as the missing-key case above: a scope state that is\n // not an object is malformed input, and substituting {} would write\n // a well-formed empty row that passes every consistency check.\n if (typeof scopeState !== \"object\" || scopeState === null) {\n this.logger.warn(\n `refusing to index ${documentId} scope \"${scopeName}\" at operation ${index}: ` +\n `resultingState carries a non-object \"${scopeName}\" value; leaving the existing snapshot intact`,\n );\n continue;\n }\n\n // The previous `content` is the whole prior scope state - hundreds of\n // kilobytes of jsonb on a large drive - and only the header-meta\n // carry-over below reads it. Selecting it unconditionally made every\n // write pay to decompress and ship a copy of the state it was about\n // to overwrite.\n const needsExistingContent =\n scopeName === \"header\" && preserveHeaderMeta;\n\n const existingSnapshot = await trx\n .selectFrom(\"DocumentSnapshot\")\n .select([\n \"slug\",\n \"name\",\n \"isDeleted\",\n \"snapshotVersion\",\n \"lastOperationOrdinal\",\n ])\n .$if(needsExistingContent, (qb) => qb.select(\"content\"))\n .where(\"documentId\", \"=\", documentId)\n .where(\"scope\", \"=\", scopeName)\n .where(\"branch\", \"=\", branch)\n .executeTakeFirst();\n\n // An older operation carries stale state for the whole scope.\n if (\n existingSnapshot !== undefined &&\n existingSnapshot.lastOperationOrdinal > ordinal\n ) {\n continue;\n }\n\n const newState = scopeState as Record<string, unknown>;\n\n let slug: string | null = existingSnapshot?.slug ?? null;\n let name: string | null = existingSnapshot?.name ?? null;\n\n if (scopeName === \"header\") {\n const headerSlug = newState.slug;\n const headerName = newState.name;\n\n if (typeof headerSlug === \"string\") {\n slug = headerSlug;\n }\n if (typeof headerName === \"string\") {\n name = headerName;\n }\n\n if (needsExistingContent && existingSnapshot) {\n const existingHeader = existingSnapshot.content as Record<\n string,\n unknown\n >;\n if (existingHeader && \"meta\" in existingHeader) {\n newState.meta = existingHeader.meta;\n }\n }\n\n // Never for a deleted document. Deleting removes its SlugMapping\n // rows, and resolveIdOrSlug relies on that to keep the slug branch\n // from reaching one: re-inserting here would make the document\n // resolvable by slug again, and the upsert would take the slug from\n // a live document that has since claimed it.\n if (slug && slug !== documentId && !existingSnapshot?.isDeleted) {\n await trx\n .insertInto(\"SlugMapping\")\n .values({\n slug,\n documentId,\n scope: scopeName,\n branch,\n })\n .onConflict((oc) =>\n oc.column(\"slug\").doUpdateSet({\n documentId,\n scope: scopeName,\n branch,\n }),\n )\n .execute();\n }\n }\n\n if (existingSnapshot) {\n await trx\n .updateTable(\"DocumentSnapshot\")\n .set({\n lastOperationIndex: index,\n lastOperationHash: hash,\n lastOperationOrdinal: ordinal,\n lastUpdatedAt: new Date(),\n snapshotVersion: existingSnapshot.snapshotVersion + 1,\n content: newState,\n slug,\n name,\n })\n .where(\"documentId\", \"=\", documentId)\n .where(\"scope\", \"=\", scopeName)\n .where(\"branch\", \"=\", branch)\n // Repeats the guard where the database can enforce it.\n .where(\"lastOperationOrdinal\", \"<=\", ordinal)\n .execute();\n } else {\n const snapshot: InsertableDocumentSnapshot = {\n id: uuidv4(),\n documentId,\n slug,\n name,\n scope: scopeName,\n branch,\n content: newState,\n documentType,\n lastOperationIndex: index,\n lastOperationHash: hash,\n lastOperationOrdinal: ordinal,\n identifiers: null,\n metadata: null,\n deletedAt: null,\n };\n\n await trx.insertInto(\"DocumentSnapshot\").values(snapshot).execute();\n }\n }\n }\n };\n\n if (fenced) {\n await write(fenced as unknown as Transaction<Database>);\n return;\n }\n await this._db.transaction().execute(write);\n }\n\n async exists(\n documentIds: string[],\n existence: DocumentExistence,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<boolean[]> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (documentIds.length === 0) {\n return [];\n }\n\n const existingIds =\n existence === DocumentExistence.IncludingDeleted\n ? await this.idsWithStreams(documentIds, signal)\n : await this.liveIds(documentIds);\n\n return documentIds.map((id) => existingIds.has(id));\n }\n\n async get<TDocument extends PHDocument>(\n documentId: string,\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<TDocument> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n let scopesToQuery: string[];\n if (view?.scopes && view.scopes.length > 0) {\n scopesToQuery = [...new Set([\"header\", \"document\", ...view.scopes])];\n } else {\n scopesToQuery = [];\n }\n\n let query = this._db\n .selectFrom(\"DocumentSnapshot\")\n .selectAll()\n .where(\"documentId\", \"=\", documentId)\n .where(\"branch\", \"=\", branch);\n\n if (this.deletedDocumentRead === DeletedDocumentRead.NotFound) {\n query = query.where(\"isDeleted\", \"=\", false);\n }\n\n if (scopesToQuery.length > 0) {\n query = query.where(\"scope\", \"in\", scopesToQuery);\n }\n\n const snapshots = await query.execute();\n\n if (snapshots.length === 0) {\n throw new DocumentNotFoundError(\n documentId,\n `Document not found: ${documentId}`,\n );\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const headerSnapshot = snapshots.find((s) => s.scope === \"header\");\n if (!headerSnapshot) {\n throw new Error(`Document header not found: ${documentId}`);\n }\n\n const header = headerSnapshot.content as PHDocumentHeader;\n\n const revisions = await this.operationStore.getRevisions(\n documentId,\n branch,\n signal,\n );\n header.revision = revisions.revision;\n header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n\n const state: Record<string, unknown> = {};\n for (const snapshot of snapshots) {\n if (snapshot.scope === \"header\") {\n continue;\n }\n\n // snapshot rows written before PHAuthState had a version carry auth: {}\n state[snapshot.scope] =\n snapshot.scope === \"auth\"\n ? createAuthState(snapshot.content as Partial<PHAuthState>)\n : snapshot.content;\n }\n\n const document: PHDocument = {\n header,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n state: state as any,\n operations: {},\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n initialState: state as any,\n clipboard: [],\n };\n\n return document as TDocument;\n }\n\n async getMany<TDocument extends PHDocument>(\n documentIds: string[],\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<TDocument[]> {\n if (documentIds.length === 0) {\n return [];\n }\n\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n let scopesToQuery: string[];\n if (view?.scopes && view.scopes.length > 0) {\n scopesToQuery = [...new Set([\"header\", \"document\", ...view.scopes])];\n } else {\n scopesToQuery = [];\n }\n\n let query = this._db\n .selectFrom(\"DocumentSnapshot\")\n .selectAll()\n .where(\"documentId\", \"in\", documentIds)\n .where(\"branch\", \"=\", branch)\n .where(\"isDeleted\", \"=\", false);\n\n if (scopesToQuery.length > 0) {\n query = query.where(\"scope\", \"in\", scopesToQuery);\n }\n\n const allSnapshots = await query.execute();\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const snapshotsByDocId = new Map<string, typeof allSnapshots>();\n for (const snapshot of allSnapshots) {\n const existing = snapshotsByDocId.get(snapshot.documentId) || [];\n existing.push(snapshot);\n snapshotsByDocId.set(snapshot.documentId, existing);\n }\n\n const foundDocumentIds = [...snapshotsByDocId.keys()];\n const revisionResults = await Promise.all(\n foundDocumentIds.map((docId) =>\n this.operationStore.getRevisions(docId, branch, signal),\n ),\n );\n\n const revisionsByDocId = new Map<string, DocumentRevisions>();\n for (let i = 0; i < foundDocumentIds.length; i++) {\n revisionsByDocId.set(foundDocumentIds[i], revisionResults[i]);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const documents: TDocument[] = [];\n for (const documentId of documentIds) {\n const snapshots = snapshotsByDocId.get(documentId);\n if (!snapshots || snapshots.length === 0) {\n continue;\n }\n\n const headerSnapshot = snapshots.find((s) => s.scope === \"header\");\n if (!headerSnapshot) {\n continue;\n }\n\n const header = headerSnapshot.content as PHDocumentHeader;\n const revisions = revisionsByDocId.get(documentId);\n if (revisions) {\n header.revision = revisions.revision;\n header.lastModifiedAtUtcIso = revisions.latestTimestamp;\n }\n\n const state: Record<string, unknown> = {};\n for (const snapshot of snapshots) {\n if (snapshot.scope === \"header\") {\n continue;\n }\n // snapshot rows written before PHAuthState had a version carry auth: {}\n state[snapshot.scope] =\n snapshot.scope === \"auth\"\n ? createAuthState(snapshot.content as Partial<PHAuthState>)\n : snapshot.content;\n }\n\n const document: PHDocument = {\n header,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n state: state as any,\n operations: {},\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n initialState: state as any,\n clipboard: [],\n };\n\n documents.push(document as TDocument);\n }\n\n return documents;\n }\n\n async getByIdOrSlug<TDocument extends PHDocument>(\n identifier: string,\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<TDocument> {\n const documentId = await this.resolveIdOrSlug(\n identifier,\n view,\n consistencyToken,\n signal,\n );\n return this.get<TDocument>(documentId, view, undefined, signal);\n }\n\n async findByType(\n type: string,\n view?: ViewFilter,\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<PHDocument>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n const rows = await this._db\n .selectFrom(\"DocumentSnapshot\")\n .select(\"documentId\")\n .select((eb) => eb.fn.max(\"lastUpdatedAt\").as(\"lastUpdatedAt\"))\n .where(\"documentType\", \"=\", type)\n .where(\"branch\", \"=\", branch)\n .where(\"isDeleted\", \"=\", false)\n .groupBy(\"documentId\")\n .orderBy(\"lastUpdatedAt\", \"desc\")\n .orderBy(\"documentId\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const hasMore = rows.length > limit;\n const docsToFetch = rows.slice(0, limit).map((row) => row.documentId);\n\n const documents: PHDocument[] = [];\n for (const documentId of docsToFetch) {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n try {\n const document = await this.get<PHDocument>(\n documentId,\n view,\n undefined,\n signal,\n );\n documents.push(document);\n } catch {\n continue;\n }\n }\n\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: documents,\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.findByType(\n type,\n view,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async resolveSlug(\n slug: string,\n // TODO: this should only be branch\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string | undefined> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n const mapping = await this._db\n .selectFrom(\"SlugMapping\")\n .select(\"documentId\")\n .where(\"slug\", \"=\", slug)\n .where(\"branch\", \"=\", branch)\n .executeTakeFirst();\n\n if (!mapping) {\n return undefined;\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (view?.scopes && view.scopes.length > 0) {\n const scopeCheck = await this._db\n .selectFrom(\"DocumentSnapshot\")\n .select(\"scope\")\n .where(\"documentId\", \"=\", mapping.documentId)\n .where(\"branch\", \"=\", branch)\n .where(\"scope\", \"in\", view.scopes)\n .where(\"isDeleted\", \"=\", false)\n .executeTakeFirst();\n\n if (!scopeCheck) {\n return undefined;\n }\n }\n\n return mapping.documentId;\n }\n\n // TODO: fix\n async resolveSlugs(\n slugs: string[],\n // TODO: this should only be branch\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string[]> {\n const ids = await Promise.all(\n slugs.map((slug) =>\n this.resolveSlug(slug, view, consistencyToken, signal),\n ),\n );\n return ids.filter((id) => id !== undefined) as string[];\n }\n\n async resolveIdOrSlug(\n identifier: string,\n // TODO: this should only be branch\n view?: ViewFilter,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const branch = view?.branch || \"main\";\n\n // The id branch relaxes with `get`, or resolution throws before it. The slug\n // branch never does: deleting a document removes its SlugMapping rows.\n let idCheckQuery = this._db\n .selectFrom(\"DocumentSnapshot\")\n .select(\"documentId\")\n .where(\"documentId\", \"=\", identifier)\n .where(\"branch\", \"=\", branch);\n\n if (this.deletedDocumentRead === DeletedDocumentRead.NotFound) {\n idCheckQuery = idCheckQuery.where(\"isDeleted\", \"=\", false);\n }\n\n const idCheckPromise = idCheckQuery.executeTakeFirst();\n\n const slugCheckPromise = this._db\n .selectFrom(\"SlugMapping\")\n .select(\"documentId\")\n .where(\"slug\", \"=\", identifier)\n .where(\"branch\", \"=\", branch)\n .executeTakeFirst();\n\n const [idMatch, slugMatch] = await Promise.all([\n idCheckPromise,\n slugCheckPromise,\n ]);\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const idMatchDocId = idMatch?.documentId;\n const slugMatchDocId = slugMatch?.documentId;\n\n if (idMatchDocId && slugMatchDocId && idMatchDocId !== slugMatchDocId) {\n throw new Error(\n `Ambiguous identifier \"${identifier}\": matches both document ID \"${idMatchDocId}\" and slug for document ID \"${slugMatchDocId}\". ` +\n `Please use get() for ID or resolveSlug() + get() for slug to be explicit.`,\n );\n }\n\n const resolvedDocumentId = idMatchDocId || slugMatchDocId;\n\n if (!resolvedDocumentId) {\n throw new DocumentNotFoundError(\n identifier,\n `Document not found: ${identifier}`,\n );\n }\n\n return resolvedDocumentId;\n }\n\n /**\n * Ids that have at least one stream, asked of the operation store rather than\n * of a table, so the answer holds for any store implementation. A deleted\n * document keeps its stream, so this is the id-is-taken answer, and it does\n * not drift when a snapshot row is missing.\n *\n * Asked on main because that is the branch a create writes: the store this\n * question exists to agree with validates the create against main's head.\n */\n private async idsWithStreams(\n documentIds: string[],\n signal?: AbortSignal,\n ): Promise<Set<string>> {\n const unique = [...new Set(documentIds)];\n const revisions = await Promise.all(\n unique.map((documentId) =>\n this.operationStore.getRevisions(documentId, \"main\", signal),\n ),\n );\n\n const taken = new Set<string>();\n for (let i = 0; i < unique.length; i++) {\n if (Object.keys(revisions[i].revision).length > 0) {\n taken.add(unique[i]);\n }\n }\n return taken;\n }\n\n private async liveIds(documentIds: string[]): Promise<Set<string>> {\n const rows = await this._db\n .selectFrom(\"DocumentSnapshot\")\n .select([\"documentId\"])\n .where(\"documentId\", \"in\", documentIds)\n .where(\"isDeleted\", \"=\", false)\n .distinct()\n .execute();\n\n return new Set(rows.map((row) => row.documentId));\n }\n}\n","import type { ConsistencyCoordinate, ConsistencyKey } from \"./types.js\";\n\nexport interface IConsistencyTracker {\n /**\n * Updates the tracker with new operation indexes.\n * When multiple coordinates have the same key, keeps the highest operationIndex.\n * Resolves any pending waiters whose coordinates are now satisfied.\n */\n update(coordinates: ConsistencyCoordinate[]): void;\n\n /**\n * Returns the latest operation index for a given key, or undefined if not tracked.\n */\n getLatest(key: ConsistencyKey): number | undefined;\n\n /**\n * Returns a promise that resolves when all coordinates are satisfied.\n * Rejects if the timeout is reached or the signal is aborted.\n */\n waitFor(\n coordinates: ConsistencyCoordinate[],\n timeoutMs?: number,\n signal?: AbortSignal,\n ): Promise<void>;\n\n /**\n * Returns a serializable snapshot of the current state.\n */\n serialize(): Array<[ConsistencyKey, number]>;\n\n /**\n * Restores state from a serialized snapshot.\n */\n hydrate(entries: Array<[ConsistencyKey, number]>): void;\n}\n\ntype Waiter = {\n coordinates: ConsistencyCoordinate[];\n resolve: () => void;\n reject: (reason: Error) => void;\n signal?: AbortSignal;\n timeoutId?: NodeJS.Timeout;\n};\n\n/**\n * Creates a consistency key from documentId, scope, and branch.\n */\nexport function makeConsistencyKey(\n documentId: string,\n scope: string,\n branch: string,\n): ConsistencyKey {\n return `${documentId}:${scope}:${branch}`;\n}\n\n/**\n * Tracks operation indexes for documents and provides read-after-write consistency guarantees.\n * Maintains an in-memory map of the latest operation index for each (documentId, scope, branch) tuple.\n */\nexport class ConsistencyTracker implements IConsistencyTracker {\n private state = new Map<ConsistencyKey, number>();\n private waiters: Waiter[] = [];\n\n update(coordinates: ConsistencyCoordinate[]): void {\n const deduplicated = this.deduplicateCoordinates(coordinates);\n\n for (let i = 0; i < deduplicated.length; i++) {\n const coord = deduplicated[i]!;\n const key = makeConsistencyKey(\n coord.documentId,\n coord.scope,\n coord.branch,\n );\n const current = this.state.get(key);\n if (current === undefined || coord.operationIndex > current) {\n this.state.set(key, coord.operationIndex);\n }\n }\n\n this.checkWaiters();\n }\n\n getLatest(key: ConsistencyKey): number | undefined {\n return this.state.get(key);\n }\n\n waitFor(\n coordinates: ConsistencyCoordinate[],\n timeoutMs?: number,\n signal?: AbortSignal,\n ): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(new Error(\"Operation aborted\"));\n }\n\n if (this.areCoordinatesSatisfied(coordinates)) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve, reject) => {\n const waiter: Waiter = {\n coordinates,\n resolve,\n reject,\n signal,\n };\n\n if (timeoutMs !== undefined) {\n waiter.timeoutId = setTimeout(() => {\n this.removeWaiter(waiter);\n reject(new Error(`Consistency wait timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }\n\n if (signal) {\n const abortHandler = () => {\n this.removeWaiter(waiter);\n reject(new Error(\"Operation aborted\"));\n };\n signal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n this.waiters.push(waiter);\n });\n }\n\n serialize(): Array<[ConsistencyKey, number]> {\n return Array.from(this.state.entries());\n }\n\n hydrate(entries: Array<[ConsistencyKey, number]>): void {\n this.state.clear();\n for (const [key, index] of entries) {\n this.state.set(key, index);\n }\n }\n\n private deduplicateCoordinates(\n coordinates: ConsistencyCoordinate[],\n ): ConsistencyCoordinate[] {\n const map = new Map<ConsistencyKey, ConsistencyCoordinate>();\n\n for (let i = 0; i < coordinates.length; i++) {\n const coord = coordinates[i]!;\n const key = makeConsistencyKey(\n coord.documentId,\n coord.scope,\n coord.branch,\n );\n const existing = map.get(key);\n\n if (!existing || coord.operationIndex > existing.operationIndex) {\n map.set(key, coord);\n }\n }\n\n return Array.from(map.values());\n }\n\n private areCoordinatesSatisfied(\n coordinates: ConsistencyCoordinate[],\n ): boolean {\n for (let i = 0; i < coordinates.length; i++) {\n const coord = coordinates[i]!;\n const key = makeConsistencyKey(\n coord.documentId,\n coord.scope,\n coord.branch,\n );\n const latest = this.state.get(key);\n if (latest === undefined || latest < coord.operationIndex) {\n return false;\n }\n }\n return true;\n }\n\n private checkWaiters(): void {\n const satisfiedWaiters: Waiter[] = [];\n const unsatisfiedWaiters: Waiter[] = [];\n\n for (const waiter of this.waiters) {\n if (waiter.signal?.aborted) {\n continue;\n }\n\n if (this.areCoordinatesSatisfied(waiter.coordinates)) {\n satisfiedWaiters.push(waiter);\n } else {\n unsatisfiedWaiters.push(waiter);\n }\n }\n\n this.waiters = unsatisfiedWaiters;\n\n for (const waiter of satisfiedWaiters) {\n if (waiter.timeoutId !== undefined) {\n clearTimeout(waiter.timeoutId);\n }\n waiter.resolve();\n }\n }\n\n private removeWaiter(waiter: Waiter): void {\n const index = this.waiters.indexOf(waiter);\n if (index !== -1) {\n this.waiters.splice(index, 1);\n }\n if (waiter.timeoutId !== undefined) {\n clearTimeout(waiter.timeoutId);\n }\n }\n}\n","import type { PagedResults } from \"./types.js\";\n\n/**\n * Collects all results from a paged result set by following the next() function\n * until all pages have been fetched.\n */\nexport async function collectAllPages<T>(\n firstPage: PagedResults<T>,\n signal?: AbortSignal,\n): Promise<T[]> {\n const allResults: T[] = [...firstPage.results];\n let currentPage = firstPage;\n\n while (currentPage.next) {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n currentPage = await currentPage.next();\n allResults.push(...currentPage.results);\n }\n\n return allResults;\n}\n","import type {\n Operation,\n OperationWithContext,\n} from \"@powerhousedao/shared/document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { IOperationIndex } from \"../../cache/operation-index-types.js\";\nimport type { IWriteCache } from \"../../cache/write/interfaces.js\";\nimport {\n BaseReadModel,\n defaultReadModelIndexingConfig,\n type ReadModelIndexingConfig,\n} from \"../../read-models/base-read-model.js\";\nimport { DOCUMENT_INDEXER_READ_MODEL } from \"../../read-models/names.js\";\nimport type { DocumentViewDatabase } from \"../../read-models/types.js\";\nimport { collectAllPages } from \"../../shared/collect-all-pages.js\";\nimport type { IConsistencyTracker } from \"../../shared/consistency-tracker.js\";\nimport type {\n ConsistencyToken,\n PagedResults,\n PagingOptions,\n} from \"../../shared/types.js\";\nimport type {\n DocumentGraphEdge,\n DocumentRelationship,\n IDocumentGraph,\n IDocumentIndexer,\n} from \"../interfaces.js\";\nimport { findPurged } from \"./document-purges.js\";\nimport type {\n DocumentIndexerDatabase,\n InsertableDocumentRelationship,\n Database as StorageDatabase,\n} from \"./types.js\";\n\nfunction isRelationshipAction(actionType: string): boolean {\n return (\n actionType === \"ADD_RELATIONSHIP\" ||\n actionType === \"REMOVE_RELATIONSHIP\" ||\n actionType === \"UPDATE_RELATIONSHIP\"\n );\n}\n\ntype RelationshipEnds = { sourceId: string; targetId: string };\n\nfunction addRelationshipIds(items: OperationWithContext[]): string[] {\n const ids: string[] = [];\n for (const { operation } of items) {\n if (operation.action.type !== \"ADD_RELATIONSHIP\") continue;\n const { sourceId, targetId } = operation.action.input as RelationshipEnds;\n if (typeof sourceId === \"string\") ids.push(sourceId);\n if (typeof targetId === \"string\") ids.push(targetId);\n }\n return ids;\n}\n\nfunction touchesPurged(operation: Operation, purged: Set<string>): boolean {\n const input = operation.action.input as RelationshipEnds;\n return purged.has(input.sourceId) || purged.has(input.targetId);\n}\n\nexport type IndexerDatabase = StorageDatabase &\n DocumentIndexerDatabase &\n DocumentViewDatabase;\n\nexport class KyselyDocumentIndexer\n extends BaseReadModel\n implements IDocumentIndexer\n{\n static override readonly commitsInFenceTransaction = true;\n\n private _db: Kysely<IndexerDatabase>;\n\n constructor(\n db: Kysely<IndexerDatabase>,\n operationIndex: IOperationIndex,\n writeCache: IWriteCache,\n consistencyTracker: IConsistencyTracker,\n indexing: ReadModelIndexingConfig = defaultReadModelIndexingConfig,\n ) {\n super(\n db as unknown as Kysely<DocumentViewDatabase>,\n operationIndex,\n writeCache,\n consistencyTracker,\n {\n readModelId: DOCUMENT_INDEXER_READ_MODEL,\n rebuildStateOnInit: false,\n indexing,\n purgeFence: \"locked\",\n },\n );\n this._db = db;\n }\n\n protected override writesRows(items: OperationWithContext[]): boolean {\n return items.some((item) =>\n isRelationshipAction(item.operation.action.type),\n );\n }\n\n /** Opens no transaction for a batch carrying no relationship operation. */\n protected override async commitOperations(\n items: OperationWithContext[],\n fenced?: Transaction<DocumentViewDatabase>,\n ): Promise<void> {\n const relationshipOps = items.filter((item) =>\n isRelationshipAction(item.operation.action.type),\n );\n\n if (relationshipOps.length === 0) {\n return;\n }\n\n if (fenced) {\n await this.writeRelationships(\n relationshipOps,\n fenced as unknown as Transaction<IndexerDatabase>,\n );\n return;\n }\n await this._db\n .transaction()\n .execute((trx) => this.writeRelationships(relationshipOps, trx));\n }\n\n private async writeRelationships(\n relationshipOps: OperationWithContext[],\n trx: Transaction<IndexerDatabase>,\n ): Promise<void> {\n const purged = await findPurged(trx, addRelationshipIds(relationshipOps));\n for (const item of relationshipOps) {\n const { operation } = item;\n const actionType = operation.action.type;\n\n if (actionType === \"ADD_RELATIONSHIP\") {\n // Whole: a lone target Document row would outlive the purge.\n if (touchesPurged(operation, purged)) continue;\n await this.handleAddRelationship(trx, operation);\n } else if (actionType === \"REMOVE_RELATIONSHIP\") {\n await this.handleRemoveRelationship(trx, operation);\n } else if (actionType === \"UPDATE_RELATIONSHIP\") {\n await this.handleUpdateRelationship(trx, operation);\n }\n }\n }\n\n async getOutgoing(\n documentId: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where(\"sourceId\", \"=\", documentId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getOutgoing(\n documentId,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async getIncoming(\n documentId: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where(\"targetId\", \"=\", documentId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getIncoming(\n documentId,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async getOrphanedChildren(\n parentIds: string[],\n types?: string[],\n signal?: AbortSignal,\n ): Promise<string[]> {\n if (parentIds.length === 0) {\n return [];\n }\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n let query = this._db\n .selectFrom(\"DocumentRelationship as r\")\n .select(\"r.targetId\")\n .distinct()\n .where(\"r.sourceId\", \"in\", parentIds)\n .where((eb) =>\n eb.not(\n eb.exists(\n eb\n .selectFrom(\"DocumentRelationship as other\")\n .select(\"other.id\")\n .whereRef(\"other.targetId\", \"=\", \"r.targetId\")\n .where(\"other.sourceId\", \"not in\", parentIds),\n ),\n ),\n );\n\n if (types && types.length > 0) {\n query = query.where(\"r.relationshipType\", \"in\", types);\n }\n\n const rows = await query.execute();\n return rows.map((row) => row.targetId);\n }\n\n async hasRelationship(\n sourceId: string,\n targetId: string,\n types?: string[],\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<boolean> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .select(\"id\")\n .where(\"sourceId\", \"=\", sourceId)\n .where(\"targetId\", \"=\", targetId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const result = await query.executeTakeFirst();\n\n return result !== undefined;\n }\n\n async getUndirectedRelationships(\n a: string,\n b: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where((eb) =>\n eb.or([\n eb.and([eb(\"sourceId\", \"=\", a), eb(\"targetId\", \"=\", b)]),\n eb.and([eb(\"sourceId\", \"=\", b), eb(\"targetId\", \"=\", a)]),\n ]),\n );\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getUndirectedRelationships(\n a,\n b,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async getDirectedRelationships(\n sourceId: string,\n targetId: string,\n types?: string[],\n paging?: PagingOptions,\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<PagedResults<DocumentRelationship>> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const startIndex = paging?.cursor ? parseInt(paging.cursor) : 0;\n const limit = paging?.limit || 100;\n\n let query = this._db\n .selectFrom(\"DocumentRelationship\")\n .selectAll()\n .where(\"sourceId\", \"=\", sourceId)\n .where(\"targetId\", \"=\", targetId);\n\n if (types && types.length > 0) {\n query = query.where(\"relationshipType\", \"in\", types);\n }\n\n const rows = await query\n .orderBy(\"createdAt\", \"asc\")\n .orderBy(\"id\", \"asc\")\n .offset(startIndex)\n .limit(limit + 1)\n .execute();\n\n const hasMore = rows.length > limit;\n const results = hasMore ? rows.slice(0, limit) : rows;\n const nextCursor = hasMore ? String(startIndex + limit) : undefined;\n\n return {\n results: results.map((row) => ({\n sourceId: row.sourceId,\n targetId: row.targetId,\n relationshipType: row.relationshipType,\n metadata: row.metadata\n ? (row.metadata as Record<string, unknown>)\n : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n })),\n options: paging || { cursor: \"0\", limit: 100 },\n nextCursor,\n next: hasMore\n ? () =>\n this.getDirectedRelationships(\n sourceId,\n targetId,\n types,\n { cursor: nextCursor!, limit },\n consistencyToken,\n signal,\n )\n : undefined,\n };\n }\n\n async findPath(\n sourceId: string,\n targetId: string,\n types?: string[],\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string[] | null> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n if (sourceId === targetId) {\n return [sourceId];\n }\n\n const visited = new Set<string>();\n const queue: Array<{ id: string; path: string[] }> = [\n { id: sourceId, path: [sourceId] },\n ];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n if (current.id === targetId) {\n return current.path;\n }\n\n if (visited.has(current.id)) {\n continue;\n }\n\n visited.add(current.id);\n\n const outgoingPage = await this.getOutgoing(\n current.id,\n types,\n undefined,\n consistencyToken,\n signal,\n );\n const outgoingRelationships = await collectAllPages(outgoingPage, signal);\n\n for (const rel of outgoingRelationships) {\n if (!visited.has(rel.targetId)) {\n queue.push({\n id: rel.targetId,\n path: [...current.path, rel.targetId],\n });\n }\n }\n }\n\n return null;\n }\n\n async findAncestors(\n documentId: string,\n types?: string[],\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<IDocumentGraph> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const nodes = new Set<string>([documentId]);\n const edges: DocumentGraphEdge[] = [];\n const queue: string[] = [documentId];\n const visited = new Set<string>();\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n\n if (visited.has(currentId)) {\n continue;\n }\n\n visited.add(currentId);\n\n const incomingPage = await this.getIncoming(\n currentId,\n types,\n undefined,\n consistencyToken,\n signal,\n );\n const incomingRelationships = await collectAllPages(incomingPage, signal);\n\n for (const rel of incomingRelationships) {\n nodes.add(rel.sourceId);\n edges.push({\n from: rel.sourceId,\n to: rel.targetId,\n type: rel.relationshipType,\n });\n\n if (!visited.has(rel.sourceId)) {\n queue.push(rel.sourceId);\n }\n }\n }\n\n return {\n nodes: Array.from(nodes),\n edges,\n };\n }\n\n async getRelationshipTypes(\n consistencyToken?: ConsistencyToken,\n signal?: AbortSignal,\n ): Promise<string[]> {\n if (consistencyToken) {\n await this.waitForConsistency(consistencyToken, undefined, signal);\n }\n\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n const rows = await this._db\n .selectFrom(\"DocumentRelationship\")\n .select(\"relationshipType\")\n .distinct()\n .execute();\n\n return rows.map((row) => row.relationshipType);\n }\n\n private async handleAddRelationship(\n trx: Kysely<IndexerDatabase>,\n operation: Operation,\n ): Promise<void> {\n const input = operation.action.input as {\n sourceId: string;\n targetId: string;\n relationshipType: string;\n metadata?: Record<string, unknown>;\n };\n\n const existingDoc = await trx\n .selectFrom(\"Document\")\n .select(\"id\")\n .where(\"id\", \"=\", input.sourceId)\n .executeTakeFirst();\n\n if (!existingDoc) {\n await trx\n .insertInto(\"Document\")\n .values({\n id: input.sourceId,\n })\n .execute();\n }\n\n const existingTargetDoc = await trx\n .selectFrom(\"Document\")\n .select(\"id\")\n .where(\"id\", \"=\", input.targetId)\n .executeTakeFirst();\n\n if (!existingTargetDoc) {\n await trx\n .insertInto(\"Document\")\n .values({\n id: input.targetId,\n })\n .execute();\n }\n\n const existingRel = await trx\n .selectFrom(\"DocumentRelationship\")\n .select(\"id\")\n .where(\"sourceId\", \"=\", input.sourceId)\n .where(\"targetId\", \"=\", input.targetId)\n .where(\"relationshipType\", \"=\", input.relationshipType)\n .executeTakeFirst();\n\n if (!existingRel) {\n const relationship: InsertableDocumentRelationship = {\n id: uuidv4(),\n sourceId: input.sourceId,\n targetId: input.targetId,\n relationshipType: input.relationshipType,\n metadata: input.metadata || null,\n };\n\n await trx\n .insertInto(\"DocumentRelationship\")\n .values(relationship)\n .execute();\n }\n }\n\n private async handleRemoveRelationship(\n trx: Kysely<IndexerDatabase>,\n operation: Operation,\n ): Promise<void> {\n const input = operation.action.input as {\n sourceId: string;\n targetId: string;\n relationshipType: string;\n };\n\n await trx\n .deleteFrom(\"DocumentRelationship\")\n .where(\"sourceId\", \"=\", input.sourceId)\n .where(\"targetId\", \"=\", input.targetId)\n .where(\"relationshipType\", \"=\", input.relationshipType)\n .execute();\n }\n\n private async handleUpdateRelationship(\n trx: Kysely<IndexerDatabase>,\n operation: Operation,\n ): Promise<void> {\n const input = operation.action.input as {\n sourceId: string;\n targetId: string;\n relationshipType: string;\n metadata: Record<string, unknown> | null;\n };\n\n await trx\n .updateTable(\"DocumentRelationship\")\n .set({\n metadata: input.metadata,\n updatedAt: new Date(),\n })\n .where(\"sourceId\", \"=\", input.sourceId)\n .where(\"targetId\", \"=\", input.targetId)\n .where(\"relationshipType\", \"=\", input.relationshipType)\n .execute();\n }\n}\n"],"mappings":"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"}