event-sourced-collection 0.0.11 → 0.0.13

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 +0,0 @@
1
- {"version":3,"file":"create-event-sourced-db-handle-D23nsV5c.mjs","names":[],"sources":["../src/internal/constants.ts","../src/internal/hooks.ts","../src/internal/replay.ts","../src/internal/sync-meta.ts","../src/internal/pull.ts","../src/core/sync.ts","../src/internal/push.ts","../src/core/sync-presets.ts","../src/internal/serial-queue.ts","../src/utils/logger.ts","../src/utils/uuid.ts","../src/core/create-event-sourced-db.ts","../src/core/lazy-singleton.ts","../src/core/create-event-sourced-db-handle.ts"],"sourcesContent":["export const OUTBOX_ID = \"outbox\";\nexport const INBOX_ID = \"inbox\";\nexport const DEADLETTER_ID = \"deadletter\";\nexport const SYNCMETA_ID = \"syncmeta\";\nexport const ROWVERSIONS_ID = \"rowversions\";\n\n/** `syncmeta` holds exactly one row; this is its key. */\nexport const SYNCMETA_KEY = \"singleton\";\n\nexport const RESERVED_IDS: ReadonlySet<string> = new Set([\n OUTBOX_ID,\n INBOX_ID,\n DEADLETTER_ID,\n SYNCMETA_ID,\n ROWVERSIONS_ID,\n]);\n\nexport const DEFAULT_PUSH_BATCH_SIZE = 20;\nexport const MIN_PUSH_BATCH_SIZE = 1;\nexport const MAX_PUSH_BATCH_SIZE = 100;\nexport const PAYLOAD_TOO_LARGE_ERROR_CODE = \"PAYLOAD_TOO_LARGE\";\nexport const DEFAULT_MAX_ATTEMPTS = 8;\nexport const DEFAULT_BASE_DELAY_MS = 1_000;\nexport const DEFAULT_MAX_DELAY_MS = 5 * 60 * 1_000;\nexport const DEFAULT_EVENT_SCHEMA_VERSION = 1;\n\nexport const SYNC_LOCK_PREFIX = \"event-sourced-sync\";\n\n/** Server error code that routes a rejected event to the dead-letter queue as a conflict. */\nexport const CONFLICT_ERROR_CODE = \"CONFLICT\";\n","import type { EventSourcedHooks } from \"../core/types\";\nimport type { EventSourcedLogger } from \"../utils/logger\";\n\n/**\n * Invokes a lifecycle hook. A hook that throws is logged and swallowed — user\n * observation code must never be able to fail a sync.\n *\n * @example\n * ```ts\n * const emit: EmitHook = createHookEmitter(\n * { onSyncStart: ({ trigger }) => console.info(\"sync\", trigger) },\n * log,\n * )\n *\n * emit(\"onSyncStart\", { trigger: \"manualSync\" })\n * emit(\"onDeadLetter\", deadLetterEntry) // no-op when that hook is omitted\n * ```\n */\nexport type EmitHook = <TName extends keyof EventSourcedHooks>(\n name: TName,\n argument: Parameters<NonNullable<EventSourcedHooks[TName]>>[0],\n) => void;\n\n/**\n * Builds an {@link EmitHook} bound to the user-supplied {@link EventSourcedHooks}.\n *\n * @example A throwing hook is logged, then ignored\n * ```ts\n * import { createHookEmitter } from \"./hooks\"\n *\n * const emit = createHookEmitter(\n * {\n * onDeadLetter: () => {\n * throw new Error(\"toast failed\")\n * },\n * },\n * log,\n * )\n *\n * emit(\"onDeadLetter\", entry) // sync continues; log.error(\"lifecycle hook threw\", …)\n * ```\n */\nexport function createHookEmitter(\n hooks: EventSourcedHooks | undefined,\n log: EventSourcedLogger,\n): EmitHook {\n if (!hooks) return () => {};\n\n return (name, argument) => {\n const hook = hooks[name] as ((value: unknown) => void) | undefined;\n if (!hook) return;\n\n try {\n hook(argument);\n } catch (err) {\n log.error(\"lifecycle hook threw\", {\n hook: name,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n };\n}\n","import type { Collection } from \"@tanstack/db\";\n\nimport type { DeadLetterEntry, InboxEntry, RowVersionEntry, UpcastableEvent } from \"../core/types\";\nimport { DEFAULT_EVENT_SCHEMA_VERSION, RESERVED_IDS } from \"./constants\";\nimport type { ReplayableEvent, ReplayContext, ReplayOutcome } from \"./types\";\n\nexport type ReplaySummary = { applied: number; skipped: number; deadLettered: number };\n\nexport function rowVersionId(collectionId: string, key: string | number): string {\n return `${collectionId}::${String(key)}`;\n}\n\n/**\n * Records the version a row is now at. Used to stamp `baseVersion` on future\n * local mutations so the server can detect writes authored against stale state.\n */\nexport async function recordRowVersion(\n rowversions: Collection<RowVersionEntry, string>,\n collectionId: string,\n key: string | number,\n version: string,\n globalSeq: number | null,\n): Promise<void> {\n const id = rowVersionId(collectionId, key);\n\n if (rowversions.has(id)) {\n await rowversions.update(id, (draft) => {\n draft.version = version;\n draft.globalSeq = globalSeq;\n }).isPersisted.promise;\n return;\n }\n\n await rowversions.insert({ id, collectionId, key, version, globalSeq }).isPersisted.promise;\n}\n\nexport function readRowVersion(\n rowversions: Collection<RowVersionEntry, string>,\n collectionId: string,\n key: string | number,\n): string | null {\n return rowversions.get(rowVersionId(collectionId, key))?.version ?? null;\n}\n\n/**\n * After a CONFLICT dead-letter, undo the optimistic `recordRowVersion` that\n * stamped the rejected event id as head. Restores `baseVersion`, or deletes\n * the index row when the mutation was authored against an unknown row.\n */\nexport async function restoreRowVersionAfterConflict(\n rowversions: Collection<RowVersionEntry, string>,\n collectionId: string,\n key: string | number,\n baseVersion: string | null,\n): Promise<void> {\n const id = rowVersionId(collectionId, key);\n\n if (baseVersion === null) {\n if (rowversions.has(id)) {\n await rowversions.delete(id).isPersisted.promise;\n }\n return;\n }\n\n await recordRowVersion(rowversions, collectionId, key, baseVersion, null);\n}\n\nexport async function replayEvent(\n context: ReplayContext,\n event: ReplayableEvent,\n): Promise<ReplayOutcome> {\n const { targets, log } = context;\n const { eventId, collectionId } = event;\n\n // A reserved target can never become valid, so retrying it would wedge the\n // pipeline forever. Unknown collections can become valid after a client\n // upgrade, so those honour unknownEventHandling.\n if (RESERVED_IDS.has(collectionId)) {\n const reason = `reserved collection \"${collectionId}\"`;\n log.warn(\"replay skipped: reserved collection\", {\n eventId,\n collectionId,\n type: event.type,\n key: event.key,\n });\n context.emit(\"onEventSkipped\", { eventId, collectionId, reason });\n return { status: \"skipped\", reason };\n }\n\n const migrated = upcast(context, event);\n if (migrated.status !== \"ok\") return migrated.outcome;\n\n const target = targets[collectionId];\n if (!target) {\n return unresolvable(context, event, `unknown collection \"${collectionId}\"`, {\n knownCollections: Object.keys(targets).filter((id) => !RESERVED_IDS.has(id)),\n });\n }\n\n if (!target.utils.acceptMutations) {\n return unresolvable(context, event, `collection \"${collectionId}\" is missing acceptMutations`, {\n targetId: target.id,\n });\n }\n\n const { type, key, payload } = migrated.event;\n\n log.debug(\"replay applying mutation\", { eventId, collectionId, type, key });\n\n try {\n await target.utils.acceptMutations({\n mutations: [\n {\n mutationId: eventId,\n type,\n key,\n modified: payload,\n original: payload,\n changes: payload,\n collection: target,\n },\n ],\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n log.error(\"replay mutation failed\", {\n eventId,\n collectionId,\n type,\n key,\n message: error.message,\n });\n // Reported rather than thrown: one unapplicable event must not be able to\n // wedge the pull pipeline behind it forever.\n return { status: \"failed\", error };\n }\n\n if (context.conflictDetection) {\n await recordRowVersion(\n context.rowversions,\n collectionId,\n key,\n eventId,\n event.globalSeq ?? null,\n );\n }\n\n log.info(\"replay mutation accepted\", { eventId, collectionId, type, key });\n context.emit(\"onEventApplied\", { eventId, collectionId, type, key });\n\n return { status: \"applied\" };\n}\n\ntype UpcastResult =\n | { status: \"ok\"; event: UpcastableEvent }\n | { status: \"blocked\"; outcome: ReplayOutcome };\n\n/**\n * Brings an event authored under a different schema version into the current\n * shape. Without an upcaster, older events are applied as-is (best effort) but\n * newer ones are refused, since this build cannot know what the fields mean.\n */\nfunction upcast(context: ReplayContext, event: ReplayableEvent): UpcastResult {\n const version = event.schemaVersion ?? DEFAULT_EVENT_SCHEMA_VERSION;\n\n const current: UpcastableEvent = {\n eventId: event.eventId,\n collectionId: event.collectionId,\n type: event.type,\n key: event.key,\n payload: event.payload,\n previous: event.previous ?? null,\n schemaVersion: version,\n };\n\n if (version === context.eventSchemaVersion) {\n return { status: \"ok\", event: current };\n }\n\n if (context.upcastEvent) {\n const migrated = context.upcastEvent(current);\n\n if (!migrated) {\n const reason = `upcaster dropped schema version ${version}`;\n context.log.warn(\"replay skipped: upcaster dropped event\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n schemaVersion: version,\n });\n context.emit(\"onEventSkipped\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n reason,\n });\n return { status: \"blocked\", outcome: { status: \"skipped\", reason } };\n }\n\n return { status: \"ok\", event: migrated };\n }\n\n if (version > context.eventSchemaVersion) {\n return {\n status: \"blocked\",\n outcome: unresolvable(\n context,\n event,\n `event schema version ${version} is newer than supported version ${context.eventSchemaVersion}`,\n {},\n ),\n };\n }\n\n context.log.warn(\"replaying older event schema version without an upcaster\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n schemaVersion: version,\n currentVersion: context.eventSchemaVersion,\n });\n\n return { status: \"ok\", event: current };\n}\n\nfunction unresolvable(\n context: ReplayContext,\n event: ReplayableEvent,\n reason: string,\n details: Record<string, unknown>,\n): ReplayOutcome {\n const halt = context.unknownEventHandling === \"fail\";\n\n context.log.warn(halt ? \"replay halted\" : \"replay skipped\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n type: event.type,\n key: event.key,\n reason,\n ...details,\n });\n\n if (halt) return { status: \"halted\", reason };\n\n context.emit(\"onEventSkipped\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n reason,\n });\n\n return { status: \"skipped\", reason };\n}\n\n/**\n * What to do after a replay threw: come back to it next sync, or give up and\n * park it in the dead-letter queue.\n */\nexport type ReplayFailureResolution = \"retry\" | \"deadLettered\";\n\n/**\n * Records a failed replay against its inbox row and, once the attempt budget is\n * spent, moves the event to the dead-letter queue and resolves the inbox row so\n * the cursor can advance past it. Otherwise a single event the local schema\n * cannot accept blocks every event behind it, permanently.\n */\nexport async function handleReplayFailure(\n context: ReplayContext,\n inbox: Collection<InboxEntry, string>,\n event: ReplayableEvent,\n error: Error,\n now: number,\n): Promise<ReplayFailureResolution> {\n const { deadletter, maxReplayAttempts, log } = context;\n const existing = inbox.get(event.eventId);\n const attemptCount = (existing?.attemptCount ?? 0) + 1;\n\n if (existing) {\n await inbox.update(event.eventId, (draft) => {\n draft.attemptCount = attemptCount;\n draft.lastError = error.message;\n }).isPersisted.promise;\n }\n\n if (attemptCount < maxReplayAttempts) {\n log.warn(\"replay failed; retrying on a later sync\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n attemptCount,\n maxReplayAttempts,\n message: error.message,\n });\n\n return \"retry\";\n }\n\n const reason = `replay failed after ${attemptCount} attempts: ${error.message}`;\n\n if (!deadletter.has(event.eventId)) {\n const record: DeadLetterEntry = {\n eventId: event.eventId,\n collectionId: event.collectionId,\n type: event.type,\n key: event.key,\n payload: event.payload,\n previous: event.previous ?? null,\n txId: null,\n clientId: existing?.clientId ?? null,\n schemaVersion: event.schemaVersion ?? DEFAULT_EVENT_SCHEMA_VERSION,\n timestamp: existing?.timestamp ?? now,\n localSeq: null,\n globalSeq: event.globalSeq ?? null,\n direction: \"inbound\",\n reason: \"replayFailed\",\n message: error.message,\n code: null,\n attemptCount,\n failedAt: now,\n };\n\n await deadletter.insert(record).isPersisted.promise;\n context.emit(\"onDeadLetter\", record);\n }\n\n if (existing) {\n await resolveInboxEntry(inbox, event.eventId, { status: \"skipped\", reason });\n }\n\n log.warn(\"inbound event dead-lettered\", {\n eventId: event.eventId,\n collectionId: event.collectionId,\n attemptCount,\n message: error.message,\n });\n\n return \"deadLettered\";\n}\n\n/**\n * Marks an inbox row as resolved — either applied or deliberately skipped.\n * Skipped rows still count as resolved so the pull cursor can move past them.\n */\nexport async function resolveInboxEntry(\n inbox: Collection<InboxEntry, string>,\n eventId: string,\n outcome: Extract<ReplayOutcome, { status: \"applied\" | \"skipped\" }>,\n): Promise<void> {\n await inbox.update(eventId, (draft) => {\n draft.sync = true;\n draft.skipped = outcome.status === \"skipped\";\n draft.skipReason = outcome.status === \"skipped\" ? outcome.reason : null;\n }).isPersisted.promise;\n}\n\nexport async function replayInbox(\n inbox: Collection<InboxEntry, string>,\n context: ReplayContext,\n): Promise<ReplaySummary> {\n const { log } = context;\n\n const pending = [...inbox.state.values()]\n .filter((entry) => !entry.sync)\n .sort((a, b) => a.globalSeq - b.globalSeq);\n\n log.info(\"pending inbox replay started\", { pendingCount: pending.length });\n\n let applied = 0;\n let skipped = 0;\n let deadLettered = 0;\n\n for (const entry of pending) {\n const outcome = await replayEvent(context, entry);\n\n if (outcome.status === \"halted\") break;\n\n if (outcome.status === \"failed\") {\n const resolution = await handleReplayFailure(\n context,\n inbox,\n entry,\n outcome.error,\n Date.now(),\n );\n\n // Still retryable: stop here so events stay in order until it resolves.\n if (resolution === \"retry\") break;\n\n deadLettered++;\n continue;\n }\n\n await resolveInboxEntry(inbox, entry.eventId, outcome);\n\n if (outcome.status === \"skipped\") {\n skipped++;\n continue;\n }\n\n applied++;\n\n log.info(\"pending inbox replay applied\", {\n eventId: entry.eventId,\n globalSeq: entry.globalSeq,\n collectionId: entry.collectionId,\n });\n }\n\n log.info(\"pending inbox replay finished\", { applied, skipped, deadLettered });\n\n return { applied, skipped, deadLettered };\n}\n","import type { Collection } from \"@tanstack/db\";\n\nimport type { InboxEntry, SyncMetaEntry } from \"../core/types\";\nimport { SYNCMETA_KEY } from \"./constants\";\n\nconst EMPTY: SyncMetaEntry = {\n id: SYNCMETA_KEY,\n backendId: null,\n clientId: null,\n pullCursor: 0,\n lastSyncAt: null,\n lastError: null,\n};\n\nexport function readSyncMeta(syncmeta: Collection<SyncMetaEntry, string>): SyncMetaEntry {\n return syncmeta.get(SYNCMETA_KEY) ?? EMPTY;\n}\n\nexport async function ensureSyncMeta(syncmeta: Collection<SyncMetaEntry, string>): Promise<void> {\n if (syncmeta.has(SYNCMETA_KEY)) return;\n await syncmeta.insert({ ...EMPTY }).isPersisted.promise;\n}\n\nasync function patch(\n syncmeta: Collection<SyncMetaEntry, string>,\n apply: (draft: SyncMetaEntry) => void,\n): Promise<void> {\n await ensureSyncMeta(syncmeta);\n await syncmeta.update(SYNCMETA_KEY, apply).isPersisted.promise;\n}\n\nexport function readBackendId(syncmeta: Collection<SyncMetaEntry, string>): string | null {\n return readSyncMeta(syncmeta).backendId;\n}\n\n/**\n * Resolves this device's identity, persisting it on first run so it survives\n * reloads. Without that, a client stops recognising its own pulled-back events\n * as soon as the outbox is pruned and will replay its own history as if it were\n * someone else's.\n *\n * Preference: explicit `configured` id, then the stored `syncmeta.clientId`,\n * then `generate()`.\n *\n * @example First open generates and stores an id; the next open reuses it\n * ```ts\n * import { resolveClientId } from \"./sync-meta\"\n *\n * const clientId = await resolveClientId(\n * db.collections.syncmeta,\n * undefined,\n * () => crypto.randomUUID(),\n * )\n * // later, after close + reopen on the same file:\n * const again = await resolveClientId(db.collections.syncmeta, undefined, () => {\n * throw new Error(\"should not generate a second id\")\n * })\n * // again === clientId\n * ```\n */\nexport async function resolveClientId(\n syncmeta: Collection<SyncMetaEntry, string>,\n configured: string | undefined,\n generate: () => string,\n): Promise<string> {\n const stored = readSyncMeta(syncmeta).clientId ?? null;\n const clientId = configured ?? stored ?? generate();\n\n if (stored !== clientId) {\n await patch(syncmeta, (draft) => {\n draft.clientId = clientId;\n });\n }\n\n return clientId;\n}\n\n/**\n * The cursor lives in `syncmeta` so the inbox can be pruned freely. Older\n * databases predate that row, so fall back to the highest resolved inbox\n * sequence and let the first successful pull persist it.\n *\n * @example\n * ```ts\n * import { readPullCursor } from \"./sync-meta\"\n *\n * const since = readPullCursor(db.collections.syncmeta, db.collections.inbox)\n * const page = await transport.pull(since)\n * ```\n */\nexport function readPullCursor(\n syncmeta: Collection<SyncMetaEntry, string>,\n inbox: Collection<InboxEntry, string>,\n): number {\n let cursor = readSyncMeta(syncmeta).pullCursor;\n\n for (const entry of inbox.state.values()) {\n if (entry.sync && entry.globalSeq > cursor) cursor = entry.globalSeq;\n }\n\n return cursor;\n}\n\nexport async function writePullCursor(\n syncmeta: Collection<SyncMetaEntry, string>,\n cursor: number,\n): Promise<void> {\n await patch(syncmeta, (draft) => {\n draft.pullCursor = cursor;\n });\n}\n\nexport async function writeBackendId(\n syncmeta: Collection<SyncMetaEntry, string>,\n backendId: string,\n): Promise<void> {\n await patch(syncmeta, (draft) => {\n draft.backendId = backendId;\n });\n}\n\nexport async function writeSyncOutcome(\n syncmeta: Collection<SyncMetaEntry, string>,\n lastSyncAt: number,\n lastError: string | null,\n): Promise<void> {\n await patch(syncmeta, (draft) => {\n draft.lastSyncAt = lastSyncAt;\n draft.lastError = lastError;\n });\n}\n","import type { Collection } from \"@tanstack/db\";\n\nimport type { NormalizedSyncTransport } from \"../core/sync\";\nimport type {\n BackendMismatchPolicy,\n InboxEntry,\n OutboxEntry,\n ServerEvent,\n SyncMetaEntry,\n} from \"../core/types\";\nimport { DEFAULT_EVENT_SCHEMA_VERSION } from \"./constants\";\nimport { handleReplayFailure, replayEvent, resolveInboxEntry } from \"./replay\";\nimport { readBackendId, readPullCursor, writeBackendId, writePullCursor } from \"./sync-meta\";\nimport type { ReplayContext } from \"./types\";\n\nexport type PullOutcome = {\n pulled: number;\n skipped: number;\n deadLettered: number;\n /** Outbox events put back in the queue by a backend reset, awaiting a push. */\n requeued: number;\n};\n\n/**\n * Thrown when `backendMismatch` is `\"fail\"` and the server reports a different\n * `backendId` than this client last synced with (wiped or swapped event store).\n *\n * @example\n * ```ts\n * import { BackendMismatchError } from \"event-sourced-collection\"\n *\n * const result = await db.sync()\n * const mismatch = result.errors.find((error) => error instanceof BackendMismatchError)\n * if (mismatch) {\n * console.error(\"backend changed\", mismatch.expected, mismatch.received)\n * }\n * ```\n */\nexport class BackendMismatchError extends Error {\n constructor(\n readonly expected: string | null,\n readonly received: string,\n ) {\n super(\n `Sync backend identity changed (was \"${expected ?? \"unknown\"}\", now \"${received}\"). ` +\n `The local pull cursor no longer refers to this backend.`,\n );\n this.name = \"BackendMismatchError\";\n }\n}\n\nexport type PullArgs = {\n outbox: Collection<OutboxEntry, string>;\n inbox: Collection<InboxEntry, string>;\n syncmeta: Collection<SyncMetaEntry, string>;\n pull: NonNullable<NormalizedSyncTransport[\"pull\"]>;\n clientId: string;\n pullOverlap: number;\n /** When false, local-origin pulls advance the cursor without inbox rows. */\n recordLocalEchoes: boolean;\n backendMismatch: BackendMismatchPolicy;\n context: ReplayContext;\n};\n\nexport async function pullInbox(args: PullArgs): Promise<PullOutcome> {\n const { outbox, inbox, syncmeta, pull, clientId, pullOverlap, recordLocalEchoes, context } =\n args;\n const { log } = context;\n\n let pulled = 0;\n let skipped = 0;\n let deadLettered = 0;\n let requeued = 0;\n let hasMore = true;\n let cursor = Math.max(0, readPullCursor(syncmeta, inbox) - pullOverlap);\n let identityChecked = false;\n\n while (hasMore) {\n log.debug(\"pull inbox page\", { since: cursor });\n\n const response = await pull(cursor);\n\n log.debug(\"pull inbox response\", {\n since: cursor,\n eventCount: response.events.length,\n hasMore: response.hasMore,\n cursor: response.cursor,\n backendId: response.backendId,\n });\n\n if (!identityChecked && response.backendId !== undefined) {\n identityChecked = true;\n\n const reconciled = await reconcileBackendIdentity(args, response.backendId);\n if (reconciled.reset) {\n requeued += reconciled.requeued;\n cursor = 0;\n continue;\n }\n }\n\n if (response.events.length === 0) break;\n\n const sorted = [...response.events].sort((a, b) => a.globalSeq - b.globalSeq);\n let halted = false;\n\n for (const event of sorted) {\n if (isLocalOrigin(event, outbox, clientId)) {\n if (recordLocalEchoes) {\n await markInboxEventResolved(inbox, event);\n }\n\n log.debug(\"pull skipped: event originated locally\", {\n eventId: event.eventId,\n globalSeq: event.globalSeq,\n recorded: recordLocalEchoes,\n });\n continue;\n }\n\n const existing = inbox.get(event.eventId);\n if (existing?.sync) {\n log.debug(\"pull skipped: inbox already resolved\", {\n eventId: event.eventId,\n globalSeq: event.globalSeq,\n });\n continue;\n }\n\n if (!existing) {\n await inbox.insert(toInboxEntry(event, false)).isPersisted.promise;\n log.debug(\"inbox entry inserted\", {\n eventId: event.eventId,\n globalSeq: event.globalSeq,\n collectionId: event.collectionId,\n });\n }\n\n const outcome = await replayEvent(context, event);\n\n if (outcome.status === \"halted\") {\n halted = true;\n break;\n }\n\n if (outcome.status === \"failed\") {\n const resolution = await handleReplayFailure(\n context,\n inbox,\n event,\n outcome.error,\n Date.now(),\n );\n\n if (resolution === \"retry\") {\n halted = true;\n break;\n }\n\n deadLettered++;\n continue;\n }\n\n await resolveInboxEntry(inbox, event.eventId, outcome);\n\n if (outcome.status === \"skipped\") {\n skipped++;\n continue;\n }\n\n log.info(\"pull replay applied\", {\n eventId: event.eventId,\n globalSeq: event.globalSeq,\n collectionId: event.collectionId,\n type: event.type,\n key: event.key,\n });\n\n pulled++;\n }\n\n // Leaving the cursor where it is means the halted event is retried on the\n // next sync rather than being stepped over.\n if (halted) break;\n\n const nextCursor = resolveNextCursor(cursor, sorted, response.cursor);\n\n if (nextCursor <= cursor) {\n log.warn(\"pull stopped: cursor did not advance\", {\n cursor,\n nextCursor,\n eventCount: sorted.length,\n });\n break;\n }\n\n cursor = nextCursor;\n await writePullCursor(syncmeta, cursor);\n hasMore = response.hasMore;\n }\n\n log.info(\"pull inbox finished\", { pulled, skipped, deadLettered, requeued, cursor });\n\n return { pulled, skipped, deadLettered, requeued };\n}\n\ntype ReconcileOutcome = { reset: false } | { reset: true; requeued: number };\n\n/**\n * Detects a wiped or swapped backend. Reports `reset` when the caller should\n * restart the pull from zero.\n */\nasync function reconcileBackendIdentity(\n args: PullArgs,\n received: string,\n): Promise<ReconcileOutcome> {\n const { syncmeta, inbox, backendMismatch, context } = args;\n const { log } = context;\n\n const stored = readBackendId(syncmeta);\n\n if (stored === received) return { reset: false };\n\n if (stored === null) {\n await writeBackendId(syncmeta, received);\n log.info(\"sync backend identity recorded\", { backendId: received });\n return { reset: false };\n }\n\n context.emit(\"onBackendMismatch\", {\n expected: stored,\n received,\n policy: backendMismatch,\n });\n\n if (backendMismatch === \"fail\") {\n throw new BackendMismatchError(stored, received);\n }\n\n if (backendMismatch === \"ignore\") {\n log.warn(\"sync backend identity changed; ignoring per configuration\", {\n expected: stored,\n received,\n });\n return { reset: false };\n }\n\n log.warn(\"sync backend identity changed; resetting pull cursor\", {\n expected: stored,\n received,\n });\n\n for (const entry of inbox.state.values()) {\n await inbox.delete(entry.eventId).isPersisted.promise;\n }\n\n const requeued = await requeueSyncedOutbox(args.outbox);\n\n await writeBackendId(syncmeta, received);\n await writePullCursor(syncmeta, 0);\n\n log.info(\"sync backend identity reset complete\", {\n backendId: received,\n inboxCleared: true,\n outboxRequeued: requeued,\n });\n\n return { reset: true, requeued };\n}\n\n/**\n * Marks previously confirmed outbox events as pending again. The new backend\n * has never seen them, so without this the client keeps local rows it believes\n * are safely synced and never uploads them again. Servers deduplicate by\n * `eventId`, so re-pushing to a *restored* backend is a no-op.\n *\n * `baseVersion` is cleared because it refers to event ids from the old\n * backend's history, which the new one cannot resolve.\n */\nasync function requeueSyncedOutbox(outbox: Collection<OutboxEntry, string>): Promise<number> {\n const synced = [...outbox.state.values()].filter((entry) => entry.sync);\n\n for (const entry of synced) {\n await outbox.update(entry.eventId, (draft) => {\n draft.sync = false;\n draft.syncStatus = \"pending\";\n draft.globalSeq = null;\n draft.baseVersion = null;\n draft.attemptCount = 0;\n draft.nextAttemptAt = null;\n draft.lastError = null;\n draft.lastErrorCode = null;\n draft.retryable = null;\n }).isPersisted.promise;\n }\n\n return synced.length;\n}\n\nfunction isLocalOrigin(\n event: ServerEvent,\n outbox: Collection<OutboxEntry, string>,\n clientId: string,\n): boolean {\n // clientId keeps origin detection working after the outbox has been pruned.\n return outbox.has(event.eventId) || event.clientId === clientId;\n}\n\nfunction resolveNextCursor(\n cursor: number,\n events: ReadonlyArray<ServerEvent>,\n serverCursor: string | undefined,\n): number {\n let next = cursor;\n\n for (const event of events) {\n if (event.globalSeq > next) next = event.globalSeq;\n }\n\n const parsed = Number(serverCursor);\n if (serverCursor !== undefined && Number.isFinite(parsed) && parsed > next) {\n next = parsed;\n }\n\n return next;\n}\n\nasync function markInboxEventResolved(\n inbox: Collection<InboxEntry, string>,\n event: ServerEvent,\n): Promise<void> {\n const existing = inbox.get(event.eventId);\n\n if (!existing) {\n await inbox.insert(toInboxEntry(event, true)).isPersisted.promise;\n return;\n }\n\n if (!existing.sync || existing.globalSeq !== event.globalSeq) {\n await inbox.update(event.eventId, (draft) => {\n draft.globalSeq = event.globalSeq;\n draft.sync = true;\n }).isPersisted.promise;\n }\n}\n\nexport function toInboxEntry(event: ServerEvent, sync: boolean): InboxEntry {\n return {\n eventId: event.eventId,\n globalSeq: event.globalSeq,\n collectionId: event.collectionId,\n type: event.type,\n key: event.key,\n payload: event.payload,\n previous: event.previous ?? null,\n clientId: event.clientId ?? null,\n schemaVersion: event.schemaVersion ?? DEFAULT_EVENT_SCHEMA_VERSION,\n timestamp: event.timestamp,\n sync,\n skipped: false,\n skipReason: null,\n attemptCount: 0,\n lastError: null,\n };\n}\n","import type {\n OutboundEvent,\n PullEventsFn,\n PullResponse,\n PushConfirmation,\n PushEventsFn,\n PushResponse,\n SyncHandlersConfig,\n SyncTransport,\n SyncUrlConfig,\n} from \"./types\";\n\nexport type NormalizedSyncTransport = {\n push?: PushEventsFn;\n pull?: (since: number) => Promise<PullResponse>;\n};\n\ntype HeaderConfig = SyncHandlersConfig[\"headers\"];\n\n/**\n * Builds a {@link SyncTransport} that POSTs outbound events and GETs\n * `pull?since=N`. Pass this as `sync` when you already have REST endpoints.\n *\n * @example\n * ```ts\n * import { createHttpTransport } from \"event-sourced-collection\"\n * import { createBrowserEventSourcedDB } from \"event-sourced-collection/browser\"\n *\n * const sync = createHttpTransport({\n * push: \"/api/sync/events\",\n * pull: \"/api/sync/events\",\n * headers: () => ({ Authorization: `Bearer ${localStorage.getItem(\"token\") ?? \"\"}` }),\n * })\n *\n * const { ensureDb } = createBrowserEventSourcedDB({\n * databaseName: \"app.sqlite\",\n * collections: { todos: { getKey: (todo: { id: string }) => todo.id } },\n * sync,\n * modules: async () => {\n * const { createCollection } = await import(\"@tanstack/db\")\n * const persistence = await import(\"@tanstack/browser-db-sqlite-persistence\")\n * return { createCollection, ...persistence }\n * },\n * })\n * ```\n */\nexport function createHttpTransport(config: SyncUrlConfig): SyncTransport {\n return {\n push: createHttpPushEvents(config.push, config.headers),\n pull: createHttpPullEvents(config.pull, config.headers),\n };\n}\n\nexport function createSyncTransport(\n config?: SyncHandlersConfig | SyncUrlConfig | SyncTransport,\n): NormalizedSyncTransport | null {\n if (!config) {\n return null;\n }\n\n if (isTransport(config)) {\n return {\n push: config.push,\n pull: config.pull,\n };\n }\n\n const pushUrl = getPushUrl(config);\n const pullUrl = getPullUrl(config);\n\n const push =\n \"pushEvents\" in config && config.pushEvents\n ? config.pushEvents\n : pushUrl\n ? createHttpPushEvents(pushUrl, config.headers)\n : undefined;\n\n const pullEvents = \"pullEvents\" in config ? config.pullEvents : undefined;\n const pull = pullEvents\n ? createPullFromHandler(pullEvents)\n : pullUrl\n ? createHttpPullEvents(pullUrl, config.headers)\n : undefined;\n\n if (!push && !pull) {\n return null;\n }\n\n return { push, pull };\n}\n\nexport function normalizePushResponse(\n response: PushResponse | ReadonlyArray<PushConfirmation>,\n): PushResponse {\n if (isConfirmationArray(response)) {\n return { confirmed: response };\n }\n\n return {\n confirmed: response.confirmed,\n failed: response.failed,\n };\n}\n\nfunction isConfirmationArray(\n response: PushResponse | ReadonlyArray<PushConfirmation>,\n): response is ReadonlyArray<PushConfirmation> {\n return Array.isArray(response);\n}\n\nfunction createHttpPushEvents(url: string, headers: HeaderConfig): PushEventsFn {\n return async (events: ReadonlyArray<OutboundEvent>): Promise<PushResponse> => {\n if (events.length === 0) return { confirmed: [] };\n\n const resolvedHeaders = await resolveHeaders(headers);\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...resolvedHeaders },\n body: JSON.stringify(events),\n });\n\n if (!response.ok) {\n throw new SyncPushError(response.status, await response.text());\n }\n\n return response.json() as Promise<PushResponse>;\n };\n}\n\nfunction createPullFromHandler(pullEvents: PullEventsFn): (since: number) => Promise<PullResponse> {\n return (since: number) => pullEvents({ since });\n}\n\nfunction createHttpPullEvents(\n url: string,\n headers: HeaderConfig,\n): (since: number) => Promise<PullResponse> {\n return async (since: number): Promise<PullResponse> => {\n const resolvedHeaders = await resolveHeaders(headers);\n const pullUrl = appendSince(url, since);\n\n const response = await fetch(pullUrl, {\n headers: { Accept: \"application/json\", ...resolvedHeaders },\n });\n\n if (!response.ok) {\n throw new SyncPullError(response.status, await response.text());\n }\n\n return response.json() as Promise<PullResponse>;\n };\n}\n\nasync function resolveHeaders(headers: HeaderConfig): Promise<Record<string, string>> {\n if (!headers) return {};\n if (typeof headers === \"function\") return headers();\n return headers;\n}\n\nfunction appendSince(url: string, since: number): string {\n const separator = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${separator}since=${encodeURIComponent(String(since))}`;\n}\n\nfunction getPushUrl(config: SyncHandlersConfig | SyncUrlConfig): string | undefined {\n if (\"pushUrl\" in config && config.pushUrl) {\n return config.pushUrl;\n }\n\n if (\"push\" in config && typeof config.push === \"string\") {\n return config.push;\n }\n\n return undefined;\n}\n\nfunction getPullUrl(config: SyncHandlersConfig | SyncUrlConfig): string | undefined {\n if (\"pullUrl\" in config && config.pullUrl) {\n return config.pullUrl;\n }\n\n if (\"pull\" in config && typeof config.pull === \"string\") {\n return config.pull;\n }\n\n return undefined;\n}\n\n/**\n * Thrown when the HTTP push endpoint returns a non-OK status.\n *\n * @example\n * ```ts\n * import { createHttpTransport, SyncPushError } from \"event-sourced-collection\"\n *\n * const sync = createHttpTransport({\n * push: \"/api/sync/events\",\n * pull: \"/api/sync/events\",\n * })\n *\n * try {\n * await sync.push(events)\n * } catch (error) {\n * if (error instanceof SyncPushError) {\n * console.error(error.status, error.body)\n * }\n * }\n * ```\n */\nexport class SyncPushError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: string,\n ) {\n super(`Event push failed: HTTP ${status}`);\n this.name = \"SyncPushError\";\n }\n}\n\n/**\n * Thrown when the HTTP pull endpoint returns a non-OK status.\n *\n * @example\n * ```ts\n * import { createHttpTransport, SyncPullError } from \"event-sourced-collection\"\n *\n * const sync = createHttpTransport({\n * push: \"/api/sync/events\",\n * pull: \"/api/sync/events\",\n * })\n *\n * try {\n * await sync.pull(0)\n * } catch (error) {\n * if (error instanceof SyncPullError) {\n * console.error(error.status, error.body)\n * }\n * }\n * ```\n */\nexport class SyncPullError extends Error {\n constructor(\n public readonly status: number,\n public readonly body: string,\n ) {\n super(`Event pull failed: HTTP ${status}`);\n this.name = \"SyncPullError\";\n }\n}\n\nexport function isTransport(\n value: SyncHandlersConfig | SyncUrlConfig | SyncTransport,\n): value is SyncTransport {\n return \"push\" in value && typeof value.push === \"function\";\n}\n","import type { Collection } from \"@tanstack/db\";\n\nimport type { NormalizedSyncTransport } from \"../core/sync\";\nimport { normalizePushResponse } from \"../core/sync\";\nimport type {\n DeadLetterEntry,\n DeadLetterReason,\n OutboundEvent,\n OutboxEntry,\n PushConfirmation,\n PushFailure,\n RowVersionEntry,\n} from \"../core/types\";\nimport type { EventSourcedLogger } from \"../utils/logger\";\nimport {\n CONFLICT_ERROR_CODE,\n DEFAULT_EVENT_SCHEMA_VERSION,\n PAYLOAD_TOO_LARGE_ERROR_CODE,\n} from \"./constants\";\nimport type { EmitHook } from \"./hooks\";\nimport { restoreRowVersionAfterConflict } from \"./replay\";\nimport type { ResolvedRetryConfig } from \"./types\";\n\nexport type PushOutcome = {\n pushed: number;\n deadLettered: number;\n /**\n * Set when a batch failed at the transport level. Reported rather than thrown\n * so the counts from batches that already succeeded are not lost.\n */\n error?: Error;\n};\n\nexport type PushArgs = {\n outbox: Collection<OutboxEntry, string>;\n deadletter: Collection<DeadLetterEntry, string>;\n rowversions: Collection<RowVersionEntry, string>;\n push: NonNullable<NormalizedSyncTransport[\"push\"]>;\n batchSize: number;\n /** JSON byte cap per request; `null` means unlimited. */\n maxBytes: number | null;\n retry: ResolvedRetryConfig;\n now: number;\n emit: EmitHook;\n log: EventSourcedLogger;\n};\n\n/**\n * Backoff for attempt N, doubling from `baseDelayMs` and capped at `maxDelayMs`.\n * Deliberately jitter-free so retry scheduling stays reproducible in tests; if\n * you have many clients hitting one server, add jitter in your push handler.\n */\nexport function backoffDelay(attemptCount: number, retry: ResolvedRetryConfig): number {\n const exponent = Math.max(0, attemptCount - 1);\n const raw = retry.baseDelayMs * 2 ** exponent;\n return Math.min(retry.maxDelayMs, raw);\n}\n\nfunction isDue(entry: OutboxEntry, now: number): boolean {\n if (entry.sync) return false;\n // A permanent rejection is dead-lettered rather than parked, so anything still\n // marked failed here is retryable and just waiting for its backoff window.\n if (entry.syncStatus === \"failed\" && entry.retryable !== true) return false;\n return (entry.nextAttemptAt ?? 0) <= now;\n}\n\nfunction byLocalSeq(a: OutboxEntry, b: OutboxEntry): number {\n if (a.localSeq !== b.localSeq) return a.localSeq - b.localSeq;\n // localSeq can collide across tabs; eventId is a uuidv7 so it breaks the tie\n // in creation order.\n return a.eventId < b.eventId ? -1 : a.eventId > b.eventId ? 1 : 0;\n}\n\nexport function toOutboundEvent(entry: OutboxEntry): OutboundEvent {\n return {\n eventId: entry.eventId,\n collectionId: entry.collectionId,\n type: entry.type,\n key: entry.key,\n payload: entry.payload,\n previous: entry.previous ?? null,\n txId: entry.txId,\n clientId: entry.clientId,\n // Rows written before these fields existed are still in persisted outboxes.\n schemaVersion: entry.schemaVersion ?? DEFAULT_EVENT_SCHEMA_VERSION,\n baseVersion: entry.baseVersion ?? null,\n timestamp: entry.timestamp,\n };\n}\n\nexport async function deadLetter(\n deadletter: Collection<DeadLetterEntry, string>,\n outbox: Collection<OutboxEntry, string>,\n entry: OutboxEntry,\n reason: DeadLetterReason,\n message: string,\n code: string | null,\n now: number,\n emit: EmitHook,\n log: EventSourcedLogger,\n rowversions?: Collection<RowVersionEntry, string>,\n): Promise<void> {\n const record: DeadLetterEntry = {\n eventId: entry.eventId,\n collectionId: entry.collectionId,\n type: entry.type,\n key: entry.key,\n payload: entry.payload,\n previous: entry.previous ?? null,\n txId: entry.txId,\n clientId: entry.clientId,\n schemaVersion: entry.schemaVersion ?? DEFAULT_EVENT_SCHEMA_VERSION,\n baseVersion: entry.baseVersion ?? null,\n timestamp: entry.timestamp,\n localSeq: entry.localSeq,\n globalSeq: entry.globalSeq ?? null,\n direction: \"outbound\",\n reason,\n message,\n code,\n attemptCount: entry.attemptCount,\n failedAt: now,\n };\n\n if (!deadletter.has(entry.eventId)) {\n await deadletter.insert(record).isPersisted.promise;\n }\n\n if (outbox.has(entry.eventId)) {\n await outbox.delete(entry.eventId).isPersisted.promise;\n }\n\n if (reason === \"conflict\" && rowversions) {\n await restoreRowVersionAfterConflict(\n rowversions,\n entry.collectionId,\n entry.key,\n entry.baseVersion ?? null,\n );\n }\n\n log.warn(\"event dead-lettered\", {\n eventId: entry.eventId,\n collectionId: entry.collectionId,\n reason,\n message,\n code,\n attemptCount: entry.attemptCount,\n });\n\n emit(\"onDeadLetter\", record);\n}\n\n/** All events of one transaction, plus the JSON bytes they add to a request body. */\ntype TxGroup = { entries: OutboxEntry[]; bytes: number };\n\ntype Batch = { groups: TxGroup[]; count: number; bytes: number };\n\nconst utf8 = new TextEncoder();\n\nfunction jsonBytes(entry: OutboxEntry): number {\n return utf8.encode(JSON.stringify(toOutboundEvent(entry))).length;\n}\n\n/** Events are ordered by localSeq, so one transaction's events are adjacent. */\nfunction groupByTransaction(events: ReadonlyArray<OutboxEntry>, measure: boolean): TxGroup[] {\n const groups: TxGroup[] = [];\n\n for (let index = 0; index < events.length;) {\n const txId = events[index]!.txId;\n const group: TxGroup = { entries: [], bytes: 0 };\n\n while (index < events.length && events[index]!.txId === txId) {\n const entry = events[index]!;\n group.entries.push(entry);\n // +1 for the comma (or the array bracket) separating it from its neighbour.\n if (measure) group.bytes += jsonBytes(entry) + 1;\n index++;\n }\n\n groups.push(group);\n }\n\n return groups;\n}\n\n/**\n * Packs transaction groups into batches of at most `size` events and\n * `maxBytes` of JSON, never separating events that share a `txId`: the server\n * commits each transaction atomically, which it cannot do if we deliver half\n * of one now and half later. A transaction with more than `size` events is\n * sent whole; one larger than `maxBytes` is returned in `oversized` instead.\n */\nfunction packBatches(\n groups: ReadonlyArray<TxGroup>,\n size: number,\n maxBytes: number | null,\n): { batches: Batch[]; oversized: TxGroup[] } {\n const batches: Batch[] = [];\n const oversized: TxGroup[] = [];\n let current: Batch = { groups: [], count: 0, bytes: 1 };\n\n const close = () => {\n if (current.count > 0) batches.push(current);\n current = { groups: [], count: 0, bytes: 1 };\n };\n\n for (const group of groups) {\n if (maxBytes !== null && group.bytes + 1 > maxBytes) {\n oversized.push(group);\n continue;\n }\n\n const overCount = current.count + group.entries.length > size;\n const overBytes = maxBytes !== null && current.bytes + group.bytes > maxBytes;\n if (current.count > 0 && (overCount || overBytes)) close();\n\n current.groups.push(group);\n current.count += group.entries.length;\n current.bytes += group.bytes;\n\n if (current.count >= size) close();\n }\n\n close();\n return { batches, oversized };\n}\n\nfunction isPayloadTooLarge(err: unknown): boolean {\n return (\n typeof err === \"object\" &&\n err !== null &&\n \"status\" in err &&\n err.status === 413\n );\n}\n\ntype PostResult = {\n confirmed: PushConfirmation[];\n failed: PushFailure[];\n /** Transactions the server would not accept even when sent alone. */\n tooLarge: OutboxEntry[];\n /** Left unsent because the transport failed; `error` says why. */\n unsent: OutboxEntry[];\n error?: unknown;\n};\n\n/**\n * Posts `groups` as one request. On HTTP 413 the request is halved along\n * transaction boundaries and each half posted in turn, down to a single\n * transaction, so one oversized event cannot hold the rest hostage.\n */\nasync function postGroups(\n push: PushArgs[\"push\"],\n groups: ReadonlyArray<TxGroup>,\n log: EventSourcedLogger,\n): Promise<PostResult> {\n const entries = groups.flatMap((group) => group.entries);\n\n try {\n const response = normalizePushResponse(await push(entries.map(toOutboundEvent)));\n return {\n confirmed: [...response.confirmed],\n failed: [...(response.failed ?? [])],\n tooLarge: [],\n unsent: [],\n };\n } catch (err) {\n if (!isPayloadTooLarge(err)) {\n return { confirmed: [], failed: [], tooLarge: [], unsent: entries, error: err };\n }\n\n if (groups.length === 1) {\n log.warn(\"push transaction too large for the server\", { events: entries.length });\n return { confirmed: [], failed: [], tooLarge: entries, unsent: [] };\n }\n\n const middle = Math.ceil(groups.length / 2);\n log.info(\"push batch hit HTTP 413, splitting\", {\n groups: groups.length,\n events: entries.length,\n });\n\n const first = await postGroups(push, groups.slice(0, middle), log);\n if (first.error !== undefined) {\n const rest = groups.slice(middle).flatMap((group) => group.entries);\n return { ...first, unsent: [...first.unsent, ...rest] };\n }\n\n const second = await postGroups(push, groups.slice(middle), log);\n return {\n confirmed: [...first.confirmed, ...second.confirmed],\n failed: [...first.failed, ...second.failed],\n tooLarge: [...first.tooLarge, ...second.tooLarge],\n unsent: second.unsent,\n error: second.error,\n };\n }\n}\n\nasync function deadLetterTooLarge(\n args: PushArgs,\n entries: ReadonlyArray<OutboxEntry>,\n message: string,\n): Promise<number> {\n for (const entry of entries) {\n await deadLetter(\n args.deadletter,\n args.outbox,\n entry,\n \"rejected\",\n message,\n PAYLOAD_TOO_LARGE_ERROR_CODE,\n args.now,\n args.emit,\n args.log,\n args.rowversions,\n );\n }\n return entries.length;\n}\n\n/**\n * Pushes due outbox events in batches limited by event count and JSON bytes.\n * Each batch's result is persisted before the next is sent, so a failure\n * part-way through keeps the progress already made instead of restarting.\n */\nexport async function pushOutbox(args: PushArgs): Promise<PushOutcome> {\n const { outbox, push, batchSize, maxBytes, now, log } = args;\n\n const due = [...outbox.state.values()].filter((entry) => isDue(entry, now)).sort(byLocalSeq);\n\n log.debug(\"push outbox\", { dueCount: due.length, batchSize, maxBytes });\n\n if (due.length === 0) return { pushed: 0, deadLettered: 0 };\n\n const { batches, oversized } = packBatches(\n groupByTransaction(due, maxBytes !== null),\n batchSize,\n maxBytes,\n );\n\n let pushed = 0;\n let deadLettered = 0;\n\n for (const group of oversized) {\n deadLettered += await deadLetterTooLarge(\n args,\n group.entries,\n `Transaction is ${group.bytes} bytes, over maxPushBytes (${maxBytes})`,\n );\n }\n\n for (const batch of batches) {\n const attempted: OutboxEntry[] = [];\n\n for (const group of batch.groups) {\n for (const entry of group.entries) {\n const attemptCount = (entry.attemptCount ?? 0) + 1;\n\n await outbox.update(entry.eventId, (draft) => {\n draft.syncStatus = \"pending\";\n draft.attemptCount = attemptCount;\n draft.lastAttemptAt = now;\n draft.nextAttemptAt = null;\n draft.lastError = null;\n draft.lastErrorCode = null;\n draft.retryable = null;\n }).isPersisted.promise;\n\n attempted.push({ ...entry, attemptCount });\n }\n }\n\n const byId = new Map(attempted.map((entry) => [entry.eventId, entry]));\n const attemptedGroups = batch.groups.map((group) => ({\n bytes: group.bytes,\n entries: group.entries.map((entry) => byId.get(entry.eventId)!),\n }));\n\n const response = await postGroups(push, attemptedGroups, log);\n\n log.info(\"push batch confirmed\", {\n sent: attempted.length,\n bytes: batch.bytes,\n confirmed: response.confirmed.length,\n failed: response.failed.length,\n tooLarge: response.tooLarge.length,\n });\n\n for (const confirmation of response.confirmed) {\n if (!outbox.has(confirmation.eventId)) continue;\n\n await outbox.update(confirmation.eventId, (draft) => {\n draft.sync = true;\n draft.syncStatus = \"synced\";\n draft.globalSeq = confirmation.globalSeq;\n draft.nextAttemptAt = null;\n draft.lastError = null;\n draft.lastErrorCode = null;\n draft.retryable = null;\n }).isPersisted.promise;\n\n pushed++;\n args.emit(\"onEventPushed\", {\n eventId: confirmation.eventId,\n globalSeq: confirmation.globalSeq,\n });\n }\n\n for (const failure of response.failed) {\n const entry = byId.get(failure.eventId);\n if (!entry) continue;\n\n deadLettered += await handleFailure(args, entry, failure);\n }\n\n deadLettered += await deadLetterTooLarge(\n args,\n response.tooLarge,\n \"Server rejected the transaction as too large (HTTP 413)\",\n );\n\n if (response.error !== undefined) {\n // Transport-level failure: back off what was not acknowledged and stop.\n // Everything confirmed so far stays synced.\n deadLettered += await backoffBatch(args, response.unsent, response.error);\n const error =\n response.error instanceof Error ? response.error : new Error(String(response.error));\n log.warn(\"push stopped after transport failure\", {\n message: error.message,\n pushed,\n remaining: due.length - pushed,\n });\n return { pushed, deadLettered, error };\n }\n }\n\n return { pushed, deadLettered };\n}\n\n/** Returns 1 when the event was dead-lettered, 0 when it stays queued for retry. */\nasync function handleFailure(\n args: PushArgs,\n entry: OutboxEntry,\n failure: PushFailure,\n): Promise<number> {\n const { outbox, deadletter, rowversions, retry, now, emit, log } = args;\n const code = failure.code ?? null;\n\n if (failure.retryable !== true) {\n const reason: DeadLetterReason = code === CONFLICT_ERROR_CODE ? \"conflict\" : \"rejected\";\n await deadLetter(\n deadletter,\n outbox,\n entry,\n reason,\n failure.message,\n code,\n now,\n emit,\n log,\n rowversions,\n );\n return 1;\n }\n\n if (entry.attemptCount >= retry.maxAttempts) {\n await deadLetter(\n deadletter,\n outbox,\n entry,\n \"maxAttemptsExceeded\",\n failure.message,\n code,\n now,\n emit,\n log,\n rowversions,\n );\n return 1;\n }\n\n const delay = backoffDelay(entry.attemptCount, retry);\n\n await outbox.update(entry.eventId, (draft) => {\n draft.sync = false;\n draft.syncStatus = \"failed\";\n draft.retryable = true;\n draft.lastError = failure.message;\n draft.lastErrorCode = code;\n draft.nextAttemptAt = now + delay;\n }).isPersisted.promise;\n\n log.warn(\"push retry scheduled\", {\n eventId: entry.eventId,\n attemptCount: entry.attemptCount,\n retryInMs: delay,\n message: failure.message,\n });\n\n return 0;\n}\n\n/** Applies retry backoff to a whole batch after a transport-level failure. */\nasync function backoffBatch(\n args: PushArgs,\n batch: ReadonlyArray<OutboxEntry>,\n err: unknown,\n): Promise<number> {\n const message = err instanceof Error ? err.message : String(err);\n let deadLettered = 0;\n\n for (const entry of batch) {\n deadLettered += await handleFailure(args, entry, {\n eventId: entry.eventId,\n message,\n retryable: true,\n });\n }\n\n return deadLettered;\n}\n","import {\n DEFAULT_PUSH_BATCH_SIZE,\n MAX_PUSH_BATCH_SIZE,\n MIN_PUSH_BATCH_SIZE,\n} from \"../internal/constants\";\nimport type { SyncPushLimits, SyncPushPreset } from \"./types\";\n\n/**\n * Push limits per hosting platform. Byte caps leave headroom under the\n * platform's request body limit (Vercel functions: 4.5 MB; AWS Lambda and\n * Netlify: 6 MB) for headers and JSON size estimation drift.\n *\n * @example\n * ```ts\n * createBrowserEventSourcedDB({ ..., syncPreset: \"vercel\" })\n * ```\n */\nexport const SYNC_PUSH_PRESETS: Readonly<Record<SyncPushPreset, SyncPushLimits>> = {\n default: { pushBatchSize: DEFAULT_PUSH_BATCH_SIZE, maxPushBytes: null },\n serverless: { pushBatchSize: 25, maxPushBytes: 4_000_000 },\n vercel: { pushBatchSize: 10, maxPushBytes: 3_500_000 },\n};\n\nexport function resolvePushLimits(config: {\n syncPreset?: SyncPushPreset;\n pushBatchSize?: number;\n maxPushBytes?: number;\n}): SyncPushLimits {\n const preset = SYNC_PUSH_PRESETS[config.syncPreset ?? \"default\"];\n const size = Math.floor(config.pushBatchSize ?? preset.pushBatchSize);\n const bytes = config.maxPushBytes ?? preset.maxPushBytes;\n\n return {\n pushBatchSize: Math.min(MAX_PUSH_BATCH_SIZE, Math.max(MIN_PUSH_BATCH_SIZE, size)),\n maxPushBytes: bytes === null ? null : Math.max(1, Math.floor(bytes)),\n };\n}\n","/**\n * Serializes async work so overlapping callers run one after another instead of\n * concurrently. Used to stop two `sync()` calls from reading the same pending\n * set and pushing it twice.\n *\n * A rejected job does not stall the queue: the next caller still runs.\n *\n * @example Overlapping syncs run in order\n * ```ts\n * import { createSerialQueue } from \"./serial-queue\"\n *\n * const runExclusive = createSerialQueue()\n *\n * const first = runExclusive(async () => {\n * await pushPending()\n * return \"first\"\n * })\n * const second = runExclusive(async () => {\n * await pushPending()\n * return \"second\"\n * })\n *\n * await Promise.all([first, second]) // \"first\" finishes before \"second\" starts\n * ```\n */\nexport function createSerialQueue(): <T>(fn: () => Promise<T>) => Promise<T> {\n let tail: Promise<unknown> = Promise.resolve();\n\n return <T>(fn: () => Promise<T>): Promise<T> => {\n const result = tail.then(fn, fn);\n tail = result.catch(() => undefined);\n return result;\n };\n}\n","export type EventSourcedLogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * Structured logger used when `debug` is enabled on a DB factory.\n *\n * @example Custom sink\n * ```ts\n * import type { EventSourcedLogger } from \"event-sourced-collection\"\n *\n * const logger: EventSourcedLogger = {\n * debug: (message, data) => console.debug(message, data),\n * info: (message, data) => console.info(message, data),\n * warn: (message, data) => console.warn(message, data),\n * error: (message, data) => console.error(message, data),\n * }\n * ```\n */\nexport type EventSourcedLogger = {\n debug: (message: string, data?: Record<string, unknown>) => void;\n info: (message: string, data?: Record<string, unknown>) => void;\n warn: (message: string, data?: Record<string, unknown>) => void;\n error: (message: string, data?: Record<string, unknown>) => void;\n};\n\nconst noopLogger: EventSourcedLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\nconst LOG_PREFIX = \"[event-sourced]\";\n\n/**\n * Builds the logger used internally when you pass `debug` to a DB factory.\n * `false` / omitted is a no-op logger; `true` logs to `console`; an object is\n * used as-is.\n *\n * @example\n * ```ts\n * import { createEventSourcedLogger } from \"event-sourced-collection\"\n * import { createBrowserEventSourcedDB } from \"event-sourced-collection/browser\"\n *\n * const debug = createEventSourcedLogger(import.meta.env.DEV)\n *\n * createBrowserEventSourcedDB({\n * databaseName: \"app.sqlite\",\n * debug,\n * collections: { todos: { getKey: (todo: { id: string }) => todo.id } },\n * modules: async () => {\n * const { createCollection } = await import(\"@tanstack/db\")\n * const persistence = await import(\"@tanstack/browser-db-sqlite-persistence\")\n * return { createCollection, ...persistence }\n * },\n * })\n * ```\n */\nexport function createEventSourcedLogger(debug?: boolean | EventSourcedLogger): EventSourcedLogger {\n if (debug === undefined || debug === false) {\n return noopLogger;\n }\n\n if (typeof debug === \"object\") {\n return debug;\n }\n\n return {\n debug: (message, data) => {\n if (data === undefined) {\n console.debug(LOG_PREFIX, message);\n return;\n }\n console.debug(LOG_PREFIX, message, data);\n },\n info: (message, data) => {\n if (data === undefined) {\n console.info(LOG_PREFIX, message);\n return;\n }\n console.info(LOG_PREFIX, message, data);\n },\n warn: (message, data) => {\n if (data === undefined) {\n console.warn(LOG_PREFIX, message);\n return;\n }\n console.warn(LOG_PREFIX, message, data);\n },\n error: (message, data) => {\n if (data === undefined) {\n console.error(LOG_PREFIX, message);\n return;\n }\n console.error(LOG_PREFIX, message, data);\n },\n };\n}\n","import { uuidv7 } from \"uuidv7\";\n\n/**\n * Time-ordered event id (UUIDv7). Used as `eventId` on outbox rows and as the\n * default device `clientId` when you do not pass one.\n *\n * @example\n * ```ts\n * import { generateEventId } from \"event-sourced-collection\"\n *\n * const eventId = generateEventId()\n * const clientId = generateEventId()\n * ```\n */\nexport function generateEventId(): string {\n return uuidv7();\n}\n","import type { Collection } from \"@tanstack/db\";\n\nimport {\n DEADLETTER_ID,\n DEFAULT_BASE_DELAY_MS,\n DEFAULT_EVENT_SCHEMA_VERSION,\n DEFAULT_MAX_ATTEMPTS,\n DEFAULT_MAX_DELAY_MS,\n INBOX_ID,\n OUTBOX_ID,\n RESERVED_IDS,\n ROWVERSIONS_ID,\n SYNCMETA_ID,\n SYNC_LOCK_PREFIX,\n} from \"../internal/constants\";\nimport { createHookEmitter } from \"../internal/hooks\";\nimport type { EmitHook } from \"../internal/hooks\";\nimport { pullInbox } from \"../internal/pull\";\nimport { pushOutbox, toOutboundEvent } from \"../internal/push\";\nimport { resolvePushLimits } from \"./sync-presets\";\nimport { readRowVersion, recordRowVersion, replayInbox } from \"../internal/replay\";\nimport { createSerialQueue } from \"../internal/serial-queue\";\nimport {\n ensureSyncMeta,\n readPullCursor,\n readSyncMeta,\n resolveClientId,\n writePullCursor,\n writeSyncOutcome,\n} from \"../internal/sync-meta\";\nimport type {\n AcceptMutationsCollection,\n MetaCollections,\n MutationHookParams,\n ReplayContext,\n ResolvedRetryConfig,\n} from \"../internal/types\";\nimport { createSyncTransport, normalizePushResponse } from \"./sync\";\nimport type {\n CollectionMap,\n DeadLetterEntry,\n EventSourcedDB,\n EventSourcedDBConfig,\n InboxEntry,\n ManualSyncResult,\n MutationType,\n OutboundEvent,\n OutboxEntry,\n PruneOptions,\n PruneResult,\n RowVersionEntry,\n SyncMetaEntry,\n SyncResult,\n SyncStatus,\n SyncTrigger,\n} from \"./types\";\nimport type { EventSourcedLogger } from \"../utils/logger\";\nimport { createEventSourcedLogger } from \"../utils/logger\";\nimport { generateEventId } from \"../utils/uuid\";\n\ntype CollectionDefConstraint = {\n getKey: (state: never) => string | number;\n schemaVersion?: number;\n indexes?: ReadonlyArray<{\n select: (row: never) => unknown;\n name?: string;\n indexType?: new (id: number, expression: never, name?: string, options?: never) => unknown;\n }>;\n};\n\ntype SeqCounter = { value: number };\n\n/**\n * Lets the mutation hooks, which are built before `syncmeta` has been\n * preloaded, read the persisted client id once it is known.\n */\ntype ClientIdRef = { value: string };\n\ntype MetaCollectionFactory = Pick<\n EventSourcedDBConfig<Record<string, CollectionDefConstraint>>,\n \"createCollection\" | \"persistedCollectionOptions\" | \"persistence\"\n>;\n\ntype MutationContext = {\n outbox: Collection<OutboxEntry, string>;\n rowversions: Collection<RowVersionEntry, string>;\n collectionId: string;\n type: MutationType;\n seq: SeqCounter;\n clientId: ClientIdRef;\n eventSchemaVersion: number;\n conflictDetection: boolean;\n emit: EmitHook;\n log: EventSourcedLogger;\n};\n\nfunction emptyResult(overrides: Partial<SyncResult> = {}): SyncResult {\n return {\n pushed: 0,\n pulled: 0,\n skipped: 0,\n deadLettered: 0,\n deferred: false,\n errors: [],\n ...overrides,\n };\n}\n\n/**\n * Low-level factory: wires persistence, collections, outbox/inbox, and sync.\n * Prefer a platform helper (`createBrowserEventSourcedDB`,\n * `createNodeEventSourcedDB`, `createReactNativeEventSourcedDB`) unless you are\n * supplying your own persistence.\n *\n * @param config - See {@link EventSourcedDBConfig} for every option.\n *\n * @example Node SQLite, opened immediately\n * ```ts\n * import { createCollection } from \"@tanstack/db\"\n * import {\n * createNodeSQLitePersistence,\n * persistedCollectionOptions,\n * } from \"@tanstack/node-db-sqlite-persistence\"\n * import Database from \"better-sqlite3\"\n * import { createEventSourcedDB } from \"event-sourced-collection\"\n *\n * type Todo = { id: string; title: string }\n *\n * const sqlite = new Database(\"app.sqlite\")\n * const db = await createEventSourcedDB({\n * persistence: createNodeSQLitePersistence({ database: sqlite }),\n * createCollection,\n * persistedCollectionOptions,\n * collections: {\n * todos: { getKey: (todo: Todo) => todo.id },\n * },\n * sync: {\n * push: \"/api/sync/events\",\n * pull: \"/api/sync/events\",\n * },\n * })\n *\n * await db.collections.todos.insert({ id: \"t1\", title: \"Ship\" }).isPersisted.promise\n * await db.sync()\n * ```\n */\nexport async function createEventSourcedDB<\n const TDefs extends Record<string, CollectionDefConstraint>,\n>(config: EventSourcedDBConfig<TDefs>): Promise<EventSourcedDB<TDefs>> {\n assertReservedNamesAvailable(config.collections);\n\n const log = createEventSourcedLogger(config.debug);\n const emit = createHookEmitter(config.hooks, log);\n\n const transport = createSyncTransport(config.sync);\n let syncEnabled = config.syncEnabled ?? true;\n\n // Provisional until `syncmeta` is preloaded and the persisted id is known.\n const clientId: ClientIdRef = { value: config.clientId ?? generateEventId() };\n const unknownEventHandling = config.unknownEventHandling ?? \"skip\";\n const pullOverlap = Math.max(0, config.pullOverlap ?? 0);\n const recordLocalEchoes = config.recordLocalEchoes ?? true;\n const eventSchemaVersion = config.eventSchemaVersion ?? DEFAULT_EVENT_SCHEMA_VERSION;\n const { pushBatchSize, maxPushBytes } = resolvePushLimits(config);\n const backendMismatch = config.backendMismatch ?? \"resetCursor\";\n const conflictDetection = config.conflictDetection ?? false;\n const lockName = `${SYNC_LOCK_PREFIX}:${config.lockName ?? \"default\"}`;\n\n const retry: ResolvedRetryConfig = {\n maxAttempts: Math.max(1, config.retry?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS),\n baseDelayMs: Math.max(0, config.retry?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS),\n maxDelayMs: Math.max(0, config.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS),\n };\n\n log.info(\"creating event-sourced db\", {\n collectionIds: Object.keys(config.collections),\n hasTransport: transport !== null,\n hasLock: Boolean(config.lock),\n syncEnabled,\n unknownEventHandling,\n pullOverlap,\n recordLocalEchoes,\n pushBatchSize,\n maxPushBytes,\n backendMismatch,\n conflictDetection,\n eventSchemaVersion,\n });\n\n const defaultSchemaVersion = config.schemaVersion ?? 1;\n const seq: SeqCounter = { value: 0 };\n\n const meta: MetaCollections = {\n outbox: createMetaCollection<OutboxEntry>(\n config,\n OUTBOX_ID,\n (entry) => entry.eventId,\n defaultSchemaVersion,\n ),\n inbox: createMetaCollection<InboxEntry>(\n config,\n INBOX_ID,\n (entry) => entry.eventId,\n defaultSchemaVersion,\n ),\n deadletter: createMetaCollection<DeadLetterEntry>(\n config,\n DEADLETTER_ID,\n (entry) => entry.eventId,\n defaultSchemaVersion,\n ),\n syncmeta: createMetaCollection<SyncMetaEntry>(\n config,\n SYNCMETA_ID,\n (entry) => entry.id,\n defaultSchemaVersion,\n ),\n rowversions: createMetaCollection<RowVersionEntry>(\n config,\n ROWVERSIONS_ID,\n (entry) => entry.id,\n defaultSchemaVersion,\n ),\n };\n\n const { outbox, inbox, deadletter, syncmeta, rowversions } = meta;\n const userCollections = {} as CollectionMap<TDefs>;\n\n for (const collectionId of Object.keys(config.collections)) {\n const def = config.collections[collectionId]!;\n const getKey = def.getKey as (item: Record<string, unknown>) => string | number;\n\n const mutationContext = {\n outbox,\n rowversions,\n collectionId,\n seq,\n clientId,\n eventSchemaVersion,\n conflictDetection,\n emit,\n log,\n };\n\n const options = config.persistedCollectionOptions<Record<string, unknown>, string | number>({\n id: collectionId,\n getKey,\n persistence: config.persistence,\n schemaVersion: def.schemaVersion ?? defaultSchemaVersion,\n gcTime: Number.POSITIVE_INFINITY,\n onInsert: createMutationHook({ ...mutationContext, type: \"insert\" }),\n onUpdate: createMutationHook({ ...mutationContext, type: \"update\" }),\n onDelete: createMutationHook({ ...mutationContext, type: \"delete\" }),\n });\n\n const collection = config.createCollection(options);\n applyCollectionIndexes(collection, collectionId, def.indexes, log);\n\n log.debug(\"registered collection\", {\n collectionId,\n hasAcceptMutations: Boolean((collection as AcceptMutationsCollection).utils?.acceptMutations),\n });\n\n (userCollections as Record<string, unknown>)[collectionId] = collection;\n }\n\n const collections = {\n ...(userCollections as CollectionMap<TDefs>),\n ...meta,\n } as EventSourcedDB<TDefs>[\"collections\"];\n\n const replayTargets = collections as unknown as Record<string, AcceptMutationsCollection>;\n\n let isSyncing = false;\n const statusListeners = new Set<(status: SyncStatus) => void>();\n\n const notifyStatus = (): void => {\n if (statusListeners.size === 0) return;\n const status = getSyncStatus();\n for (const listener of statusListeners) listener(status);\n };\n\n const subscriptions = [\n outbox.subscribeChanges(notifyStatus),\n inbox.subscribeChanges(() => {}),\n deadletter.subscribeChanges(notifyStatus),\n syncmeta.subscribeChanges(notifyStatus),\n ];\n\n for (const collection of Object.values(meta)) {\n await collection.preload();\n }\n\n await ensureSyncMeta(syncmeta);\n\n clientId.value = await resolveClientId(syncmeta, config.clientId, generateEventId);\n\n seq.value = nextLocalSeq(outbox);\n\n // User collections must be hydrated before we hand the DB to the app.\n // Otherwise seeders like `ensureAppSettings` see an empty `get()` and\n // re-insert rows that already exist on disk / on the server.\n for (const collection of Object.values(userCollections)) {\n await collection.preload();\n }\n\n log.info(\"preloaded collections\", {\n outboxCount: outbox.state.size,\n inboxCount: inbox.state.size,\n deadLetterCount: deadletter.state.size,\n userCollectionIds: Object.keys(userCollections),\n nextLocalSeq: seq.value,\n clientId: clientId.value,\n pullCursor: readPullCursor(syncmeta, inbox),\n });\n\n const replayContext: ReplayContext = {\n targets: replayTargets,\n rowversions,\n deadletter,\n unknownEventHandling,\n eventSchemaVersion,\n upcastEvent: config.upcastEvent,\n conflictDetection,\n maxReplayAttempts: retry.maxAttempts,\n emit,\n log,\n };\n\n await replayInbox(inbox, replayContext);\n\n emit(\"onReady\", { clientId: clientId.value, pullCursor: readPullCursor(syncmeta, inbox) });\n\n // Serializes callers within this context; the optional lock extends that\n // across tabs so only one of them syncs at a time.\n const runExclusive = createSerialQueue();\n\n function recordError(phase: \"push\" | \"pull\" | \"replay\", label: string, err: unknown): Error {\n const error = toError(err);\n log.error(`${label} ${phase} failed`, { message: error.message });\n emit(\"onSyncError\", { phase, error });\n return error;\n }\n\n async function pushPull(label: string): Promise<SyncResult> {\n await outbox.preload();\n await inbox.preload();\n\n const errors: Error[] = [];\n let pushed = 0;\n let pulled = 0;\n let skipped = 0;\n let deadLettered = 0;\n\n async function runPush(): Promise<void> {\n if (!transport?.push) {\n log.debug(`${label} push skipped: no push transport configured`);\n return;\n }\n\n try {\n const outcome = await pushOutbox({\n outbox,\n deadletter,\n rowversions,\n push: transport.push,\n batchSize: pushBatchSize,\n maxBytes: maxPushBytes,\n retry,\n now: Date.now(),\n emit,\n log,\n });\n pushed += outcome.pushed;\n deadLettered += outcome.deadLettered;\n if (outcome.error) {\n errors.push(recordError(\"push\", label, outcome.error));\n }\n } catch (err) {\n errors.push(recordError(\"push\", label, err));\n }\n }\n\n await runPush();\n\n let requeued = 0;\n\n try {\n if (transport?.pull) {\n const outcome = await pullInbox({\n outbox,\n inbox,\n syncmeta,\n pull: transport.pull,\n clientId: clientId.value,\n pullOverlap,\n recordLocalEchoes,\n backendMismatch,\n context: replayContext,\n });\n pulled = outcome.pulled;\n skipped = outcome.skipped;\n deadLettered += outcome.deadLettered;\n requeued = outcome.requeued;\n } else {\n log.debug(`${label} pull skipped: no pull transport configured`);\n }\n } catch (err) {\n errors.push(recordError(\"pull\", label, err));\n }\n\n // A backend reset is only discovered during pull, by which point this\n // sync's push has already run. Upload the requeued history now so a single\n // sync is enough to recover rather than leaving the gap open until the next.\n if (requeued > 0) {\n log.info(`${label} re-pushing history after backend reset`, { requeued });\n await runPush();\n }\n\n await writeSyncOutcome(syncmeta, Date.now(), errors[0]?.message ?? null);\n\n return { pushed, pulled, skipped, deadLettered, deferred: false, errors };\n }\n\n /** Runs `fn` under the cross-context lock when one is configured. */\n async function withLock<T>(fn: () => Promise<T>, deferred: T): Promise<T> {\n if (!config.lock) return fn();\n\n const outcome = await config.lock.tryRun(lockName, fn);\n\n if (!outcome.acquired) {\n log.debug(\"sync deferred: lock held by another context\", { lockName });\n return deferred;\n }\n\n return outcome.result;\n }\n\n async function tracked<T extends SyncResult>(\n trigger: SyncTrigger,\n fn: () => Promise<T>,\n ): Promise<T> {\n isSyncing = true;\n notifyStatus();\n emit(\"onSyncStart\", { trigger });\n\n try {\n const result = await fn();\n emit(\"onSyncComplete\", { trigger, result });\n return result;\n } finally {\n isSyncing = false;\n notifyStatus();\n }\n }\n\n function sync(): Promise<SyncResult> {\n return runExclusive(async () => {\n if (!syncEnabled) {\n log.debug(\"sync skipped: sync disabled\");\n return emptyResult();\n }\n\n if (!transport) {\n log.warn(\"sync skipped: no transport configured\");\n return emptyResult();\n }\n\n return withLock(\n () =>\n tracked(\"sync\", async () => {\n log.info(\"sync started\");\n const result = await pushPull(\"sync\");\n log.info(\"sync finished\", {\n pushed: result.pushed,\n pulled: result.pulled,\n skipped: result.skipped,\n deadLettered: result.deadLettered,\n errorCount: result.errors.length,\n });\n return result;\n }),\n emptyResult({ deferred: true }),\n );\n });\n }\n\n function manualSync(): Promise<ManualSyncResult> {\n return runExclusive(() =>\n withLock<ManualSyncResult>(\n () =>\n tracked(\"manualSync\", async () => {\n log.info(\"manual sync started\");\n\n await outbox.preload();\n await inbox.preload();\n\n let result: SyncResult = emptyResult();\n\n if (syncEnabled && transport) {\n result = await pushPull(\"manual sync\");\n } else if (!syncEnabled) {\n log.debug(\"manual sync push/pull skipped: sync disabled\");\n } else {\n log.warn(\"manual sync: no transport configured, skipping push/pull\");\n }\n\n const errors = [...result.errors];\n let replayed = 0;\n\n try {\n const outcome = await replayInbox(inbox, replayContext);\n replayed = outcome.applied;\n result = { ...result, skipped: result.skipped + outcome.skipped };\n } catch (err) {\n errors.push(recordError(\"replay\", \"manual sync\", err));\n }\n\n log.info(\"manual sync finished\", {\n pushed: result.pushed,\n pulled: result.pulled,\n skipped: result.skipped,\n deadLettered: result.deadLettered,\n replayed,\n errorCount: errors.length,\n });\n\n return { ...result, replayed, errors };\n }),\n { ...emptyResult({ deferred: true }), replayed: 0 },\n ),\n );\n }\n\n function getSyncStatus(): SyncStatus {\n let pendingCount = 0;\n let failedCount = 0;\n\n for (const entry of outbox.state.values()) {\n if (entry.sync) continue;\n pendingCount++;\n if (entry.syncStatus === \"failed\") failedCount++;\n }\n\n const stored = readSyncMeta(syncmeta);\n\n return {\n isSyncing,\n isSynced: pendingCount === 0,\n pendingCount,\n failedCount,\n deadLetterCount: deadletter.state.size,\n pullCursor: readPullCursor(syncmeta, inbox),\n backendId: stored.backendId,\n lastSyncAt: stored.lastSyncAt,\n lastError: stored.lastError,\n };\n }\n\n function subscribeSyncStatus(listener: (status: SyncStatus) => void): () => void {\n statusListeners.add(listener);\n listener(getSyncStatus());\n return () => statusListeners.delete(listener);\n }\n\n /**\n * Retries dead-lettered events.\n * - Outbound: pushes directly to the sync transport (does not requeue the outbox).\n * - Inbound: requeues into the inbox and replays immediately.\n * Omit `eventId` to retry everything. Returns how many were successfully\n * cleared from the dead-letter queue.\n */\n function retryDeadLetter(eventId?: string): Promise<number> {\n return runExclusive(async () => {\n const targets = selectDeadLetters(deadletter, eventId);\n const outbound: DeadLetterEntry[] = [];\n let cleared = 0;\n let inboundRequeued = 0;\n\n for (const entry of targets) {\n if ((entry.direction ?? \"outbound\") === \"inbound\") {\n await requeueInboundDeadLetter(inbox, entry);\n await deadletter.delete(entry.eventId).isPersisted.promise;\n inboundRequeued++;\n cleared++;\n } else {\n outbound.push(entry);\n }\n }\n\n if (inboundRequeued > 0) {\n await replayInbox(inbox, replayContext);\n }\n\n if (outbound.length > 0) {\n if (!transport?.push) {\n throw new Error(\n \"Cannot retry outbound dead-letter events: no push transport is configured.\",\n );\n }\n\n const events: OutboundEvent[] = outbound.map((entry) =>\n toOutboundEvent({\n eventId: entry.eventId,\n collectionId: entry.collectionId,\n type: entry.type,\n key: entry.key,\n payload: entry.payload,\n previous: entry.previous,\n txId: entry.txId ?? entry.eventId,\n clientId: entry.clientId ?? clientId.value,\n schemaVersion: entry.schemaVersion,\n baseVersion: entry.baseVersion ?? null,\n timestamp: entry.timestamp,\n localSeq: entry.localSeq ?? 0,\n globalSeq: null,\n sync: false,\n syncStatus: \"pending\",\n attemptCount: entry.attemptCount,\n lastAttemptAt: null,\n nextAttemptAt: null,\n lastError: null,\n lastErrorCode: null,\n retryable: null,\n }),\n );\n\n const response = normalizePushResponse(await transport.push(events));\n const confirmed = new Set(response.confirmed.map((item) => item.eventId));\n const failedById = new Map((response.failed ?? []).map((item) => [item.eventId, item]));\n const now = Date.now();\n\n for (const confirmation of response.confirmed) {\n const entry = outbound.find((row) => row.eventId === confirmation.eventId);\n if (!entry) continue;\n\n if (deadletter.has(entry.eventId)) {\n await deadletter.delete(entry.eventId).isPersisted.promise;\n }\n\n if (conflictDetection) {\n await recordRowVersion(\n rowversions,\n entry.collectionId,\n entry.key,\n entry.eventId,\n confirmation.globalSeq,\n );\n }\n\n emit(\"onEventPushed\", {\n eventId: confirmation.eventId,\n globalSeq: confirmation.globalSeq,\n });\n cleared++;\n }\n\n for (const entry of outbound) {\n if (confirmed.has(entry.eventId)) continue;\n\n const failure = failedById.get(entry.eventId);\n const message = failure?.message ?? \"push failed during dead-letter retry\";\n const code = failure?.code ?? null;\n\n if (deadletter.has(entry.eventId)) {\n await deadletter.update(entry.eventId, (draft) => {\n draft.attemptCount = (draft.attemptCount ?? 0) + 1;\n draft.message = message;\n draft.code = code;\n draft.failedAt = now;\n }).isPersisted.promise;\n }\n }\n\n log.info(\"outbound dead-letter events pushed\", {\n attempted: outbound.length,\n confirmed: response.confirmed.length,\n failed: response.failed?.length ?? 0,\n });\n } else {\n log.info(\"dead-letter events retried\", {\n count: targets.length,\n inbound: inboundRequeued,\n });\n }\n\n return cleared;\n });\n }\n\n function discardDeadLetter(eventId?: string): Promise<number> {\n return runExclusive(async () => {\n const targets = selectDeadLetters(deadletter, eventId);\n\n for (const entry of targets) {\n await deadletter.delete(entry.eventId).isPersisted.promise;\n }\n\n log.info(\"dead-letter events discarded\", { count: targets.length });\n\n return targets.length;\n });\n }\n\n function pruneSyncedEvents(options: PruneOptions = {}): Promise<PruneResult> {\n return runExclusive(async () => {\n const olderThanMs = Math.max(0, options.olderThanMs ?? 0);\n const keepLast = Math.max(0, options.keepLast ?? 0);\n const cutoff = Date.now() - olderThanMs;\n\n // The cursor is derived partly from resolved inbox rows, so persist it\n // before those rows are removed.\n await writePullCursor(syncmeta, readPullCursor(syncmeta, inbox));\n\n const outboxTargets = trimKeepLast(\n [...outbox.state.values()]\n .filter((entry) => entry.sync && entry.timestamp <= cutoff)\n .sort((a, b) => a.localSeq - b.localSeq),\n keepLast,\n );\n\n const inboxTargets = trimKeepLast(\n [...inbox.state.values()]\n .filter((entry) => entry.sync && entry.timestamp <= cutoff)\n .sort((a, b) => a.globalSeq - b.globalSeq),\n keepLast,\n );\n\n for (const entry of outboxTargets) {\n await outbox.delete(entry.eventId).isPersisted.promise;\n }\n\n for (const entry of inboxTargets) {\n await inbox.delete(entry.eventId).isPersisted.promise;\n }\n\n log.info(\"pruned synced events\", {\n outbox: outboxTargets.length,\n inbox: inboxTargets.length,\n });\n\n return { outbox: outboxTargets.length, inbox: inboxTargets.length };\n });\n }\n\n function getSyncEnabled(): boolean {\n return syncEnabled;\n }\n\n function setSyncEnabled(enabled: boolean): void {\n syncEnabled = enabled;\n log.debug(\"sync enabled updated\", { syncEnabled: enabled });\n }\n\n function dispose(): void {\n log.debug(\"disposing event-sourced db\");\n statusListeners.clear();\n for (const subscription of subscriptions) {\n subscription.unsubscribe();\n }\n }\n\n return {\n collections,\n sync,\n manualSync,\n getSyncEnabled,\n setSyncEnabled,\n getSyncStatus,\n subscribeSyncStatus,\n retryDeadLetter,\n discardDeadLetter,\n pruneSyncedEvents,\n dispose,\n };\n}\n\nfunction selectDeadLetters(\n deadletter: Collection<DeadLetterEntry, string>,\n eventId?: string,\n): DeadLetterEntry[] {\n if (eventId === undefined) {\n return [...deadletter.state.values()].sort(\n (a, b) => (a.localSeq ?? a.globalSeq ?? 0) - (b.localSeq ?? b.globalSeq ?? 0),\n );\n }\n\n const entry = deadletter.get(eventId);\n return entry ? [entry] : [];\n}\n\n/** Puts a parked inbound event back in the inbox so replay can pick it up again. */\nasync function requeueInboundDeadLetter(\n inbox: Collection<InboxEntry, string>,\n entry: DeadLetterEntry,\n): Promise<void> {\n if (inbox.has(entry.eventId)) {\n await inbox.update(entry.eventId, (draft) => {\n draft.sync = false;\n draft.skipped = false;\n draft.skipReason = null;\n draft.attemptCount = 0;\n draft.lastError = null;\n }).isPersisted.promise;\n return;\n }\n\n await inbox.insert({\n eventId: entry.eventId,\n globalSeq: entry.globalSeq ?? 0,\n collectionId: entry.collectionId,\n type: entry.type,\n key: entry.key,\n payload: entry.payload,\n previous: entry.previous,\n clientId: entry.clientId,\n schemaVersion: entry.schemaVersion,\n timestamp: entry.timestamp,\n sync: false,\n skipped: false,\n skipReason: null,\n attemptCount: 0,\n lastError: null,\n }).isPersisted.promise;\n}\n\n/** Drops the newest `keepLast` items from an ascending-sorted removal list. */\nfunction trimKeepLast<T>(items: ReadonlyArray<T>, keepLast: number): T[] {\n if (keepLast <= 0) return [...items];\n return items.slice(0, Math.max(0, items.length - keepLast));\n}\n\nfunction createMetaCollection<TEntry extends object>(\n config: MetaCollectionFactory,\n id: string,\n getKey: (entry: TEntry) => string,\n schemaVersion: number,\n): Collection<TEntry, string> {\n const options = config.persistedCollectionOptions<TEntry, string>({\n id,\n getKey,\n persistence: config.persistence,\n schemaVersion,\n });\n\n return config.createCollection(options);\n}\n\ntype IndexableCollection = {\n createIndex: (\n indexCallback: (row: Record<string, unknown>) => unknown,\n config?: {\n name?: string;\n indexType?: new (id: number, expression: never, name?: string, options?: never) => unknown;\n },\n ) => unknown;\n getIndexMetadata?: () => ReadonlyArray<unknown>;\n on?: (event: \"status:ready\", callback: () => void) => () => void;\n};\n\nfunction applyCollectionIndexes(\n collection: Collection<Record<string, unknown>, string | number>,\n collectionId: string,\n indexes: CollectionDefConstraint[\"indexes\"],\n log: EventSourcedLogger,\n): void {\n if (!indexes?.length) return;\n\n const indexable = collection as IndexableCollection;\n\n const register = (): void => {\n if ((indexable.getIndexMetadata?.().length ?? 0) > 0) return;\n\n for (const indexDef of indexes) {\n indexable.createIndex(indexDef.select as (row: Record<string, unknown>) => unknown, {\n name: indexDef.name,\n indexType: indexDef.indexType,\n });\n\n log.debug(\"registered collection index\", { collectionId, name: indexDef.name });\n }\n };\n\n register();\n\n indexable.on?.(\"status:ready\", register);\n}\n\nfunction createMutationHook(context: MutationContext) {\n const {\n outbox,\n rowversions,\n collectionId,\n type,\n seq,\n clientId,\n eventSchemaVersion,\n conflictDetection,\n emit,\n log,\n } = context;\n\n return async (params: MutationHookParams): Promise<Record<string, unknown>> => {\n const txId = generateEventId();\n const timestamp = Date.now();\n\n for (const mutation of params.transaction.mutations) {\n const payload = type === \"delete\" ? mutation.original : mutation.modified;\n const eventId = generateEventId();\n\n const entry: OutboxEntry = {\n eventId,\n collectionId,\n type,\n key: mutation.key,\n payload,\n previous: type === \"insert\" ? null : mutation.original,\n txId,\n clientId: clientId.value,\n schemaVersion: eventSchemaVersion,\n baseVersion: conflictDetection\n ? readRowVersion(rowversions, collectionId, mutation.key)\n : null,\n timestamp,\n localSeq: allocateLocalSeq(outbox, seq),\n globalSeq: null,\n sync: false,\n syncStatus: \"pending\",\n attemptCount: 0,\n lastAttemptAt: null,\n nextAttemptAt: null,\n lastError: null,\n lastErrorCode: null,\n retryable: null,\n };\n\n await outbox.insert(entry).isPersisted.promise;\n\n if (conflictDetection) {\n await recordRowVersion(rowversions, collectionId, mutation.key, eventId, null);\n }\n\n log.debug(\"outbox entry created\", {\n eventId,\n collectionId,\n type,\n key: entry.key,\n localSeq: entry.localSeq,\n txId,\n });\n\n emit(\"onMutation\", entry);\n }\n\n return {};\n };\n}\n\n/**\n * Reads the high-water mark from live outbox state rather than trusting the\n * cached counter alone, so a second tab writing to the same persisted store\n * cannot hand out a localSeq that has already been used.\n */\nfunction allocateLocalSeq(outbox: Collection<OutboxEntry, string>, seq: SeqCounter): number {\n const allocated = Math.max(seq.value, nextLocalSeq(outbox));\n seq.value = allocated + 1;\n return allocated;\n}\n\nfunction nextLocalSeq(outbox: Collection<OutboxEntry, string>): number {\n let max = -1;\n\n for (const entry of outbox.state.values()) {\n if (entry.localSeq > max) max = entry.localSeq;\n }\n\n return max + 1;\n}\n\nfunction assertReservedNamesAvailable(collections: Record<string, unknown>): void {\n for (const id of Object.keys(collections)) {\n if (RESERVED_IDS.has(id)) {\n throw new Error(\n `Collection id \"${id}\" is reserved. Built-in collections are: ${[...RESERVED_IDS]\n .map((name) => `\"${name}\"`)\n .join(\", \")}.`,\n );\n }\n }\n}\n\nfunction toError(err: unknown): Error {\n return err instanceof Error ? err : new Error(String(err));\n}\n","export type LazySingletonOptions = {\n /** Runs on every `ensure()` / proxy access (e.g. `typeof window` checks). */\n guard?: () => void;\n /** Thrown when `proxy` is used before `ensure()` resolves. */\n notInitializedMessage?: string;\n};\n\n/**\n * Result of {@link createLazySingleton}.\n *\n * @example\n * ```ts\n * import { createLazySingleton } from \"event-sourced-collection\"\n *\n * const { ensure, proxy, reset } = createLazySingleton(async () => ({ ready: true }))\n * await ensure()\n * console.log(proxy.ready) // true\n * reset()\n * ```\n */\nexport type LazySingleton<T extends object> = {\n ensure: () => Promise<T>;\n proxy: T;\n reset: () => void;\n};\n\n/**\n * One-shot async factory with a proxy that is safe to export as a module\n * singleton. Platform DB helpers are built on this.\n *\n * @example Export a proxy, initialize at app startup\n * ```ts\n * import { createLazySingleton } from \"event-sourced-collection\"\n *\n * type Client = { ping: () => Promise<string> }\n *\n * const { ensure, proxy: client } = createLazySingleton<Client>(async () => ({\n * ping: async () => \"ok\",\n * }))\n *\n * export async function start() {\n * await ensure()\n * }\n *\n * export { client }\n * // client.ping() throws until start() has run\n * ```\n */\nexport function createLazySingleton<T extends object>(\n factory: () => Promise<T>,\n options: LazySingletonOptions = {},\n): LazySingleton<T> {\n let instance: T | null = null;\n let initPromise: Promise<T> | null = null;\n\n const ensure = async (): Promise<T> => {\n options.guard?.();\n\n if (instance) {\n return instance;\n }\n\n if (!initPromise) {\n initPromise = factory()\n .then((resolved) => {\n instance = resolved;\n return resolved;\n })\n .catch((error: unknown) => {\n initPromise = null;\n throw error;\n });\n }\n\n return initPromise;\n };\n\n const message =\n options.notInitializedMessage ?? \"Instance is not initialized. Call ensure() first.\";\n\n const proxy = new Proxy({} as T, {\n get(_target, prop, receiver) {\n if (!instance) {\n throw new Error(message);\n }\n return Reflect.get(instance, prop, receiver);\n },\n has(_target, prop) {\n if (!instance) {\n throw new Error(message);\n }\n return Reflect.has(instance, prop);\n },\n getPrototypeOf() {\n if (!instance) {\n throw new Error(message);\n }\n return Reflect.getPrototypeOf(instance);\n },\n });\n\n const reset = (): void => {\n instance = null;\n initPromise = null;\n };\n\n return { ensure, proxy, reset };\n}\n","import { createEventSourcedDB } from \"./create-event-sourced-db\";\nimport { createLazySingleton } from \"./lazy-singleton\";\nimport type { EventSourcedDB, EventSourcedDBConfig } from \"./types\";\n\ntype CollectionDefConstraint = {\n getKey: (state: never) => string | number;\n};\n\n/**\n * Lazy handle returned by platform helpers and {@link createEventSourcedDBHandle}.\n *\n * @example\n * ```ts\n * import { createBrowserEventSourcedDB } from \"event-sourced-collection/browser\"\n *\n * const { ensureDb, db, close } = createBrowserEventSourcedDB({\n * databaseName: \"app.sqlite\",\n * collections: { todos: { getKey: (todo: { id: string }) => todo.id } },\n * modules: async () => {\n * const { createCollection } = await import(\"@tanstack/db\")\n * const persistence = await import(\"@tanstack/browser-db-sqlite-persistence\")\n * return { createCollection, ...persistence }\n * },\n * })\n *\n * await ensureDb()\n * await db.collections.todos.insert({ id: \"t1\" }).isPersisted.promise\n * await close()\n * ```\n */\nexport type EventSourcedDBHandle<TDefs extends Record<string, CollectionDefConstraint>> = {\n /** Opens (or returns) the singleton DB. Call once at app startup before using `db`. */\n ensureDb: () => Promise<EventSourcedDB<TDefs>>;\n /**\n * Proxy that forwards to the live DB after `ensureDb()` resolves. Accessing a\n * property before initialization throws.\n */\n db: EventSourcedDB<TDefs>;\n /** Disposes the DB, runs platform cleanup, and resets the singleton. */\n close: () => Promise<void>;\n};\n\nexport type EventSourcedDBHandleSetup<TDefs extends Record<string, CollectionDefConstraint>> =\n EventSourcedDBConfig<TDefs> & {\n /** Optional platform teardown (close SQLite, dispose coordinators). */\n close?: () => Promise<void> | void;\n };\n\n/**\n * Lazy singleton around {@link createEventSourcedDB}. Platform helpers use this\n * after they have turned TanStack persistence modules into `persistence`.\n * Call this yourself only when you need a custom open/close path.\n *\n * @example Custom persistence, still lazy like the platform helpers\n * ```ts\n * import { createCollection } from \"@tanstack/db\"\n * import {\n * createNodeSQLitePersistence,\n * persistedCollectionOptions,\n * } from \"@tanstack/node-db-sqlite-persistence\"\n * import Database from \"better-sqlite3\"\n * import { createEventSourcedDBHandle } from \"event-sourced-collection\"\n *\n * type Todo = { id: string; title: string }\n *\n * const { ensureDb, db, close } = createEventSourcedDBHandle({\n * setup: async () => {\n * const sqlite = new Database(\"app.sqlite\")\n * return {\n * persistence: createNodeSQLitePersistence({ database: sqlite }),\n * createCollection,\n * persistedCollectionOptions,\n * collections: { todos: { getKey: (todo: Todo) => todo.id } },\n * close: () => sqlite.close(),\n * }\n * },\n * })\n *\n * await ensureDb()\n * console.log(db.collections.todos.size)\n * await close()\n * ```\n */\nexport function createEventSourcedDBHandle<\n const TDefs extends Record<string, CollectionDefConstraint>,\n>(options: {\n setup: () => Promise<EventSourcedDBHandleSetup<TDefs>>;\n guard?: () => void;\n notInitializedMessage?: string;\n}): EventSourcedDBHandle<TDefs> {\n let activeDb: EventSourcedDB<TDefs> | null = null;\n let closePlatform: (() => Promise<void> | void) | null = null;\n\n const factory = async (): Promise<EventSourcedDB<TDefs>> => {\n const { close, ...dbConfig } = await options.setup();\n closePlatform = close ?? null;\n const database = await createEventSourcedDB<TDefs>(dbConfig);\n activeDb = database;\n return database;\n };\n\n const singleton = createLazySingleton<EventSourcedDB<TDefs>>(factory, {\n guard: options.guard,\n notInitializedMessage:\n options.notInitializedMessage ??\n \"Event-sourced DB is not initialized. Call ensureDb() before using db.\",\n });\n\n const close = async (): Promise<void> => {\n if (activeDb) {\n activeDb.dispose();\n activeDb = null;\n }\n if (closePlatform) {\n await closePlatform();\n closePlatform = null;\n }\n singleton.reset();\n };\n\n return {\n ensureDb: singleton.ensure,\n db: singleton.proxy,\n close,\n };\n}\n\n/** Bindings object, or a function that loads them on first `ensureDb()`. */\nexport type ModulesInput<T> = T | (() => T | Promise<T>);\n\n/**\n * Resolves {@link ModulesInput}: returns the object, or awaits the loader.\n *\n * @example Keep WASM off the SSR bundle until the first `ensureDb()`\n * ```ts\n * import { resolveModules, type ModulesInput } from \"event-sourced-collection\"\n *\n * type BrowserModules = {\n * createCollection: typeof import(\"@tanstack/db\").createCollection\n * }\n *\n * const modules: ModulesInput<BrowserModules> = async () => {\n * const { createCollection } = await import(\"@tanstack/db\")\n * return { createCollection }\n * }\n *\n * const resolved = await resolveModules(modules)\n * ```\n */\nexport async function resolveModules<T>(modules: ModulesInput<T>): Promise<T> {\n return typeof modules === \"function\" ? await (modules as () => T | Promise<T>)() : modules;\n}\n"],"mappings":"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"}