@tearleads/client-sdk 0.1.82 → 0.1.84
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/data/documents/documentSync.js.map +1 -1
- package/data/documents/shared/crypto.js.map +1 -1
- package/data/documents/shared/types.d.ts +1 -1
- package/data/documents/shared/types.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistence.js +2 -2
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.d.ts +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +3 -3
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataPullContinuationPersistence.js +1 -1
- package/data/persistence/container-contents/containerMetadataPullContinuationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
- package/data/persistence/container-contents/containerPendingUpdatePersistence.js +2 -2
- package/data/persistence/container-contents/containerPendingUpdatePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
- package/data/persistence/documents/documentDiscoveryReset.d.ts +6 -0
- package/data/persistence/documents/documentsPersistence.js +2 -2
- package/data/persistence/documents/documentsPersistence.js.map +1 -1
- package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js +1 -1
- package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js.map +1 -1
- package/data/persistence/documents/internal/discardDocument.js +2 -2
- package/data/persistence/documents/internal/discardDocument.js.map +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js +2 -2
- package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js +3 -3
- package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentPullContinuationPersistence.js +1 -1
- package/data/persistence/documents/internal/documentPullContinuationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentRecordIdentity.js.map +1 -1
- package/data/persistence/documents/internal/documentRows.js.map +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
- package/data/persistence/documents/internal/rowQueryPersistence.js +1 -1
- package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
- package/data/persistence/documents/internal/syncQueuePersistence.js +2 -2
- package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentHistoryPersistence.d.ts +1 -1
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentHistoryPersistence.js +5 -5
- package/data/persistence/documents/records/documentHistoryPersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPendingUpdatePersistence.d.ts +2 -2
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPendingUpdatePersistence.js +2 -2
- package/data/persistence/documents/records/documentPendingUpdatePersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPersistenceTypes.d.ts +2 -2
- package/data/persistence/documents/records/documentPersistenceTypes.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentRecordPersistence.d.ts +1 -1
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentRecordPersistence.js +4 -4
- package/data/persistence/documents/records/documentRecordPersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentSyncFailurePersistence.d.ts +2 -2
- package/data/{sqlite/documentPersistence → persistence/documents/records}/documentSyncFailurePersistence.js +3 -3
- package/data/persistence/documents/records/documentSyncFailurePersistence.js.map +1 -0
- package/data/{sqlite/documentPersistence → persistence/documents/records}/index.d.ts +2 -2
- package/data/{sqlite/documentPersistence → persistence/documents/records}/index.js +4 -4
- package/data/persistence/documents/records/index.js.map +1 -0
- package/data/persistence/documents/types.d.ts +2 -2
- package/data/persistence/documents/types.js.map +1 -1
- package/{workflows/sync/remoteResetPrincipalScope.d.ts → data/persistence/principalPolicy/principalPolicyRemoteReset.d.ts} +1 -1
- package/{workflows/sync/remoteResetPrincipalScope.js → data/persistence/principalPolicy/principalPolicyRemoteReset.js} +7 -7
- package/data/persistence/principalPolicy/principalPolicyRemoteReset.js.map +1 -0
- package/data/persistence/verifiedManifestBundlePersistence.d.ts +2 -0
- package/data/persistence/verifiedManifestBundlePersistence.js +7 -0
- package/data/persistence/verifiedManifestBundlePersistence.js.map +1 -1
- package/data/sqlite/{documentPersistence/documentOrphanBlobReclaims.js → schema/documentOrphanBlobReclaimSchema.js} +1 -1
- package/data/sqlite/schema/documentOrphanBlobReclaimSchema.js.map +1 -0
- package/data/sqlite/schema/index.js +1 -1
- package/data/sqlite/schema/index.js.map +1 -1
- package/data/sqlite/sqliteBindBudget.js +12 -0
- package/data/sqlite/sqliteBindBudget.js.map +1 -1
- package/package.json +1 -1
- package/workflows/container-contents/container-state/create/createIntentSeed.js.map +1 -1
- package/workflows/container-contents/container-state/create/createWithMetadataPlan.js.map +1 -1
- package/workflows/container-contents/container-state/types.js.map +1 -1
- package/workflows/container-contents/metadata/index.js.map +1 -1
- package/workflows/container-contents/metadata/metadataEvents.d.ts +1 -1
- package/workflows/container-contents/metadata/metadataEvents.js.map +1 -1
- package/workflows/container-contents/metadata/metadataIncomingUpdateIsolation.js +1 -1
- package/workflows/container-contents/metadata/metadataIncomingUpdateIsolation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataRemoteSync.d.ts +1 -1
- package/workflows/container-contents/metadata/metadataRemoteSync.js.map +1 -1
- package/workflows/container-contents/pendingWrites/index.js +1 -1
- package/workflows/container-contents/pendingWrites/index.js.map +1 -1
- package/workflows/container-contents/recovery/accessRestoration.js +1 -1
- package/workflows/container-contents/recovery/accessRestoration.js.map +1 -1
- package/workflows/container-contents/remoteReset/containerRemoteReset.d.ts +185 -0
- package/workflows/container-contents/remoteReset/containerRemoteReset.js +174 -0
- package/workflows/container-contents/remoteReset/containerRemoteReset.js.map +1 -0
- package/workflows/container-contents/remoteReset/remoteResetCursorScope.d.ts +14 -0
- package/workflows/{sync → container-contents/remoteReset}/remoteResetCursorScope.js +2 -2
- package/workflows/container-contents/remoteReset/remoteResetCursorScope.js.map +1 -0
- package/workflows/documents/create/documentCreationPersistence.js.map +1 -1
- package/workflows/documents/create/index.d.ts +1 -1
- package/workflows/documents/create/index.js.map +1 -1
- package/workflows/documents/documentMutationCommit.d.ts +1 -1
- package/workflows/documents/documentMutationCommit.js.map +1 -1
- package/workflows/documents/index.d.ts +2 -2
- package/workflows/documents/index.js +2 -2
- package/workflows/documents/index.js.map +1 -1
- package/workflows/documents/remoteReset/documentRemoteReset.d.ts +56 -0
- package/workflows/documents/remoteReset/documentRemoteReset.js +135 -0
- package/workflows/documents/remoteReset/documentRemoteReset.js.map +1 -0
- package/workflows/{sync → documents/remoteReset}/remoteResetAttachments.js +3 -3
- package/workflows/documents/remoteReset/remoteResetAttachments.js.map +1 -0
- package/workflows/{sync → documents/remoteReset}/remoteResetPlans.d.ts +1 -1
- package/workflows/{sync → documents/remoteReset}/remoteResetPlans.js +7 -7
- package/workflows/documents/remoteReset/remoteResetPlans.js.map +1 -0
- package/workflows/documents/sync/index.js.map +1 -1
- package/workflows/documents/sync/initialSync.d.ts +1 -1
- package/workflows/documents/sync/initialSync.js.map +1 -1
- package/workflows/documents/sync/readOnlySync.d.ts +1 -1
- package/workflows/documents/sync/readOnlySync.js.map +1 -1
- package/workflows/documents/sync/syncAttemptPlanning.js.map +1 -1
- package/workflows/documents/sync/syncAttemptState.d.ts +1 -1
- package/workflows/documents/sync/syncAttemptState.js.map +1 -1
- package/workflows/documents/sync/syncResponseResult.js.map +1 -1
- package/workflows/documents/sync/syncSubmittedResult.js.map +1 -1
- package/workflows/documents/syncFailures/index.js.map +1 -1
- package/workflows/documents/syncPlan/syncContentKeys.d.ts +1 -1
- package/workflows/documents/syncPlan/syncContentKeys.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanMaterial.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanRequestBounds.js.map +1 -1
- package/workflows/documents/syncRekeys/syncContainerRekeys.js.map +1 -1
- package/workflows/documents/syncRekeys/syncRecoveryRekey.d.ts +1 -1
- package/workflows/documents/syncRekeys/syncRecoveryRekey.js +1 -1
- package/workflows/documents/syncRekeys/syncRecoveryRekey.js.map +1 -1
- package/workflows/organizations/readModel/listLocalOrganizations.js +1 -1
- package/workflows/organizations/readModel/listLocalOrganizations.js.map +1 -1
- package/workflows/organizations/readModel/organizationRemoteReset.js +25 -0
- package/workflows/organizations/readModel/organizationRemoteReset.js.map +1 -0
- package/workflows/registration/persistRegistrationBootstrap.d.ts +1 -1
- package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
- package/workflows/sync/remoteReset.js +60 -229
- package/workflows/sync/remoteReset.js.map +1 -1
- package/workflows/sync/remoteResetScope.d.ts +7 -10
- package/workflows/sync/remoteResetScope.js +26 -108
- package/workflows/sync/remoteResetScope.js.map +1 -1
- package/data/sqlite/documentPersistence/documentHistoryPersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/documentOrphanBlobReclaims.js.map +0 -1
- package/data/sqlite/documentPersistence/documentPendingUpdatePersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/documentPersistenceTypes.js.map +0 -1
- package/data/sqlite/documentPersistence/documentRecordPersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/documentSyncFailurePersistence.js.map +0 -1
- package/data/sqlite/documentPersistence/index.js.map +0 -1
- package/workflows/sync/remoteResetAttachments.js.map +0 -1
- package/workflows/sync/remoteResetBatches.js +0 -13
- package/workflows/sync/remoteResetBatches.js.map +0 -1
- package/workflows/sync/remoteResetCursorScope.js.map +0 -1
- package/workflows/sync/remoteResetPlans.js.map +0 -1
- package/workflows/sync/remoteResetPrincipalScope.js.map +0 -1
- /package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPersistenceTypes.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readOnlySync.js","sourceRoot":"","sources":["readOnlySync.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentCreateResponse,\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isAccessManifestBundleWireResponse,\n isDocumentContentKeyBundleResponse,\n isDocumentKekTargetsResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isRetryableDocumentSyncConflict,\n persistedDocumentSyncStateFromResponse,\n submitDocumentSync,\n} from \"../../../data/documents/shared/responses\";\nimport { limitDocumentSyncRequestBytes } from \"../../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nimport type {\n DocumentSyncUpdateIsolationError,\n IncomingDocumentSyncUpdateValidator,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type {\n DocumentCreateAuthor,\n DocumentSyncApi,\n DocumentSyncPlan,\n DocumentWriterPublicKeyResolver,\n PersistedDocumentSyncState,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport {\n assertRawContinuationCanRetry,\n refreshSyncAttemptWriterProjection,\n resolveSyncAttemptWriterProjection,\n} from \"../syncFailures\";\nimport {\n handleUpstreamDeletedDocumentSyncFailure,\n projectionIntegrityErrorCode,\n type RemoteDocumentDeletionHandler,\n type TerminalSubmitFailureHandler,\n} from \"../syncFailures/syncFailureClassification\";\nimport { DocumentRawHistoryUnavailableError } from \"../syncPlan/syncContentKeys\";\nimport { buildDocumentSyncPlan } from \"../syncPlan/syncPlanIdentity\";\nimport { buildMaterializedDocumentSyncPlan } from \"../syncPlan/syncPlanMaterial\";\nimport type { RekeyPendingUpdate } from \"../syncRekeys/syncRecoveryRekey\";\nimport {\n handleReadOnlyProjectionCompletionError,\n REFRESH_CACHED_PROJECTION,\n} from \"./readOnlyProjectionFailure\";\nimport type { DocumentSyncContainerRekeyBuilder } from \"./syncAttemptState\";\nimport { syncRemoteDocumentResultFromResponse } from \"./syncResponseResult\";\nimport { type DocumentSyncTraceEmitter, traceSubmitFailed } from \"./syncTrace\";\n\nasync function completeReadOnlyRemoteDocumentSyncWithProjection(\n input: Omit<ReadOnlyDocumentSyncCompletionInput, \"writerProjection\"> & {\n writerProjection: DocumentWriterProjectionResponse;\n },\n): Promise<SyncRemoteDocumentResult> {\n const materializedPlan = await buildMaterializedDocumentSyncPlan({\n author: input.author,\n execSql: input.execSql,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n pullCursor: input.pullContinuation?.cursor,\n onSyncTrace: input.onSyncTrace,\n pendingUpdates: [],\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n\n const result = await syncRemoteDocumentResultFromResponse({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n materializedPlan,\n recoveryPendingUpdatesById: new Map(),\n resolveWriterPublicKey: input.resolveWriterPublicKey,\n response: input.response,\n targetSecretKey: input.targetSecretKey,\n validateIncomingUpdates: input.validateIncomingUpdates,\n writerProjection: input.writerProjection,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n });\n return {\n ...result,\n hasIncompletePull: !input.pullComplete,\n };\n}\n\nfunction parsePersistedDocumentSyncRecord<T>(\n value: string | null | undefined,\n label: string,\n isRecord: (value: unknown) => value is T,\n): T | null {\n if (!value) {\n return null;\n }\n\n try {\n const record = readCanonicalRecord(JSON.parse(value), label);\n return isRecord(record) ? record : null;\n } catch {\n return null;\n }\n}\n\nfunction parsePersistedDocumentSyncState(\n persistedState: PersistedDocumentSyncState | null | undefined,\n documentId: string,\n): {\n contentKeyBundle: DocumentCreateResponse[\"contentKeyBundle\"];\n documentKekTargets: DocumentSyncResponse[\"documentKekTargets\"];\n documentManifest: DocumentCreateResponse[\"accessManifest\"];\n} | null {\n if (persistedState?.documentId !== documentId) {\n return null;\n }\n\n const contentKeyBundle = parsePersistedDocumentSyncRecord(\n persistedState.contentKeyBundle,\n \"Persisted document sync content-key bundle\",\n isDocumentContentKeyBundleResponse,\n );\n const documentKekTargets = parsePersistedDocumentSyncRecord(\n persistedState.documentKekTargets,\n \"Persisted document sync KEK targets\",\n isDocumentKekTargetsResponse,\n );\n const documentManifest = parsePersistedDocumentSyncRecord(\n persistedState.documentManifestBundle,\n \"Persisted document sync manifest\",\n isAccessManifestBundleWireResponse,\n );\n\n if (!contentKeyBundle || !documentKekTargets || !documentManifest) {\n return null;\n }\n\n return {\n contentKeyBundle,\n documentKekTargets,\n documentManifest,\n };\n}\n\nasync function buildReadOnlyDocumentSyncPlanFromPersistedState(input: {\n author: DocumentCreateAuthor;\n documentId: string;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n signedAt?: string | undefined;\n}): Promise<DocumentSyncPlan | null> {\n const persisted = parsePersistedDocumentSyncState(\n input.persistedState,\n input.documentId,\n );\n if (!persisted) {\n return null;\n }\n\n const plan = await buildDocumentSyncPlan({\n author: input.author,\n contentKeyBundle: persisted.contentKeyBundle,\n documentId: input.documentId,\n documentKekTargets: persisted.documentKekTargets,\n documentManifest: persisted.documentManifest,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n outgoingUpdates: [],\n pullCursor: input.pullContinuation?.cursor,\n signedAt: input.signedAt,\n });\n const request = limitDocumentSyncRequestBytes(plan.request);\n return request === plan.request ? plan : { ...plan, request };\n}\n\ntype PersistedReadOnlyDocumentSyncResult =\n | {\n kind: \"completed\";\n result: SyncRemoteDocumentResult | null;\n }\n | {\n kind: \"not_completed\";\n };\n\ninterface ReadOnlyDocumentSyncCompletionInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n documentId: string;\n execSql: ExecSql;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n pullComplete: boolean;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n response: DocumentSyncResponse;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nasync function tryCompleteReadOnlyRemoteDocumentSyncWithProjection(input: {\n allowCachedProjectionRefresh: boolean;\n completion: ReadOnlyDocumentSyncCompletionInput;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION\n> {\n try {\n return await completeReadOnlyRemoteDocumentSyncWithProjection({\n ...input.completion,\n writerProjection: input.writerProjection,\n });\n } catch (error) {\n return handleReadOnlyProjectionCompletionError(error, {\n allowCachedProjectionRefresh: input.allowCachedProjectionRefresh,\n historyMode: input.completion.historyMode,\n });\n }\n}\nasync function completeReadOnlyRemoteDocumentSyncWithUpdates(\n input: ReadOnlyDocumentSyncCompletionInput,\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n const reusableWriterProjection =\n input.writerProjection?.documentId === input.documentId\n ? input.writerProjection\n : null;\n const writerProjection =\n reusableWriterProjection ??\n (await resolveSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n reusableWriterProjection: null,\n stillCurrent: input.stillCurrent,\n }));\n if (!writerProjection) {\n return { kind: \"completed\", result: null };\n }\n const canRefreshProjection =\n input.historyMode === \"raw\" || Boolean(reusableWriterProjection);\n let result:\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION = null;\n let retryAfterRollback = false;\n try {\n result = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection({\n allowCachedProjectionRefresh: canRefreshProjection,\n completion: input,\n writerProjection,\n });\n } catch (error) {\n if (projectionIntegrityErrorCode(error) !== \"rollback\") {\n throw error;\n }\n retryAfterRollback = true;\n }\n if (\n !retryAfterRollback &&\n result !== REFRESH_CACHED_PROJECTION &&\n !(result instanceof DocumentRawHistoryUnavailableError) &&\n (result || !reusableWriterProjection)\n ) {\n return { kind: \"completed\", result };\n }\n const freshWriterProjection = await refreshSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n stillCurrent: input.stillCurrent,\n unavailableError:\n result instanceof DocumentRawHistoryUnavailableError ? result : undefined,\n });\n if (!freshWriterProjection) {\n return { kind: \"completed\", result: null };\n }\n const freshResult = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection(\n {\n allowCachedProjectionRefresh: false,\n completion: input,\n writerProjection: freshWriterProjection,\n },\n );\n if (\n freshResult === REFRESH_CACHED_PROJECTION ||\n freshResult instanceof DocumentRawHistoryUnavailableError\n ) {\n throw new Error(\"Fresh document projection unexpectedly requested refresh\");\n }\n return freshResult\n ? { kind: \"completed\", result: freshResult }\n : { kind: \"not_completed\" };\n}\nasync function syncReadOnlyRemoteDocumentFromPersistedState(\n input: Omit<\n ReadOnlyDocumentSyncCompletionInput,\n \"pullComplete\" | \"response\"\n > & {\n persistedState?: PersistedDocumentSyncState | null | undefined;\n },\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n let plan: DocumentSyncPlan | null;\n try {\n plan = await buildReadOnlyDocumentSyncPlanFromPersistedState(input);\n } catch {\n plan = null;\n }\n if (!plan) {\n return { kind: \"not_completed\" };\n }\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n const submitted = await submitDocumentSync({\n apiClient: input.apiClient,\n expectedCommitLsnMode: input.pullContinuation?.commitLsnMode,\n plan,\n });\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted.ok) {\n if (\n await handleUpstreamDeletedDocumentSyncFailure({\n documentId: input.documentId,\n failure: submitted,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n })\n ) {\n return { kind: \"completed\", result: null };\n }\n\n if (isRetryableDocumentSyncConflict(submitted)) {\n traceSubmitFailed(input.onSyncTrace, {\n action: \"retry\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n assertRawContinuationCanRetry(input.historyMode, input.pullContinuation);\n return { kind: \"not_completed\" };\n }\n\n traceSubmitFailed(input.onSyncTrace, {\n action: \"stop\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n submitted.report();\n return { kind: \"completed\", result: null };\n }\n\n if (submitted.response.updates.length > 0) {\n return completeReadOnlyRemoteDocumentSyncWithUpdates({\n ...input,\n pullComplete: submitted.pullComplete,\n response: submitted.response,\n });\n }\n\n try {\n const persistedState = await persistedDocumentSyncStateFromResponse(\n plan,\n submitted.response,\n { resolveWriterPublicKey: input.resolveWriterPublicKey },\n );\n\n return {\n kind: \"completed\",\n result: {\n contentKey: new Uint8Array(),\n decryptedUpdates: [],\n exhaustedPendingUpdateCount: 0,\n hasDeferredPendingUpdates: false,\n hasIncompletePull: !submitted.pullComplete,\n persistedState,\n plan,\n rekeyedPendingUpdateIds: [],\n response: submitted.response,\n settledPendingUpdateIds: [],\n acceptedRecoveryBaseline: false,\n },\n };\n } catch (error) {\n if (input.historyMode === \"raw\") {\n throw error;\n }\n return { kind: \"not_completed\" };\n }\n}\n\nexport interface SyncRemoteDocumentInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n /**\n * Supplies a full-history Loro snapshot of the local document so a\n * write-bearing pass can heal a stale content-key bundle by rotating to a\n * fresh content key anchored by a rotation baseline.\n */\n buildRotationSnapshot?: (() => Promise<Uint8Array | null>) | undefined;\n /** Overrides automatic ancestor repair for each submission's current projection. */\n buildContainerRekeys?: DocumentSyncContainerRekeyBuilder;\n documentId: string;\n execSql: ExecSql;\n /** Explicit read-only recovery that bypasses rotation-baseline redirect. */\n historyMode?: \"raw\" | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n /** Atomically commits the verified purge proof with matching local teardown. */\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n /** Clipboard-safe trace sink (see syncTrace.ts); never receives content. */\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n /**\n * Fires when a pass WITHOUT queued writes cannot resolve its writer\n * projection (e.g. a coded 409 from the projection route). Read-only\n * revalidation otherwise fails silently — one burned request and a trace\n * line — leaving the document permanently stale with nothing durable to\n * explain why (edge-case row 13).\n */\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n /** Records a verified response update that could not be decrypted/imported. */\n onIncomingUpdateIsolationFailure?:\n | ((failure: DocumentSyncUpdateIsolationError) => void | Promise<void>)\n | undefined;\n /** Fires immediately before a materialized outgoing batch is submitted. */\n onOutgoingUpdatesMaterialized?:\n | ((updateIds: readonly string[]) => void)\n | undefined;\n /** Invalidates continuation state after the server rejects its snapshot. */\n onPullContinuationInvalidated?:\n | ((continuation: DocumentSyncPullContinuation) => void | Promise<void>)\n | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates?: readonly PendingUpdateRecord[] | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n rekeyPendingUpdate?: RekeyPendingUpdate | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n /** Validates decrypted updates against scratch state before callers persist. */\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport async function tryPersistedReadOnlyDocumentSync(\n input: SyncRemoteDocumentInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<PersistedReadOnlyDocumentSyncResult | null> {\n if (input.stillCurrent?.() === false) return null;\n if ((input.pendingUpdates ?? []).length > 0) return null;\n\n return syncReadOnlyRemoteDocumentFromPersistedState({\n ...input,\n resolveProjectionUserKey,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"readOnlySync.js","sourceRoot":"","sources":["readOnlySync.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentCreateResponse,\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isAccessManifestBundleWireResponse,\n isDocumentContentKeyBundleResponse,\n isDocumentKekTargetsResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isRetryableDocumentSyncConflict,\n persistedDocumentSyncStateFromResponse,\n submitDocumentSync,\n} from \"../../../data/documents/shared/responses\";\nimport { limitDocumentSyncRequestBytes } from \"../../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nimport type {\n DocumentSyncUpdateIsolationError,\n IncomingDocumentSyncUpdateValidator,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type {\n DocumentCreateAuthor,\n DocumentSyncApi,\n DocumentSyncPlan,\n DocumentWriterPublicKeyResolver,\n PersistedDocumentSyncState,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport {\n assertRawContinuationCanRetry,\n refreshSyncAttemptWriterProjection,\n resolveSyncAttemptWriterProjection,\n} from \"../syncFailures\";\nimport {\n handleUpstreamDeletedDocumentSyncFailure,\n projectionIntegrityErrorCode,\n type RemoteDocumentDeletionHandler,\n type TerminalSubmitFailureHandler,\n} from \"../syncFailures/syncFailureClassification\";\nimport { DocumentRawHistoryUnavailableError } from \"../syncPlan/syncContentKeys\";\nimport { buildDocumentSyncPlan } from \"../syncPlan/syncPlanIdentity\";\nimport { buildMaterializedDocumentSyncPlan } from \"../syncPlan/syncPlanMaterial\";\nimport type { RekeyPendingUpdate } from \"../syncRekeys/syncRecoveryRekey\";\nimport {\n handleReadOnlyProjectionCompletionError,\n REFRESH_CACHED_PROJECTION,\n} from \"./readOnlyProjectionFailure\";\nimport type { DocumentSyncContainerRekeyBuilder } from \"./syncAttemptState\";\nimport { syncRemoteDocumentResultFromResponse } from \"./syncResponseResult\";\nimport { type DocumentSyncTraceEmitter, traceSubmitFailed } from \"./syncTrace\";\n\nasync function completeReadOnlyRemoteDocumentSyncWithProjection(\n input: Omit<ReadOnlyDocumentSyncCompletionInput, \"writerProjection\"> & {\n writerProjection: DocumentWriterProjectionResponse;\n },\n): Promise<SyncRemoteDocumentResult> {\n const materializedPlan = await buildMaterializedDocumentSyncPlan({\n author: input.author,\n execSql: input.execSql,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n pullCursor: input.pullContinuation?.cursor,\n onSyncTrace: input.onSyncTrace,\n pendingUpdates: [],\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n\n const result = await syncRemoteDocumentResultFromResponse({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n materializedPlan,\n recoveryPendingUpdatesById: new Map(),\n resolveWriterPublicKey: input.resolveWriterPublicKey,\n response: input.response,\n targetSecretKey: input.targetSecretKey,\n validateIncomingUpdates: input.validateIncomingUpdates,\n writerProjection: input.writerProjection,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n });\n return {\n ...result,\n hasIncompletePull: !input.pullComplete,\n };\n}\n\nfunction parsePersistedDocumentSyncRecord<T>(\n value: string | null | undefined,\n label: string,\n isRecord: (value: unknown) => value is T,\n): T | null {\n if (!value) {\n return null;\n }\n\n try {\n const record = readCanonicalRecord(JSON.parse(value), label);\n return isRecord(record) ? record : null;\n } catch {\n return null;\n }\n}\n\nfunction parsePersistedDocumentSyncState(\n persistedState: PersistedDocumentSyncState | null | undefined,\n documentId: string,\n): {\n contentKeyBundle: DocumentCreateResponse[\"contentKeyBundle\"];\n documentKekTargets: DocumentSyncResponse[\"documentKekTargets\"];\n documentManifest: DocumentCreateResponse[\"accessManifest\"];\n} | null {\n if (persistedState?.documentId !== documentId) {\n return null;\n }\n\n const contentKeyBundle = parsePersistedDocumentSyncRecord(\n persistedState.contentKeyBundle,\n \"Persisted document sync content-key bundle\",\n isDocumentContentKeyBundleResponse,\n );\n const documentKekTargets = parsePersistedDocumentSyncRecord(\n persistedState.documentKekTargets,\n \"Persisted document sync KEK targets\",\n isDocumentKekTargetsResponse,\n );\n const documentManifest = parsePersistedDocumentSyncRecord(\n persistedState.documentManifestBundle,\n \"Persisted document sync manifest\",\n isAccessManifestBundleWireResponse,\n );\n\n if (!contentKeyBundle || !documentKekTargets || !documentManifest) {\n return null;\n }\n\n return {\n contentKeyBundle,\n documentKekTargets,\n documentManifest,\n };\n}\n\nasync function buildReadOnlyDocumentSyncPlanFromPersistedState(input: {\n author: DocumentCreateAuthor;\n documentId: string;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n signedAt?: string | undefined;\n}): Promise<DocumentSyncPlan | null> {\n const persisted = parsePersistedDocumentSyncState(\n input.persistedState,\n input.documentId,\n );\n if (!persisted) {\n return null;\n }\n\n const plan = await buildDocumentSyncPlan({\n author: input.author,\n contentKeyBundle: persisted.contentKeyBundle,\n documentId: input.documentId,\n documentKekTargets: persisted.documentKekTargets,\n documentManifest: persisted.documentManifest,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n outgoingUpdates: [],\n pullCursor: input.pullContinuation?.cursor,\n signedAt: input.signedAt,\n });\n const request = limitDocumentSyncRequestBytes(plan.request);\n return request === plan.request ? plan : { ...plan, request };\n}\n\ntype PersistedReadOnlyDocumentSyncResult =\n | {\n kind: \"completed\";\n result: SyncRemoteDocumentResult | null;\n }\n | {\n kind: \"not_completed\";\n };\n\ninterface ReadOnlyDocumentSyncCompletionInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n documentId: string;\n execSql: ExecSql;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n pullComplete: boolean;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n response: DocumentSyncResponse;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nasync function tryCompleteReadOnlyRemoteDocumentSyncWithProjection(input: {\n allowCachedProjectionRefresh: boolean;\n completion: ReadOnlyDocumentSyncCompletionInput;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION\n> {\n try {\n return await completeReadOnlyRemoteDocumentSyncWithProjection({\n ...input.completion,\n writerProjection: input.writerProjection,\n });\n } catch (error) {\n return handleReadOnlyProjectionCompletionError(error, {\n allowCachedProjectionRefresh: input.allowCachedProjectionRefresh,\n historyMode: input.completion.historyMode,\n });\n }\n}\nasync function completeReadOnlyRemoteDocumentSyncWithUpdates(\n input: ReadOnlyDocumentSyncCompletionInput,\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n const reusableWriterProjection =\n input.writerProjection?.documentId === input.documentId\n ? input.writerProjection\n : null;\n const writerProjection =\n reusableWriterProjection ??\n (await resolveSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n reusableWriterProjection: null,\n stillCurrent: input.stillCurrent,\n }));\n if (!writerProjection) {\n return { kind: \"completed\", result: null };\n }\n const canRefreshProjection =\n input.historyMode === \"raw\" || Boolean(reusableWriterProjection);\n let result:\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION = null;\n let retryAfterRollback = false;\n try {\n result = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection({\n allowCachedProjectionRefresh: canRefreshProjection,\n completion: input,\n writerProjection,\n });\n } catch (error) {\n if (projectionIntegrityErrorCode(error) !== \"rollback\") {\n throw error;\n }\n retryAfterRollback = true;\n }\n if (\n !retryAfterRollback &&\n result !== REFRESH_CACHED_PROJECTION &&\n !(result instanceof DocumentRawHistoryUnavailableError) &&\n (result || !reusableWriterProjection)\n ) {\n return { kind: \"completed\", result };\n }\n const freshWriterProjection = await refreshSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n stillCurrent: input.stillCurrent,\n unavailableError:\n result instanceof DocumentRawHistoryUnavailableError ? result : undefined,\n });\n if (!freshWriterProjection) {\n return { kind: \"completed\", result: null };\n }\n const freshResult = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection(\n {\n allowCachedProjectionRefresh: false,\n completion: input,\n writerProjection: freshWriterProjection,\n },\n );\n if (\n freshResult === REFRESH_CACHED_PROJECTION ||\n freshResult instanceof DocumentRawHistoryUnavailableError\n ) {\n throw new Error(\"Fresh document projection unexpectedly requested refresh\");\n }\n return freshResult\n ? { kind: \"completed\", result: freshResult }\n : { kind: \"not_completed\" };\n}\nasync function syncReadOnlyRemoteDocumentFromPersistedState(\n input: Omit<\n ReadOnlyDocumentSyncCompletionInput,\n \"pullComplete\" | \"response\"\n > & {\n persistedState?: PersistedDocumentSyncState | null | undefined;\n },\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n let plan: DocumentSyncPlan | null;\n try {\n plan = await buildReadOnlyDocumentSyncPlanFromPersistedState(input);\n } catch {\n plan = null;\n }\n if (!plan) {\n return { kind: \"not_completed\" };\n }\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n const submitted = await submitDocumentSync({\n apiClient: input.apiClient,\n expectedCommitLsnMode: input.pullContinuation?.commitLsnMode,\n plan,\n });\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted.ok) {\n if (\n await handleUpstreamDeletedDocumentSyncFailure({\n documentId: input.documentId,\n failure: submitted,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n })\n ) {\n return { kind: \"completed\", result: null };\n }\n\n if (isRetryableDocumentSyncConflict(submitted)) {\n traceSubmitFailed(input.onSyncTrace, {\n action: \"retry\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n assertRawContinuationCanRetry(input.historyMode, input.pullContinuation);\n return { kind: \"not_completed\" };\n }\n\n traceSubmitFailed(input.onSyncTrace, {\n action: \"stop\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n submitted.report();\n return { kind: \"completed\", result: null };\n }\n\n if (submitted.response.updates.length > 0) {\n return completeReadOnlyRemoteDocumentSyncWithUpdates({\n ...input,\n pullComplete: submitted.pullComplete,\n response: submitted.response,\n });\n }\n\n try {\n const persistedState = await persistedDocumentSyncStateFromResponse(\n plan,\n submitted.response,\n { resolveWriterPublicKey: input.resolveWriterPublicKey },\n );\n\n return {\n kind: \"completed\",\n result: {\n contentKey: new Uint8Array(),\n decryptedUpdates: [],\n exhaustedPendingUpdateCount: 0,\n hasDeferredPendingUpdates: false,\n hasIncompletePull: !submitted.pullComplete,\n persistedState,\n plan,\n rekeyedPendingUpdateIds: [],\n response: submitted.response,\n settledPendingUpdateIds: [],\n acceptedRecoveryBaseline: false,\n },\n };\n } catch (error) {\n if (input.historyMode === \"raw\") {\n throw error;\n }\n return { kind: \"not_completed\" };\n }\n}\n\nexport interface SyncRemoteDocumentInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n /**\n * Supplies a full-history Loro snapshot of the local document so a\n * write-bearing pass can heal a stale content-key bundle by rotating to a\n * fresh content key anchored by a rotation baseline.\n */\n buildRotationSnapshot?: (() => Promise<Uint8Array | null>) | undefined;\n /** Overrides automatic ancestor repair for each submission's current projection. */\n buildContainerRekeys?: DocumentSyncContainerRekeyBuilder;\n documentId: string;\n execSql: ExecSql;\n /** Explicit read-only recovery that bypasses rotation-baseline redirect. */\n historyMode?: \"raw\" | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n /** Atomically commits the verified purge proof with matching local teardown. */\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n /** Clipboard-safe trace sink (see syncTrace.ts); never receives content. */\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n /**\n * Fires when a pass WITHOUT queued writes cannot resolve its writer\n * projection (e.g. a coded 409 from the projection route). Read-only\n * revalidation otherwise fails silently — one burned request and a trace\n * line — leaving the document permanently stale with nothing durable to\n * explain why (edge-case row 13).\n */\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n /** Records a verified response update that could not be decrypted/imported. */\n onIncomingUpdateIsolationFailure?:\n | ((failure: DocumentSyncUpdateIsolationError) => void | Promise<void>)\n | undefined;\n /** Fires immediately before a materialized outgoing batch is submitted. */\n onOutgoingUpdatesMaterialized?:\n | ((updateIds: readonly string[]) => void)\n | undefined;\n /** Invalidates continuation state after the server rejects its snapshot. */\n onPullContinuationInvalidated?:\n | ((continuation: DocumentSyncPullContinuation) => void | Promise<void>)\n | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates?: readonly PendingUpdateRecord[] | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n rekeyPendingUpdate?: RekeyPendingUpdate | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n /** Validates decrypted updates against scratch state before callers persist. */\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport async function tryPersistedReadOnlyDocumentSync(\n input: SyncRemoteDocumentInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<PersistedReadOnlyDocumentSyncResult | null> {\n if (input.stillCurrent?.() === false) return null;\n if ((input.pendingUpdates ?? []).length > 0) return null;\n\n return syncReadOnlyRemoteDocumentFromPersistedState({\n ...input,\n resolveProjectionUserKey,\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncAttemptPlanning.js","sourceRoot":"","sources":["syncAttemptPlanning.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mCAAmC,EAAE,MAAM,kEAAkE,CAAC;AACvH,OAAO,EAAE,sCAAsC,EAAE,MAAM,wCAAwC,CAAC;AAChG,OAAO,EAAE,+BAA+B,EAAE,MAAM,+DAA+D,CAAC;AAChH,OAAO,EAEL,6BAA6B,GAC9B,MAAM,oDAAoD,CAAC;AAE5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,iCAAiC,EACjC,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,oCAAoC,EACpC,oCAAoC,GACrC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,iCAAiC,EAAE,MAAM,6CAA6C,CAAC;AAChG,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAGhF;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAA8B,EAC9B,yBAAkC;IAElC,OAAO,yBAAyB;QAC9B,CAAC,CAAC,KAAK,CAAC,uBAAuB;QAC/B,CAAC,CAAC,KAAK,CAAC,2BAA2B,CAAC;AACxC,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAO7C;IACC,IAAI,CAAC;QACH,MAAM,cAAc,GAClB,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,IACE,cAAc,CAAC,MAAM;YACrB,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAC9B,CACE,MAAM,sCAAsC,CAAC;gBAC3C,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,gBAAgB;gBAC/C,KAAK,EAAE,wBAAwB;aAChC,CAAC,CACH,CAAC,cAAc,CACjB,EACD,CAAC;YACD,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,qEAAqE;QACrE,6EAA6E;QAC7E,MAAM,QAAQ,GACZ,cAAc,CAAC,MAAM;YACrB,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB;YAChC,KAAK,CAAC,IAAI,CAAC,qBAAqB;YAC9B,CAAC,CAAC,MAAM,iCAAiC,CACrC,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,gBAAgB,CACvB;YACH,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAC/D,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,OAAO,MAAM,sBAAsB,CAAC;YAClC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS;YAC/B,mBAAmB,EAAE,CAAC,UAAU,EAAE,EAAE,CAClC,2BAA2B,CAAC;gBAC1B,cAAc;gBACd,cAAc,EACZ,UAAU,KAAK,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;gBACjE,MAAM,EAAE,6BAA6B,CACnC,KAAK,CAAC,gBAAgB,EACtB,KAAK,CAAC,IAAI,CAAC,MAAM,CAClB;gBACD,UAAU,EAAE,KAAK,CAAC,gBAAgB,EAAE,MAAM;gBAC1C,UAAU;gBACV,2BAA2B,EAAE,KAAK,CAAC,2BAA2B;gBAC9D,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC;YACJ,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU;YACjC,uBAAuB,EAAE,KAAK,CAAC,IAAI,CAAC,uBAAuB;YAC3D,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC,eAAe;YAC3C,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW;YACnC,iBAAiB,EAAE,wBAAwB,CACzC,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,yBAAyB,CAChC;YACD,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY;YACrC,gBAAgB,EAAE,QAAQ,CAAC,UAAU;SACtC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,oCAAoC;YACvD,OAAO,OAAgB,CAAC;QAC1B,IAAI,KAAK,YAAY,oCAAoC,EAAE,CAAC;YAC1D,OAAO,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,KAAK,YAAY,mCAAmC,EAAE,CAAC;YACzD,OAAO,iCAAiC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,+BAA+B,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,wBAAwB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;AACH,CAAC","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { ContainerKekRepairInaccessibleError } from \"../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { assertDocumentManifestBundleConsistent } from \"../../../data/documents/shared/readers\";\nimport { isDocumentSyncRequestLimitError } from \"../../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { PendingUpdateRecord } from \"../../../data/
|
|
1
|
+
{"version":3,"file":"syncAttemptPlanning.js","sourceRoot":"","sources":["syncAttemptPlanning.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { ContainerKekRepairInaccessibleError } from \"../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { assertDocumentManifestBundleConsistent } from \"../../../data/documents/shared/readers\";\nimport { isDocumentSyncRequestLimitError } from \"../../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport { retrySyncPlanOrAbandon } from \"../syncFailures\";\nimport {\n abandonAncestorRepair,\n abandonBlockedSync,\n abandonInaccessibleAncestorRepair,\n abandonOversizedSyncPlan,\n} from \"../syncFailures/syncAbandon\";\nimport type { TerminalSubmitFailureHandler } from \"../syncFailures/syncFailureClassification\";\nimport {\n DocumentAncestorRepairAbandonedError,\n DocumentSyncPreparationRequiredError,\n} from \"../syncFailures/syncRepairAbandon\";\nimport { prepareSyncAttemptContainerRekeys } from \"../syncRekeys/syncContainerRekeyPreparation\";\nimport { buildRemoteDocumentSyncPlan } from \"../syncRekeys/syncContainerRekeys\";\nimport type { SyncRemoteDocumentInput } from \"./readOnlySync\";\n\n/**\n * A write-bearing pass records through the submit handler (its queued writes\n * are what the failure blocks). A read-only pass records through the\n * revalidation handler so the refusal still leaves a durable trail instead\n * of silently never revalidating (edge-case row 13). A cursor continuation is\n * wire-level read-only, but its failure still blocks the queued writes it\n * deliberately deferred. Update-id recovery likewise empties the in-flight\n * batch while durable rows remain. Both keep the submit classification and\n * its 403 handling.\n */\nexport function projectionFailureHandler(\n input: SyncRemoteDocumentInput,\n failureBlocksQueuedWrites: boolean,\n): TerminalSubmitFailureHandler | undefined {\n return failureBlocksQueuedWrites\n ? input.onTerminalSubmitFailure\n : input.onReadOnlyProjectionFailure;\n}\nexport async function planDocumentSyncAttempt(input: {\n pendingUpdates: readonly PendingUpdateRecord[];\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n regenerateQueuedCheckpoints: boolean;\n sync: SyncRemoteDocumentInput;\n failureBlocksQueuedWrites: boolean;\n writerProjection: DocumentWriterProjectionResponse;\n}) {\n try {\n const pendingUpdates =\n input.pullContinuation === undefined ? input.pendingUpdates : [];\n if (\n pendingUpdates.length &&\n input.sync.isRemoteSyncBlocked?.(\n (\n await assertDocumentManifestBundleConsistent({\n bundle: input.writerProjection.documentManifest,\n label: \"Document sync manifest\",\n })\n ).organizationId,\n )\n ) {\n return abandonBlockedSync(input.sync);\n }\n // Durable repair happens once at this explicit attempt boundary. The\n // retryable builder below may only sign inline plans against its projection.\n const prepared =\n pendingUpdates.length &&\n !input.sync.buildContainerRekeys &&\n input.sync.buildRotationSnapshot\n ? await prepareSyncAttemptContainerRekeys(\n input.sync,\n input.writerProjection,\n )\n : { projection: input.writerProjection, plans: undefined };\n if (!prepared) return null;\n return await retrySyncPlanOrAbandon({\n apiClient: input.sync.apiClient,\n buildWithProjection: (projection) =>\n buildRemoteDocumentSyncPlan({\n pendingUpdates,\n preparedRekeys:\n projection === prepared.projection ? prepared.plans : undefined,\n minLsn: resolvePullContinuationMinLsn(\n input.pullContinuation,\n input.sync.minLsn,\n ),\n pullCursor: input.pullContinuation?.cursor,\n projection,\n regenerateQueuedCheckpoints: input.regenerateQueuedCheckpoints,\n sync: input.sync,\n }),\n documentId: input.sync.documentId,\n onRemoteDocumentDeleted: input.sync.onRemoteDocumentDeleted,\n onSyncAbandoned: input.sync.onSyncAbandoned,\n onSyncTrace: input.sync.onSyncTrace,\n onTerminalFailure: projectionFailureHandler(\n input.sync,\n input.failureBlocksQueuedWrites,\n ),\n stillCurrent: input.sync.stillCurrent,\n writerProjection: prepared.projection,\n });\n } catch (error) {\n if (error instanceof DocumentSyncPreparationRequiredError)\n return \"retry\" as const;\n if (error instanceof DocumentAncestorRepairAbandonedError) {\n return abandonAncestorRepair(input.sync, error);\n }\n if (error instanceof ContainerKekRepairInaccessibleError) {\n return abandonInaccessibleAncestorRepair(input.sync, error);\n }\n if (!isDocumentSyncRequestLimitError(error)) {\n throw error;\n }\n return abandonOversizedSyncPlan(input.sync, error);\n }\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import type { DocumentWriterProjectionResponse } from "../../../internal/validat
|
|
|
2
2
|
import type { MaterializedContainerRekeyPlan } from "../../../data/containers/shared/types.js";
|
|
3
3
|
import type { DocumentSyncPullContinuation } from "../../../data/documents/shared/sync/syncPagination.js";
|
|
4
4
|
import type { SyncRemoteDocumentResult } from "../../../data/documents/shared/types.js";
|
|
5
|
-
import type { PendingUpdateRecord } from "../../../data/
|
|
5
|
+
import type { PendingUpdateRecord } from "../../../data/persistence/documents/records/index.js";
|
|
6
6
|
export type DocumentSyncContainerRekeyBuilder = (writerProjection: DocumentWriterProjectionResponse, verification: {
|
|
7
7
|
readonly persistVerificationCheckpoints: false;
|
|
8
8
|
}) => Promise<readonly MaterializedContainerRekeyPlan[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncAttemptState.js","sourceRoot":"","sources":["syncAttemptState.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { MaterializedContainerRekeyPlan } from \"../../../data/containers/shared/types\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { SyncRemoteDocumentResult } from \"../../../data/documents/shared/types\";\nimport type { PendingUpdateRecord } from \"../../../data/
|
|
1
|
+
{"version":3,"file":"syncAttemptState.js","sourceRoot":"","sources":["syncAttemptState.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { MaterializedContainerRekeyPlan } from \"../../../data/containers/shared/types\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { SyncRemoteDocumentResult } from \"../../../data/documents/shared/types\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\n\nexport type DocumentSyncContainerRekeyBuilder = (\n writerProjection: DocumentWriterProjectionResponse,\n verification: { readonly persistVerificationCheckpoints: false },\n) => Promise<readonly MaterializedContainerRekeyPlan[]>;\n\nexport interface RemoteDocumentSyncAttemptState {\n pendingUpdates: readonly PendingUpdateRecord[];\n pullContinuation: DocumentSyncPullContinuation | undefined;\n recoveryPendingUpdatesById: Map<string, PendingUpdateRecord>;\n regenerateQueuedCheckpoints: boolean;\n reusableWriterProjection: DocumentWriterProjectionResponse | null;\n}\n\nexport type RemoteDocumentSyncAttemptOutcome =\n | { kind: \"complete\"; result: SyncRemoteDocumentResult | null }\n | { kind: \"recover\"; updates: Map<string, PendingUpdateRecord> }\n | { kind: \"regenerate\" }\n | {\n kind: \"retry\";\n pullContinuation: DocumentSyncPullContinuation | undefined;\n };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncResponseResult.js","sourceRoot":"","sources":["syncResponseResult.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport type {\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { decryptDocumentSyncUpdatesByEpoch } from \"../../../data/documents/shared/crypto\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport {\n DocumentSyncResponseUpdateContentKeyError,\n persistedDocumentSyncStateFromResponse,\n} from \"../../../data/documents/shared/responses\";\nimport {\n type IncomingDocumentSyncUpdateValidator,\n isolateDocumentSyncBatchError,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport type {\n DocumentWriterPublicKeyResolver,\n MaterializedDocumentSyncPlan,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport type { TerminalSubmitFailureHandler } from \"../syncFailures/syncFailureClassification\";\nimport { unwrapDocumentSyncResponseContentKeys } from \"../syncPlan/syncContentKeys\";\nimport {\n acceptedHeldBackPendingUpdateIds,\n responseAcceptedRecoveryBaseline,\n} from \"../syncPlan/syncPlanRequestBounds\";\nimport {\n type RekeyPendingUpdate,\n rekeyAndReportUnsettledRecoveryPendingUpdates,\n settledPendingUpdateIdsFromSync,\n} from \"../syncRekeys/syncRecoveryRekey\";\n\nfunction isolateContentKeyResponseFailure(\n error: unknown,\n response: DocumentSyncResponse,\n): never {\n if (\n !(error instanceof DocumentSyncResponseUpdateContentKeyError) ||\n response.updates.length === 0\n ) {\n throw error;\n }\n throw isolateDocumentSyncBatchError({\n cause: new KeyingVerificationError(\"invalid_shape\", error.message),\n stage: \"content_key\",\n updateIds: response.updates.map((update) => update.id),\n });\n}\n\ntype SyncRemoteDocumentResultInput = {\n execSql: ExecSql;\n materializedPlan: MaterializedDocumentSyncPlan;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n recoveryPendingUpdatesById: ReadonlyMap<string, PendingUpdateRecord>;\n rekeyPendingUpdate?: RekeyPendingUpdate | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n response: DocumentSyncResponse;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n writerProjection: DocumentWriterProjectionResponse;\n};\n\n/** @internal Exercises poison precedence for the decryptable subset of a raw page. */\nexport async function validateDecryptableRawHistorySiblings(input: {\n contentKeysByEpoch: ReadonlyMap<number, Uint8Array>;\n documentId: string;\n organizationId: string;\n response: DocumentSyncResponse;\n updates: readonly DocumentSyncResponse[\"updates\"][number][];\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n}): Promise<void> {\n if (input.updates.length === 0) return;\n const decryptedUpdates = await decryptDocumentSyncUpdatesByEpoch({\n contentKeysByEpoch: input.contentKeysByEpoch,\n documentId: input.documentId,\n organizationId: input.organizationId,\n updates: input.updates,\n });\n // The current wire contract authenticates each update's operation range but\n // not its exact dependency set. An unresolved import therefore cannot prove\n // that the missing parent belongs to an unavailable sibling; preserve the\n // isolation failure instead of downgrading unrelated poison to availability.\n await input.validateIncomingUpdates({\n decryptedUpdates,\n response: { ...input.response, updates: [...input.updates] },\n });\n}\n\nasync function resolveVerifiedResponseState(\n input: SyncRemoteDocumentResultInput,\n) {\n const { plan } = input.materializedPlan;\n let persistedState: Awaited<\n ReturnType<typeof persistedDocumentSyncStateFromResponse>\n >;\n try {\n persistedState = await persistedDocumentSyncStateFromResponse(\n plan,\n input.response,\n {\n resolveWriterPublicKey: input.resolveWriterPublicKey,\n },\n );\n } catch (error) {\n // Missing or future bundles are response-integrity failures. They must be\n // poison-isolated before key availability is considered, because the\n // referenced update has not yet authenticated against a bundle.\n isolateContentKeyResponseFailure(error, input.response);\n }\n if ((plan.request.containerRekeys?.length ?? 0) > 0) {\n await assertDocumentWriterProjectionConsistent(input.writerProjection, {\n allowStaleContentKeyBundle: true,\n execSql: input.execSql,\n stillCurrent: input.stillCurrent,\n ...projectionVerificationOptions(input),\n });\n }\n const contentKeysByEpoch = await unwrapDocumentSyncResponseContentKeys({\n currentContentKey: input.materializedPlan.contentKey,\n currentContentKeyEpoch: plan.contentKeyEpoch,\n execSql: input.execSql,\n historyMode: plan.request.historyMode,\n onRawHistoryUnavailable: async ({ contentKeysByEpoch, updates }) =>\n validateDecryptableRawHistorySiblings({\n contentKeysByEpoch,\n documentId: plan.documentId,\n organizationId: plan.organizationId,\n response: input.response,\n updates,\n validateIncomingUpdates: input.validateIncomingUpdates,\n }),\n response: input.response,\n targetSecretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n return { contentKeysByEpoch, persistedState };\n}\n\nexport async function syncRemoteDocumentResultFromResponse(\n input: SyncRemoteDocumentResultInput,\n): Promise<SyncRemoteDocumentResult> {\n const { plan } = input.materializedPlan;\n const { contentKeysByEpoch, persistedState } =\n await resolveVerifiedResponseState(input);\n const decryptedUpdates = await decryptDocumentSyncUpdatesByEpoch({\n contentKeysByEpoch,\n documentId: plan.documentId,\n organizationId: plan.organizationId,\n updates: input.response.updates,\n });\n await input.validateIncomingUpdates({\n decryptedUpdates,\n response: input.response,\n });\n const recoveryBaselineId =\n input.materializedPlan.staleRecoveryBaselineUpdateId;\n const acceptedRecoveryBaseline = responseAcceptedRecoveryBaseline(\n input.materializedPlan,\n input.response,\n );\n // Two heal-specific corrections: the synthetic heal baseline matches no\n // pending-queue row, so its ack must not count as a settled pending update;\n // and checkpoints the heal held back ARE settled by it — the committed\n // covering baseline subsumes their full-history content, and resubmitting\n // them post-heal could become the LATEST baseline at the healed epoch and\n // shrink the redirect's coverage below the pre-heal frontier.\n const settledPendingUpdateIds = [\n ...settledPendingUpdateIdsFromSync({\n decryptedUpdates,\n recoveryPendingUpdatesById: input.recoveryPendingUpdatesById,\n response: input.response,\n }).filter((updateId) => updateId !== recoveryBaselineId),\n ...acceptedHeldBackPendingUpdateIds(input.materializedPlan, input.response),\n ];\n const { exhaustedPendingUpdateCount, rekeyedPendingUpdateIds } =\n await rekeyAndReportUnsettledRecoveryPendingUpdates({\n execSql: input.execSql,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n recoveryPendingUpdatesById: input.recoveryPendingUpdatesById,\n rekeyPendingUpdate: input.rekeyPendingUpdate,\n settledPendingUpdateIds,\n stillCurrent: input.stillCurrent,\n });\n\n return {\n exhaustedPendingUpdateCount,\n contentKey: input.materializedPlan.contentKey,\n decryptedUpdates,\n hasDeferredPendingUpdates: false,\n hasIncompletePull: false,\n persistedState,\n plan,\n rekeyedPendingUpdateIds,\n response: input.response,\n settledPendingUpdateIds,\n acceptedRecoveryBaseline,\n writerProjection: input.writerProjection,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"syncResponseResult.js","sourceRoot":"","sources":["syncResponseResult.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport type {\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { decryptDocumentSyncUpdatesByEpoch } from \"../../../data/documents/shared/crypto\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport {\n DocumentSyncResponseUpdateContentKeyError,\n persistedDocumentSyncStateFromResponse,\n} from \"../../../data/documents/shared/responses\";\nimport {\n type IncomingDocumentSyncUpdateValidator,\n isolateDocumentSyncBatchError,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport type {\n DocumentWriterPublicKeyResolver,\n MaterializedDocumentSyncPlan,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport type { TerminalSubmitFailureHandler } from \"../syncFailures/syncFailureClassification\";\nimport { unwrapDocumentSyncResponseContentKeys } from \"../syncPlan/syncContentKeys\";\nimport {\n acceptedHeldBackPendingUpdateIds,\n responseAcceptedRecoveryBaseline,\n} from \"../syncPlan/syncPlanRequestBounds\";\nimport {\n type RekeyPendingUpdate,\n rekeyAndReportUnsettledRecoveryPendingUpdates,\n settledPendingUpdateIdsFromSync,\n} from \"../syncRekeys/syncRecoveryRekey\";\n\nfunction isolateContentKeyResponseFailure(\n error: unknown,\n response: DocumentSyncResponse,\n): never {\n if (\n !(error instanceof DocumentSyncResponseUpdateContentKeyError) ||\n response.updates.length === 0\n ) {\n throw error;\n }\n throw isolateDocumentSyncBatchError({\n cause: new KeyingVerificationError(\"invalid_shape\", error.message),\n stage: \"content_key\",\n updateIds: response.updates.map((update) => update.id),\n });\n}\n\ntype SyncRemoteDocumentResultInput = {\n execSql: ExecSql;\n materializedPlan: MaterializedDocumentSyncPlan;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n recoveryPendingUpdatesById: ReadonlyMap<string, PendingUpdateRecord>;\n rekeyPendingUpdate?: RekeyPendingUpdate | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n response: DocumentSyncResponse;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n writerProjection: DocumentWriterProjectionResponse;\n};\n\n/** @internal Exercises poison precedence for the decryptable subset of a raw page. */\nexport async function validateDecryptableRawHistorySiblings(input: {\n contentKeysByEpoch: ReadonlyMap<number, Uint8Array>;\n documentId: string;\n organizationId: string;\n response: DocumentSyncResponse;\n updates: readonly DocumentSyncResponse[\"updates\"][number][];\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n}): Promise<void> {\n if (input.updates.length === 0) return;\n const decryptedUpdates = await decryptDocumentSyncUpdatesByEpoch({\n contentKeysByEpoch: input.contentKeysByEpoch,\n documentId: input.documentId,\n organizationId: input.organizationId,\n updates: input.updates,\n });\n // The current wire contract authenticates each update's operation range but\n // not its exact dependency set. An unresolved import therefore cannot prove\n // that the missing parent belongs to an unavailable sibling; preserve the\n // isolation failure instead of downgrading unrelated poison to availability.\n await input.validateIncomingUpdates({\n decryptedUpdates,\n response: { ...input.response, updates: [...input.updates] },\n });\n}\n\nasync function resolveVerifiedResponseState(\n input: SyncRemoteDocumentResultInput,\n) {\n const { plan } = input.materializedPlan;\n let persistedState: Awaited<\n ReturnType<typeof persistedDocumentSyncStateFromResponse>\n >;\n try {\n persistedState = await persistedDocumentSyncStateFromResponse(\n plan,\n input.response,\n {\n resolveWriterPublicKey: input.resolveWriterPublicKey,\n },\n );\n } catch (error) {\n // Missing or future bundles are response-integrity failures. They must be\n // poison-isolated before key availability is considered, because the\n // referenced update has not yet authenticated against a bundle.\n isolateContentKeyResponseFailure(error, input.response);\n }\n if ((plan.request.containerRekeys?.length ?? 0) > 0) {\n await assertDocumentWriterProjectionConsistent(input.writerProjection, {\n allowStaleContentKeyBundle: true,\n execSql: input.execSql,\n stillCurrent: input.stillCurrent,\n ...projectionVerificationOptions(input),\n });\n }\n const contentKeysByEpoch = await unwrapDocumentSyncResponseContentKeys({\n currentContentKey: input.materializedPlan.contentKey,\n currentContentKeyEpoch: plan.contentKeyEpoch,\n execSql: input.execSql,\n historyMode: plan.request.historyMode,\n onRawHistoryUnavailable: async ({ contentKeysByEpoch, updates }) =>\n validateDecryptableRawHistorySiblings({\n contentKeysByEpoch,\n documentId: plan.documentId,\n organizationId: plan.organizationId,\n response: input.response,\n updates,\n validateIncomingUpdates: input.validateIncomingUpdates,\n }),\n response: input.response,\n targetSecretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n return { contentKeysByEpoch, persistedState };\n}\n\nexport async function syncRemoteDocumentResultFromResponse(\n input: SyncRemoteDocumentResultInput,\n): Promise<SyncRemoteDocumentResult> {\n const { plan } = input.materializedPlan;\n const { contentKeysByEpoch, persistedState } =\n await resolveVerifiedResponseState(input);\n const decryptedUpdates = await decryptDocumentSyncUpdatesByEpoch({\n contentKeysByEpoch,\n documentId: plan.documentId,\n organizationId: plan.organizationId,\n updates: input.response.updates,\n });\n await input.validateIncomingUpdates({\n decryptedUpdates,\n response: input.response,\n });\n const recoveryBaselineId =\n input.materializedPlan.staleRecoveryBaselineUpdateId;\n const acceptedRecoveryBaseline = responseAcceptedRecoveryBaseline(\n input.materializedPlan,\n input.response,\n );\n // Two heal-specific corrections: the synthetic heal baseline matches no\n // pending-queue row, so its ack must not count as a settled pending update;\n // and checkpoints the heal held back ARE settled by it — the committed\n // covering baseline subsumes their full-history content, and resubmitting\n // them post-heal could become the LATEST baseline at the healed epoch and\n // shrink the redirect's coverage below the pre-heal frontier.\n const settledPendingUpdateIds = [\n ...settledPendingUpdateIdsFromSync({\n decryptedUpdates,\n recoveryPendingUpdatesById: input.recoveryPendingUpdatesById,\n response: input.response,\n }).filter((updateId) => updateId !== recoveryBaselineId),\n ...acceptedHeldBackPendingUpdateIds(input.materializedPlan, input.response),\n ];\n const { exhaustedPendingUpdateCount, rekeyedPendingUpdateIds } =\n await rekeyAndReportUnsettledRecoveryPendingUpdates({\n execSql: input.execSql,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n recoveryPendingUpdatesById: input.recoveryPendingUpdatesById,\n rekeyPendingUpdate: input.rekeyPendingUpdate,\n settledPendingUpdateIds,\n stillCurrent: input.stillCurrent,\n });\n\n return {\n exhaustedPendingUpdateCount,\n contentKey: input.materializedPlan.contentKey,\n decryptedUpdates,\n hasDeferredPendingUpdates: false,\n hasIncompletePull: false,\n persistedState,\n plan,\n rekeyedPendingUpdateIds,\n response: input.response,\n settledPendingUpdateIds,\n acceptedRecoveryBaseline,\n writerProjection: input.writerProjection,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncSubmittedResult.js","sourceRoot":"","sources":["syncSubmittedResult.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport type {\n MaterializedDocumentSyncPlan,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport {\n type ProjectionUserKeyResolver,\n verifyDocumentWriterProjectionAuthorization,\n} from \"../../../data/keyingProjectionVerification\";\nimport { isKeyingVerificationError } from \"../../../data/keyingProjectionVerification/error\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport { refreshSyncAttemptWriterProjection } from \"../syncFailures\";\nimport { DocumentRawHistoryUnavailableError } from \"../syncPlan/syncContentKeys\";\nimport {\n hasDeferredPendingUpdatesAfterSubmit,\n responseAcceptedRecoveryBaseline,\n} from \"../syncPlan/syncPlanRequestBounds\";\nimport type { SyncRemoteDocumentInput } from \"./readOnlySync\";\nimport { syncRemoteDocumentResultFromResponse } from \"./syncResponseResult\";\nimport { traceHealed } from \"./syncTrace\";\n\ntype SubmittedDocumentSyncResultInput = {\n materializedPlan: MaterializedDocumentSyncPlan;\n pendingUpdateIds: readonly string[];\n pullComplete: boolean;\n recoveryPendingUpdatesById: ReadonlyMap<string, PendingUpdateRecord>;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n response: DocumentSyncResponse;\n sync: SyncRemoteDocumentInput;\n writerProjection: DocumentWriterProjectionResponse;\n};\n\n/** @internal Applies post-verification heal effects under the sync generation. */\nexport function applyAcceptedHealSideEffects(input: {\n documentId: string;\n evictWriterProjection?: ((documentId: string) => void) | undefined;\n materializedPlan: MaterializedDocumentSyncPlan;\n onSyncTrace: SyncRemoteDocumentInput[\"onSyncTrace\"];\n response: DocumentSyncResponse;\n stillCurrent: SyncRemoteDocumentInput[\"stillCurrent\"];\n}): void {\n if (\n !input.materializedPlan.healedStaleContentKeyBundle ||\n !responseAcceptedRecoveryBaseline(input.materializedPlan, input.response) ||\n input.stillCurrent?.() === false\n ) {\n return;\n }\n input.evictWriterProjection?.(input.documentId);\n if (input.stillCurrent?.() === false) {\n return;\n }\n traceHealed(input.onSyncTrace, {\n accepted: input.response.acceptedOutgoingUpdateIds.length,\n documentId: input.materializedPlan.plan.documentId,\n epoch: input.materializedPlan.plan.contentKeyEpoch,\n });\n}\n\nasync function submittedDocumentSyncResult(\n input: SubmittedDocumentSyncResultInput,\n): Promise<SyncRemoteDocumentResult> {\n const result = await syncRemoteDocumentResultFromResponse({\n ...projectionVerificationOptions(input.sync),\n execSql: input.sync.execSql,\n materializedPlan: input.materializedPlan,\n onTerminalSubmitFailure: input.sync.onTerminalSubmitFailure,\n recoveryPendingUpdatesById: input.recoveryPendingUpdatesById,\n rekeyPendingUpdate: input.sync.rekeyPendingUpdate,\n resolveWriterPublicKey: input.sync.resolveWriterPublicKey,\n response: input.response,\n stillCurrent: input.sync.stillCurrent,\n targetSecretKey: input.sync.targetSecretKey,\n validateIncomingUpdates: input.sync.validateIncomingUpdates,\n writerProjection: input.writerProjection,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n });\n if (\n (input.materializedPlan.plan.request.containerRekeys?.length ?? 0) > 0 &&\n input.sync.stillCurrent?.() !== false\n ) {\n input.sync.apiClient.clearWriterProjectionCaches?.();\n }\n applyAcceptedHealSideEffects({\n documentId: input.sync.documentId,\n evictWriterProjection:\n input.sync.apiClient.evictDocumentWriterProjection?.bind(\n input.sync.apiClient,\n ),\n materializedPlan: input.materializedPlan,\n onSyncTrace: input.sync.onSyncTrace,\n response: input.response,\n stillCurrent: input.sync.stillCurrent,\n });\n return {\n ...result,\n hasDeferredPendingUpdates:\n (input.materializedPlan.plan.request.pullCursor !== undefined &&\n input.pendingUpdateIds.length > 0 &&\n result.exhaustedPendingUpdateCount === 0) ||\n hasDeferredPendingUpdatesAfterSubmit({\n acceptedRecoveryBaseline: result.acceptedRecoveryBaseline,\n exhaustedPendingUpdateCount: result.exhaustedPendingUpdateCount,\n pendingUpdateIds: input.pendingUpdateIds,\n rekeyedPendingUpdateIds: result.rekeyedPendingUpdateIds,\n settledPendingUpdateIds: result.settledPendingUpdateIds,\n }),\n hasIncompletePull: !input.pullComplete,\n };\n}\n\nasync function retrySubmittedResponseWithFreshProjection(\n input: SubmittedDocumentSyncResultInput,\n unavailableError: unknown,\n refreshAuthorization: boolean,\n): Promise<SyncRemoteDocumentResult | null> {\n const writerProjection = await refreshSyncAttemptWriterProjection({\n apiClient: input.sync.apiClient,\n documentId: input.sync.documentId,\n onRemoteDocumentDeleted: input.sync.onRemoteDocumentDeleted,\n onSyncAbandoned: input.sync.onSyncAbandoned,\n onSyncTrace: input.sync.onSyncTrace,\n onTerminalFailure: input.sync.onReadOnlyProjectionFailure,\n stillCurrent: input.sync.stillCurrent,\n unavailableError,\n });\n if (!writerProjection) return null;\n const materializedPlan = refreshAuthorization\n ? {\n ...input.materializedPlan,\n plan: {\n ...input.materializedPlan.plan,\n documentWriterAuthorization:\n await verifyDocumentWriterProjectionAuthorization({\n execSql: input.sync.execSql,\n projection: writerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.sync.stillCurrent,\n warmReferencedPrincipalPolicies:\n input.sync.warmReferencedPrincipalPolicies,\n }),\n },\n }\n : input.materializedPlan;\n // Keep the submitted request, keys, and response frozen. Only refreshed,\n // verified evidence may be added; this retry never resubmits outgoing edits.\n return submittedDocumentSyncResult({\n ...input,\n materializedPlan,\n writerProjection,\n });\n}\n\nexport async function resolveSubmittedDocumentSyncResult(\n input: SubmittedDocumentSyncResultInput,\n): Promise<SyncRemoteDocumentResult | null> {\n try {\n return await submittedDocumentSyncResult(input);\n } catch (error) {\n const missingDependency =\n isKeyingVerificationError(error) && error.code === \"missing_dependency\";\n if (\n !missingDependency &&\n (input.sync.historyMode !== \"raw\" ||\n !(error instanceof DocumentRawHistoryUnavailableError))\n ) {\n throw error;\n }\n return retrySubmittedResponseWithFreshProjection(\n input,\n error,\n missingDependency,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"syncSubmittedResult.js","sourceRoot":"","sources":["syncSubmittedResult.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport type {\n MaterializedDocumentSyncPlan,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport {\n type ProjectionUserKeyResolver,\n verifyDocumentWriterProjectionAuthorization,\n} from \"../../../data/keyingProjectionVerification\";\nimport { isKeyingVerificationError } from \"../../../data/keyingProjectionVerification/error\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport { refreshSyncAttemptWriterProjection } from \"../syncFailures\";\nimport { DocumentRawHistoryUnavailableError } from \"../syncPlan/syncContentKeys\";\nimport {\n hasDeferredPendingUpdatesAfterSubmit,\n responseAcceptedRecoveryBaseline,\n} from \"../syncPlan/syncPlanRequestBounds\";\nimport type { SyncRemoteDocumentInput } from \"./readOnlySync\";\nimport { syncRemoteDocumentResultFromResponse } from \"./syncResponseResult\";\nimport { traceHealed } from \"./syncTrace\";\n\ntype SubmittedDocumentSyncResultInput = {\n materializedPlan: MaterializedDocumentSyncPlan;\n pendingUpdateIds: readonly string[];\n pullComplete: boolean;\n recoveryPendingUpdatesById: ReadonlyMap<string, PendingUpdateRecord>;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n response: DocumentSyncResponse;\n sync: SyncRemoteDocumentInput;\n writerProjection: DocumentWriterProjectionResponse;\n};\n\n/** @internal Applies post-verification heal effects under the sync generation. */\nexport function applyAcceptedHealSideEffects(input: {\n documentId: string;\n evictWriterProjection?: ((documentId: string) => void) | undefined;\n materializedPlan: MaterializedDocumentSyncPlan;\n onSyncTrace: SyncRemoteDocumentInput[\"onSyncTrace\"];\n response: DocumentSyncResponse;\n stillCurrent: SyncRemoteDocumentInput[\"stillCurrent\"];\n}): void {\n if (\n !input.materializedPlan.healedStaleContentKeyBundle ||\n !responseAcceptedRecoveryBaseline(input.materializedPlan, input.response) ||\n input.stillCurrent?.() === false\n ) {\n return;\n }\n input.evictWriterProjection?.(input.documentId);\n if (input.stillCurrent?.() === false) {\n return;\n }\n traceHealed(input.onSyncTrace, {\n accepted: input.response.acceptedOutgoingUpdateIds.length,\n documentId: input.materializedPlan.plan.documentId,\n epoch: input.materializedPlan.plan.contentKeyEpoch,\n });\n}\n\nasync function submittedDocumentSyncResult(\n input: SubmittedDocumentSyncResultInput,\n): Promise<SyncRemoteDocumentResult> {\n const result = await syncRemoteDocumentResultFromResponse({\n ...projectionVerificationOptions(input.sync),\n execSql: input.sync.execSql,\n materializedPlan: input.materializedPlan,\n onTerminalSubmitFailure: input.sync.onTerminalSubmitFailure,\n recoveryPendingUpdatesById: input.recoveryPendingUpdatesById,\n rekeyPendingUpdate: input.sync.rekeyPendingUpdate,\n resolveWriterPublicKey: input.sync.resolveWriterPublicKey,\n response: input.response,\n stillCurrent: input.sync.stillCurrent,\n targetSecretKey: input.sync.targetSecretKey,\n validateIncomingUpdates: input.sync.validateIncomingUpdates,\n writerProjection: input.writerProjection,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n });\n if (\n (input.materializedPlan.plan.request.containerRekeys?.length ?? 0) > 0 &&\n input.sync.stillCurrent?.() !== false\n ) {\n input.sync.apiClient.clearWriterProjectionCaches?.();\n }\n applyAcceptedHealSideEffects({\n documentId: input.sync.documentId,\n evictWriterProjection:\n input.sync.apiClient.evictDocumentWriterProjection?.bind(\n input.sync.apiClient,\n ),\n materializedPlan: input.materializedPlan,\n onSyncTrace: input.sync.onSyncTrace,\n response: input.response,\n stillCurrent: input.sync.stillCurrent,\n });\n return {\n ...result,\n hasDeferredPendingUpdates:\n (input.materializedPlan.plan.request.pullCursor !== undefined &&\n input.pendingUpdateIds.length > 0 &&\n result.exhaustedPendingUpdateCount === 0) ||\n hasDeferredPendingUpdatesAfterSubmit({\n acceptedRecoveryBaseline: result.acceptedRecoveryBaseline,\n exhaustedPendingUpdateCount: result.exhaustedPendingUpdateCount,\n pendingUpdateIds: input.pendingUpdateIds,\n rekeyedPendingUpdateIds: result.rekeyedPendingUpdateIds,\n settledPendingUpdateIds: result.settledPendingUpdateIds,\n }),\n hasIncompletePull: !input.pullComplete,\n };\n}\n\nasync function retrySubmittedResponseWithFreshProjection(\n input: SubmittedDocumentSyncResultInput,\n unavailableError: unknown,\n refreshAuthorization: boolean,\n): Promise<SyncRemoteDocumentResult | null> {\n const writerProjection = await refreshSyncAttemptWriterProjection({\n apiClient: input.sync.apiClient,\n documentId: input.sync.documentId,\n onRemoteDocumentDeleted: input.sync.onRemoteDocumentDeleted,\n onSyncAbandoned: input.sync.onSyncAbandoned,\n onSyncTrace: input.sync.onSyncTrace,\n onTerminalFailure: input.sync.onReadOnlyProjectionFailure,\n stillCurrent: input.sync.stillCurrent,\n unavailableError,\n });\n if (!writerProjection) return null;\n const materializedPlan = refreshAuthorization\n ? {\n ...input.materializedPlan,\n plan: {\n ...input.materializedPlan.plan,\n documentWriterAuthorization:\n await verifyDocumentWriterProjectionAuthorization({\n execSql: input.sync.execSql,\n projection: writerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.sync.stillCurrent,\n warmReferencedPrincipalPolicies:\n input.sync.warmReferencedPrincipalPolicies,\n }),\n },\n }\n : input.materializedPlan;\n // Keep the submitted request, keys, and response frozen. Only refreshed,\n // verified evidence may be added; this retry never resubmits outgoing edits.\n return submittedDocumentSyncResult({\n ...input,\n materializedPlan,\n writerProjection,\n });\n}\n\nexport async function resolveSubmittedDocumentSyncResult(\n input: SubmittedDocumentSyncResultInput,\n): Promise<SyncRemoteDocumentResult | null> {\n try {\n return await submittedDocumentSyncResult(input);\n } catch (error) {\n const missingDependency =\n isKeyingVerificationError(error) && error.code === \"missing_dependency\";\n if (\n !missingDependency &&\n (input.sync.historyMode !== \"raw\" ||\n !(error instanceof DocumentRawHistoryUnavailableError))\n ) {\n throw error;\n }\n return retrySubmittedResponseWithFreshProjection(\n input,\n error,\n missingDependency,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DOCUMENT_SYNC_ERROR_CODES,\n type DocumentSyncResponse,\n type DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isUpstreamDeletedDocumentSyncFailure,\n submitDocumentSync,\n} from \"../../../data/documents/shared/responses\";\nimport {\n type DocumentSyncCommitLsnMode,\n type DocumentSyncPullContinuation,\n InvalidDocumentSyncPullContinuationError,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type {\n DocumentSyncApi,\n DocumentSyncPlan,\n DocumentSyncSubmitFailure,\n MaterializedDocumentSyncPlan,\n} from \"../../../data/documents/shared/types\";\nimport type { ReferencedPrincipalPolicyWarmer } from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport {\n type DocumentSyncTraceEmitter,\n traceProjectionFailed,\n traceSubmitFailed,\n} from \"../sync/syncTrace\";\nimport {\n canRecoverDocumentUpdateIdConflict,\n canRetryDocumentSyncConflict,\n handleUpstreamDeletedDocumentSyncFailure,\n isCheckpointCoverageConflict,\n type RemoteDocumentDeletionHandler,\n shouldRetrySyncWithFreshWriterProjection,\n type TerminalSubmitFailureHandler,\n} from \"./syncFailureClassification\";\nimport { recoverDocumentSyncPolicyRepair } from \"./syncPolicyRepair\";\n\nconst REMOTE_DOCUMENT_DELETED = Symbol(\"remoteDocumentDeleted\");\n\nexport function assertRawContinuationCanRetry(\n historyMode: \"raw\" | undefined,\n pullContinuation: DocumentSyncPullContinuation | undefined,\n): void {\n if (historyMode === \"raw\" && pullContinuation !== undefined) {\n throw new InvalidDocumentSyncPullContinuationError(\n \"Document raw-history continuation became stale\",\n );\n }\n}\n\ntype DocumentWriterProjectionResolution =\n | DocumentWriterProjectionResponse\n | typeof REMOTE_DOCUMENT_DELETED\n | null;\n\ntype FailedDocumentSyncAction =\n | \"retry\"\n | \"stop\"\n | {\n readonly kind: \"recover_update_id_conflict\";\n readonly recoveryPendingUpdatesById: Map<string, PendingUpdateRecord>;\n }\n | { readonly kind: \"regenerate_queued_checkpoints\" };\n\ntype DocumentSyncAttemptSubmission =\n | {\n readonly kind: \"completed\";\n readonly pullComplete: boolean;\n readonly response: DocumentSyncResponse;\n }\n | FailedDocumentSyncAction\n | \"cancelled\"\n | \"blocked\";\n\nasync function resolveFailedDocumentSyncAction(input: {\n attempt: number;\n canRegenerateQueuedCheckpoints?: boolean | undefined;\n documentId: string;\n failure: DocumentSyncSubmitFailure;\n maxAttempts: number;\n onInlineRepairRefused?: (() => void) | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates: readonly PendingUpdateRecord[];\n}): Promise<FailedDocumentSyncAction> {\n const action = await classifyFailedDocumentSyncAction(input);\n traceSubmitFailed(input.onSyncTrace, {\n action:\n action === \"retry\" || action === \"stop\"\n ? action\n : action.kind === \"recover_update_id_conflict\"\n ? \"recover-update-ids\"\n : \"regenerate-checkpoints\",\n code: input.failure.code,\n documentId: input.documentId,\n status: input.failure.status,\n });\n return action;\n}\n\nasync function classifyFailedDocumentSyncAction(input: {\n attempt: number;\n canRegenerateQueuedCheckpoints?: boolean | undefined;\n documentId: string;\n failure: DocumentSyncSubmitFailure;\n maxAttempts: number;\n onInlineRepairRefused?: (() => void) | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates: readonly PendingUpdateRecord[];\n}): Promise<FailedDocumentSyncAction> {\n if (\n await handleUpstreamDeletedDocumentSyncFailure({\n documentId: input.documentId,\n failure: input.failure,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n })\n ) {\n return \"stop\";\n }\n\n if (\n canRetryDocumentSyncConflict({\n attempt: input.attempt,\n failure: input.failure,\n maxAttempts: input.maxAttempts,\n })\n ) {\n return \"retry\";\n }\n\n // The write rolled back whole. Its inline repairs would have stranded a\n // level above a directly granted container, and a flat rekey list cannot say\n // what each must carry: the retry commits them standalone instead.\n if (\n input.attempt < input.maxAttempts &&\n input.onInlineRepairRefused &&\n input.failure.code === DOCUMENT_SYNC_ERROR_CODES.descendantRekeysRequired\n ) {\n input.onInlineRepairRefused();\n return \"retry\";\n }\n\n if (\n canRecoverDocumentUpdateIdConflict({\n attempt: input.attempt,\n failure: input.failure,\n maxAttempts: input.maxAttempts,\n pendingUpdateCount: input.pendingUpdates.length,\n })\n ) {\n return {\n kind: \"recover_update_id_conflict\",\n recoveryPendingUpdatesById: new Map(\n input.pendingUpdates.map((update) => [update.id, update]),\n ),\n };\n }\n\n if (\n input.attempt < input.maxAttempts &&\n input.canRegenerateQueuedCheckpoints === true &&\n isCheckpointCoverageConflict(input.failure)\n ) {\n return { kind: \"regenerate_queued_checkpoints\" };\n }\n\n input.failure.report();\n await input.onTerminalSubmitFailure?.(input.failure);\n return \"stop\";\n}\n\nasync function submitDocumentSyncAttempt(input: {\n apiClient: DocumentSyncApi;\n attempt: number;\n canRegenerateQueuedCheckpoints?: boolean | undefined;\n documentId: string;\n expectedCommitLsnMode?: DocumentSyncCommitLsnMode | undefined;\n maxAttempts: number;\n onInlineRepairRefused?: (() => void) | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates: readonly PendingUpdateRecord[];\n plan: DocumentSyncPlan;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<DocumentSyncAttemptSubmission> {\n if (input.stillCurrent?.() === false) return \"cancelled\";\n const submitted = await submitDocumentSync({\n apiClient: input.apiClient,\n expectedCommitLsnMode: input.expectedCommitLsnMode,\n plan: input.plan,\n });\n if (input.stillCurrent?.() === false) return \"cancelled\";\n if (!submitted) {\n return \"stop\";\n }\n if (submitted.ok) {\n return {\n kind: \"completed\",\n pullComplete: submitted.pullComplete,\n response: submitted.response,\n };\n }\n\n await recoverDocumentSyncPolicyRepair({\n failure: submitted,\n plan: input.plan,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n if (input.stillCurrent?.() === false) return \"cancelled\";\n\n return resolveFailedDocumentSyncAction({\n attempt: input.attempt,\n canRegenerateQueuedCheckpoints: input.canRegenerateQueuedCheckpoints,\n documentId: input.documentId,\n failure: submitted,\n maxAttempts: input.maxAttempts,\n onInlineRepairRefused: input.onInlineRepairRefused,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n pendingUpdates: input.pendingUpdates,\n });\n}\n\nexport async function submitDocumentSyncAttemptIfAllowed(\n input: Parameters<typeof submitDocumentSyncAttempt>[0] & {\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n onOutgoingUpdatesMaterialized?:\n | ((updateIds: readonly string[]) => void)\n | undefined;\n failureBlocksQueuedWrites?: boolean | undefined;\n },\n): Promise<DocumentSyncAttemptSubmission> {\n const {\n failureBlocksQueuedWrites,\n isRemoteSyncBlocked,\n onOutgoingUpdatesMaterialized,\n ...submissionInput\n } = input;\n const hasRemoteWrites =\n input.plan.request.outgoingUpdates.length > 0 ||\n (input.plan.request.containerRekeys?.length ?? 0) > 0;\n if (hasRemoteWrites && isRemoteSyncBlocked?.(input.plan.organizationId)) {\n return \"blocked\";\n }\n if (input.stillCurrent?.() === false) return \"cancelled\";\n\n onOutgoingUpdatesMaterialized?.(\n input.plan.request.outgoingUpdates.map(({ id }) => id),\n );\n\n return submitDocumentSyncAttempt({\n ...submissionInput,\n // A read-only pass carries no writes, so a terminal failure describes a\n // pull, not queued local data — recording it would flag the next local\n // edit as failed before it was ever attempted. A cursor continuation and\n // update-id recovery both submit an empty request while durable rows still\n // exist; a terminal 403 there IS what blocks the queued edits.\n onTerminalSubmitFailure:\n hasRemoteWrites || failureBlocksQueuedWrites\n ? submissionInput.onTerminalSubmitFailure\n : undefined,\n });\n}\n\nasync function resolveDocumentSyncWriterProjection(input: {\n apiClient: DocumentSyncApi;\n documentId: string;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n /**\n * Invoked when the projection fetch fails terminally. Write-bearing sync\n * passes persist this: without a writer projection their queued writes can\n * never submit, so the failure (e.g. a 403 after access revocation) is what\n * the write queue should surface.\n */\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n reusableWriterProjection: DocumentWriterProjectionResponse | null;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<DocumentWriterProjectionResolution> {\n if (input.stillCurrent?.() === false) return null;\n if (input.reusableWriterProjection) {\n return input.reusableWriterProjection;\n }\n\n const result = await input.apiClient.getDocumentWriterProjectionResult(\n input.documentId,\n { reportErrors: false },\n );\n if (input.stillCurrent?.() === false) return null;\n if (result.ok) {\n return result.data;\n }\n if (isUpstreamDeletedDocumentSyncFailure(result)) {\n return REMOTE_DOCUMENT_DELETED;\n }\n traceProjectionFailed(input.onSyncTrace, {\n code: result.code,\n documentId: input.documentId,\n status: result.status,\n });\n result.report();\n await input.onTerminalFailure?.(result);\n return null;\n}\n\nexport async function retrySyncPlan(input: {\n apiClient: DocumentSyncApi;\n buildWithProjection: (\n projection: DocumentWriterProjectionResponse,\n ) => Promise<MaterializedDocumentSyncPlan>;\n documentId: string;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n stillCurrent?: (() => boolean) | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | readonly [MaterializedDocumentSyncPlan, DocumentWriterProjectionResponse]\n | null\n> {\n try {\n return [\n await input.buildWithProjection(input.writerProjection),\n input.writerProjection,\n ];\n } catch (error) {\n if (\n !input.apiClient.evictDocumentWriterProjection ||\n !shouldRetrySyncWithFreshWriterProjection(error)\n ) {\n throw error;\n }\n }\n if (input.stillCurrent?.() === false) return null;\n\n // Only this document's projection was stale; evict just it so unrelated\n // documents keep their warm cache instead of a global wipe.\n input.apiClient.evictDocumentWriterProjection?.(input.documentId);\n const writerProjection = await resolveDocumentSyncWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onTerminalFailure,\n reusableWriterProjection: null,\n stillCurrent: input.stillCurrent,\n });\n if (input.stillCurrent?.() === false) return null;\n if (writerProjection === REMOTE_DOCUMENT_DELETED) {\n await input.onRemoteDocumentDeleted?.({ documentId: input.documentId });\n return null;\n }\n if (!writerProjection) {\n return null;\n }\n\n return [await input.buildWithProjection(writerProjection), writerProjection];\n}\n\n/**\n * Resolves the writer projection for one sync attempt, converting the two\n * unrecoverable outcomes into an abandoned (null) result with a named reason\n * so callers that turn a null sync into their own error can surface the real\n * cause.\n */\nexport async function resolveSyncAttemptWriterProjection(input: {\n apiClient: DocumentSyncApi;\n documentId: string;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n reusableWriterProjection: DocumentWriterProjectionResponse | null;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<DocumentWriterProjectionResponse | null> {\n const writerProjection = await resolveDocumentSyncWriterProjection(input);\n if (input.stillCurrent?.() === false) return null;\n if (writerProjection === REMOTE_DOCUMENT_DELETED) {\n await input.onRemoteDocumentDeleted?.({ documentId: input.documentId });\n if (input.stillCurrent?.() !== false) {\n input.onSyncAbandoned?.(\"the remote document was deleted\");\n }\n return null;\n }\n if (!writerProjection) {\n input.onSyncAbandoned?.(\n \"the document writer projection could not be fetched\",\n );\n return null;\n }\n return writerProjection;\n}\n\nexport async function refreshSyncAttemptWriterProjection(\n input: Omit<\n Parameters<typeof resolveSyncAttemptWriterProjection>[0],\n \"reusableWriterProjection\"\n > & { unavailableError?: unknown },\n): Promise<DocumentWriterProjectionResponse | null> {\n const { onRemoteDocumentDeleted, unavailableError, ...resolutionInput } =\n input;\n if (input.stillCurrent?.() === false) return null;\n if (input.apiClient.evictDocumentWriterProjection) {\n input.apiClient.evictDocumentWriterProjection(input.documentId);\n } else {\n input.apiClient.clearWriterProjectionCaches?.();\n }\n let remoteDocumentDeleted = false;\n const writerProjection = await resolveSyncAttemptWriterProjection({\n ...resolutionInput,\n onRemoteDocumentDeleted: async (deleted) => {\n remoteDocumentDeleted = true;\n await onRemoteDocumentDeleted?.(deleted);\n },\n reusableWriterProjection: null,\n });\n if (\n !writerProjection &&\n unavailableError !== undefined &&\n !remoteDocumentDeleted &&\n input.stillCurrent?.() !== false\n ) {\n throw unavailableError;\n }\n return writerProjection;\n}\n\nexport async function retrySyncPlanOrAbandon(input: {\n apiClient: DocumentSyncApi;\n buildWithProjection: (\n projection: DocumentWriterProjectionResponse,\n ) => Promise<MaterializedDocumentSyncPlan>;\n documentId: string;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n stillCurrent?: (() => boolean) | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | readonly [MaterializedDocumentSyncPlan, DocumentWriterProjectionResponse]\n | null\n> {\n const planned = await retrySyncPlan(input);\n if (!planned && input.stillCurrent?.() !== false) {\n input.onSyncAbandoned?.(\n \"a sync plan could not be built against the current projection\",\n );\n }\n return planned;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DOCUMENT_SYNC_ERROR_CODES,\n type DocumentSyncResponse,\n type DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isUpstreamDeletedDocumentSyncFailure,\n submitDocumentSync,\n} from \"../../../data/documents/shared/responses\";\nimport {\n type DocumentSyncCommitLsnMode,\n type DocumentSyncPullContinuation,\n InvalidDocumentSyncPullContinuationError,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type {\n DocumentSyncApi,\n DocumentSyncPlan,\n DocumentSyncSubmitFailure,\n MaterializedDocumentSyncPlan,\n} from \"../../../data/documents/shared/types\";\nimport type { ReferencedPrincipalPolicyWarmer } from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport {\n type DocumentSyncTraceEmitter,\n traceProjectionFailed,\n traceSubmitFailed,\n} from \"../sync/syncTrace\";\nimport {\n canRecoverDocumentUpdateIdConflict,\n canRetryDocumentSyncConflict,\n handleUpstreamDeletedDocumentSyncFailure,\n isCheckpointCoverageConflict,\n type RemoteDocumentDeletionHandler,\n shouldRetrySyncWithFreshWriterProjection,\n type TerminalSubmitFailureHandler,\n} from \"./syncFailureClassification\";\nimport { recoverDocumentSyncPolicyRepair } from \"./syncPolicyRepair\";\n\nconst REMOTE_DOCUMENT_DELETED = Symbol(\"remoteDocumentDeleted\");\n\nexport function assertRawContinuationCanRetry(\n historyMode: \"raw\" | undefined,\n pullContinuation: DocumentSyncPullContinuation | undefined,\n): void {\n if (historyMode === \"raw\" && pullContinuation !== undefined) {\n throw new InvalidDocumentSyncPullContinuationError(\n \"Document raw-history continuation became stale\",\n );\n }\n}\n\ntype DocumentWriterProjectionResolution =\n | DocumentWriterProjectionResponse\n | typeof REMOTE_DOCUMENT_DELETED\n | null;\n\ntype FailedDocumentSyncAction =\n | \"retry\"\n | \"stop\"\n | {\n readonly kind: \"recover_update_id_conflict\";\n readonly recoveryPendingUpdatesById: Map<string, PendingUpdateRecord>;\n }\n | { readonly kind: \"regenerate_queued_checkpoints\" };\n\ntype DocumentSyncAttemptSubmission =\n | {\n readonly kind: \"completed\";\n readonly pullComplete: boolean;\n readonly response: DocumentSyncResponse;\n }\n | FailedDocumentSyncAction\n | \"cancelled\"\n | \"blocked\";\n\nasync function resolveFailedDocumentSyncAction(input: {\n attempt: number;\n canRegenerateQueuedCheckpoints?: boolean | undefined;\n documentId: string;\n failure: DocumentSyncSubmitFailure;\n maxAttempts: number;\n onInlineRepairRefused?: (() => void) | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates: readonly PendingUpdateRecord[];\n}): Promise<FailedDocumentSyncAction> {\n const action = await classifyFailedDocumentSyncAction(input);\n traceSubmitFailed(input.onSyncTrace, {\n action:\n action === \"retry\" || action === \"stop\"\n ? action\n : action.kind === \"recover_update_id_conflict\"\n ? \"recover-update-ids\"\n : \"regenerate-checkpoints\",\n code: input.failure.code,\n documentId: input.documentId,\n status: input.failure.status,\n });\n return action;\n}\n\nasync function classifyFailedDocumentSyncAction(input: {\n attempt: number;\n canRegenerateQueuedCheckpoints?: boolean | undefined;\n documentId: string;\n failure: DocumentSyncSubmitFailure;\n maxAttempts: number;\n onInlineRepairRefused?: (() => void) | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates: readonly PendingUpdateRecord[];\n}): Promise<FailedDocumentSyncAction> {\n if (\n await handleUpstreamDeletedDocumentSyncFailure({\n documentId: input.documentId,\n failure: input.failure,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n })\n ) {\n return \"stop\";\n }\n\n if (\n canRetryDocumentSyncConflict({\n attempt: input.attempt,\n failure: input.failure,\n maxAttempts: input.maxAttempts,\n })\n ) {\n return \"retry\";\n }\n\n // The write rolled back whole. Its inline repairs would have stranded a\n // level above a directly granted container, and a flat rekey list cannot say\n // what each must carry: the retry commits them standalone instead.\n if (\n input.attempt < input.maxAttempts &&\n input.onInlineRepairRefused &&\n input.failure.code === DOCUMENT_SYNC_ERROR_CODES.descendantRekeysRequired\n ) {\n input.onInlineRepairRefused();\n return \"retry\";\n }\n\n if (\n canRecoverDocumentUpdateIdConflict({\n attempt: input.attempt,\n failure: input.failure,\n maxAttempts: input.maxAttempts,\n pendingUpdateCount: input.pendingUpdates.length,\n })\n ) {\n return {\n kind: \"recover_update_id_conflict\",\n recoveryPendingUpdatesById: new Map(\n input.pendingUpdates.map((update) => [update.id, update]),\n ),\n };\n }\n\n if (\n input.attempt < input.maxAttempts &&\n input.canRegenerateQueuedCheckpoints === true &&\n isCheckpointCoverageConflict(input.failure)\n ) {\n return { kind: \"regenerate_queued_checkpoints\" };\n }\n\n input.failure.report();\n await input.onTerminalSubmitFailure?.(input.failure);\n return \"stop\";\n}\n\nasync function submitDocumentSyncAttempt(input: {\n apiClient: DocumentSyncApi;\n attempt: number;\n canRegenerateQueuedCheckpoints?: boolean | undefined;\n documentId: string;\n expectedCommitLsnMode?: DocumentSyncCommitLsnMode | undefined;\n maxAttempts: number;\n onInlineRepairRefused?: (() => void) | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates: readonly PendingUpdateRecord[];\n plan: DocumentSyncPlan;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<DocumentSyncAttemptSubmission> {\n if (input.stillCurrent?.() === false) return \"cancelled\";\n const submitted = await submitDocumentSync({\n apiClient: input.apiClient,\n expectedCommitLsnMode: input.expectedCommitLsnMode,\n plan: input.plan,\n });\n if (input.stillCurrent?.() === false) return \"cancelled\";\n if (!submitted) {\n return \"stop\";\n }\n if (submitted.ok) {\n return {\n kind: \"completed\",\n pullComplete: submitted.pullComplete,\n response: submitted.response,\n };\n }\n\n await recoverDocumentSyncPolicyRepair({\n failure: submitted,\n plan: input.plan,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n if (input.stillCurrent?.() === false) return \"cancelled\";\n\n return resolveFailedDocumentSyncAction({\n attempt: input.attempt,\n canRegenerateQueuedCheckpoints: input.canRegenerateQueuedCheckpoints,\n documentId: input.documentId,\n failure: submitted,\n maxAttempts: input.maxAttempts,\n onInlineRepairRefused: input.onInlineRepairRefused,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalSubmitFailure: input.onTerminalSubmitFailure,\n pendingUpdates: input.pendingUpdates,\n });\n}\n\nexport async function submitDocumentSyncAttemptIfAllowed(\n input: Parameters<typeof submitDocumentSyncAttempt>[0] & {\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n onOutgoingUpdatesMaterialized?:\n | ((updateIds: readonly string[]) => void)\n | undefined;\n failureBlocksQueuedWrites?: boolean | undefined;\n },\n): Promise<DocumentSyncAttemptSubmission> {\n const {\n failureBlocksQueuedWrites,\n isRemoteSyncBlocked,\n onOutgoingUpdatesMaterialized,\n ...submissionInput\n } = input;\n const hasRemoteWrites =\n input.plan.request.outgoingUpdates.length > 0 ||\n (input.plan.request.containerRekeys?.length ?? 0) > 0;\n if (hasRemoteWrites && isRemoteSyncBlocked?.(input.plan.organizationId)) {\n return \"blocked\";\n }\n if (input.stillCurrent?.() === false) return \"cancelled\";\n\n onOutgoingUpdatesMaterialized?.(\n input.plan.request.outgoingUpdates.map(({ id }) => id),\n );\n\n return submitDocumentSyncAttempt({\n ...submissionInput,\n // A read-only pass carries no writes, so a terminal failure describes a\n // pull, not queued local data — recording it would flag the next local\n // edit as failed before it was ever attempted. A cursor continuation and\n // update-id recovery both submit an empty request while durable rows still\n // exist; a terminal 403 there IS what blocks the queued edits.\n onTerminalSubmitFailure:\n hasRemoteWrites || failureBlocksQueuedWrites\n ? submissionInput.onTerminalSubmitFailure\n : undefined,\n });\n}\n\nasync function resolveDocumentSyncWriterProjection(input: {\n apiClient: DocumentSyncApi;\n documentId: string;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n /**\n * Invoked when the projection fetch fails terminally. Write-bearing sync\n * passes persist this: without a writer projection their queued writes can\n * never submit, so the failure (e.g. a 403 after access revocation) is what\n * the write queue should surface.\n */\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n reusableWriterProjection: DocumentWriterProjectionResponse | null;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<DocumentWriterProjectionResolution> {\n if (input.stillCurrent?.() === false) return null;\n if (input.reusableWriterProjection) {\n return input.reusableWriterProjection;\n }\n\n const result = await input.apiClient.getDocumentWriterProjectionResult(\n input.documentId,\n { reportErrors: false },\n );\n if (input.stillCurrent?.() === false) return null;\n if (result.ok) {\n return result.data;\n }\n if (isUpstreamDeletedDocumentSyncFailure(result)) {\n return REMOTE_DOCUMENT_DELETED;\n }\n traceProjectionFailed(input.onSyncTrace, {\n code: result.code,\n documentId: input.documentId,\n status: result.status,\n });\n result.report();\n await input.onTerminalFailure?.(result);\n return null;\n}\n\nexport async function retrySyncPlan(input: {\n apiClient: DocumentSyncApi;\n buildWithProjection: (\n projection: DocumentWriterProjectionResponse,\n ) => Promise<MaterializedDocumentSyncPlan>;\n documentId: string;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n stillCurrent?: (() => boolean) | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | readonly [MaterializedDocumentSyncPlan, DocumentWriterProjectionResponse]\n | null\n> {\n try {\n return [\n await input.buildWithProjection(input.writerProjection),\n input.writerProjection,\n ];\n } catch (error) {\n if (\n !input.apiClient.evictDocumentWriterProjection ||\n !shouldRetrySyncWithFreshWriterProjection(error)\n ) {\n throw error;\n }\n }\n if (input.stillCurrent?.() === false) return null;\n\n // Only this document's projection was stale; evict just it so unrelated\n // documents keep their warm cache instead of a global wipe.\n input.apiClient.evictDocumentWriterProjection?.(input.documentId);\n const writerProjection = await resolveDocumentSyncWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onTerminalFailure,\n reusableWriterProjection: null,\n stillCurrent: input.stillCurrent,\n });\n if (input.stillCurrent?.() === false) return null;\n if (writerProjection === REMOTE_DOCUMENT_DELETED) {\n await input.onRemoteDocumentDeleted?.({ documentId: input.documentId });\n return null;\n }\n if (!writerProjection) {\n return null;\n }\n\n return [await input.buildWithProjection(writerProjection), writerProjection];\n}\n\n/**\n * Resolves the writer projection for one sync attempt, converting the two\n * unrecoverable outcomes into an abandoned (null) result with a named reason\n * so callers that turn a null sync into their own error can surface the real\n * cause.\n */\nexport async function resolveSyncAttemptWriterProjection(input: {\n apiClient: DocumentSyncApi;\n documentId: string;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n reusableWriterProjection: DocumentWriterProjectionResponse | null;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<DocumentWriterProjectionResponse | null> {\n const writerProjection = await resolveDocumentSyncWriterProjection(input);\n if (input.stillCurrent?.() === false) return null;\n if (writerProjection === REMOTE_DOCUMENT_DELETED) {\n await input.onRemoteDocumentDeleted?.({ documentId: input.documentId });\n if (input.stillCurrent?.() !== false) {\n input.onSyncAbandoned?.(\"the remote document was deleted\");\n }\n return null;\n }\n if (!writerProjection) {\n input.onSyncAbandoned?.(\n \"the document writer projection could not be fetched\",\n );\n return null;\n }\n return writerProjection;\n}\n\nexport async function refreshSyncAttemptWriterProjection(\n input: Omit<\n Parameters<typeof resolveSyncAttemptWriterProjection>[0],\n \"reusableWriterProjection\"\n > & { unavailableError?: unknown },\n): Promise<DocumentWriterProjectionResponse | null> {\n const { onRemoteDocumentDeleted, unavailableError, ...resolutionInput } =\n input;\n if (input.stillCurrent?.() === false) return null;\n if (input.apiClient.evictDocumentWriterProjection) {\n input.apiClient.evictDocumentWriterProjection(input.documentId);\n } else {\n input.apiClient.clearWriterProjectionCaches?.();\n }\n let remoteDocumentDeleted = false;\n const writerProjection = await resolveSyncAttemptWriterProjection({\n ...resolutionInput,\n onRemoteDocumentDeleted: async (deleted) => {\n remoteDocumentDeleted = true;\n await onRemoteDocumentDeleted?.(deleted);\n },\n reusableWriterProjection: null,\n });\n if (\n !writerProjection &&\n unavailableError !== undefined &&\n !remoteDocumentDeleted &&\n input.stillCurrent?.() !== false\n ) {\n throw unavailableError;\n }\n return writerProjection;\n}\n\nexport async function retrySyncPlanOrAbandon(input: {\n apiClient: DocumentSyncApi;\n buildWithProjection: (\n projection: DocumentWriterProjectionResponse,\n ) => Promise<MaterializedDocumentSyncPlan>;\n documentId: string;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n onTerminalFailure?: TerminalSubmitFailureHandler | undefined;\n stillCurrent?: (() => boolean) | undefined;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | readonly [MaterializedDocumentSyncPlan, DocumentWriterProjectionResponse]\n | null\n> {\n const planned = await retrySyncPlan(input);\n if (!planned && input.stillCurrent?.() !== false) {\n input.onSyncAbandoned?.(\n \"a sync plan could not be built against the current projection\",\n );\n }\n return planned;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DocumentSyncResponse, DocumentWriterProjectionResponse } from "../../../internal/validators/response/index.js";
|
|
2
2
|
import type { DocumentSyncPreparedUpdate, ProjectionVerificationOptions } from "../../../data/documents/shared/types.js";
|
|
3
|
-
import type { PendingUpdateRecord } from "../../../data/
|
|
3
|
+
import type { PendingUpdateRecord } from "../../../data/persistence/documents/records/index.js";
|
|
4
4
|
import type { ExecSql } from "../../../data/sqlite/sqlSchema.js";
|
|
5
5
|
type SyncResponseUpdate = DocumentSyncResponse["updates"][number];
|
|
6
6
|
type RawHistoryUnavailableValidator = (input: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncContentKeys.js","sourceRoot":"","sources":["syncContentKeys.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { importContentKeyMaterial } from \"../../../data/documents/shared/contentRecordKeys\";\nimport { encryptDocumentPendingUpdate } from \"../../../data/documents/shared/crypto\";\nimport {\n ContainerKekHistoryUnavailableError,\n collectContainerKeksForDocumentSync,\n DocumentContentKeyUnavailableError,\n DocumentHistoryUnavailableError,\n unwrapDocumentContentKeyFromBundle,\n} from \"../../../data/documents/shared/projection\";\nimport { readWriteHeader } from \"../../../data/documents/shared/readers\";\nimport { assertDocumentSyncUpdateEncryptedRecord } from \"../../../data/documents/shared/sync/documentSyncUpdateDecryption\";\nimport {\n isDocumentSyncUpdateIsolationError,\n isolateDocumentSyncBatchError,\n isolateDocumentSyncUpdateError,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport type {\n DocumentSyncPreparedUpdate,\n ProjectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { isKeyingVerificationError } from \"../../../data/keyingProjectionVerification/error\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\n\ntype SyncResponseUpdate = DocumentSyncResponse[\"updates\"][number];\ntype RawHistoryUnavailableCause =\n | DocumentContentKeyUnavailableError\n | DocumentHistoryUnavailableError;\n\nfunction isRawHistoryUnavailableCause(\n error: unknown,\n): error is RawHistoryUnavailableCause {\n return (\n error instanceof DocumentContentKeyUnavailableError ||\n (error instanceof DocumentHistoryUnavailableError &&\n error.historyCause instanceof ContainerKekHistoryUnavailableError)\n );\n}\n\ntype RawHistoryUnavailableValidator = (input: {\n contentKeysByEpoch: ReadonlyMap<number, Uint8Array>;\n updates: readonly SyncResponseUpdate[];\n}) => void | Promise<void>;\n\n/** A raw recovery cannot reconstruct history without this retained epoch. */\nexport class DocumentRawHistoryUnavailableError extends Error {\n readonly code = \"document_raw_history_epoch_unavailable\";\n\n constructor(\n readonly contentKeyEpoch: number,\n cause: unknown,\n ) {\n super(\n `Document raw-history recovery cannot decrypt content-key epoch ${contentKeyEpoch}`,\n { cause },\n );\n this.name = \"DocumentRawHistoryUnavailableError\";\n }\n}\n\nasync function assertResponseEncryptedRecords(\n updates: readonly SyncResponseUpdate[],\n): Promise<void> {\n const inspections = await Promise.allSettled(\n updates.map(assertDocumentSyncUpdateEncryptedRecord),\n );\n const failures = inspections.flatMap((inspection, index) =>\n inspection.status === \"rejected\"\n ? [{ index, reason: inspection.reason }]\n : [],\n );\n const firstFailure = failures[0];\n if (failures.length === 1 && firstFailure) {\n throw firstFailure.reason;\n }\n if (failures.length > 1 && firstFailure) {\n const stage =\n isDocumentSyncUpdateIsolationError(firstFailure.reason) &&\n failures.every(\n ({ reason }) =>\n isDocumentSyncUpdateIsolationError(reason) &&\n reason.stage === firstFailure.reason.stage,\n )\n ? firstFailure.reason.stage\n : \"encrypted_record\";\n throw isolateDocumentSyncBatchError({\n cause: new Error(\"Multiple document encrypted records are invalid\"),\n stage,\n updateIds: failures.map(({ index }) => updates[index]?.id ?? \"unknown\"),\n });\n }\n}\n\nasync function throwRawHistoryUnavailable(input: {\n contentKeysByEpoch: ReadonlyMap<number, Uint8Array>;\n response: DocumentSyncResponse;\n unavailable: { cause: RawHistoryUnavailableCause; contentKeyEpoch: number };\n validate?: RawHistoryUnavailableValidator | undefined;\n}): Promise<never> {\n await assertResponseEncryptedRecords(input.response.updates);\n await input.validate?.({\n contentKeysByEpoch: input.contentKeysByEpoch,\n updates: input.response.updates.filter((update) =>\n input.contentKeysByEpoch.has(\n readWriteHeader(\n update.writeHeader,\n \"Document sync response write header\",\n ).contentKeyEpoch,\n ),\n ),\n });\n throw new DocumentRawHistoryUnavailableError(\n input.unavailable.contentKeyEpoch,\n input.unavailable.cause,\n );\n}\n\nexport async function prepareDocumentOutgoingUpdates(input: {\n contentKey: Uint8Array;\n contentKeyEpoch: number;\n documentId: string;\n organizationId: string;\n pendingUpdates: readonly PendingUpdateRecord[];\n}): Promise<DocumentSyncPreparedUpdate[]> {\n if (input.pendingUpdates.length === 0) {\n return [];\n }\n const contentKeyMaterial = await importContentKeyMaterial(input.contentKey);\n\n return Promise.all(\n input.pendingUpdates.map(async (update) => {\n const encrypted = await encryptDocumentPendingUpdate({\n contentKeyMaterial,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n organizationId: input.organizationId,\n update,\n });\n\n return {\n contentRecordId: encrypted.contentRecordId,\n encryptedData: encrypted.encryptedData,\n id: update.id,\n partialStartVersionVector: update.partialStartVersionVector,\n partialEndVersionVector: update.partialEndVersionVector,\n metadataHash: encrypted.metadataHash,\n ciphertextHash: encrypted.ciphertextHash,\n plaintextHash: encrypted.plaintextHash,\n ...(update.sourceVersionVector\n ? {\n checkpointKind: \"rotate_baseline\" as const,\n checkpointPayloadKind: \"full_history_snapshot\" as const,\n sourceVersionVector: update.sourceVersionVector,\n }\n : {}),\n };\n }),\n );\n}\n\nfunction syncResponseContentKeyBundlesByEpoch(\n response: DocumentSyncResponse,\n): ReadonlyMap<number, DocumentSyncResponse[\"contentKeyBundle\"]> {\n const byEpoch = new Map<number, DocumentSyncResponse[\"contentKeyBundle\"]>();\n\n for (const bundle of [\n response.contentKeyBundle,\n ...response.contentKeyBundles,\n ]) {\n if (byEpoch.has(bundle.contentKeyEpoch)) {\n throw new Error(\"Document sync response repeats a content-key epoch\");\n }\n byEpoch.set(bundle.contentKeyEpoch, bundle);\n }\n\n return byEpoch;\n}\n\nfunction syncResponseUpdatesByContentKeyEpoch(\n response: DocumentSyncResponse,\n): ReadonlyMap<number, readonly SyncResponseUpdate[]> {\n const updatesByEpoch = new Map<number, SyncResponseUpdate[]>();\n for (const update of response.updates) {\n let contentKeyEpoch: number;\n try {\n contentKeyEpoch = readWriteHeader(\n update.writeHeader,\n \"Document sync response write header\",\n ).contentKeyEpoch;\n } catch (error) {\n throw isolateDocumentSyncUpdateError({\n cause: error,\n responseUpdate: update,\n stage: \"write_header\",\n updateId: update.id,\n });\n }\n const epochUpdates = updatesByEpoch.get(contentKeyEpoch);\n if (epochUpdates) epochUpdates.push(update);\n else updatesByEpoch.set(contentKeyEpoch, [update]);\n }\n return updatesByEpoch;\n}\n\nfunction assertBundleMatchesUpdateHeaders(input: {\n bundle: DocumentSyncResponse[\"contentKeyBundle\"];\n requireOriginalTargets: boolean;\n updates: readonly SyncResponseUpdate[];\n}): void {\n for (const update of input.updates) {\n const header = readWriteHeader(\n update.writeHeader,\n \"Document sync response write header\",\n );\n if (\n header.objectId !== input.bundle.documentId ||\n header.contentKeyEpoch !== input.bundle.contentKeyEpoch ||\n (input.requireOriginalTargets &&\n (header.accessManifestHash !== input.bundle.linkSetManifestHash ||\n header.targetHash !== input.bundle.targetHash))\n ) {\n throw new Error(\n input.requireOriginalTargets\n ? \"Document sync response content key is unavailable and its bundle differs from the original update headers\"\n : \"Document sync response content-key bundle does not match its update headers\",\n );\n }\n }\n}\n\n/**\n * Linking can rewrap a retained key at the same content epoch. Its latest bundle\n * then has newer targets than older signed updates. A usable key is validated\n * by the caller's authenticated record decryption; the update's own historical\n * manifest, targets and signature are verified independently before this step.\n *\n * If the key cannot be recovered, require the original target commitments before\n * calling that an availability failure. Substituted unavailable targets must\n * still be quarantined, never disguised as legitimate missing history.\n */\nasync function unwrapHistoricalContentKey(input: {\n bundle: DocumentSyncResponse[\"contentKeyBundle\"];\n documentId: string;\n collectedKeks: Awaited<\n ReturnType<typeof collectContainerKeksForDocumentSync>\n >;\n updates: readonly SyncResponseUpdate[];\n}): Promise<Uint8Array> {\n assertBundleMatchesUpdateHeaders({ ...input, requireOriginalTargets: false });\n try {\n return await unwrapDocumentContentKeyFromBundle(\n input.bundle,\n input.documentId,\n input.collectedKeks.keksByEpochId,\n input.collectedKeks.predecessorFailuresByEpochId,\n input.collectedKeks.unattributedPredecessorFailuresByContainerId,\n );\n } catch (error) {\n if (isRawHistoryUnavailableCause(error)) {\n assertBundleMatchesUpdateHeaders({\n ...input,\n requireOriginalTargets: true,\n });\n }\n throw error;\n }\n}\n\n/** @internal Keeps epoch-wide failures anonymous and integrity failures typed. */\nexport function throwDocumentSyncContentKeyFailure(input: {\n cause: unknown;\n updates: readonly SyncResponseUpdate[];\n}): never {\n if (isKeyingVerificationError(input.cause)) {\n throw input.cause;\n }\n if (\n input.cause instanceof DocumentHistoryUnavailableError &&\n isKeyingVerificationError(input.cause.historyCause)\n ) {\n throw input.cause.historyCause;\n }\n throw isolateDocumentSyncBatchError({\n cause: input.cause,\n stage: \"content_key\",\n updateIds: input.updates.map((update) => update.id),\n });\n}\n\nexport async function unwrapDocumentSyncResponseContentKeys(\n input: {\n currentContentKey: Uint8Array;\n currentContentKeyEpoch: number;\n execSql?: ExecSql | undefined;\n historyMode?: \"raw\" | undefined;\n /** @internal Validate every decryptable sibling before raw availability wins. */\n onRawHistoryUnavailable?: RawHistoryUnavailableValidator | undefined;\n response: DocumentSyncResponse;\n targetSecretKey: Uint8Array;\n writerProjection: DocumentWriterProjectionResponse;\n } & ProjectionVerificationOptions,\n): Promise<ReadonlyMap<number, Uint8Array>> {\n // A stale read-only pass can carry an empty placeholder when none of its\n // authorizing paths reaches the bundle target. Do not mark that epoch as\n // resolved: every served update must instead unwrap its bundle through the\n // verified predecessor KEK chain or fail with an honest error.\n const contentKeysByEpoch = new Map<number, Uint8Array>(\n input.currentContentKey.byteLength > 0\n ? [[input.currentContentKeyEpoch, input.currentContentKey]]\n : [],\n );\n const updatesByContentKeyEpoch = syncResponseUpdatesByContentKeyEpoch(\n input.response,\n );\n const missingContentKeyEpochs = [...updatesByContentKeyEpoch.keys()].filter(\n (contentKeyEpoch) => !contentKeysByEpoch.has(contentKeyEpoch),\n );\n missingContentKeyEpochs.sort((left, right) => left - right);\n if (missingContentKeyEpochs.length === 0) {\n return contentKeysByEpoch;\n }\n const missingUpdates = missingContentKeyEpochs.flatMap(\n (contentKeyEpoch) => updatesByContentKeyEpoch.get(contentKeyEpoch) ?? [],\n );\n let bundlesByEpoch: ReturnType<typeof syncResponseContentKeyBundlesByEpoch>;\n try {\n bundlesByEpoch = syncResponseContentKeyBundlesByEpoch(input.response);\n } catch (error) {\n throwDocumentSyncContentKeyFailure({\n cause: error,\n updates: missingUpdates,\n });\n }\n const absentBundleEpoch = missingContentKeyEpochs.find(\n (contentKeyEpoch) => !bundlesByEpoch.has(contentKeyEpoch),\n );\n if (absentBundleEpoch !== undefined) {\n throwDocumentSyncContentKeyFailure({\n cause: new Error(\"Document sync response content-key bundle missing\"),\n updates:\n updatesByContentKeyEpoch.get(absentBundleEpoch) ?? missingUpdates,\n });\n }\n const collectedKeks = await collectContainerKeksForDocumentSync({\n execSql: input.execSql,\n secretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n let unavailableRawHistory:\n | { cause: RawHistoryUnavailableCause; contentKeyEpoch: number }\n | undefined;\n\n for (const contentKeyEpoch of missingContentKeyEpochs) {\n const bundle = bundlesByEpoch.get(contentKeyEpoch);\n const responseUpdates =\n updatesByContentKeyEpoch.get(contentKeyEpoch) ?? missingUpdates;\n if (!bundle) {\n const error = new Error(\n \"Document sync response content-key bundle missing\",\n );\n throwDocumentSyncContentKeyFailure({\n cause: error,\n updates: responseUpdates,\n });\n }\n try {\n contentKeysByEpoch.set(\n bundle.contentKeyEpoch,\n await unwrapHistoricalContentKey({\n bundle,\n collectedKeks,\n documentId: input.writerProjection.documentId,\n updates: responseUpdates,\n }),\n );\n } catch (error) {\n if (input.historyMode === \"raw\" && isRawHistoryUnavailableCause(error)) {\n unavailableRawHistory ??= { cause: error, contentKeyEpoch };\n continue;\n }\n throwDocumentSyncContentKeyFailure({\n cause: error,\n updates: responseUpdates,\n });\n }\n }\n\n if (unavailableRawHistory) {\n await throwRawHistoryUnavailable({\n contentKeysByEpoch,\n response: input.response,\n unavailable: unavailableRawHistory,\n validate: input.onRawHistoryUnavailable,\n });\n }\n\n return contentKeysByEpoch;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"syncContentKeys.js","sourceRoot":"","sources":["syncContentKeys.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { importContentKeyMaterial } from \"../../../data/documents/shared/contentRecordKeys\";\nimport { encryptDocumentPendingUpdate } from \"../../../data/documents/shared/crypto\";\nimport {\n ContainerKekHistoryUnavailableError,\n collectContainerKeksForDocumentSync,\n DocumentContentKeyUnavailableError,\n DocumentHistoryUnavailableError,\n unwrapDocumentContentKeyFromBundle,\n} from \"../../../data/documents/shared/projection\";\nimport { readWriteHeader } from \"../../../data/documents/shared/readers\";\nimport { assertDocumentSyncUpdateEncryptedRecord } from \"../../../data/documents/shared/sync/documentSyncUpdateDecryption\";\nimport {\n isDocumentSyncUpdateIsolationError,\n isolateDocumentSyncBatchError,\n isolateDocumentSyncUpdateError,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport type {\n DocumentSyncPreparedUpdate,\n ProjectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { isKeyingVerificationError } from \"../../../data/keyingProjectionVerification/error\";\nimport type { PendingUpdateRecord } from \"../../../data/persistence/documents/records\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\n\ntype SyncResponseUpdate = DocumentSyncResponse[\"updates\"][number];\ntype RawHistoryUnavailableCause =\n | DocumentContentKeyUnavailableError\n | DocumentHistoryUnavailableError;\n\nfunction isRawHistoryUnavailableCause(\n error: unknown,\n): error is RawHistoryUnavailableCause {\n return (\n error instanceof DocumentContentKeyUnavailableError ||\n (error instanceof DocumentHistoryUnavailableError &&\n error.historyCause instanceof ContainerKekHistoryUnavailableError)\n );\n}\n\ntype RawHistoryUnavailableValidator = (input: {\n contentKeysByEpoch: ReadonlyMap<number, Uint8Array>;\n updates: readonly SyncResponseUpdate[];\n}) => void | Promise<void>;\n\n/** A raw recovery cannot reconstruct history without this retained epoch. */\nexport class DocumentRawHistoryUnavailableError extends Error {\n readonly code = \"document_raw_history_epoch_unavailable\";\n\n constructor(\n readonly contentKeyEpoch: number,\n cause: unknown,\n ) {\n super(\n `Document raw-history recovery cannot decrypt content-key epoch ${contentKeyEpoch}`,\n { cause },\n );\n this.name = \"DocumentRawHistoryUnavailableError\";\n }\n}\n\nasync function assertResponseEncryptedRecords(\n updates: readonly SyncResponseUpdate[],\n): Promise<void> {\n const inspections = await Promise.allSettled(\n updates.map(assertDocumentSyncUpdateEncryptedRecord),\n );\n const failures = inspections.flatMap((inspection, index) =>\n inspection.status === \"rejected\"\n ? [{ index, reason: inspection.reason }]\n : [],\n );\n const firstFailure = failures[0];\n if (failures.length === 1 && firstFailure) {\n throw firstFailure.reason;\n }\n if (failures.length > 1 && firstFailure) {\n const stage =\n isDocumentSyncUpdateIsolationError(firstFailure.reason) &&\n failures.every(\n ({ reason }) =>\n isDocumentSyncUpdateIsolationError(reason) &&\n reason.stage === firstFailure.reason.stage,\n )\n ? firstFailure.reason.stage\n : \"encrypted_record\";\n throw isolateDocumentSyncBatchError({\n cause: new Error(\"Multiple document encrypted records are invalid\"),\n stage,\n updateIds: failures.map(({ index }) => updates[index]?.id ?? \"unknown\"),\n });\n }\n}\n\nasync function throwRawHistoryUnavailable(input: {\n contentKeysByEpoch: ReadonlyMap<number, Uint8Array>;\n response: DocumentSyncResponse;\n unavailable: { cause: RawHistoryUnavailableCause; contentKeyEpoch: number };\n validate?: RawHistoryUnavailableValidator | undefined;\n}): Promise<never> {\n await assertResponseEncryptedRecords(input.response.updates);\n await input.validate?.({\n contentKeysByEpoch: input.contentKeysByEpoch,\n updates: input.response.updates.filter((update) =>\n input.contentKeysByEpoch.has(\n readWriteHeader(\n update.writeHeader,\n \"Document sync response write header\",\n ).contentKeyEpoch,\n ),\n ),\n });\n throw new DocumentRawHistoryUnavailableError(\n input.unavailable.contentKeyEpoch,\n input.unavailable.cause,\n );\n}\n\nexport async function prepareDocumentOutgoingUpdates(input: {\n contentKey: Uint8Array;\n contentKeyEpoch: number;\n documentId: string;\n organizationId: string;\n pendingUpdates: readonly PendingUpdateRecord[];\n}): Promise<DocumentSyncPreparedUpdate[]> {\n if (input.pendingUpdates.length === 0) {\n return [];\n }\n const contentKeyMaterial = await importContentKeyMaterial(input.contentKey);\n\n return Promise.all(\n input.pendingUpdates.map(async (update) => {\n const encrypted = await encryptDocumentPendingUpdate({\n contentKeyMaterial,\n contentKeyEpoch: input.contentKeyEpoch,\n documentId: input.documentId,\n organizationId: input.organizationId,\n update,\n });\n\n return {\n contentRecordId: encrypted.contentRecordId,\n encryptedData: encrypted.encryptedData,\n id: update.id,\n partialStartVersionVector: update.partialStartVersionVector,\n partialEndVersionVector: update.partialEndVersionVector,\n metadataHash: encrypted.metadataHash,\n ciphertextHash: encrypted.ciphertextHash,\n plaintextHash: encrypted.plaintextHash,\n ...(update.sourceVersionVector\n ? {\n checkpointKind: \"rotate_baseline\" as const,\n checkpointPayloadKind: \"full_history_snapshot\" as const,\n sourceVersionVector: update.sourceVersionVector,\n }\n : {}),\n };\n }),\n );\n}\n\nfunction syncResponseContentKeyBundlesByEpoch(\n response: DocumentSyncResponse,\n): ReadonlyMap<number, DocumentSyncResponse[\"contentKeyBundle\"]> {\n const byEpoch = new Map<number, DocumentSyncResponse[\"contentKeyBundle\"]>();\n\n for (const bundle of [\n response.contentKeyBundle,\n ...response.contentKeyBundles,\n ]) {\n if (byEpoch.has(bundle.contentKeyEpoch)) {\n throw new Error(\"Document sync response repeats a content-key epoch\");\n }\n byEpoch.set(bundle.contentKeyEpoch, bundle);\n }\n\n return byEpoch;\n}\n\nfunction syncResponseUpdatesByContentKeyEpoch(\n response: DocumentSyncResponse,\n): ReadonlyMap<number, readonly SyncResponseUpdate[]> {\n const updatesByEpoch = new Map<number, SyncResponseUpdate[]>();\n for (const update of response.updates) {\n let contentKeyEpoch: number;\n try {\n contentKeyEpoch = readWriteHeader(\n update.writeHeader,\n \"Document sync response write header\",\n ).contentKeyEpoch;\n } catch (error) {\n throw isolateDocumentSyncUpdateError({\n cause: error,\n responseUpdate: update,\n stage: \"write_header\",\n updateId: update.id,\n });\n }\n const epochUpdates = updatesByEpoch.get(contentKeyEpoch);\n if (epochUpdates) epochUpdates.push(update);\n else updatesByEpoch.set(contentKeyEpoch, [update]);\n }\n return updatesByEpoch;\n}\n\nfunction assertBundleMatchesUpdateHeaders(input: {\n bundle: DocumentSyncResponse[\"contentKeyBundle\"];\n requireOriginalTargets: boolean;\n updates: readonly SyncResponseUpdate[];\n}): void {\n for (const update of input.updates) {\n const header = readWriteHeader(\n update.writeHeader,\n \"Document sync response write header\",\n );\n if (\n header.objectId !== input.bundle.documentId ||\n header.contentKeyEpoch !== input.bundle.contentKeyEpoch ||\n (input.requireOriginalTargets &&\n (header.accessManifestHash !== input.bundle.linkSetManifestHash ||\n header.targetHash !== input.bundle.targetHash))\n ) {\n throw new Error(\n input.requireOriginalTargets\n ? \"Document sync response content key is unavailable and its bundle differs from the original update headers\"\n : \"Document sync response content-key bundle does not match its update headers\",\n );\n }\n }\n}\n\n/**\n * Linking can rewrap a retained key at the same content epoch. Its latest bundle\n * then has newer targets than older signed updates. A usable key is validated\n * by the caller's authenticated record decryption; the update's own historical\n * manifest, targets and signature are verified independently before this step.\n *\n * If the key cannot be recovered, require the original target commitments before\n * calling that an availability failure. Substituted unavailable targets must\n * still be quarantined, never disguised as legitimate missing history.\n */\nasync function unwrapHistoricalContentKey(input: {\n bundle: DocumentSyncResponse[\"contentKeyBundle\"];\n documentId: string;\n collectedKeks: Awaited<\n ReturnType<typeof collectContainerKeksForDocumentSync>\n >;\n updates: readonly SyncResponseUpdate[];\n}): Promise<Uint8Array> {\n assertBundleMatchesUpdateHeaders({ ...input, requireOriginalTargets: false });\n try {\n return await unwrapDocumentContentKeyFromBundle(\n input.bundle,\n input.documentId,\n input.collectedKeks.keksByEpochId,\n input.collectedKeks.predecessorFailuresByEpochId,\n input.collectedKeks.unattributedPredecessorFailuresByContainerId,\n );\n } catch (error) {\n if (isRawHistoryUnavailableCause(error)) {\n assertBundleMatchesUpdateHeaders({\n ...input,\n requireOriginalTargets: true,\n });\n }\n throw error;\n }\n}\n\n/** @internal Keeps epoch-wide failures anonymous and integrity failures typed. */\nexport function throwDocumentSyncContentKeyFailure(input: {\n cause: unknown;\n updates: readonly SyncResponseUpdate[];\n}): never {\n if (isKeyingVerificationError(input.cause)) {\n throw input.cause;\n }\n if (\n input.cause instanceof DocumentHistoryUnavailableError &&\n isKeyingVerificationError(input.cause.historyCause)\n ) {\n throw input.cause.historyCause;\n }\n throw isolateDocumentSyncBatchError({\n cause: input.cause,\n stage: \"content_key\",\n updateIds: input.updates.map((update) => update.id),\n });\n}\n\nexport async function unwrapDocumentSyncResponseContentKeys(\n input: {\n currentContentKey: Uint8Array;\n currentContentKeyEpoch: number;\n execSql?: ExecSql | undefined;\n historyMode?: \"raw\" | undefined;\n /** @internal Validate every decryptable sibling before raw availability wins. */\n onRawHistoryUnavailable?: RawHistoryUnavailableValidator | undefined;\n response: DocumentSyncResponse;\n targetSecretKey: Uint8Array;\n writerProjection: DocumentWriterProjectionResponse;\n } & ProjectionVerificationOptions,\n): Promise<ReadonlyMap<number, Uint8Array>> {\n // A stale read-only pass can carry an empty placeholder when none of its\n // authorizing paths reaches the bundle target. Do not mark that epoch as\n // resolved: every served update must instead unwrap its bundle through the\n // verified predecessor KEK chain or fail with an honest error.\n const contentKeysByEpoch = new Map<number, Uint8Array>(\n input.currentContentKey.byteLength > 0\n ? [[input.currentContentKeyEpoch, input.currentContentKey]]\n : [],\n );\n const updatesByContentKeyEpoch = syncResponseUpdatesByContentKeyEpoch(\n input.response,\n );\n const missingContentKeyEpochs = [...updatesByContentKeyEpoch.keys()].filter(\n (contentKeyEpoch) => !contentKeysByEpoch.has(contentKeyEpoch),\n );\n missingContentKeyEpochs.sort((left, right) => left - right);\n if (missingContentKeyEpochs.length === 0) {\n return contentKeysByEpoch;\n }\n const missingUpdates = missingContentKeyEpochs.flatMap(\n (contentKeyEpoch) => updatesByContentKeyEpoch.get(contentKeyEpoch) ?? [],\n );\n let bundlesByEpoch: ReturnType<typeof syncResponseContentKeyBundlesByEpoch>;\n try {\n bundlesByEpoch = syncResponseContentKeyBundlesByEpoch(input.response);\n } catch (error) {\n throwDocumentSyncContentKeyFailure({\n cause: error,\n updates: missingUpdates,\n });\n }\n const absentBundleEpoch = missingContentKeyEpochs.find(\n (contentKeyEpoch) => !bundlesByEpoch.has(contentKeyEpoch),\n );\n if (absentBundleEpoch !== undefined) {\n throwDocumentSyncContentKeyFailure({\n cause: new Error(\"Document sync response content-key bundle missing\"),\n updates:\n updatesByContentKeyEpoch.get(absentBundleEpoch) ?? missingUpdates,\n });\n }\n const collectedKeks = await collectContainerKeksForDocumentSync({\n execSql: input.execSql,\n secretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n let unavailableRawHistory:\n | { cause: RawHistoryUnavailableCause; contentKeyEpoch: number }\n | undefined;\n\n for (const contentKeyEpoch of missingContentKeyEpochs) {\n const bundle = bundlesByEpoch.get(contentKeyEpoch);\n const responseUpdates =\n updatesByContentKeyEpoch.get(contentKeyEpoch) ?? missingUpdates;\n if (!bundle) {\n const error = new Error(\n \"Document sync response content-key bundle missing\",\n );\n throwDocumentSyncContentKeyFailure({\n cause: error,\n updates: responseUpdates,\n });\n }\n try {\n contentKeysByEpoch.set(\n bundle.contentKeyEpoch,\n await unwrapHistoricalContentKey({\n bundle,\n collectedKeks,\n documentId: input.writerProjection.documentId,\n updates: responseUpdates,\n }),\n );\n } catch (error) {\n if (input.historyMode === \"raw\" && isRawHistoryUnavailableCause(error)) {\n unavailableRawHistory ??= { cause: error, contentKeyEpoch };\n continue;\n }\n throwDocumentSyncContentKeyFailure({\n cause: error,\n updates: responseUpdates,\n });\n }\n }\n\n if (unavailableRawHistory) {\n await throwRawHistoryUnavailable({\n contentKeysByEpoch,\n response: input.response,\n unavailable: unavailableRawHistory,\n validate: input.onRawHistoryUnavailable,\n });\n }\n\n return contentKeysByEpoch;\n}\n"]}
|