@tearleads/client-sdk 0.1.73 → 0.1.74

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tearleads/client-sdk",
3
- "version": "0.1.73",
3
+ "version": "0.1.74",
4
4
  "description": "React-free Tearleads client runtime: local SQLite persistence, keys, sync, encrypted blobs, and domain workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -127,7 +127,7 @@ async function syncDocumentState(state, currentDoc, nextRecord, encapsulationKey
127
127
  return nextRemoteRecord;
128
128
  }
129
129
  // Pre-register the IDs we are about to send so the author's OWN
130
- // `document_update_created` echo (fanned back over redis) is classified as
130
+ // `document_update_created` echo (fanned back over realtime) is classified as
131
131
  // self-authored and never re-arms a redundant sync. Registering BEFORE the
132
132
  // network await closes the race where the echo lands before
133
133
  // finalizeDocumentSync records the accepted IDs — the gap that turned every
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { reportAndRethrowKeyingVerificationError } from \"../../../../data/keyingProjectionVerification/error\";\nimport {\n type DocumentRecord,\n type DocumentSyncLane,\n isDatabaseUnavailableError,\n type PendingUpdateRecord,\n registerDocumentSyncLane,\n resolveDocumentCreateAuthor,\n} from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { awaitInitializationForSync } from \"../initialization\";\nimport { listPendingUpdates } from \"../persistence\";\nimport {\n type DocumentState,\n type DocumentStoreState,\n type DocumentSyncAttempt,\n type EncapsulationKeyPair,\n setDocumentSyncing,\n} from \"../state\";\nimport { logRevalidationUnavailable as logUnavailable } from \"./remoteRevalidationTelemetry\";\nimport {\n getActiveDocumentRemoteWork,\n runDocumentRemoteWork,\n} from \"./remoteWork\";\nimport {\n cleanupPreRegisteredUpdateIdsOnFailure,\n discardPreRegisteredUpdateIds,\n preRegisterMaterializedDocumentSyncUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport { syncPendingAttachments } from \"./syncAttachments\";\nimport { syncDetachedAttachmentBindings } from \"./syncDetachedAttachments\";\nimport { finalizeDocumentSync } from \"./syncFinalize\";\nimport {\n captureDocumentStoreAttachmentSyncGeneration,\n captureDocumentStoreRemoteSyncGeneration,\n captureDocumentStoreSyncGeneration,\n type DocumentStoreSyncGeneration,\n type DocumentStoreSyncLaneGeneration,\n isDocumentStoreRemoteSyncBlocked,\n isDocumentStoreSyncGenerationCurrent,\n isDocumentStoreSyncLaneGenerationCurrent,\n} from \"./syncGeneration\";\nimport { prepareDocumentOutgoingCoverage } from \"./syncOutgoingCoverage\";\nimport { requestRemoteDocumentSync } from \"./syncRequest\";\nimport { ensureSeededRemoteDocument } from \"./syncSeededCreate\";\nimport {\n isContainerAwaitingRemoteCreate,\n shouldSkipCleanScheduledDocumentSync,\n} from \"./syncShared\";\n\nfunction canRunScheduledSync(state: DocumentStoreState): boolean {\n return (\n // A deferred birth waits for its attach to carry it (see\n // deferredInitialUpdate.ts); a pass now would ship it on its own.\n state.deferInitialUpdate !== true &&\n state.doc !== null &&\n state.snapshot.ready &&\n state.runtime.state.online &&\n state.runtime.auth.isAuthenticated &&\n state.runtime.crypto.encapsulationKeyPair !== null &&\n resolveDocumentCreateAuthor(state.runtime) !== null\n );\n}\n\nasync function requestOutgoingDocumentBatch(input: {\n readonly currentDoc: DocumentState;\n readonly encapsulationKeyPair: EncapsulationKeyPair;\n readonly generation: DocumentStoreSyncGeneration;\n readonly pendingUpdates: PendingUpdateRecord[];\n readonly record: DocumentRecord;\n readonly state: DocumentStoreState;\n}): Promise<{\n sentUpdateIds: string[];\n syncAttempt: DocumentSyncAttempt | null;\n}> {\n const { planningUpdates, queuedUpdateCount } = prepareDocumentStoreSyncQueue(\n input.pendingUpdates,\n );\n const sentUpdateIds: string[] = [];\n const syncAttempt = await cleanupPreRegisteredUpdateIdsOnFailure(\n input.state,\n sentUpdateIds,\n () =>\n requestRemoteDocumentSync({\n currentDoc: input.currentDoc,\n currentRecord: input.record,\n encapsulationKeyPair: input.encapsulationKeyPair,\n generation: input.generation,\n onOutgoingUpdatesMaterialized: (updateIds) =>\n preRegisterMaterializedDocumentSyncUpdateIds(\n input.state,\n sentUpdateIds,\n updateIds,\n ),\n pendingUpdates: planningUpdates,\n queuedUpdateCount,\n state: input.state,\n unavailableWriterLogMessage:\n \"Documents: skipped sync because the writer context is unavailable.\",\n }),\n );\n return { sentUpdateIds, syncAttempt };\n}\n\n/**\n * Keep the full durable queue visible to stale-heal/checkpoint classification.\n * The workflow planner owns the final count and byte bounds, and the exact\n * materialized batch is pre-registered immediately before each submit.\n */\nexport function prepareDocumentStoreSyncQueue(\n pendingUpdates: PendingUpdateRecord[],\n): {\n planningUpdates: PendingUpdateRecord[];\n queuedUpdateCount: number;\n} {\n return {\n planningUpdates: pendingUpdates,\n queuedUpdateCount: pendingUpdates.length,\n };\n}\n\nexport function canSyncDetachedAttachmentBindings(\n record: DocumentRecord,\n pendingUpdateCount: number,\n): boolean {\n return (\n pendingUpdateCount === 0 &&\n (record.pullContinuation ?? null) === null &&\n !record.pullContinuationRecoveryRequired\n );\n}\n\nasync function syncDocumentState(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<DocumentRecord> {\n // Snapshot the remote-update signal sequence before any await. The GET below\n // fetches server state as of its own snapshot; any remote event delivered\n // after this point describes an update that may not be in that response, so\n // finalizeDocumentSync must not clear the signal if this sequence has moved.\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n let pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (pendingUpdates.length === 0 && isDocumentStoreRemoteSyncBlocked(state)) {\n return nextRecord;\n }\n // Create the remote document even when nothing is queued to send: a note\n // created and never edited enqueues no updates, but its local row is still a\n // pending create the write queue reports — it must flush, not sit. Defer\n // while the container itself still awaits its remote create — with OR\n // without queued edits, since the create cannot succeed before its parent\n // exists and attempting it just records a spurious failure. The structural\n // lane primes this store again as soon as the container create lands.\n if (!nextRecord.documentId) {\n const containerAwaitsCreate = await isContainerAwaitingRemoteCreate(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (containerAwaitsCreate) return nextRecord;\n }\n const created = await ensureSeededRemoteDocument({\n consumedRemoteUpdateSignalSeq,\n currentDoc,\n encapsulationKeyPair,\n generation,\n nextRecord,\n pendingUpdates,\n state,\n });\n let nextRemoteRecord = created.record;\n pendingUpdates = created.pendingUpdates;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (!nextRemoteRecord?.documentId) return nextRecord;\n\n const preparedCoverage = await prepareDocumentOutgoingCoverage({\n currentDoc,\n generation,\n pendingUpdates,\n state,\n });\n if (!preparedCoverage) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n nextRemoteRecord = preparedCoverage.record;\n pendingUpdates = preparedCoverage.pendingUpdates;\n\n if (\n shouldSkipCleanScheduledDocumentSync({\n currentRecord: nextRemoteRecord,\n pendingUpdates,\n state,\n })\n ) {\n return nextRemoteRecord;\n }\n\n // Pre-register the IDs we are about to send so the author's OWN\n // `document_update_created` echo (fanned back over redis) is classified as\n // self-authored and never re-arms a redundant sync. Registering BEFORE the\n // network await closes the race where the echo lands before\n // finalizeDocumentSync records the accepted IDs — the gap that turned every\n // fast keystroke into an extra self-triggered sync.\n const { sentUpdateIds, syncAttempt } = await requestOutgoingDocumentBatch({\n currentDoc,\n encapsulationKeyPair,\n generation,\n pendingUpdates,\n record: nextRemoteRecord,\n state,\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n if (!syncAttempt) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n logUnavailable(state, wasRemoteProbe);\n return nextRemoteRecord;\n }\n\n return cleanupPreRegisteredUpdateIdsOnFailure(state, sentUpdateIds, () =>\n finalizeDocumentSync(\n state,\n currentDoc,\n nextRemoteRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n sentUpdateIds,\n wasRemoteProbe,\n ),\n );\n}\n\nasync function revalidateRemoteDocumentBeforeAttachments(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<{ canSyncAttachments: boolean; nextRecord: DocumentRecord }> {\n if (state.pendingAttachments.length === 0 || !nextRecord.documentId) {\n return { canSyncAttachments: true, nextRecord };\n }\n\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n const syncAttempt = await requestRemoteDocumentSync({\n state,\n currentDoc,\n currentRecord: nextRecord,\n encapsulationKeyPair,\n generation,\n pendingUpdates: [],\n unavailableWriterLogMessage:\n \"Documents: skipped pre-attachment revalidation because the writer context is unavailable.\",\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return { canSyncAttachments: false, nextRecord };\n }\n if (!syncAttempt) {\n logUnavailable(state, wasRemoteProbe);\n return { canSyncAttachments: false, nextRecord };\n }\n\n const refreshedRecord = await finalizeDocumentSync(\n state,\n currentDoc,\n nextRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n [],\n wasRemoteProbe,\n );\n return {\n canSyncAttachments:\n !syncAttempt.synced.hasIncompletePull &&\n refreshedRecord.pullContinuation == null &&\n refreshedRecord.pullContinuationRecoveryRequired !== true &&\n isDocumentStoreSyncGenerationCurrent(state, generation),\n nextRecord: refreshedRecord,\n };\n}\n\nasync function runDocumentSyncPass(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const currentDoc = state.doc;\n const encapsulationKeyPair = state.runtime.crypto.encapsulationKeyPair;\n let nextRecord = state.record;\n\n if (!currentDoc || !nextRecord || !encapsulationKeyPair) {\n return;\n }\n\n const generation = captureDocumentStoreRemoteSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n const attachmentGeneration = captureDocumentStoreAttachmentSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n if (!generation || !attachmentGeneration) {\n requestDocumentStoreSync(state);\n return;\n }\n\n const revalidation = await revalidateRemoteDocumentBeforeAttachments(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n nextRecord = revalidation.nextRecord;\n if (!revalidation.canSyncAttachments) {\n return;\n }\n\n const attachmentResult = await syncPendingAttachments(\n state,\n nextRecord,\n encapsulationKeyPair,\n attachmentGeneration,\n );\n nextRecord = attachmentResult.nextRecord;\n if (state.pendingAttachments.length > 0) {\n return;\n }\n // A settled bind and the content update carrying its digest are two server\n // writes. Push the content in this same pass rather than re-arming a later\n // one, so a device lost between them is the only remaining window: peers\n // otherwise see the old digest against the new binding.\n\n nextRecord = await syncDocumentState(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n\n if (!state.doc || !state.record) return;\n\n const pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n if (!canSyncDetachedAttachmentBindings(nextRecord, pendingUpdates.length)) {\n return;\n }\n\n await syncDetachedAttachmentBindings(state, nextRecord, generation);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n }\n}\n\nasync function runScheduledSyncIteration(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n if (!(await awaitInitializationForSync(state))) {\n return false;\n }\n if (!isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)) {\n return true;\n }\n\n if (!canRunScheduledSync(state)) {\n return true;\n }\n\n try {\n await runDocumentSyncPass(state, syncLaneGeneration);\n return true;\n } catch (error) {\n if (isDatabaseUnavailableError(error)) {\n return false;\n }\n\n await reportAndRethrowKeyingVerificationError(\n error,\n state.runtime.util.reportSecurityIncident,\n {\n objectId: state.record?.documentId ?? state.localId,\n objectKind: \"document\",\n operation: \"document.sync\",\n },\n );\n\n throw error;\n }\n}\n\nasync function runScheduledSyncLoop(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const syncingGeneration = captureDocumentStoreSyncGeneration(\n state,\n state.doc,\n );\n setDocumentSyncing(state, true);\n\n try {\n await runScheduledSyncIteration(state, syncLaneGeneration);\n } finally {\n if (\n syncingGeneration &&\n isDocumentStoreSyncGenerationCurrent(state, syncingGeneration) &&\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n setDocumentSyncing(state, false);\n }\n }\n}\n\nexport function registerDocumentStoreSyncLane(\n state: DocumentStoreState,\n getSyncLaneGeneration: () => DocumentStoreSyncLaneGeneration | null,\n): DocumentSyncLane {\n return registerDocumentSyncLane({\n domainScope: state.runtime.state.domainScope,\n localId: state.localId,\n priority: () =>\n state.remoteUpdatePending || state.record?.snapshotEndVersion === \"\"\n ? -1\n : 0,\n logError: (message, error) => {\n // Read the runtime lazily: a store's runtime is replaced in place, and a\n // reference captured here would report into a torn-down host.\n const { log, logError } = state.runtime.util;\n // Return the host's result: both callbacks are declared `=> void` but may\n // be async, and the lane reporter only catches a rejection it is handed.\n return logError ? logError(message, error) : log(message);\n },\n run: () => {\n const syncLaneGeneration = getSyncLaneGeneration();\n if (!syncLaneGeneration) return Promise.resolve();\n const activeWork = getActiveDocumentRemoteWork(state);\n if (activeWork) {\n // Re-arm on settlement, not immediately: immediate re-requests would\n // spin this lane and starve other work while the HTTP request is held.\n void activeWork.then(() => {\n if (\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n requestDocumentStoreSync(state);\n }\n });\n return Promise.resolve();\n }\n return runDocumentRemoteWork(state, () =>\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ? runScheduledSyncLoop(state, syncLaneGeneration)\n : Promise.resolve(),\n );\n },\n });\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { reportAndRethrowKeyingVerificationError } from \"../../../../data/keyingProjectionVerification/error\";\nimport {\n type DocumentRecord,\n type DocumentSyncLane,\n isDatabaseUnavailableError,\n type PendingUpdateRecord,\n registerDocumentSyncLane,\n resolveDocumentCreateAuthor,\n} from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { awaitInitializationForSync } from \"../initialization\";\nimport { listPendingUpdates } from \"../persistence\";\nimport {\n type DocumentState,\n type DocumentStoreState,\n type DocumentSyncAttempt,\n type EncapsulationKeyPair,\n setDocumentSyncing,\n} from \"../state\";\nimport { logRevalidationUnavailable as logUnavailable } from \"./remoteRevalidationTelemetry\";\nimport {\n getActiveDocumentRemoteWork,\n runDocumentRemoteWork,\n} from \"./remoteWork\";\nimport {\n cleanupPreRegisteredUpdateIdsOnFailure,\n discardPreRegisteredUpdateIds,\n preRegisterMaterializedDocumentSyncUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport { syncPendingAttachments } from \"./syncAttachments\";\nimport { syncDetachedAttachmentBindings } from \"./syncDetachedAttachments\";\nimport { finalizeDocumentSync } from \"./syncFinalize\";\nimport {\n captureDocumentStoreAttachmentSyncGeneration,\n captureDocumentStoreRemoteSyncGeneration,\n captureDocumentStoreSyncGeneration,\n type DocumentStoreSyncGeneration,\n type DocumentStoreSyncLaneGeneration,\n isDocumentStoreRemoteSyncBlocked,\n isDocumentStoreSyncGenerationCurrent,\n isDocumentStoreSyncLaneGenerationCurrent,\n} from \"./syncGeneration\";\nimport { prepareDocumentOutgoingCoverage } from \"./syncOutgoingCoverage\";\nimport { requestRemoteDocumentSync } from \"./syncRequest\";\nimport { ensureSeededRemoteDocument } from \"./syncSeededCreate\";\nimport {\n isContainerAwaitingRemoteCreate,\n shouldSkipCleanScheduledDocumentSync,\n} from \"./syncShared\";\n\nfunction canRunScheduledSync(state: DocumentStoreState): boolean {\n return (\n // A deferred birth waits for its attach to carry it (see\n // deferredInitialUpdate.ts); a pass now would ship it on its own.\n state.deferInitialUpdate !== true &&\n state.doc !== null &&\n state.snapshot.ready &&\n state.runtime.state.online &&\n state.runtime.auth.isAuthenticated &&\n state.runtime.crypto.encapsulationKeyPair !== null &&\n resolveDocumentCreateAuthor(state.runtime) !== null\n );\n}\n\nasync function requestOutgoingDocumentBatch(input: {\n readonly currentDoc: DocumentState;\n readonly encapsulationKeyPair: EncapsulationKeyPair;\n readonly generation: DocumentStoreSyncGeneration;\n readonly pendingUpdates: PendingUpdateRecord[];\n readonly record: DocumentRecord;\n readonly state: DocumentStoreState;\n}): Promise<{\n sentUpdateIds: string[];\n syncAttempt: DocumentSyncAttempt | null;\n}> {\n const { planningUpdates, queuedUpdateCount } = prepareDocumentStoreSyncQueue(\n input.pendingUpdates,\n );\n const sentUpdateIds: string[] = [];\n const syncAttempt = await cleanupPreRegisteredUpdateIdsOnFailure(\n input.state,\n sentUpdateIds,\n () =>\n requestRemoteDocumentSync({\n currentDoc: input.currentDoc,\n currentRecord: input.record,\n encapsulationKeyPair: input.encapsulationKeyPair,\n generation: input.generation,\n onOutgoingUpdatesMaterialized: (updateIds) =>\n preRegisterMaterializedDocumentSyncUpdateIds(\n input.state,\n sentUpdateIds,\n updateIds,\n ),\n pendingUpdates: planningUpdates,\n queuedUpdateCount,\n state: input.state,\n unavailableWriterLogMessage:\n \"Documents: skipped sync because the writer context is unavailable.\",\n }),\n );\n return { sentUpdateIds, syncAttempt };\n}\n\n/**\n * Keep the full durable queue visible to stale-heal/checkpoint classification.\n * The workflow planner owns the final count and byte bounds, and the exact\n * materialized batch is pre-registered immediately before each submit.\n */\nexport function prepareDocumentStoreSyncQueue(\n pendingUpdates: PendingUpdateRecord[],\n): {\n planningUpdates: PendingUpdateRecord[];\n queuedUpdateCount: number;\n} {\n return {\n planningUpdates: pendingUpdates,\n queuedUpdateCount: pendingUpdates.length,\n };\n}\n\nexport function canSyncDetachedAttachmentBindings(\n record: DocumentRecord,\n pendingUpdateCount: number,\n): boolean {\n return (\n pendingUpdateCount === 0 &&\n (record.pullContinuation ?? null) === null &&\n !record.pullContinuationRecoveryRequired\n );\n}\n\nasync function syncDocumentState(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<DocumentRecord> {\n // Snapshot the remote-update signal sequence before any await. The GET below\n // fetches server state as of its own snapshot; any remote event delivered\n // after this point describes an update that may not be in that response, so\n // finalizeDocumentSync must not clear the signal if this sequence has moved.\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n let pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (pendingUpdates.length === 0 && isDocumentStoreRemoteSyncBlocked(state)) {\n return nextRecord;\n }\n // Create the remote document even when nothing is queued to send: a note\n // created and never edited enqueues no updates, but its local row is still a\n // pending create the write queue reports — it must flush, not sit. Defer\n // while the container itself still awaits its remote create — with OR\n // without queued edits, since the create cannot succeed before its parent\n // exists and attempting it just records a spurious failure. The structural\n // lane primes this store again as soon as the container create lands.\n if (!nextRecord.documentId) {\n const containerAwaitsCreate = await isContainerAwaitingRemoteCreate(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (containerAwaitsCreate) return nextRecord;\n }\n const created = await ensureSeededRemoteDocument({\n consumedRemoteUpdateSignalSeq,\n currentDoc,\n encapsulationKeyPair,\n generation,\n nextRecord,\n pendingUpdates,\n state,\n });\n let nextRemoteRecord = created.record;\n pendingUpdates = created.pendingUpdates;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n if (!nextRemoteRecord?.documentId) return nextRecord;\n\n const preparedCoverage = await prepareDocumentOutgoingCoverage({\n currentDoc,\n generation,\n pendingUpdates,\n state,\n });\n if (!preparedCoverage) {\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n nextRemoteRecord = preparedCoverage.record;\n pendingUpdates = preparedCoverage.pendingUpdates;\n\n if (\n shouldSkipCleanScheduledDocumentSync({\n currentRecord: nextRemoteRecord,\n pendingUpdates,\n state,\n })\n ) {\n return nextRemoteRecord;\n }\n\n // Pre-register the IDs we are about to send so the author's OWN\n // `document_update_created` echo (fanned back over realtime) is classified as\n // self-authored and never re-arms a redundant sync. Registering BEFORE the\n // network await closes the race where the echo lands before\n // finalizeDocumentSync records the accepted IDs — the gap that turned every\n // fast keystroke into an extra self-triggered sync.\n const { sentUpdateIds, syncAttempt } = await requestOutgoingDocumentBatch({\n currentDoc,\n encapsulationKeyPair,\n generation,\n pendingUpdates,\n record: nextRemoteRecord,\n state,\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRemoteRecord;\n }\n if (!syncAttempt) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n logUnavailable(state, wasRemoteProbe);\n return nextRemoteRecord;\n }\n\n return cleanupPreRegisteredUpdateIdsOnFailure(state, sentUpdateIds, () =>\n finalizeDocumentSync(\n state,\n currentDoc,\n nextRemoteRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n sentUpdateIds,\n wasRemoteProbe,\n ),\n );\n}\n\nasync function revalidateRemoteDocumentBeforeAttachments(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n nextRecord: DocumentRecord,\n encapsulationKeyPair: EncapsulationKeyPair,\n generation: DocumentStoreSyncGeneration,\n): Promise<{ canSyncAttachments: boolean; nextRecord: DocumentRecord }> {\n if (state.pendingAttachments.length === 0 || !nextRecord.documentId) {\n return { canSyncAttachments: true, nextRecord };\n }\n\n const consumedRemoteUpdateSignalSeq = state.remoteUpdateSignalSeq;\n const wasRemoteProbe = state.remoteUpdatePending;\n const syncAttempt = await requestRemoteDocumentSync({\n state,\n currentDoc,\n currentRecord: nextRecord,\n encapsulationKeyPair,\n generation,\n pendingUpdates: [],\n unavailableWriterLogMessage:\n \"Documents: skipped pre-attachment revalidation because the writer context is unavailable.\",\n });\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return { canSyncAttachments: false, nextRecord };\n }\n if (!syncAttempt) {\n logUnavailable(state, wasRemoteProbe);\n return { canSyncAttachments: false, nextRecord };\n }\n\n const refreshedRecord = await finalizeDocumentSync(\n state,\n currentDoc,\n nextRecord,\n syncAttempt,\n consumedRemoteUpdateSignalSeq,\n generation,\n [],\n wasRemoteProbe,\n );\n return {\n canSyncAttachments:\n !syncAttempt.synced.hasIncompletePull &&\n refreshedRecord.pullContinuation == null &&\n refreshedRecord.pullContinuationRecoveryRequired !== true &&\n isDocumentStoreSyncGenerationCurrent(state, generation),\n nextRecord: refreshedRecord,\n };\n}\n\nasync function runDocumentSyncPass(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const currentDoc = state.doc;\n const encapsulationKeyPair = state.runtime.crypto.encapsulationKeyPair;\n let nextRecord = state.record;\n\n if (!currentDoc || !nextRecord || !encapsulationKeyPair) {\n return;\n }\n\n const generation = captureDocumentStoreRemoteSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n const attachmentGeneration = captureDocumentStoreAttachmentSyncGeneration(\n state,\n currentDoc,\n syncLaneGeneration,\n );\n if (!generation || !attachmentGeneration) {\n requestDocumentStoreSync(state);\n return;\n }\n\n const revalidation = await revalidateRemoteDocumentBeforeAttachments(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n nextRecord = revalidation.nextRecord;\n if (!revalidation.canSyncAttachments) {\n return;\n }\n\n const attachmentResult = await syncPendingAttachments(\n state,\n nextRecord,\n encapsulationKeyPair,\n attachmentGeneration,\n );\n nextRecord = attachmentResult.nextRecord;\n if (state.pendingAttachments.length > 0) {\n return;\n }\n // A settled bind and the content update carrying its digest are two server\n // writes. Push the content in this same pass rather than re-arming a later\n // one, so a device lost between them is the only remaining window: peers\n // otherwise see the old digest against the new binding.\n\n nextRecord = await syncDocumentState(\n state,\n currentDoc,\n nextRecord,\n encapsulationKeyPair,\n generation,\n );\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n\n if (!state.doc || !state.record) return;\n\n const pendingUpdates = await listPendingUpdates(state);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n return;\n }\n if (!canSyncDetachedAttachmentBindings(nextRecord, pendingUpdates.length)) {\n return;\n }\n\n await syncDetachedAttachmentBindings(state, nextRecord, generation);\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n requestDocumentStoreSync(state);\n }\n}\n\nasync function runScheduledSyncIteration(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n if (!(await awaitInitializationForSync(state))) {\n return false;\n }\n if (!isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)) {\n return true;\n }\n\n if (!canRunScheduledSync(state)) {\n return true;\n }\n\n try {\n await runDocumentSyncPass(state, syncLaneGeneration);\n return true;\n } catch (error) {\n if (isDatabaseUnavailableError(error)) {\n return false;\n }\n\n await reportAndRethrowKeyingVerificationError(\n error,\n state.runtime.util.reportSecurityIncident,\n {\n objectId: state.record?.documentId ?? state.localId,\n objectKind: \"document\",\n operation: \"document.sync\",\n },\n );\n\n throw error;\n }\n}\n\nasync function runScheduledSyncLoop(\n state: DocumentStoreState,\n syncLaneGeneration: DocumentStoreSyncLaneGeneration,\n) {\n const syncingGeneration = captureDocumentStoreSyncGeneration(\n state,\n state.doc,\n );\n setDocumentSyncing(state, true);\n\n try {\n await runScheduledSyncIteration(state, syncLaneGeneration);\n } finally {\n if (\n syncingGeneration &&\n isDocumentStoreSyncGenerationCurrent(state, syncingGeneration) &&\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n setDocumentSyncing(state, false);\n }\n }\n}\n\nexport function registerDocumentStoreSyncLane(\n state: DocumentStoreState,\n getSyncLaneGeneration: () => DocumentStoreSyncLaneGeneration | null,\n): DocumentSyncLane {\n return registerDocumentSyncLane({\n domainScope: state.runtime.state.domainScope,\n localId: state.localId,\n priority: () =>\n state.remoteUpdatePending || state.record?.snapshotEndVersion === \"\"\n ? -1\n : 0,\n logError: (message, error) => {\n // Read the runtime lazily: a store's runtime is replaced in place, and a\n // reference captured here would report into a torn-down host.\n const { log, logError } = state.runtime.util;\n // Return the host's result: both callbacks are declared `=> void` but may\n // be async, and the lane reporter only catches a rejection it is handed.\n return logError ? logError(message, error) : log(message);\n },\n run: () => {\n const syncLaneGeneration = getSyncLaneGeneration();\n if (!syncLaneGeneration) return Promise.resolve();\n const activeWork = getActiveDocumentRemoteWork(state);\n if (activeWork) {\n // Re-arm on settlement, not immediately: immediate re-requests would\n // spin this lane and starve other work while the HTTP request is held.\n void activeWork.then(() => {\n if (\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ) {\n requestDocumentStoreSync(state);\n }\n });\n return Promise.resolve();\n }\n return runDocumentRemoteWork(state, () =>\n isDocumentStoreSyncLaneGenerationCurrent(state, syncLaneGeneration)\n ? runScheduledSyncLoop(state, syncLaneGeneration)\n : Promise.resolve(),\n );\n },\n });\n}\n"]}
@@ -143,11 +143,12 @@ export async function finalizeDocumentSync(state, currentDoc, currentRecord, syn
143
143
  requestDocumentStoreSync(state);
144
144
  return state.record ?? currentRecord;
145
145
  }
146
- // The sent IDs were pre-registered as self-authored before the network call so
147
- // the redis echo can never beat us. Reconcile against what the server actually
148
- // accepted: an ID we sent but the server did not accept will never be echoed,
149
- // so drop it to keep locallyAcceptedUpdateIds from leaking. Accepted IDs (a
150
- // subset of what we sent) stay registered until their echo consumes them.
146
+ // The sent IDs were pre-registered as self-authored before the network call
147
+ // so the realtime echo can never beat us. Reconcile against what the server
148
+ // actually accepted: an ID we sent but the server did not accept will never
149
+ // be echoed, so drop it to keep locallyAcceptedUpdateIds from leaking.
150
+ // Accepted IDs (a subset of what we sent) stay registered until their echo
151
+ // consumes them.
151
152
  discardUnacceptedPreRegisteredUpdateIds(state, sentUpdateIds, synced.response.acceptedOutgoingUpdateIds);
152
153
  // Persist on the identity-write chain: synced.persistedState carries this
153
154
  // pass's documentId, so it would clobber a relink that landed mid-pass. If
@@ -1 +1 @@
1
- {"version":3,"file":"syncFinalize.js","sourceRoot":"","sources":["syncFinalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EAEL,gCAAgC,EAChC,uCAAuC,GACxC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAO9E,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,sBAAsB,IAAI,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EACL,6BAA6B,EAC7B,uCAAuC,GACxC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,oCAAoC,GACrC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAElE,SAAS,2CAA2C,CAClD,gBAEC,EACD,MAAqC;IAErC,OAAO,CACL,gBAAgB,CAAC,gBAAgB,CAAC,eAAe;QAC/C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,eAAe;QAClD,gBAAgB,CAAC,gBAAgB,CAAC,mBAAmB;YACnD,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,mBAAmB;QACtD,gBAAgB,CAAC,gBAAgB,CAAC,UAAU;YAC1C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,UAAU;QAC7C,gBAAgB,CAAC,kBAAkB,CAAC,mBAAmB;YACrD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,mBAAmB;QACxD,gBAAgB,CAAC,kBAAkB,CAAC,qBAAqB;YACvD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,qBAAqB,CAC3D,CAAC;AACJ,CAAC;AAED,SAAS,qCAAqC,CAC5C,KAAyB,EACzB,MAAqC;IAErC,MAAM,gBAAgB,GACpB,MAAM,CAAC,gBAAgB;QACvB,CAAC,KAAK,CAAC,gBAAgB,EAAE,UAAU,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU;YAC5D,CAAC,CAAC,KAAK,CAAC,gBAAgB;YACxB,CAAC,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,gBAAgB;QACrB,2CAA2C,CAAC,gBAAgB,EAAE,MAAM,CAAC;QACrE,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,MAAqC;IACjE,OAAO,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAC5C,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CACjC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAC1B,KAAyB,EACzB,aAA6B,EAC7B,MAAqC;IAErC,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,kBAAkB,CAAC;IACxE,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,YAAY,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB;YACrD,CAAC,CAAC,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,EAAE;YAC9C,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;IACD,OAAO;QACL,kBAAkB,EAAE,mBAAmB,CAAC;YACtC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,GAAG,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAC5B,CAAC,MAAM,EAAE,EAAE,CACT,qBAAqB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,uBAAuB,CACnE;SACF,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAC9B,WAAgC;IAEhC,OAAO;QACL,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAAC,uBAAuB;QACpE,gBAAgB,EAAE,uCAAuC,CACvD,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,mBAAmB,CAChC;QACD,iBAAiB,EAAE;YACjB,gBAAgB,EAAE,WAAW,CAAC,wBAAwB;YACtD,MAAM,EAAE,WAAW,CAAC,aAAa;SAClC;QACD,mBAAmB,EAAE,QAAQ;QAC7B,cAAc,EAAE,oBAAoB,CAAC,WAAW,CAAC,MAAM,CAAC;QACxD,gCAAgC,EAAE,IAAI;QACtC,oBAAoB,EAAE,IAAI;KAC3B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,KAAyB,EACzB,UAAyB,EACzB,aAA6B,EAC7B,WAAgC,EAChC,UAAuC;IAEvC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACxC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,kBAAkB,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,IAAI,CAAC;IAC5D,MAAM,OAAO,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,GAAG,EAAE,CACrB,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,2BAA2B,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,kBAAkB,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CACxC,KAAK,EACL,SAAS,EACT;YACE,GAAG,MAAM,CAAC,cAAc;YACxB,aAAa,EACX,MAAM,CAAC,QAAQ,CAAC,SAAS,IAAI,aAAa,CAAC,aAAa,IAAI,IAAI;YAClE,gBAAgB,EAAE,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC;YACvD,GAAG,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC;SACrD,EACD;YACE,GAAG,OAAO;YACV,0BAA0B,EAAE,6BAA6B,CAAC;gBACxD,WAAW,EAAE,KAAK,CAAC,kBAAkB;gBACrC,eAAe,EAAE,mBAAmB,CAAC,SAAS,CAAC;gBAC/C,KAAK,EAAE,OAAO;aACf,CAAC;SACH,EACD,UAAU,CACX,CAAC;QACF,IACE,SAAS;YACT,SAAS,EAAE;YACX,CAAC,SAAS,CAAC,0BAA0B;YACrC,CAAC,SAAS,CAAC,sBAAsB,EACjC,CAAC;YACD,uEAAuE;YACvE,sEAAsE;YACtE,yDAAyD;YACzD,sEAAsE;YACtE,yEAAyE;YACzE,yEAAyE;YACzE,0BAA0B,CACxB,KAAK,EACL,UAAU,EACV,SAAS,CAAC,MAAM,EAChB,WAAW,EACX,UAAU,CACX,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,wBAAwB,CACnC,KAAK,EACL,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,OAAO,EACP,SAAS,CACV,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,KAAyB,EACzB,WAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAC/B,MAAM,mBAAmB,GAAG,gCAAgC,CAAC,KAAK,EAAE;QAClE,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;QAC/D,mBAAmB,EAAE,WAAW,CAAC,mBAAmB;QACpD,kBAAkB,EAAE,MAAM,CAAC,uBAAuB,CAAC,MAAM;QACzD,kBAAkB,EAAE,MAAM,CAAC,uBAAuB,CAAC,MAAM;QACzD,wBAAwB,EAAE,MAAM,CAAC,wBAAwB;KAC1D,CAAC,CAAC;IACH,OAAO,CACL,MAAM,CAAC,yBAAyB;QAChC,MAAM,CAAC,iBAAiB;QACxB,mBAAmB,CACpB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAyB,EACzB,UAAyB,EACzB,aAA6B,EAC7B,WAAgC,EAChC,6BAAqC,EACrC,UAAuC,EACvC,aAAgC,EAChC,cAAuB;IAEvB,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAC/B,IAAI,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QAC7D,6BAA6B,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpD,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC;IACvC,CAAC;IAED,+EAA+E;IAC/E,+EAA+E;IAC/E,8EAA8E;IAC9E,4EAA4E;IAC5E,0EAA0E;IAC1E,uCAAuC,CACrC,KAAK,EACL,aAAa,EACb,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAC1C,CAAC;IACF,0EAA0E;IAC1E,2EAA2E;IAC3E,2EAA2E;IAC3E,0EAA0E;IAC1E,kBAAkB;IAClB,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;QAChC,IACE,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC;YACxD,CAAC,0BAA0B,CACzB,UAAU,EACV,aAAa,EACb,MAAM,CAAC,IAAI,CAAC,UAAU,CACvB,EACD,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,UAAU,IAAI,aAAa,EAAE,CAAC;QACjD,CAAC;QAED,+BAA+B,CAC7B,KAAK,EACL,qCAAqC,CAAC,KAAK,EAAE,MAAM,CAAC,EACpD,WAAW,CAAC,0BAA0B,CACvC,CAAC;QACF,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAC3C,KAAK,EACL,UAAU,EACV,aAAa,EACb,WAAW,EACX,UAAU,CACX,CAAC;QACF,IACE,CAAC,SAAS;YACV,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,EACxD,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;QACnD,CAAC;QAED,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,gBAAgB,IAAI,IAAI,CAAC;QACnE,IAAI,SAAS,CAAC,0BAA0B,EAAE,CAAC;YACzC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAChC,CAAC;QACD,oEAAoE;QACpE,0EAA0E;QAC1E,mEAAmE;QACnE,eAAe,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC;QACxD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,6BAA6B,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpD,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QAC7D,6BAA6B,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpD,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC;IACpC,CAAC;IAED,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,WAAW;IACX,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC9B,+BAA+B,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,uBAAuB,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;QAChD,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,sBAAsB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IACxE,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9E,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n emptyVersionVector,\n encodeVersionVector,\n getImportBlobMetadata,\n mergeVersionVectors,\n} from \"@tearleads/loro\";\nimport { readPullContinuation } from \"../../../../data/documents/shared/sync/syncPagination\";\nimport {\n type DocumentRecord,\n settleOutgoingPassAndDecideReArm,\n shouldClearDocumentSyncFailureAfterPass,\n} from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { hydrateAttachmentBlobs } from \"../attachments/attachmentHydration\";\nimport { chainIdentityWrite } from \"../identityWriteChain\";\nimport { publishPersistedDocument, saveDocumentRecord } from \"../persistence\";\nimport type {\n DocumentState,\n DocumentStoreState,\n DocumentSyncAttempt,\n SaveDocumentRecordOptions,\n} from \"../state\";\nimport { installDocumentWriterProjection } from \"../writerProjectionGeneration\";\nimport { logRevalidationApplied as logApplied } from \"./remoteRevalidationTelemetry\";\nimport {\n discardPreRegisteredUpdateIds,\n discardUnacceptedPreRegisteredUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport {\n type DocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"./syncGeneration\";\nimport { clearConsumedRemoteUpdateSignal } from \"./syncRemoteSignals\";\nimport {\n applyIncomingSyncedUpdates,\n documentSyncContextMatches,\n importSyncedDocumentUpdates,\n} from \"./syncUpdateImport\";\nimport { extendDocumentVersionCoverage } from \"./versionCoverage\";\n\nfunction documentWriterProjectionMatchesSyncResponse(\n writerProjection: NonNullable<\n DocumentSyncAttempt[\"synced\"][\"writerProjection\"]\n >,\n synced: DocumentSyncAttempt[\"synced\"],\n): boolean {\n return (\n writerProjection.contentKeyBundle.contentKeyEpoch ===\n synced.response.contentKeyBundle.contentKeyEpoch &&\n writerProjection.contentKeyBundle.linkSetManifestHash ===\n synced.response.contentKeyBundle.linkSetManifestHash &&\n writerProjection.contentKeyBundle.targetHash ===\n synced.response.contentKeyBundle.targetHash &&\n writerProjection.documentKekTargets.linkSetManifestHash ===\n synced.response.documentKekTargets.linkSetManifestHash &&\n writerProjection.documentKekTargets.documentKeyTargetHash ===\n synced.response.documentKekTargets.documentKeyTargetHash\n );\n}\n\nfunction resolveSyncedDocumentWriterProjection(\n state: DocumentStoreState,\n synced: DocumentSyncAttempt[\"synced\"],\n) {\n const writerProjection =\n synced.writerProjection ??\n (state.writerProjection?.documentId === synced.plan.documentId\n ? state.writerProjection\n : null);\n return writerProjection &&\n documentWriterProjectionMatchesSyncResponse(writerProjection, synced)\n ? writerProjection\n : null;\n}\n\n/**\n * Durable-history tail: append pulled updates BEFORE the record persist so\n * the tail stays a superset of what the snapshot covers (duplicates are\n * idempotent by op identity; a crash between the writes can only leave the\n * safe superset).\n */\nfunction pulledHistoryUpdates(synced: DocumentSyncAttempt[\"synced\"]): string[] {\n return synced.decryptedUpdates.map((update) =>\n bytesToBase64(update.updateData),\n );\n}\n\n/**\n * The frontier a finalize persist may publish: the stored frontier advanced\n * by exactly the pulled updates just appended to the durable tail — never the\n * live document's version, which can transiently include an in-flight local\n * edit whose durable row has not landed yet.\n */\nfunction coveredSyncFrontier(\n state: DocumentStoreState,\n currentRecord: DocumentRecord,\n synced: DocumentSyncAttempt[\"synced\"],\n): { snapshotEndVersion: string } | Record<string, never> {\n const liveFrontier = (state.record ?? currentRecord).snapshotEndVersion;\n if (synced.decryptedUpdates.length === 0) {\n // A completed empty pull distinguishes a real blank note from discovery.\n // An intermediate page cannot establish that no content exists yet.\n return liveFrontier === \"\" && !synced.hasIncompletePull\n ? { snapshotEndVersion: emptyVersionVector() }\n : {};\n }\n return {\n snapshotEndVersion: mergeVersionVectors([\n ...(liveFrontier.length > 0 ? [liveFrontier] : []),\n ...synced.decryptedUpdates.map(\n (update) =>\n getImportBlobMetadata(update.updateData).partialEndVersionVector,\n ),\n ]),\n };\n}\n\nfunction documentSyncSaveOptions(\n syncAttempt: DocumentSyncAttempt,\n): SaveDocumentRecordOptions {\n return {\n acceptedPendingUpdateIds: syncAttempt.synced.settledPendingUpdateIds,\n clearSyncFailure: shouldClearDocumentSyncFailureAfterPass(\n syncAttempt.synced,\n syncAttempt.outgoingUpdateCount,\n ),\n expectedSyncState: {\n pullContinuation: syncAttempt.consumedPullContinuation,\n record: syncAttempt.requestRecord,\n },\n historyUpdateOrigin: \"remote\",\n historyUpdates: pulledHistoryUpdates(syncAttempt.synced),\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n };\n}\n\nasync function persistSyncedDocument(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n generation: DocumentStoreSyncGeneration,\n) {\n const { synced } = syncAttempt;\n const updates = synced.decryptedUpdates;\n const candidate = currentDoc.fork();\n const previousDocumentId = state.record?.documentId ?? null;\n const options = documentSyncSaveOptions(syncAttempt);\n const isCurrent = () =>\n isDocumentStoreSyncGenerationCurrent(state, generation);\n try {\n importSyncedDocumentUpdates(candidate, updates);\n if (state.pendingBaseVersion === null) {\n throw new Error(\"Document sync requires an initialized pending base\");\n }\n const persisted = await saveDocumentRecord(\n state,\n candidate,\n {\n ...synced.persistedState,\n lastCommitLsn:\n synced.response.commitLsn ?? currentRecord.lastCommitLsn ?? null,\n pullContinuation: readPullContinuation(synced.response),\n ...coveredSyncFrontier(state, currentRecord, synced),\n },\n {\n ...options,\n pendingBaseVersionOverride: extendDocumentVersionCoverage({\n baseVersion: state.pendingBaseVersion,\n documentVersion: encodeVersionVector(candidate),\n spans: updates,\n }),\n },\n generation,\n );\n if (\n persisted &&\n isCurrent() &&\n !persisted.pullContinuationSuperseded &&\n !persisted.syncIdentitySuperseded\n ) {\n // Publish a remote edit only once its history and continuation commit.\n // Importing earlier lets a losing CAS expose text that the next local\n // write authors against an older, reloaded CRDT history.\n // The durable CAS already checked the request's complete context. The\n // successful row is now live, so publication uses that committed context\n // (which may contain refreshed keying metadata) and the same generation.\n applyIncomingSyncedUpdates(\n state,\n currentDoc,\n persisted.record,\n syncAttempt,\n generation,\n );\n }\n return await publishPersistedDocument(\n state,\n currentDoc,\n persisted,\n previousDocumentId,\n options,\n isCurrent,\n );\n } finally {\n candidate.free();\n }\n}\n\nexport function shouldReArmDocumentSync(\n state: DocumentStoreState,\n syncAttempt: DocumentSyncAttempt,\n): boolean {\n const { synced } = syncAttempt;\n const shouldReArmOutgoing = settleOutgoingPassAndDecideReArm(state, {\n exhaustedPendingUpdateCount: synced.exhaustedPendingUpdateCount,\n outgoingUpdateCount: syncAttempt.outgoingUpdateCount,\n rekeyedUpdateCount: synced.rekeyedPendingUpdateIds.length,\n settledUpdateCount: synced.settledPendingUpdateIds.length,\n acceptedRecoveryBaseline: synced.acceptedRecoveryBaseline,\n });\n return (\n synced.hasDeferredPendingUpdates ||\n synced.hasIncompletePull ||\n shouldReArmOutgoing\n );\n}\n\nexport async function finalizeDocumentSync(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n consumedRemoteUpdateSignalSeq: number,\n generation: DocumentStoreSyncGeneration,\n sentUpdateIds: readonly string[],\n wasRemoteProbe: boolean,\n): Promise<DocumentRecord> {\n const { synced } = syncAttempt;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? currentRecord;\n }\n\n // The sent IDs were pre-registered as self-authored before the network call so\n // the redis echo can never beat us. Reconcile against what the server actually\n // accepted: an ID we sent but the server did not accept will never be echoed,\n // so drop it to keep locallyAcceptedUpdateIds from leaking. Accepted IDs (a\n // subset of what we sent) stay registered until their echo consumes them.\n discardUnacceptedPreRegisteredUpdateIds(\n state,\n sentUpdateIds,\n synced.response.acceptedOutgoingUpdateIds,\n );\n // Persist on the identity-write chain: synced.persistedState carries this\n // pass's documentId, so it would clobber a relink that landed mid-pass. If\n // the identity moved, the response describes the OLD document — skip every\n // response-derived in-memory mutation and let the new identity's own sync\n // pass take over.\n let responseApplied = false;\n const { record: nextRecord } = await chainIdentityWrite(state, async () => {\n const liveRecord = state.record;\n if (\n !isDocumentStoreSyncGenerationCurrent(state, generation) ||\n !documentSyncContextMatches(\n liveRecord,\n currentRecord,\n synced.plan.documentId,\n )\n ) {\n return { record: liveRecord ?? currentRecord };\n }\n\n installDocumentWriterProjection(\n state,\n resolveSyncedDocumentWriterProjection(state, synced),\n syncAttempt.writerProjectionGeneration,\n );\n const persisted = await persistSyncedDocument(\n state,\n currentDoc,\n currentRecord,\n syncAttempt,\n generation,\n );\n if (\n !persisted ||\n !isDocumentStoreSyncGenerationCurrent(state, generation)\n ) {\n return { record: state.record ?? currentRecord };\n }\n\n state.pullContinuation = persisted.record.pullContinuation ?? null;\n if (persisted.pullContinuationSuperseded) {\n state.writerProjection = null;\n }\n // A CAS loss means neither this response's acknowledgements nor its\n // continuation were committed. Keep the pass unapplied so its signals and\n // accepted-id registrations cannot be cleared without a follow-up.\n responseApplied = !persisted.pullContinuationSuperseded;\n return persisted;\n });\n if (!responseApplied) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return nextRecord;\n }\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n\n // A bounded pull request owns the whole page chain. Completing the signal on\n // an intermediate page would let a failed/null continuation pass report the\n // original request as successful even though the server frontier was never\n // drained.\n if (!synced.hasIncompletePull) {\n clearConsumedRemoteUpdateSignal(state, consumedRemoteUpdateSignalSeq);\n }\n\n if (shouldReArmDocumentSync(state, syncAttempt)) {\n requestDocumentStoreSync(state);\n }\n\n await hydrateAttachmentBlobs(state, currentDoc, nextRecord, generation);\n logApplied(state, currentDoc, synced.decryptedUpdates.length, wasRemoteProbe);\n return nextRecord;\n}\n"]}
1
+ {"version":3,"file":"syncFinalize.js","sourceRoot":"","sources":["syncFinalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EAEL,gCAAgC,EAChC,uCAAuC,GACxC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAO9E,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,sBAAsB,IAAI,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EACL,6BAA6B,EAC7B,uCAAuC,GACxC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,oCAAoC,GACrC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAElE,SAAS,2CAA2C,CAClD,gBAEC,EACD,MAAqC;IAErC,OAAO,CACL,gBAAgB,CAAC,gBAAgB,CAAC,eAAe;QAC/C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,eAAe;QAClD,gBAAgB,CAAC,gBAAgB,CAAC,mBAAmB;YACnD,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,mBAAmB;QACtD,gBAAgB,CAAC,gBAAgB,CAAC,UAAU;YAC1C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,UAAU;QAC7C,gBAAgB,CAAC,kBAAkB,CAAC,mBAAmB;YACrD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,mBAAmB;QACxD,gBAAgB,CAAC,kBAAkB,CAAC,qBAAqB;YACvD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,qBAAqB,CAC3D,CAAC;AACJ,CAAC;AAED,SAAS,qCAAqC,CAC5C,KAAyB,EACzB,MAAqC;IAErC,MAAM,gBAAgB,GACpB,MAAM,CAAC,gBAAgB;QACvB,CAAC,KAAK,CAAC,gBAAgB,EAAE,UAAU,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU;YAC5D,CAAC,CAAC,KAAK,CAAC,gBAAgB;YACxB,CAAC,CAAC,IAAI,CAAC,CAAC;IACZ,OAAO,gBAAgB;QACrB,2CAA2C,CAAC,gBAAgB,EAAE,MAAM,CAAC;QACrE,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,MAAqC;IACjE,OAAO,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAC5C,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CACjC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAC1B,KAAyB,EACzB,aAA6B,EAC7B,MAAqC;IAErC,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,kBAAkB,CAAC;IACxE,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,YAAY,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB;YACrD,CAAC,CAAC,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,EAAE;YAC9C,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;IACD,OAAO;QACL,kBAAkB,EAAE,mBAAmB,CAAC;YACtC,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,GAAG,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAC5B,CAAC,MAAM,EAAE,EAAE,CACT,qBAAqB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,uBAAuB,CACnE;SACF,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAC9B,WAAgC;IAEhC,OAAO;QACL,wBAAwB,EAAE,WAAW,CAAC,MAAM,CAAC,uBAAuB;QACpE,gBAAgB,EAAE,uCAAuC,CACvD,WAAW,CAAC,MAAM,EAClB,WAAW,CAAC,mBAAmB,CAChC;QACD,iBAAiB,EAAE;YACjB,gBAAgB,EAAE,WAAW,CAAC,wBAAwB;YACtD,MAAM,EAAE,WAAW,CAAC,aAAa;SAClC;QACD,mBAAmB,EAAE,QAAQ;QAC7B,cAAc,EAAE,oBAAoB,CAAC,WAAW,CAAC,MAAM,CAAC;QACxD,gCAAgC,EAAE,IAAI;QACtC,oBAAoB,EAAE,IAAI;KAC3B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,KAAyB,EACzB,UAAyB,EACzB,aAA6B,EAC7B,WAAgC,EAChC,UAAuC;IAEvC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACxC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IACpC,MAAM,kBAAkB,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,IAAI,CAAC;IAC5D,MAAM,OAAO,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,GAAG,EAAE,CACrB,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,2BAA2B,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,kBAAkB,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CACxC,KAAK,EACL,SAAS,EACT;YACE,GAAG,MAAM,CAAC,cAAc;YACxB,aAAa,EACX,MAAM,CAAC,QAAQ,CAAC,SAAS,IAAI,aAAa,CAAC,aAAa,IAAI,IAAI;YAClE,gBAAgB,EAAE,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC;YACvD,GAAG,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC;SACrD,EACD;YACE,GAAG,OAAO;YACV,0BAA0B,EAAE,6BAA6B,CAAC;gBACxD,WAAW,EAAE,KAAK,CAAC,kBAAkB;gBACrC,eAAe,EAAE,mBAAmB,CAAC,SAAS,CAAC;gBAC/C,KAAK,EAAE,OAAO;aACf,CAAC;SACH,EACD,UAAU,CACX,CAAC;QACF,IACE,SAAS;YACT,SAAS,EAAE;YACX,CAAC,SAAS,CAAC,0BAA0B;YACrC,CAAC,SAAS,CAAC,sBAAsB,EACjC,CAAC;YACD,uEAAuE;YACvE,sEAAsE;YACtE,yDAAyD;YACzD,sEAAsE;YACtE,yEAAyE;YACzE,yEAAyE;YACzE,0BAA0B,CACxB,KAAK,EACL,UAAU,EACV,SAAS,CAAC,MAAM,EAChB,WAAW,EACX,UAAU,CACX,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,wBAAwB,CACnC,KAAK,EACL,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,OAAO,EACP,SAAS,CACV,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,KAAyB,EACzB,WAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAC/B,MAAM,mBAAmB,GAAG,gCAAgC,CAAC,KAAK,EAAE;QAClE,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;QAC/D,mBAAmB,EAAE,WAAW,CAAC,mBAAmB;QACpD,kBAAkB,EAAE,MAAM,CAAC,uBAAuB,CAAC,MAAM;QACzD,kBAAkB,EAAE,MAAM,CAAC,uBAAuB,CAAC,MAAM;QACzD,wBAAwB,EAAE,MAAM,CAAC,wBAAwB;KAC1D,CAAC,CAAC;IACH,OAAO,CACL,MAAM,CAAC,yBAAyB;QAChC,MAAM,CAAC,iBAAiB;QACxB,mBAAmB,CACpB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAyB,EACzB,UAAyB,EACzB,aAA6B,EAC7B,WAAgC,EAChC,6BAAqC,EACrC,UAAuC,EACvC,aAAgC,EAChC,cAAuB;IAEvB,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;IAC/B,IAAI,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QAC7D,6BAA6B,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpD,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC;IACvC,CAAC;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,uEAAuE;IACvE,2EAA2E;IAC3E,iBAAiB;IACjB,uCAAuC,CACrC,KAAK,EACL,aAAa,EACb,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAC1C,CAAC;IACF,0EAA0E;IAC1E,2EAA2E;IAC3E,2EAA2E;IAC3E,0EAA0E;IAC1E,kBAAkB;IAClB,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;QAChC,IACE,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC;YACxD,CAAC,0BAA0B,CACzB,UAAU,EACV,aAAa,EACb,MAAM,CAAC,IAAI,CAAC,UAAU,CACvB,EACD,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,UAAU,IAAI,aAAa,EAAE,CAAC;QACjD,CAAC;QAED,+BAA+B,CAC7B,KAAK,EACL,qCAAqC,CAAC,KAAK,EAAE,MAAM,CAAC,EACpD,WAAW,CAAC,0BAA0B,CACvC,CAAC;QACF,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAC3C,KAAK,EACL,UAAU,EACV,aAAa,EACb,WAAW,EACX,UAAU,CACX,CAAC;QACF,IACE,CAAC,SAAS;YACV,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,EACxD,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;QACnD,CAAC;QAED,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,gBAAgB,IAAI,IAAI,CAAC;QACnE,IAAI,SAAS,CAAC,0BAA0B,EAAE,CAAC;YACzC,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAChC,CAAC;QACD,oEAAoE;QACpE,0EAA0E;QAC1E,mEAAmE;QACnE,eAAe,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC;QACxD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,6BAA6B,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpD,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,oCAAoC,CAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QAC7D,6BAA6B,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpD,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC;IACpC,CAAC;IAED,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,WAAW;IACX,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC9B,+BAA+B,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,uBAAuB,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;QAChD,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,sBAAsB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IACxE,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9E,OAAO,UAAU,CAAC;AACpB,CAAC","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n emptyVersionVector,\n encodeVersionVector,\n getImportBlobMetadata,\n mergeVersionVectors,\n} from \"@tearleads/loro\";\nimport { readPullContinuation } from \"../../../../data/documents/shared/sync/syncPagination\";\nimport {\n type DocumentRecord,\n settleOutgoingPassAndDecideReArm,\n shouldClearDocumentSyncFailureAfterPass,\n} from \"../../../../workflows/documents\";\nimport { requestDocumentStoreSync } from \"../../registry\";\nimport { hydrateAttachmentBlobs } from \"../attachments/attachmentHydration\";\nimport { chainIdentityWrite } from \"../identityWriteChain\";\nimport { publishPersistedDocument, saveDocumentRecord } from \"../persistence\";\nimport type {\n DocumentState,\n DocumentStoreState,\n DocumentSyncAttempt,\n SaveDocumentRecordOptions,\n} from \"../state\";\nimport { installDocumentWriterProjection } from \"../writerProjectionGeneration\";\nimport { logRevalidationApplied as logApplied } from \"./remoteRevalidationTelemetry\";\nimport {\n discardPreRegisteredUpdateIds,\n discardUnacceptedPreRegisteredUpdateIds,\n} from \"./syncAcceptedUpdateIds\";\nimport {\n type DocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"./syncGeneration\";\nimport { clearConsumedRemoteUpdateSignal } from \"./syncRemoteSignals\";\nimport {\n applyIncomingSyncedUpdates,\n documentSyncContextMatches,\n importSyncedDocumentUpdates,\n} from \"./syncUpdateImport\";\nimport { extendDocumentVersionCoverage } from \"./versionCoverage\";\n\nfunction documentWriterProjectionMatchesSyncResponse(\n writerProjection: NonNullable<\n DocumentSyncAttempt[\"synced\"][\"writerProjection\"]\n >,\n synced: DocumentSyncAttempt[\"synced\"],\n): boolean {\n return (\n writerProjection.contentKeyBundle.contentKeyEpoch ===\n synced.response.contentKeyBundle.contentKeyEpoch &&\n writerProjection.contentKeyBundle.linkSetManifestHash ===\n synced.response.contentKeyBundle.linkSetManifestHash &&\n writerProjection.contentKeyBundle.targetHash ===\n synced.response.contentKeyBundle.targetHash &&\n writerProjection.documentKekTargets.linkSetManifestHash ===\n synced.response.documentKekTargets.linkSetManifestHash &&\n writerProjection.documentKekTargets.documentKeyTargetHash ===\n synced.response.documentKekTargets.documentKeyTargetHash\n );\n}\n\nfunction resolveSyncedDocumentWriterProjection(\n state: DocumentStoreState,\n synced: DocumentSyncAttempt[\"synced\"],\n) {\n const writerProjection =\n synced.writerProjection ??\n (state.writerProjection?.documentId === synced.plan.documentId\n ? state.writerProjection\n : null);\n return writerProjection &&\n documentWriterProjectionMatchesSyncResponse(writerProjection, synced)\n ? writerProjection\n : null;\n}\n\n/**\n * Durable-history tail: append pulled updates BEFORE the record persist so\n * the tail stays a superset of what the snapshot covers (duplicates are\n * idempotent by op identity; a crash between the writes can only leave the\n * safe superset).\n */\nfunction pulledHistoryUpdates(synced: DocumentSyncAttempt[\"synced\"]): string[] {\n return synced.decryptedUpdates.map((update) =>\n bytesToBase64(update.updateData),\n );\n}\n\n/**\n * The frontier a finalize persist may publish: the stored frontier advanced\n * by exactly the pulled updates just appended to the durable tail — never the\n * live document's version, which can transiently include an in-flight local\n * edit whose durable row has not landed yet.\n */\nfunction coveredSyncFrontier(\n state: DocumentStoreState,\n currentRecord: DocumentRecord,\n synced: DocumentSyncAttempt[\"synced\"],\n): { snapshotEndVersion: string } | Record<string, never> {\n const liveFrontier = (state.record ?? currentRecord).snapshotEndVersion;\n if (synced.decryptedUpdates.length === 0) {\n // A completed empty pull distinguishes a real blank note from discovery.\n // An intermediate page cannot establish that no content exists yet.\n return liveFrontier === \"\" && !synced.hasIncompletePull\n ? { snapshotEndVersion: emptyVersionVector() }\n : {};\n }\n return {\n snapshotEndVersion: mergeVersionVectors([\n ...(liveFrontier.length > 0 ? [liveFrontier] : []),\n ...synced.decryptedUpdates.map(\n (update) =>\n getImportBlobMetadata(update.updateData).partialEndVersionVector,\n ),\n ]),\n };\n}\n\nfunction documentSyncSaveOptions(\n syncAttempt: DocumentSyncAttempt,\n): SaveDocumentRecordOptions {\n return {\n acceptedPendingUpdateIds: syncAttempt.synced.settledPendingUpdateIds,\n clearSyncFailure: shouldClearDocumentSyncFailureAfterPass(\n syncAttempt.synced,\n syncAttempt.outgoingUpdateCount,\n ),\n expectedSyncState: {\n pullContinuation: syncAttempt.consumedPullContinuation,\n record: syncAttempt.requestRecord,\n },\n historyUpdateOrigin: \"remote\",\n historyUpdates: pulledHistoryUpdates(syncAttempt.synced),\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n };\n}\n\nasync function persistSyncedDocument(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n generation: DocumentStoreSyncGeneration,\n) {\n const { synced } = syncAttempt;\n const updates = synced.decryptedUpdates;\n const candidate = currentDoc.fork();\n const previousDocumentId = state.record?.documentId ?? null;\n const options = documentSyncSaveOptions(syncAttempt);\n const isCurrent = () =>\n isDocumentStoreSyncGenerationCurrent(state, generation);\n try {\n importSyncedDocumentUpdates(candidate, updates);\n if (state.pendingBaseVersion === null) {\n throw new Error(\"Document sync requires an initialized pending base\");\n }\n const persisted = await saveDocumentRecord(\n state,\n candidate,\n {\n ...synced.persistedState,\n lastCommitLsn:\n synced.response.commitLsn ?? currentRecord.lastCommitLsn ?? null,\n pullContinuation: readPullContinuation(synced.response),\n ...coveredSyncFrontier(state, currentRecord, synced),\n },\n {\n ...options,\n pendingBaseVersionOverride: extendDocumentVersionCoverage({\n baseVersion: state.pendingBaseVersion,\n documentVersion: encodeVersionVector(candidate),\n spans: updates,\n }),\n },\n generation,\n );\n if (\n persisted &&\n isCurrent() &&\n !persisted.pullContinuationSuperseded &&\n !persisted.syncIdentitySuperseded\n ) {\n // Publish a remote edit only once its history and continuation commit.\n // Importing earlier lets a losing CAS expose text that the next local\n // write authors against an older, reloaded CRDT history.\n // The durable CAS already checked the request's complete context. The\n // successful row is now live, so publication uses that committed context\n // (which may contain refreshed keying metadata) and the same generation.\n applyIncomingSyncedUpdates(\n state,\n currentDoc,\n persisted.record,\n syncAttempt,\n generation,\n );\n }\n return await publishPersistedDocument(\n state,\n currentDoc,\n persisted,\n previousDocumentId,\n options,\n isCurrent,\n );\n } finally {\n candidate.free();\n }\n}\n\nexport function shouldReArmDocumentSync(\n state: DocumentStoreState,\n syncAttempt: DocumentSyncAttempt,\n): boolean {\n const { synced } = syncAttempt;\n const shouldReArmOutgoing = settleOutgoingPassAndDecideReArm(state, {\n exhaustedPendingUpdateCount: synced.exhaustedPendingUpdateCount,\n outgoingUpdateCount: syncAttempt.outgoingUpdateCount,\n rekeyedUpdateCount: synced.rekeyedPendingUpdateIds.length,\n settledUpdateCount: synced.settledPendingUpdateIds.length,\n acceptedRecoveryBaseline: synced.acceptedRecoveryBaseline,\n });\n return (\n synced.hasDeferredPendingUpdates ||\n synced.hasIncompletePull ||\n shouldReArmOutgoing\n );\n}\n\nexport async function finalizeDocumentSync(\n state: DocumentStoreState,\n currentDoc: DocumentState,\n currentRecord: DocumentRecord,\n syncAttempt: DocumentSyncAttempt,\n consumedRemoteUpdateSignalSeq: number,\n generation: DocumentStoreSyncGeneration,\n sentUpdateIds: readonly string[],\n wasRemoteProbe: boolean,\n): Promise<DocumentRecord> {\n const { synced } = syncAttempt;\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? currentRecord;\n }\n\n // The sent IDs were pre-registered as self-authored before the network call\n // so the realtime echo can never beat us. Reconcile against what the server\n // actually accepted: an ID we sent but the server did not accept will never\n // be echoed, so drop it to keep locallyAcceptedUpdateIds from leaking.\n // Accepted IDs (a subset of what we sent) stay registered until their echo\n // consumes them.\n discardUnacceptedPreRegisteredUpdateIds(\n state,\n sentUpdateIds,\n synced.response.acceptedOutgoingUpdateIds,\n );\n // Persist on the identity-write chain: synced.persistedState carries this\n // pass's documentId, so it would clobber a relink that landed mid-pass. If\n // the identity moved, the response describes the OLD document — skip every\n // response-derived in-memory mutation and let the new identity's own sync\n // pass take over.\n let responseApplied = false;\n const { record: nextRecord } = await chainIdentityWrite(state, async () => {\n const liveRecord = state.record;\n if (\n !isDocumentStoreSyncGenerationCurrent(state, generation) ||\n !documentSyncContextMatches(\n liveRecord,\n currentRecord,\n synced.plan.documentId,\n )\n ) {\n return { record: liveRecord ?? currentRecord };\n }\n\n installDocumentWriterProjection(\n state,\n resolveSyncedDocumentWriterProjection(state, synced),\n syncAttempt.writerProjectionGeneration,\n );\n const persisted = await persistSyncedDocument(\n state,\n currentDoc,\n currentRecord,\n syncAttempt,\n generation,\n );\n if (\n !persisted ||\n !isDocumentStoreSyncGenerationCurrent(state, generation)\n ) {\n return { record: state.record ?? currentRecord };\n }\n\n state.pullContinuation = persisted.record.pullContinuation ?? null;\n if (persisted.pullContinuationSuperseded) {\n state.writerProjection = null;\n }\n // A CAS loss means neither this response's acknowledgements nor its\n // continuation were committed. Keep the pass unapplied so its signals and\n // accepted-id registrations cannot be cleared without a follow-up.\n responseApplied = !persisted.pullContinuationSuperseded;\n return persisted;\n });\n if (!responseApplied) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return nextRecord;\n }\n\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n discardPreRegisteredUpdateIds(state, sentUpdateIds);\n requestDocumentStoreSync(state);\n return state.record ?? nextRecord;\n }\n\n // A bounded pull request owns the whole page chain. Completing the signal on\n // an intermediate page would let a failed/null continuation pass report the\n // original request as successful even though the server frontier was never\n // drained.\n if (!synced.hasIncompletePull) {\n clearConsumedRemoteUpdateSignal(state, consumedRemoteUpdateSignalSeq);\n }\n\n if (shouldReArmDocumentSync(state, syncAttempt)) {\n requestDocumentStoreSync(state);\n }\n\n await hydrateAttachmentBlobs(state, currentDoc, nextRecord, generation);\n logApplied(state, currentDoc, synced.decryptedUpdates.length, wasRemoteProbe);\n return nextRecord;\n}\n"]}