@tearleads/client-sdk 0.1.82 → 0.1.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/data/documents/documentSync.js.map +1 -1
  2. package/data/documents/shared/crypto.js.map +1 -1
  3. package/data/documents/shared/types.d.ts +1 -1
  4. package/data/documents/shared/types.js.map +1 -1
  5. package/data/persistence/container-contents/containerContentsPersistence.js +2 -2
  6. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  7. package/data/persistence/container-contents/containerContentsPersistenceTypes.d.ts +1 -1
  8. package/data/persistence/container-contents/containerContentsPersistenceTypes.js.map +1 -1
  9. package/data/persistence/container-contents/containerDeletionPersistence.js +1 -1
  10. package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
  11. package/data/persistence/container-contents/containerDocumentReassignment.js +7 -9
  12. package/data/persistence/container-contents/containerDocumentReassignment.js.map +1 -1
  13. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +3 -3
  14. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  15. package/data/persistence/container-contents/containerMetadataPullContinuationPersistence.js +1 -1
  16. package/data/persistence/container-contents/containerMetadataPullContinuationPersistence.js.map +1 -1
  17. package/data/persistence/container-contents/containerMetadataRows.js +4 -20
  18. package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
  19. package/data/persistence/container-contents/containerPendingUpdatePersistence.js +2 -2
  20. package/data/persistence/container-contents/containerPendingUpdatePersistence.js.map +1 -1
  21. package/data/persistence/container-contents/containerRebindPersistence.js +4 -17
  22. package/data/persistence/container-contents/containerRebindPersistence.js.map +1 -1
  23. package/data/persistence/container-contents/containerReconcilePersistence.js +1 -1
  24. package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
  25. package/data/persistence/container-contents/containerRemovalWork.js +1 -1
  26. package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
  27. package/data/persistence/container-contents/containerStructuralRepair.js +5 -11
  28. package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
  29. package/data/persistence/container-contents/documentContainerProjectionPersistence.js +34 -9
  30. package/data/persistence/container-contents/documentContainerProjectionPersistence.js.map +1 -1
  31. package/data/persistence/container-contents/dormantContainerMetadata.js +4 -14
  32. package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
  33. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +5 -9
  34. package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
  35. package/data/persistence/documents/documentDiscoveryReset.d.ts +6 -0
  36. package/data/persistence/documents/documentProjectionContainers.js +28 -0
  37. package/data/persistence/documents/documentProjectionContainers.js.map +1 -0
  38. package/data/persistence/documents/documentsPersistence.js +5 -9
  39. package/data/persistence/documents/documentsPersistence.js.map +1 -1
  40. package/data/persistence/documents/internal/containerDocumentTombstones.js +4 -11
  41. package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
  42. package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js +1 -1
  43. package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js.map +1 -1
  44. package/data/persistence/documents/internal/discardDocument.js +2 -2
  45. package/data/persistence/documents/internal/discardDocument.js.map +1 -1
  46. package/data/persistence/documents/internal/documentDeletionPersistence.js +8 -22
  47. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  48. package/data/persistence/documents/internal/documentMutationPersistence.js +3 -3
  49. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  50. package/data/persistence/documents/internal/documentPullContinuationPersistence.js +1 -1
  51. package/data/persistence/documents/internal/documentPullContinuationPersistence.js.map +1 -1
  52. package/data/persistence/documents/internal/documentRecordIdentity.js.map +1 -1
  53. package/data/persistence/documents/internal/documentRows.js.map +1 -1
  54. package/data/persistence/documents/internal/ensureDocumentsSchema.js +1 -1
  55. package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
  56. package/data/persistence/documents/internal/orphanSideRows.js +1 -1
  57. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  58. package/data/persistence/documents/internal/rowQueryPersistence.js +1 -1
  59. package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
  60. package/data/persistence/documents/internal/syncQueuePersistence.js +2 -2
  61. package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
  62. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentHistoryPersistence.d.ts +1 -1
  63. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentHistoryPersistence.js +5 -5
  64. package/data/persistence/documents/records/documentHistoryPersistence.js.map +1 -0
  65. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPendingUpdatePersistence.d.ts +2 -2
  66. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPendingUpdatePersistence.js +2 -2
  67. package/data/persistence/documents/records/documentPendingUpdatePersistence.js.map +1 -0
  68. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPersistenceTypes.d.ts +2 -2
  69. package/data/persistence/documents/records/documentPersistenceTypes.js.map +1 -0
  70. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentRecordPersistence.d.ts +1 -1
  71. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentRecordPersistence.js +4 -4
  72. package/data/persistence/documents/records/documentRecordPersistence.js.map +1 -0
  73. package/data/persistence/documents/records/documentRowsInTransaction.js +68 -0
  74. package/data/persistence/documents/records/documentRowsInTransaction.js.map +1 -0
  75. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentSyncFailurePersistence.d.ts +2 -2
  76. package/data/{sqlite/documentPersistence → persistence/documents/records}/documentSyncFailurePersistence.js +3 -3
  77. package/data/persistence/documents/records/documentSyncFailurePersistence.js.map +1 -0
  78. package/data/{sqlite/documentPersistence → persistence/documents/records}/index.d.ts +2 -2
  79. package/data/{sqlite/documentPersistence → persistence/documents/records}/index.js +4 -4
  80. package/data/persistence/documents/records/index.js.map +1 -0
  81. package/data/persistence/documents/types.d.ts +2 -2
  82. package/data/persistence/documents/types.js.map +1 -1
  83. package/data/persistence/keyingCheckpoints/documentPurgeCheckpointPersistence.d.ts +2 -0
  84. package/data/persistence/keyingCheckpoints/documentPurgeCheckpointPersistence.js +9 -0
  85. package/data/persistence/keyingCheckpoints/documentPurgeCheckpointPersistence.js.map +1 -1
  86. package/data/persistence/keyingCheckpoints/keyingCheckpointPersistence.js +9 -0
  87. package/data/persistence/keyingCheckpoints/keyingCheckpointPersistence.js.map +1 -1
  88. package/data/persistence/principalPolicy/principalPolicyPersistence.js +3 -9
  89. package/data/persistence/principalPolicy/principalPolicyPersistence.js.map +1 -1
  90. package/{workflows/sync/remoteResetPrincipalScope.d.ts → data/persistence/principalPolicy/principalPolicyRemoteReset.d.ts} +1 -1
  91. package/{workflows/sync/remoteResetPrincipalScope.js → data/persistence/principalPolicy/principalPolicyRemoteReset.js} +16 -13
  92. package/data/persistence/principalPolicy/principalPolicyRemoteReset.js.map +1 -0
  93. package/data/persistence/verifiedManifestBundlePersistence.d.ts +2 -0
  94. package/data/persistence/verifiedManifestBundlePersistence.js +7 -0
  95. package/data/persistence/verifiedManifestBundlePersistence.js.map +1 -1
  96. package/data/sqlite/{documentPersistence/documentOrphanBlobReclaims.js → schema/documentOrphanBlobReclaimSchema.js} +1 -1
  97. package/data/sqlite/schema/documentOrphanBlobReclaimSchema.js.map +1 -0
  98. package/data/sqlite/schema/index.js +1 -1
  99. package/data/sqlite/schema/index.js.map +1 -1
  100. package/data/sqlite/sqliteBindBudget.js +12 -0
  101. package/data/sqlite/sqliteBindBudget.js.map +1 -1
  102. package/package.json +1 -1
  103. package/workflows/container-contents/container-state/create/createIntentSeed.js.map +1 -1
  104. package/workflows/container-contents/container-state/create/createWithMetadataPlan.js.map +1 -1
  105. package/workflows/container-contents/container-state/types.js.map +1 -1
  106. package/workflows/container-contents/metadata/index.js.map +1 -1
  107. package/workflows/container-contents/metadata/metadataEvents.d.ts +1 -1
  108. package/workflows/container-contents/metadata/metadataEvents.js.map +1 -1
  109. package/workflows/container-contents/metadata/metadataIncomingUpdateIsolation.js +1 -1
  110. package/workflows/container-contents/metadata/metadataIncomingUpdateIsolation.js.map +1 -1
  111. package/workflows/container-contents/metadata/metadataRemoteSync.d.ts +1 -1
  112. package/workflows/container-contents/metadata/metadataRemoteSync.js.map +1 -1
  113. package/workflows/container-contents/pendingWrites/index.js +1 -1
  114. package/workflows/container-contents/pendingWrites/index.js.map +1 -1
  115. package/workflows/container-contents/recovery/accessRestoration.js +1 -1
  116. package/workflows/container-contents/recovery/accessRestoration.js.map +1 -1
  117. package/workflows/container-contents/remoteReset/containerRemoteReset.d.ts +185 -0
  118. package/workflows/container-contents/remoteReset/containerRemoteReset.js +174 -0
  119. package/workflows/container-contents/remoteReset/containerRemoteReset.js.map +1 -0
  120. package/workflows/container-contents/remoteReset/remoteResetCursorScope.d.ts +14 -0
  121. package/workflows/{sync → container-contents/remoteReset}/remoteResetCursorScope.js +2 -2
  122. package/workflows/container-contents/remoteReset/remoteResetCursorScope.js.map +1 -0
  123. package/workflows/documents/create/documentCreationPersistence.js.map +1 -1
  124. package/workflows/documents/create/index.d.ts +1 -1
  125. package/workflows/documents/create/index.js.map +1 -1
  126. package/workflows/documents/documentMutationCommit.d.ts +1 -1
  127. package/workflows/documents/documentMutationCommit.js.map +1 -1
  128. package/workflows/documents/index.d.ts +2 -2
  129. package/workflows/documents/index.js +2 -2
  130. package/workflows/documents/index.js.map +1 -1
  131. package/workflows/documents/remoteReset/documentRemoteReset.d.ts +56 -0
  132. package/workflows/documents/remoteReset/documentRemoteReset.js +135 -0
  133. package/workflows/documents/remoteReset/documentRemoteReset.js.map +1 -0
  134. package/workflows/{sync → documents/remoteReset}/remoteResetAttachments.js +3 -3
  135. package/workflows/documents/remoteReset/remoteResetAttachments.js.map +1 -0
  136. package/workflows/{sync → documents/remoteReset}/remoteResetPlans.d.ts +1 -1
  137. package/workflows/{sync → documents/remoteReset}/remoteResetPlans.js +7 -7
  138. package/workflows/documents/remoteReset/remoteResetPlans.js.map +1 -0
  139. package/workflows/documents/sync/index.js.map +1 -1
  140. package/workflows/documents/sync/initialSync.d.ts +1 -1
  141. package/workflows/documents/sync/initialSync.js.map +1 -1
  142. package/workflows/documents/sync/readOnlySync.d.ts +1 -1
  143. package/workflows/documents/sync/readOnlySync.js.map +1 -1
  144. package/workflows/documents/sync/syncAttemptPlanning.js.map +1 -1
  145. package/workflows/documents/sync/syncAttemptState.d.ts +1 -1
  146. package/workflows/documents/sync/syncAttemptState.js.map +1 -1
  147. package/workflows/documents/sync/syncResponseResult.js.map +1 -1
  148. package/workflows/documents/sync/syncSubmittedResult.js.map +1 -1
  149. package/workflows/documents/syncFailures/index.js.map +1 -1
  150. package/workflows/documents/syncPlan/syncContentKeys.d.ts +1 -1
  151. package/workflows/documents/syncPlan/syncContentKeys.js.map +1 -1
  152. package/workflows/documents/syncPlan/syncPlanMaterial.js.map +1 -1
  153. package/workflows/documents/syncPlan/syncPlanRequestBounds.js.map +1 -1
  154. package/workflows/documents/syncRekeys/syncContainerRekeys.js.map +1 -1
  155. package/workflows/documents/syncRekeys/syncRecoveryRekey.d.ts +1 -1
  156. package/workflows/documents/syncRekeys/syncRecoveryRekey.js +1 -1
  157. package/workflows/documents/syncRekeys/syncRecoveryRekey.js.map +1 -1
  158. package/workflows/organizations/readModel/listLocalOrganizations.js +1 -1
  159. package/workflows/organizations/readModel/listLocalOrganizations.js.map +1 -1
  160. package/workflows/organizations/readModel/organizationRemoteReset.js +25 -0
  161. package/workflows/organizations/readModel/organizationRemoteReset.js.map +1 -0
  162. package/workflows/registration/persistRegistrationBootstrap.d.ts +1 -1
  163. package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
  164. package/workflows/sync/remoteReset.js +60 -229
  165. package/workflows/sync/remoteReset.js.map +1 -1
  166. package/workflows/sync/remoteResetScope.d.ts +7 -10
  167. package/workflows/sync/remoteResetScope.js +26 -108
  168. package/workflows/sync/remoteResetScope.js.map +1 -1
  169. package/data/sqlite/documentPersistence/documentHistoryPersistence.js.map +0 -1
  170. package/data/sqlite/documentPersistence/documentOrphanBlobReclaims.js.map +0 -1
  171. package/data/sqlite/documentPersistence/documentPendingUpdatePersistence.js.map +0 -1
  172. package/data/sqlite/documentPersistence/documentPersistenceTypes.js.map +0 -1
  173. package/data/sqlite/documentPersistence/documentRecordPersistence.js.map +0 -1
  174. package/data/sqlite/documentPersistence/documentSyncFailurePersistence.js.map +0 -1
  175. package/data/sqlite/documentPersistence/index.js.map +0 -1
  176. package/workflows/sync/remoteResetAttachments.js.map +0 -1
  177. package/workflows/sync/remoteResetBatches.js +0 -13
  178. package/workflows/sync/remoteResetBatches.js.map +0 -1
  179. package/workflows/sync/remoteResetCursorScope.js.map +0 -1
  180. package/workflows/sync/remoteResetPlans.js.map +0 -1
  181. package/workflows/sync/remoteResetPrincipalScope.js.map +0 -1
  182. /package/data/{sqlite/documentPersistence → persistence/documents/records}/documentPersistenceTypes.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"remoteReset.js","sourceRoot":"","sources":["remoteReset.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, or } from \"drizzle-orm\";\nimport {\n deleteDocumentPlacementRowsByContainerIds,\n deleteDocumentPlacementRowsByDocumentIds,\n} from \"../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { recordSupersededContainerBindingsInTransaction } from \"../../data/persistence/container-contents/supersededContainerBindings\";\nimport { clearDocumentDiscoveryEvidenceOnRemoteReset } from \"../../data/persistence/documents/documentDiscoveryReset\";\nimport {\n queuedUpdateRow,\n unqueueDocumentScopesInTransaction,\n} from \"../../data/sqlite/documentPersistence/documentPendingUpdatePersistence\";\nimport { CLEARED_DOCUMENT_SYNC_FAILURE } from \"../../data/sqlite/documentPersistence/documentSyncFailurePersistence\";\nimport {\n clientSqlTables,\n containerHydrationTombstones,\n containers,\n documentAttachmentBlobProjection,\n documentHistoryUpdates,\n documentPendingAttachments,\n documentProjection,\n documents,\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../data/sqlite/schema\";\nimport { documentIntentLinkTargets } from \"../../data/sqlite/schema/documentPlacementIntentSchema\";\nimport { organizationDataUsageSnapshots } from \"../../data/sqlite/schema/organizationDataUsageSchema\";\nimport {\n organizationPresentationDenials,\n organizationReadModelContainerGrants,\n organizationReadModelDirectoryUsers,\n organizationReadModelGroupMembers,\n organizationReadModelGroups,\n organizationReadModelRequesters,\n organizationReadModelState,\n} from \"../../data/sqlite/schema/organizationReadModelSchema\";\nimport { verifiedAccessManifestBundles } from \"../../data/sqlite/schema/verifiedManifestBundleSchema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { ensureSqlTables } from \"../../data/sqlite/sqlTableSchema\";\nimport { runOrganizationPresentationReset } from \"../organizations/readModel/organizationPresentationAccessState\";\nimport { clearResetPendingAttachments } from \"./remoteResetAttachments\";\nimport { remoteResetBatches } from \"./remoteResetBatches\";\nimport { clearRemoteResetSyncCursors } from \"./remoteResetCursorScope\";\nimport {\n buildResetPlans,\n type ResetAttachmentUpload,\n type ResetDocumentUpdate,\n} from \"./remoteResetPlans\";\nimport { clearRemoteResetPrincipalRows } from \"./remoteResetPrincipalScope\";\nimport {\n type RemoteResetInput,\n type RemoteSyncStateSnapshot,\n readRemoteSyncStateSnapshot,\n} from \"./remoteResetScope\";\n\nexport type {\n RemoteResetInput,\n RemoteResetReplacement,\n} from \"./remoteResetScope\";\n\nconst CONTAINER_CREATE_INTENT_TYPE = \"container.create\";\n\nexport interface ClearRemoteSyncStateResult {\n readonly clearedContainerCreateIntentCount: number;\n readonly clearedContainerMoveIntentCount: number;\n readonly clearedDocumentMoveIntentCount: number;\n readonly clearedPrincipalPolicyCount: number;\n readonly clearedSyncCursorCount: number;\n readonly queuedAttachmentUploadCount: number;\n readonly queuedContainerCreateCount: number;\n readonly queuedDocumentUpdateCount: number;\n readonly resetContainerCount: number;\n readonly resetDocumentCount: number;\n}\n\nasync function clearOrganizationPresentationRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<void> {\n for (const table of [\n organizationDataUsageSnapshots,\n organizationReadModelContainerGrants,\n organizationReadModelGroupMembers,\n organizationReadModelDirectoryUsers,\n organizationReadModelGroups,\n organizationReadModelRequesters,\n organizationReadModelState,\n organizationPresentationDenials,\n ] as const) {\n await tx\n .delete(table)\n .where(eq(table.organizationId, organizationId))\n .run();\n }\n}\n\ninterface ScopedRemoteRowsInput {\n attachmentUploads: readonly ResetAttachmentUpload[];\n organizationId: string;\n snapshot: RemoteSyncStateSnapshot;\n tx: ClientSQLiteTransactionScope;\n}\n\nasync function clearScopedContainerRows(\n input: ScopedRemoteRowsInput,\n): Promise<void> {\n for (const containerBatch of remoteResetBatches(\n input.snapshot.containerIds,\n )) {\n await deleteDocumentPlacementRowsByContainerIds(input.tx, containerBatch);\n await input.tx\n .delete(localIntents)\n .where(\n and(\n inContainerIntentLanes(),\n inArray(localIntents.subjectId, containerBatch),\n ),\n )\n .run();\n await input.tx\n .delete(containerHydrationTombstones)\n .where(inArray(containerHydrationTombstones.containerId, containerBatch))\n .run();\n }\n}\n\nasync function clearScopedDocumentRows(\n input: ScopedRemoteRowsInput,\n): Promise<void> {\n const { snapshot, tx } = input;\n for (const documentIdBatch of remoteResetBatches(snapshot.oldDocumentIds)) {\n await deleteDocumentPlacementRowsByDocumentIds(tx, documentIdBatch);\n }\n await clearResetPendingAttachments({\n attachmentUploads: input.attachmentUploads,\n documentLocalIds: snapshot.documentLocalIds,\n tx,\n });\n for (const localIdBatch of remoteResetBatches(snapshot.documentLocalIds)) {\n const placementIntents = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n inArray(localIntents.localId, localIdBatch),\n );\n await tx\n .delete(documentIntentLinkTargets)\n .where(\n inArray(\n documentIntentLinkTargets.intentId,\n tx\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(placementIntents),\n ),\n )\n .run();\n await tx.delete(localIntents).where(placementIntents).run();\n }\n // Sync failures clear with the document columns in resetRemoteColumns.\n for (const documentBatch of remoteResetBatches(snapshot.documentRows)) {\n await unqueueDocumentScopesInTransaction(tx, documentBatch);\n }\n}\n\nasync function clearScopedRemoteRows(\n input: ScopedRemoteRowsInput,\n): Promise<void> {\n const { organizationId, tx } = input;\n await clearOrganizationPresentationRows(tx, organizationId);\n for (const table of [\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n verifiedAccessManifestBundles,\n ] as const) {\n await tx\n .delete(table)\n .where(eq(table.organizationId, organizationId))\n .run();\n }\n await clearDocumentDiscoveryEvidenceOnRemoteReset(tx, {\n containerIds: input.snapshot.containerIds,\n documentIds: input.snapshot.oldDocumentIds,\n });\n await clearRemoteResetPrincipalRows(input);\n await clearScopedContainerRows(input);\n await clearScopedDocumentRows(input);\n await clearRemoteResetSyncCursors({\n containerIds: input.snapshot.containerIds,\n tx,\n });\n}\n\nasync function resetRemoteColumns(input: {\n now: string;\n reset: RemoteResetInput;\n snapshot: RemoteSyncStateSnapshot;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { now, reset, snapshot, tx } = input;\n for (const row of snapshot.documentRows) {\n await tx\n .update(documents)\n .set({\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n lastCommitLsn: null,\n pullContinuation: null,\n recoveryDocumentId: row.documentId ?? row.recoveryDocumentId,\n ...CLEARED_DOCUMENT_SYNC_FAILURE,\n updatedAt: now,\n })\n .where(\n and(\n eq(documents.appKind, row.appKind),\n eq(documents.localId, row.localId),\n ),\n )\n .run();\n }\n for (const localIdBatch of remoteResetBatches(snapshot.documentLocalIds)) {\n await tx\n .update(documentProjection)\n .set({\n documentId: null,\n organizationId:\n reset.replacement?.organizationId ?? reset.organizationId,\n })\n .where(inArray(documentProjection.localId, localIdBatch))\n .run();\n }\n // Replacement re-homes folders under their ids; the purged organization\n // can never bind them again on this device.\n for (const containerIds of reset.replacement\n ? remoteResetBatches(snapshot.containerIds)\n : []) {\n await recordSupersededContainerBindingsInTransaction(tx, {\n containerIds,\n organizationId: reset.organizationId,\n supersededAt: now,\n });\n }\n for (const row of snapshot.containerRows) {\n await tx\n .update(containers)\n .set({\n metadataDocumentId: null,\n organizationId:\n reset.replacement?.organizationId ?? reset.organizationId,\n parentId:\n reset.replacement && row.parentId === null\n ? reset.replacement.rootContainerId\n : row.parentId,\n serverCreatedAt: null,\n serverUpdatedAt: null,\n ...(reset.replacement ? { systemSlot: null } : {}),\n localUpdatedAt: now,\n })\n .where(eq(containers.id, row.id))\n .run();\n }\n}\n\nasync function queueResetDocumentUpdates(input: {\n documentUpdates: readonly ResetDocumentUpdate[];\n now: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n for (const updateBatch of remoteResetBatches(input.documentUpdates)) {\n await input.tx\n .insert(documentHistoryUpdates)\n .values(\n updateBatch.map((update) =>\n queuedUpdateRow({\n createdAt: input.now,\n origin: \"outbox\",\n pendingUpdate: update,\n scope: update,\n updateId: crypto.randomUUID(),\n }),\n ),\n )\n .run();\n }\n}\n\nasync function queueResetContainerCreates(input: {\n now: string;\n reset: RemoteResetInput;\n snapshot: RemoteSyncStateSnapshot;\n tx: ClientSQLiteTransactionScope;\n}): Promise<number> {\n const rows = input.snapshot.containerRows.flatMap((row) => {\n const parentId =\n row.parentId ?? input.reset.replacement?.rootContainerId ?? null;\n return parentId ? [{ id: row.id, parentId }] : [];\n });\n if (rows.length === 0) return 0;\n for (const rowBatch of remoteResetBatches(rows)) {\n await input.tx\n .insert(localIntents)\n .values(\n rowBatch.map((row) => ({\n id: crypto.randomUUID(),\n lane: LOCAL_INTENT_LANES.containerCreate,\n subjectId: row.id,\n targetContainerId: row.parentId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\" as const,\n remoteContainerId: null,\n remoteMetadataAccessStateHash: null,\n remoteMetadataDocumentId: null,\n lastError: null,\n createdAt: input.now,\n updatedAt: input.now,\n })),\n )\n .run();\n }\n return rows.length;\n}\n\nasync function queueResetAttachmentUploads(input: {\n attachmentUploads: readonly ResetAttachmentUpload[];\n now: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n for (const attachmentBatch of remoteResetBatches(input.attachmentUploads)) {\n await input.tx\n .insert(documentPendingAttachments)\n .values(\n attachmentBatch.map((attachment) => ({\n ...attachment,\n createdAt: input.now,\n })),\n )\n .run();\n await input.tx\n .delete(documentAttachmentBlobProjection)\n .where(\n or(\n ...attachmentBatch.map((attachment) =>\n and(\n eq(documentAttachmentBlobProjection.localId, attachment.localId),\n eq(documentAttachmentBlobProjection.slotId, attachment.slotId),\n ),\n ),\n ),\n )\n .run();\n }\n}\n\nasync function clearRemoteSyncStateInTransaction(input: {\n plans: Awaited<ReturnType<typeof buildResetPlans>>;\n reset: RemoteResetInput;\n snapshot: RemoteSyncStateSnapshot;\n tx: ClientSQLiteTransactionScope;\n}): Promise<ClearRemoteSyncStateResult> {\n const now = new Date().toISOString();\n const { snapshot } = input;\n await clearScopedRemoteRows({\n attachmentUploads: input.plans.attachmentUploads,\n organizationId: input.reset.organizationId,\n snapshot,\n tx: input.tx,\n });\n await resetRemoteColumns({ now, reset: input.reset, snapshot, tx: input.tx });\n await queueResetDocumentUpdates({\n documentUpdates: input.plans.documentUpdates,\n now,\n tx: input.tx,\n });\n const queuedContainerCreateCount = await queueResetContainerCreates({\n now,\n reset: input.reset,\n snapshot,\n tx: input.tx,\n });\n await queueResetAttachmentUploads({\n attachmentUploads: input.plans.attachmentUploads,\n now,\n tx: input.tx,\n });\n return {\n clearedContainerCreateIntentCount:\n snapshot.clearedContainerCreateIntentCount,\n clearedContainerMoveIntentCount: snapshot.clearedContainerMoveIntentCount,\n clearedDocumentMoveIntentCount: snapshot.clearedDocumentMoveIntentCount,\n clearedPrincipalPolicyCount: snapshot.clearedPrincipalPolicyCount,\n clearedSyncCursorCount: snapshot.clearedSyncCursorCount,\n queuedAttachmentUploadCount: input.plans.attachmentUploads.length,\n queuedContainerCreateCount,\n queuedDocumentUpdateCount: input.plans.documentUpdates.length,\n resetContainerCount: snapshot.containerRows.length,\n resetDocumentCount: snapshot.documentRows.length,\n };\n}\n\nexport async function clearRemoteSyncState(\n execSql: ExecSql,\n reset: RemoteResetInput,\n canCommit?: (() => boolean) | undefined,\n): Promise<ClearRemoteSyncStateResult> {\n return runOrganizationPresentationReset(\n execSql,\n reset.organizationId,\n async () => {\n await ensureSqlTables(execSql, clientSqlTables);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const resetInTransaction = async (tx: ClientSQLiteTransactionScope) => {\n if (canCommit && !canCommit()) {\n throw new Error(\n \"Remote sync reset aborted: session identity changed\",\n );\n }\n const snapshot = await readRemoteSyncStateSnapshot(\n tx,\n reset.organizationId,\n );\n const plans = await buildResetPlans(tx, snapshot.documentRows);\n return clearRemoteSyncStateInTransaction({\n plans,\n reset,\n snapshot,\n tx,\n });\n };\n if (!canCommit) {\n return runtime.transaction(resetInTransaction);\n }\n const outcome = await runtime.guardedTransaction(\n resetInTransaction,\n canCommit,\n );\n if (!outcome.committed || !outcome.result) {\n throw new Error(\"Remote sync reset aborted: session identity changed\");\n }\n return outcome.result;\n },\n );\n}\n"]}
1
+ {"version":3,"file":"remoteReset.js","sourceRoot":"","sources":["remoteReset.ts"],"names":[],"mappings":"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","sourcesContent":["import { clearRemoteResetPrincipalRows } from \"../../data/persistence/principalPolicy/principalPolicyRemoteReset\";\nimport { deleteVerifiedManifestBundlesForOrganization } from \"../../data/persistence/verifiedManifestBundlePersistence\";\nimport { clientSqlTables } from \"../../data/sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { ensureSqlTables } from \"../../data/sqlite/sqlTableSchema\";\nimport {\n clearContainerRowsForRemoteReset,\n clearDocumentPlacementsForRemoteReset,\n clearDormantContainerMetadataForRemoteReset,\n clearRemoteResetSyncCursors,\n queueContainerCreatesForRemoteReset,\n resetContainerServerIdentity,\n} from \"../container-contents/remoteReset/containerRemoteReset\";\nimport {\n buildResetPlans,\n clearDocumentDiscoveryEvidenceOnRemoteReset,\n clearDocumentRowsForRemoteReset,\n queueAttachmentReuploadsForRemoteReset,\n queueDocumentRepublishForRemoteReset,\n resetDocumentServerIdentity,\n} from \"../documents/remoteReset/documentRemoteReset\";\nimport {\n clearOrganizationReadModelsForRemoteReset,\n runOrganizationPresentationReset,\n} from \"../organizations/readModel/organizationRemoteReset\";\nimport {\n type RemoteResetInput,\n type RemoteSyncStateSnapshot,\n readRemoteSyncStateSnapshot,\n} from \"./remoteResetScope\";\n\nexport type {\n RemoteResetInput,\n RemoteResetReplacement,\n} from \"./remoteResetScope\";\n\nexport interface ClearRemoteSyncStateResult {\n readonly clearedContainerCreateIntentCount: number;\n readonly clearedContainerMoveIntentCount: number;\n readonly clearedDocumentMoveIntentCount: number;\n readonly clearedPrincipalPolicyCount: number;\n readonly clearedSyncCursorCount: number;\n readonly queuedAttachmentUploadCount: number;\n readonly queuedContainerCreateCount: number;\n readonly queuedDocumentUpdateCount: number;\n readonly resetContainerCount: number;\n readonly resetDocumentCount: number;\n}\n\n// Each subsystem resets its own tables; this runs their steps in one\n// transaction. Steps on different tables are independent, and each subsystem\n// clears its rows before it queues new ones.\nasync function clearRemoteSyncStateInTransaction(input: {\n plans: Awaited<ReturnType<typeof buildResetPlans>>;\n reset: RemoteResetInput;\n snapshot: RemoteSyncStateSnapshot;\n tx: ClientSQLiteTransactionScope;\n}): Promise<ClearRemoteSyncStateResult> {\n const now = new Date().toISOString();\n const { plans, reset, snapshot, tx } = input;\n const { organizationId } = reset;\n\n // Forget what the server told this device about the organization.\n await clearOrganizationReadModelsForRemoteReset(tx, organizationId);\n await clearDormantContainerMetadataForRemoteReset(tx, organizationId);\n await deleteVerifiedManifestBundlesForOrganization(tx, organizationId);\n await clearDocumentDiscoveryEvidenceOnRemoteReset(tx, {\n containerIds: snapshot.containerIds,\n documentIds: snapshot.oldDocumentIds,\n });\n await clearRemoteResetPrincipalRows({ organizationId, snapshot, tx });\n await clearContainerRowsForRemoteReset({\n containerIds: snapshot.containerIds,\n tx,\n });\n await clearDocumentPlacementsForRemoteReset({\n documentLocalIds: snapshot.documentLocalIds,\n oldDocumentIds: snapshot.oldDocumentIds,\n tx,\n });\n await clearDocumentRowsForRemoteReset({\n attachmentUploads: plans.attachmentUploads,\n documentLocalIds: snapshot.documentLocalIds,\n documentRows: snapshot.documentRows,\n tx,\n });\n await clearRemoteResetSyncCursors({\n containerIds: snapshot.containerIds,\n tx,\n });\n\n // Strip server identity from the rows the device keeps.\n await resetDocumentServerIdentity({\n documentLocalIds: snapshot.documentLocalIds,\n documentRows: snapshot.documentRows,\n now,\n organizationId: reset.replacement?.organizationId ?? organizationId,\n tx,\n });\n await resetContainerServerIdentity({\n containerIds: snapshot.containerIds,\n containerRows: snapshot.containerRows,\n now,\n reset,\n tx,\n });\n\n // Queue the local content to be published again.\n await queueDocumentRepublishForRemoteReset({\n documentUpdates: plans.documentUpdates,\n now,\n tx,\n });\n const queuedContainerCreateCount = await queueContainerCreatesForRemoteReset({\n containerRows: snapshot.containerRows,\n now,\n reset,\n tx,\n });\n await queueAttachmentReuploadsForRemoteReset({\n attachmentUploads: plans.attachmentUploads,\n now,\n tx,\n });\n return {\n clearedContainerCreateIntentCount:\n snapshot.clearedContainerCreateIntentCount,\n clearedContainerMoveIntentCount: snapshot.clearedContainerMoveIntentCount,\n clearedDocumentMoveIntentCount: snapshot.clearedDocumentMoveIntentCount,\n clearedPrincipalPolicyCount: snapshot.clearedPrincipalPolicyCount,\n clearedSyncCursorCount: snapshot.clearedSyncCursorCount,\n queuedAttachmentUploadCount: plans.attachmentUploads.length,\n queuedContainerCreateCount,\n queuedDocumentUpdateCount: plans.documentUpdates.length,\n resetContainerCount: snapshot.containerRows.length,\n resetDocumentCount: snapshot.documentRows.length,\n };\n}\n\nexport async function clearRemoteSyncState(\n execSql: ExecSql,\n reset: RemoteResetInput,\n canCommit?: (() => boolean) | undefined,\n): Promise<ClearRemoteSyncStateResult> {\n return runOrganizationPresentationReset(\n execSql,\n reset.organizationId,\n async () => {\n await ensureSqlTables(execSql, clientSqlTables);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const resetInTransaction = async (tx: ClientSQLiteTransactionScope) => {\n if (canCommit && !canCommit()) {\n throw new Error(\n \"Remote sync reset aborted: session identity changed\",\n );\n }\n const snapshot = await readRemoteSyncStateSnapshot(\n tx,\n reset.organizationId,\n );\n const plans = await buildResetPlans(tx, snapshot.documentRows);\n return clearRemoteSyncStateInTransaction({\n plans,\n reset,\n snapshot,\n tx,\n });\n };\n if (!canCommit) {\n return runtime.transaction(resetInTransaction);\n }\n const outcome = await runtime.guardedTransaction(\n resetInTransaction,\n canCommit,\n );\n if (!outcome.committed || !outcome.result) {\n throw new Error(\"Remote sync reset aborted: session identity changed\");\n }\n return outcome.result;\n },\n );\n}\n"]}
@@ -1,6 +1,7 @@
1
+ import { type RemoteResetPrincipalKey } from "../../data/persistence/principalPolicy/principalPolicyRemoteReset.js";
1
2
  import type { ClientSQLiteTransactionScope } from "../../data/sqlite/sqlitePersistenceRuntime.js";
2
- import type { ResetDocumentScope } from "./remoteResetPlans.js";
3
- import { type RemoteResetPrincipalKey } from "./remoteResetPrincipalScope.js";
3
+ import { type ResetContainerRow } from "../container-contents/remoteReset/containerRemoteReset.js";
4
+ import { type ResetDocumentRow } from "../documents/remoteReset/documentRemoteReset.js";
4
5
  export interface RemoteResetReplacement {
5
6
  readonly organizationId: string;
6
7
  readonly rootContainerId: string;
@@ -9,14 +10,6 @@ export interface RemoteResetInput {
9
10
  readonly organizationId: string;
10
11
  readonly replacement?: RemoteResetReplacement | undefined;
11
12
  }
12
- export interface ResetContainerRow {
13
- readonly id: string;
14
- readonly parentId: string | null;
15
- }
16
- export interface ResetDocumentRow extends ResetDocumentScope {
17
- readonly documentId: string | null;
18
- readonly recoveryDocumentId: string | null;
19
- }
20
13
  export interface RemoteSyncStateSnapshot {
21
14
  readonly clearedContainerCreateIntentCount: number;
22
15
  readonly clearedContainerMoveIntentCount: number;
@@ -30,4 +23,8 @@ export interface RemoteSyncStateSnapshot {
30
23
  readonly oldDocumentIds: readonly string[];
31
24
  readonly principalKeys: readonly RemoteResetPrincipalKey[];
32
25
  }
26
+ /**
27
+ * Reads what a reset of the organization covers, from each subsystem that owns
28
+ * part of it: folders, then the documents in them, then principal policies.
29
+ */
33
30
  export declare function readRemoteSyncStateSnapshot(tx: ClientSQLiteTransactionScope, organizationId: string): Promise<RemoteSyncStateSnapshot>;
@@ -1,121 +1,39 @@
1
- import { eq } from "drizzle-orm";
2
- import { containerSyncWatermarks, containers, documentContainerProjection, documentProjection, documents, dormantContainerMetadata, LOCAL_INTENT_LANES, localIntents, } from "../../data/sqlite/schema/index.js";
3
- import { isRemoteResetSyncCursor } from "./remoteResetCursorScope.js";
4
- import { loadRemoteResetPrincipalScope, } from "./remoteResetPrincipalScope.js";
1
+ import { loadRemoteResetPrincipalScope, } from "../../data/persistence/principalPolicy/principalPolicyRemoteReset.js";
2
+ import { countContainerResetIntents, countRemoteResetSyncCursors, listDocumentPlacementRows, loadContainerResetScope, } from "../container-contents/remoteReset/containerRemoteReset.js";
3
+ import { loadDocumentResetScope, } from "../documents/remoteReset/documentRemoteReset.js";
5
4
  function principalKeyOfRow(row) {
6
5
  return `${row.principalType}\0${row.principalId}`;
7
6
  }
8
- function scopeKey(scope) {
9
- return `${scope.appKind}\0${scope.localId}`;
10
- }
11
- async function loadContainerScope(tx, organizationId) {
12
- const liveContainerRows = (await tx
13
- .select({ id: containers.id, parentId: containers.parentId })
14
- .from(containers)
15
- .where(eq(containers.organizationId, organizationId))).flatMap((row) => (row.id ? [{ id: row.id, parentId: row.parentId }] : []));
16
- const dormantContainerRows = await tx
17
- .select({ id: dormantContainerMetadata.containerId })
18
- .from(dormantContainerMetadata)
19
- .where(eq(dormantContainerMetadata.organizationId, organizationId));
20
- const containerRows = liveContainerRows;
21
- return {
22
- containerIds: [
23
- ...new Set([
24
- ...containerRows.map((row) => row.id),
25
- ...dormantContainerRows.map((row) => row.id),
26
- ]),
27
- ],
28
- containerRows,
29
- };
30
- }
31
- async function loadDocumentScope(input) {
32
- const { organizationId, tx } = input;
33
- const containerIdSet = new Set(input.containerIds);
34
- const [allDocuments, projectionRows, linkRows] = await loadDocumentAssociationRows(tx);
35
- const linkedDocumentIds = new Set(linkRows
36
- .filter((row) => containerIdSet.has(row.containerId))
37
- .map((row) => row.documentId));
38
- const projectedLocalIds = new Set(projectionRows
39
- .filter((row) => (row.containerId !== null && containerIdSet.has(row.containerId)) ||
40
- row.organizationId === organizationId ||
41
- (row.documentId !== null && linkedDocumentIds.has(row.documentId)))
42
- .flatMap((row) => (row.localId ? [row.localId] : [])));
43
- const documentRows = allDocuments.filter((row) => (row.appKind === "container-metadata" &&
44
- containerIdSet.has(row.localId)) ||
45
- (row.appKind === "documents" && projectedLocalIds.has(row.localId)) ||
46
- (row.documentId !== null && linkedDocumentIds.has(row.documentId)));
47
- return {
48
- documentLocalIds: [
49
- ...new Set(documentRows
50
- .filter((row) => row.appKind === "documents")
51
- .map((row) => row.localId)),
52
- ],
53
- documentRows,
54
- oldDocumentIds: [
55
- ...new Set(documentRows.flatMap((row) => (row.documentId ? [row.documentId] : []))),
56
- ],
57
- };
58
- }
59
- function loadDocumentAssociationRows(tx) {
60
- return Promise.all([
61
- tx
62
- .select({
63
- appKind: documents.appKind,
64
- documentId: documents.documentId,
65
- localId: documents.localId,
66
- recoveryDocumentId: documents.recoveryDocumentId,
67
- })
68
- .from(documents),
69
- tx.select().from(documentProjection),
70
- tx.select().from(documentContainerProjection),
71
- ]);
72
- }
73
- async function loadSnapshotCounts(input) {
74
- const { organizationId, tx } = input;
75
- const containerIdSet = new Set(input.containerIds);
76
- const documentScopeKeys = new Set(input.documentRows.map(scopeKey));
77
- const [principalScope, intents] = await Promise.all([
78
- loadRemoteResetPrincipalScope(tx, organizationId),
79
- tx
80
- .select({
81
- lane: localIntents.lane,
82
- localId: localIntents.localId,
83
- subjectId: localIntents.subjectId,
84
- })
85
- .from(localIntents),
86
- ]);
87
- const containerIntentCount = (lane) => intents.filter((row) => row.lane === lane && containerIdSet.has(row.subjectId)).length;
88
- const principalKeys = principalScope.principalKeys;
89
- const principalKeySet = new Set(principalKeys.map(principalKeyOfRow));
90
- const scopedContainerIds = new Set(input.containerIds);
91
- const syncLanes = await tx.select().from(containerSyncWatermarks);
92
- return {
93
- clearedContainerCreateIntentCount: containerIntentCount(LOCAL_INTENT_LANES.containerCreate),
94
- clearedContainerMoveIntentCount: containerIntentCount(LOCAL_INTENT_LANES.containerMove),
95
- clearedDocumentMoveIntentCount: intents.filter((row) => row.lane === LOCAL_INTENT_LANES.documentPlacement &&
96
- row.localId !== null &&
97
- documentScopeKeys.has(scopeKey({ appKind: "documents", localId: row.localId }))).length,
98
- clearedPrincipalPolicyCount: principalScope.policyRows.filter((row) => principalKeySet.has(`${row.type}\0${row.id}`)).length,
99
- clearedSyncCursorCount: syncLanes.filter((row) => isRemoteResetSyncCursor({
100
- containerIds: scopedContainerIds,
101
- row,
102
- })).length,
103
- principalKeys,
104
- };
105
- }
7
+ /**
8
+ * Reads what a reset of the organization covers, from each subsystem that owns
9
+ * part of it: folders, then the documents in them, then principal policies.
10
+ */
106
11
  export async function readRemoteSyncStateSnapshot(tx, organizationId) {
107
- const containerScope = await loadContainerScope(tx, organizationId);
108
- const documentScope = await loadDocumentScope({
12
+ const containerScope = await loadContainerResetScope(tx, organizationId);
13
+ const documentScope = await loadDocumentResetScope({
109
14
  containerIds: containerScope.containerIds,
110
15
  organizationId,
16
+ placementRows: await listDocumentPlacementRows(tx),
111
17
  tx,
112
18
  });
113
- const counts = await loadSnapshotCounts({
19
+ const principalScope = await loadRemoteResetPrincipalScope(tx, organizationId);
20
+ const intentCounts = await countContainerResetIntents({
114
21
  containerIds: containerScope.containerIds,
115
- documentRows: documentScope.documentRows,
116
- organizationId,
22
+ documentLocalIds: documentScope.documentLocalIds,
117
23
  tx,
118
24
  });
119
- return { ...containerScope, ...documentScope, ...counts };
25
+ const principalKeys = principalScope.principalKeys;
26
+ const principalKeySet = new Set(principalKeys.map(principalKeyOfRow));
27
+ return {
28
+ ...containerScope,
29
+ ...documentScope,
30
+ ...intentCounts,
31
+ clearedPrincipalPolicyCount: principalScope.policyRows.filter((row) => principalKeySet.has(`${row.type}\0${row.id}`)).length,
32
+ clearedSyncCursorCount: await countRemoteResetSyncCursors({
33
+ containerIds: containerScope.containerIds,
34
+ tx,
35
+ }),
36
+ principalKeys,
37
+ };
120
38
  }
121
39
  //# sourceMappingURL=remoteResetScope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"remoteResetScope.js","sourceRoot":"","sources":["remoteResetScope.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport {\n containerSyncWatermarks,\n containers,\n documentContainerProjection,\n documentProjection,\n documents,\n dormantContainerMetadata,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../data/sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport { isRemoteResetSyncCursor } from \"./remoteResetCursorScope\";\nimport type { ResetDocumentScope } from \"./remoteResetPlans\";\nimport {\n loadRemoteResetPrincipalScope,\n type RemoteResetPrincipalKey,\n} from \"./remoteResetPrincipalScope\";\n\nexport interface RemoteResetReplacement {\n readonly organizationId: string;\n readonly rootContainerId: string;\n}\n\nexport interface RemoteResetInput {\n readonly organizationId: string;\n readonly replacement?: RemoteResetReplacement | undefined;\n}\n\nexport interface ResetContainerRow {\n readonly id: string;\n readonly parentId: string | null;\n}\n\nexport interface ResetDocumentRow extends ResetDocumentScope {\n readonly documentId: string | null;\n readonly recoveryDocumentId: string | null;\n}\n\nexport interface RemoteSyncStateSnapshot {\n readonly clearedContainerCreateIntentCount: number;\n readonly clearedContainerMoveIntentCount: number;\n readonly clearedDocumentMoveIntentCount: number;\n readonly clearedPrincipalPolicyCount: number;\n readonly clearedSyncCursorCount: number;\n readonly containerIds: readonly string[];\n readonly containerRows: readonly ResetContainerRow[];\n readonly documentLocalIds: readonly string[];\n readonly documentRows: readonly ResetDocumentRow[];\n readonly oldDocumentIds: readonly string[];\n readonly principalKeys: readonly RemoteResetPrincipalKey[];\n}\n\nfunction principalKeyOfRow(row: {\n readonly principalId: string;\n readonly principalType: string;\n}): string {\n return `${row.principalType}\\0${row.principalId}`;\n}\n\nfunction scopeKey(scope: ResetDocumentScope): string {\n return `${scope.appKind}\\0${scope.localId}`;\n}\n\nasync function loadContainerScope(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<{\n containerIds: string[];\n containerRows: ResetContainerRow[];\n}> {\n const liveContainerRows = (\n await tx\n .select({ id: containers.id, parentId: containers.parentId })\n .from(containers)\n .where(eq(containers.organizationId, organizationId))\n ).flatMap((row) => (row.id ? [{ id: row.id, parentId: row.parentId }] : []));\n const dormantContainerRows = await tx\n .select({ id: dormantContainerMetadata.containerId })\n .from(dormantContainerMetadata)\n .where(eq(dormantContainerMetadata.organizationId, organizationId));\n const containerRows = liveContainerRows;\n return {\n containerIds: [\n ...new Set([\n ...containerRows.map((row) => row.id),\n ...dormantContainerRows.map((row) => row.id),\n ]),\n ],\n containerRows,\n };\n}\n\nasync function loadDocumentScope(input: {\n containerIds: readonly string[];\n organizationId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<{\n documentLocalIds: string[];\n documentRows: ResetDocumentRow[];\n oldDocumentIds: string[];\n}> {\n const { organizationId, tx } = input;\n const containerIdSet = new Set(input.containerIds);\n const [allDocuments, projectionRows, linkRows] =\n await loadDocumentAssociationRows(tx);\n const linkedDocumentIds = new Set(\n linkRows\n .filter((row) => containerIdSet.has(row.containerId))\n .map((row) => row.documentId),\n );\n const projectedLocalIds = new Set(\n projectionRows\n .filter(\n (row) =>\n (row.containerId !== null && containerIdSet.has(row.containerId)) ||\n row.organizationId === organizationId ||\n (row.documentId !== null && linkedDocumentIds.has(row.documentId)),\n )\n .flatMap((row) => (row.localId ? [row.localId] : [])),\n );\n const documentRows = allDocuments.filter(\n (row) =>\n (row.appKind === \"container-metadata\" &&\n containerIdSet.has(row.localId)) ||\n (row.appKind === \"documents\" && projectedLocalIds.has(row.localId)) ||\n (row.documentId !== null && linkedDocumentIds.has(row.documentId)),\n );\n return {\n documentLocalIds: [\n ...new Set(\n documentRows\n .filter((row) => row.appKind === \"documents\")\n .map((row) => row.localId),\n ),\n ],\n documentRows,\n oldDocumentIds: [\n ...new Set(\n documentRows.flatMap((row) => (row.documentId ? [row.documentId] : [])),\n ),\n ],\n };\n}\n\nfunction loadDocumentAssociationRows(tx: ClientSQLiteTransactionScope) {\n return Promise.all([\n tx\n .select({\n appKind: documents.appKind,\n documentId: documents.documentId,\n localId: documents.localId,\n recoveryDocumentId: documents.recoveryDocumentId,\n })\n .from(documents),\n tx.select().from(documentProjection),\n tx.select().from(documentContainerProjection),\n ]);\n}\n\nasync function loadSnapshotCounts(input: {\n containerIds: readonly string[];\n documentRows: readonly ResetDocumentRow[];\n organizationId: string;\n tx: ClientSQLiteTransactionScope;\n}) {\n const { organizationId, tx } = input;\n const containerIdSet = new Set(input.containerIds);\n const documentScopeKeys = new Set(input.documentRows.map(scopeKey));\n const [principalScope, intents] = await Promise.all([\n loadRemoteResetPrincipalScope(tx, organizationId),\n tx\n .select({\n lane: localIntents.lane,\n localId: localIntents.localId,\n subjectId: localIntents.subjectId,\n })\n .from(localIntents),\n ]);\n const containerIntentCount = (lane: string) =>\n intents.filter(\n (row) => row.lane === lane && containerIdSet.has(row.subjectId),\n ).length;\n const principalKeys = principalScope.principalKeys;\n const principalKeySet = new Set(principalKeys.map(principalKeyOfRow));\n const scopedContainerIds = new Set(input.containerIds);\n const syncLanes = await tx.select().from(containerSyncWatermarks);\n\n return {\n clearedContainerCreateIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerCreate,\n ),\n clearedContainerMoveIntentCount: containerIntentCount(\n LOCAL_INTENT_LANES.containerMove,\n ),\n clearedDocumentMoveIntentCount: intents.filter(\n (row) =>\n row.lane === LOCAL_INTENT_LANES.documentPlacement &&\n row.localId !== null &&\n documentScopeKeys.has(\n scopeKey({ appKind: \"documents\", localId: row.localId }),\n ),\n ).length,\n clearedPrincipalPolicyCount: principalScope.policyRows.filter((row) =>\n principalKeySet.has(`${row.type}\\0${row.id}`),\n ).length,\n clearedSyncCursorCount: syncLanes.filter((row) =>\n isRemoteResetSyncCursor({\n containerIds: scopedContainerIds,\n row,\n }),\n ).length,\n principalKeys,\n };\n}\n\nexport async function readRemoteSyncStateSnapshot(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<RemoteSyncStateSnapshot> {\n const containerScope = await loadContainerScope(tx, organizationId);\n const documentScope = await loadDocumentScope({\n containerIds: containerScope.containerIds,\n organizationId,\n tx,\n });\n const counts = await loadSnapshotCounts({\n containerIds: containerScope.containerIds,\n documentRows: documentScope.documentRows,\n organizationId,\n tx,\n });\n return { ...containerScope, ...documentScope, ...counts };\n}\n"]}
1
+ {"version":3,"file":"remoteResetScope.js","sourceRoot":"","sources":["remoteResetScope.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,GAE9B,MAAM,mEAAmE,CAAC;AAE3E,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,yBAAyB,EACzB,uBAAuB,GAExB,MAAM,wDAAwD,CAAC;AAChE,OAAO,EACL,sBAAsB,GAEvB,MAAM,8CAA8C,CAAC;AA0BtD,SAAS,iBAAiB,CAAC,GAG1B;IACC,OAAO,GAAG,GAAG,CAAC,aAAa,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,EAAgC,EAChC,cAAsB;IAEtB,MAAM,cAAc,GAAG,MAAM,uBAAuB,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC;QACjD,YAAY,EAAE,cAAc,CAAC,YAAY;QACzC,cAAc;QACd,aAAa,EAAE,MAAM,yBAAyB,CAAC,EAAE,CAAC;QAClD,EAAE;KACH,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,MAAM,6BAA6B,CACxD,EAAE,EACF,cAAc,CACf,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,0BAA0B,CAAC;QACpD,YAAY,EAAE,cAAc,CAAC,YAAY;QACzC,gBAAgB,EAAE,aAAa,CAAC,gBAAgB;QAChD,EAAE;KACH,CAAC,CAAC;IACH,MAAM,aAAa,GAAG,cAAc,CAAC,aAAa,CAAC;IACnD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACtE,OAAO;QACL,GAAG,cAAc;QACjB,GAAG,aAAa;QAChB,GAAG,YAAY;QACf,2BAA2B,EAAE,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CACpE,eAAe,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAC9C,CAAC,MAAM;QACR,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;YACxD,YAAY,EAAE,cAAc,CAAC,YAAY;YACzC,EAAE;SACH,CAAC;QACF,aAAa;KACd,CAAC;AACJ,CAAC","sourcesContent":["import {\n loadRemoteResetPrincipalScope,\n type RemoteResetPrincipalKey,\n} from \"../../data/persistence/principalPolicy/principalPolicyRemoteReset\";\nimport type { ClientSQLiteTransactionScope } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport {\n countContainerResetIntents,\n countRemoteResetSyncCursors,\n listDocumentPlacementRows,\n loadContainerResetScope,\n type ResetContainerRow,\n} from \"../container-contents/remoteReset/containerRemoteReset\";\nimport {\n loadDocumentResetScope,\n type ResetDocumentRow,\n} from \"../documents/remoteReset/documentRemoteReset\";\n\nexport interface RemoteResetReplacement {\n readonly organizationId: string;\n readonly rootContainerId: string;\n}\n\nexport interface RemoteResetInput {\n readonly organizationId: string;\n readonly replacement?: RemoteResetReplacement | undefined;\n}\n\nexport interface RemoteSyncStateSnapshot {\n readonly clearedContainerCreateIntentCount: number;\n readonly clearedContainerMoveIntentCount: number;\n readonly clearedDocumentMoveIntentCount: number;\n readonly clearedPrincipalPolicyCount: number;\n readonly clearedSyncCursorCount: number;\n readonly containerIds: readonly string[];\n readonly containerRows: readonly ResetContainerRow[];\n readonly documentLocalIds: readonly string[];\n readonly documentRows: readonly ResetDocumentRow[];\n readonly oldDocumentIds: readonly string[];\n readonly principalKeys: readonly RemoteResetPrincipalKey[];\n}\n\nfunction principalKeyOfRow(row: {\n readonly principalId: string;\n readonly principalType: string;\n}): string {\n return `${row.principalType}\\0${row.principalId}`;\n}\n\n/**\n * Reads what a reset of the organization covers, from each subsystem that owns\n * part of it: folders, then the documents in them, then principal policies.\n */\nexport async function readRemoteSyncStateSnapshot(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<RemoteSyncStateSnapshot> {\n const containerScope = await loadContainerResetScope(tx, organizationId);\n const documentScope = await loadDocumentResetScope({\n containerIds: containerScope.containerIds,\n organizationId,\n placementRows: await listDocumentPlacementRows(tx),\n tx,\n });\n const principalScope = await loadRemoteResetPrincipalScope(\n tx,\n organizationId,\n );\n const intentCounts = await countContainerResetIntents({\n containerIds: containerScope.containerIds,\n documentLocalIds: documentScope.documentLocalIds,\n tx,\n });\n const principalKeys = principalScope.principalKeys;\n const principalKeySet = new Set(principalKeys.map(principalKeyOfRow));\n return {\n ...containerScope,\n ...documentScope,\n ...intentCounts,\n clearedPrincipalPolicyCount: principalScope.policyRows.filter((row) =>\n principalKeySet.has(`${row.type}\\0${row.id}`),\n ).length,\n clearedSyncCursorCount: await countRemoteResetSyncCursors({\n containerIds: containerScope.containerIds,\n tx,\n }),\n principalKeys,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentHistoryPersistence.js","sourceRoot":"","sources":["documentHistoryPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes } from \"@tearleads/encoding\";\nimport {\n createDocument,\n exportFullHistoryIdentity,\n importSnapshot,\n satisfiesVersionVector,\n} from \"@tearleads/loro\";\nimport { and, eq, inArray, isNull, ne, sql } from \"drizzle-orm\";\nimport {\n documentHistoryCheckpoints,\n documentHistoryUpdates,\n documentTables,\n} from \"../schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlSchema\";\nimport type { DocumentScope } from \"./documentPersistenceTypes\";\n\n/**\n * Compaction thresholds: once the tail carries this many rows or bytes, the\n * next persist of a full-history-capable document exports a fresh checkpoint\n * and clears the tail. Small enough to keep restore replay short, large\n * enough that a full-history export (O(history)) happens once per burst of\n * edits instead of per keystroke.\n */\nexport const DOCUMENT_HISTORY_COMPACTION_MAX_ROWS = 200;\nexport const DOCUMENT_HISTORY_COMPACTION_MAX_BYTES = 512 * 1024;\n\n/**\n * Row provenance: \"local\" for updates authored on this device, \"remote\" for\n * decrypted pulled updates. Restores advance the outgoing-delta marker across\n * remote rows (already server-side); local rows never advance it.\n */\ntype DocumentHistoryUpdateOrigin = \"local\" | \"remote\";\n\n/**\n * Rows of the update log that are history tail: every row except an \"outbox\"\n * row, which only waits to be sent (see `documentHistoryUpdates`).\n */\nfunction tailInScope(scope: DocumentScope) {\n return and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n ne(documentHistoryUpdates.origin, \"outbox\"),\n );\n}\n\n/**\n * Tail rows compaction may fold into a checkpoint and delete: a queued row is\n * the only durable copy of an unsent update, so it waits for settlement even\n * when a checkpoint already covers its operations.\n */\nfunction compactableTailInScope(scope: DocumentScope) {\n return and(tailInScope(scope), isNull(documentHistoryUpdates.updateId));\n}\n\ninterface DocumentHistoryTailUpdate {\n readonly origin: DocumentHistoryUpdateOrigin;\n readonly updateData: string;\n}\n\ninterface DocumentHistoryRestoreState {\n readonly snapshot: string;\n readonly tailUpdates: readonly DocumentHistoryTailUpdate[];\n}\n\nexport async function appendDocumentHistoryUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n updates: readonly string[],\n origin: DocumentHistoryUpdateOrigin,\n): Promise<void> {\n if (updates.length === 0) {\n return;\n }\n await ensureSqlTables(execSql, documentTables);\n const createdAt = new Date().toISOString();\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n // Chunked: a catch-up pull can carry thousands of updates, and a single\n // multi-row insert would exceed SQLite's bound-variable limit.\n for (let index = 0; index < updates.length; index += HISTORY_ROW_CHUNK) {\n await db.insert(documentHistoryUpdates).values(\n updates.slice(index, index + HISTORY_ROW_CHUNK).map((updateData) => ({\n id: crypto.randomUUID(),\n appKind: scope.appKind,\n localId: scope.localId,\n updateData,\n origin,\n createdAt,\n })),\n );\n }\n });\n}\n\n/**\n * The checkpoint + ordered tail for a scope, or null when NEITHER exists (a\n * discovered shell that has not hydrated content yet; the caller starts the\n * document empty and the remote pull supplies the content). A tail WITHOUT a\n * checkpoint — a crash between the first enqueued edit's tail append and the\n * birth-checkpoint seed — restores as tail-only (`snapshot: \"\"`): those tail\n * rows can be the only durable copy of a local edit, so they must never be\n * silently ignored.\n */\nexport async function loadDocumentHistoryRestoreState(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<DocumentHistoryRestoreState | null> {\n await ensureSqlTables(execSql, documentTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n // Read the TAIL before the (full) checkpoint: if another pane compacts\n // between the two reads, this order yields old-tail + new-checkpoint — a\n // safe superset (the new checkpoint subsumes the old tail, and replay is\n // idempotent by op identity). The reverse order could yield old-checkpoint\n // + already-emptied tail, a torn read that silently drops the compacted\n // ops for the whole session.\n const tail = await db\n .select({\n id: documentHistoryUpdates.id,\n origin: documentHistoryUpdates.origin,\n updateData: documentHistoryUpdates.updateData,\n })\n .from(documentHistoryUpdates)\n .where(tailInScope(scope))\n // Insertion order: same-millisecond appends make createdAt tie and a\n // random-uuid tiebreak would replay out of order. importUpdates tolerates\n // out-of-order batches, but replay should still be deterministic.\n .orderBy(sql`rowid`);\n\n const [checkpoint] = await db\n .select({ snapshot: documentHistoryCheckpoints.snapshot })\n .from(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, scope.appKind),\n eq(documentHistoryCheckpoints.localId, scope.localId),\n ),\n )\n .limit(1);\n if (!checkpoint && tail.length === 0) {\n return null;\n }\n\n return {\n snapshot: checkpoint?.snapshot ?? \"\",\n tailUpdates: tail.map((row) => ({\n // Fail toward re-sending: an unrecognized origin never advances the\n // marker, which is the recoverable direction (a redundant re-submit\n // is idempotent; a skipped local op would be orphaned from sync).\n origin:\n row.origin === \"remote\" ? (\"remote\" as const) : (\"local\" as const),\n updateData: row.updateData,\n })),\n };\n}\n\n/**\n * Size of the tail compaction can shrink. Queued rows are excluded: they stay\n * until settlement, so counting them would re-export full history on every\n * persist while offline edits wait to sync.\n */\nexport async function readDocumentHistoryTailSize(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<{ byteLength: number; hasCheckpoint: boolean; rowCount: number }> {\n await ensureSqlTables(execSql, documentTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [totals] = await db\n .select({\n byteLength: sql<number>`coalesce(sum(length(${documentHistoryUpdates.updateData})), 0)`,\n rowCount: sql<number>`count(*)`,\n })\n .from(documentHistoryUpdates)\n .where(compactableTailInScope(scope));\n const [checkpoint] = await db\n .select({ localId: documentHistoryCheckpoints.localId })\n .from(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, scope.appKind),\n eq(documentHistoryCheckpoints.localId, scope.localId),\n ),\n )\n .limit(1);\n return {\n byteLength: Number(totals?.byteLength ?? 0),\n hasCheckpoint: checkpoint !== undefined,\n rowCount: Number(totals?.rowCount ?? 0),\n };\n}\n\ninterface DocumentHistoryTailEntry {\n readonly id: string;\n readonly updateData: string;\n}\n\n/**\n * The current compactable tail rows WITH their payloads, so a compactor can\n * prove each row's ops are covered by the snapshot it is about to install\n * (another pane's append may carry ops this pane's document has not merged\n * yet). Queued rows are never candidates.\n */\nexport async function listDocumentHistoryTailEntries(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<DocumentHistoryTailEntry[]> {\n await ensureSqlTables(execSql, documentTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: documentHistoryUpdates.id,\n updateData: documentHistoryUpdates.updateData,\n })\n .from(documentHistoryUpdates)\n .where(compactableTailInScope(scope));\n return rows.flatMap((row) =>\n row.id === null ? [] : [{ id: row.id, updateData: row.updateData }],\n );\n}\n\nconst HISTORY_ROW_CHUNK = 400;\n\n/**\n * Replace the scope's checkpoint with a fresh full-history snapshot and\n * delete ONLY the tail rows the caller captured before exporting it. Every\n * append path writes its tail row after the ops are already in the live\n * document, so any row captured before the export is provably covered by\n * the snapshot — while a row appended concurrently (between export and this\n * delete) survives for the next compaction instead of being lost.\n */\nexport async function replaceDocumentHistoryCheckpoint(\n execSql: ExecSql,\n scope: DocumentScope,\n input: {\n coveredTailIds: readonly string[];\n endVersionVector: string;\n /**\n * Skip the monotonic version gate. Only for document CREATION, where any\n * existing checkpoint under this localId is the orphan of a failed prior\n * attempt (checkpoint written, record row never committed) — a retry's\n * fresh document need not dominate that orphan to replace it.\n */\n force?: boolean;\n snapshot: string;\n /**\n * Re-checked after acquiring the serialized mutation slot (like the\n * record-save path): a store reset/recreation that happened while this\n * call waited in the queue must abort the write, or a stale compactor\n * could install the OLD document's checkpoint over the new identity's.\n */\n stillCurrent?: () => boolean;\n },\n): Promise<boolean> {\n await ensureSqlTables(execSql, documentTables);\n // Sequential (non-transactional) so callers already inside a transaction\n // can nest this. Crash between the statements leaves the new checkpoint\n // plus covered tail rows — a safe superset, since tail replay is\n // idempotent by op identity. The replacement itself is a compare-and-swap\n // on the stored revision, so the version gate cannot be bypassed by a\n // concurrent compactor between the read and the write: whoever loses the\n // CAS re-reads and re-evaluates the gate against the winner's checkpoint.\n return getClientSQLitePersistenceRuntime(execSql).runMutation(async (tx) => {\n if (input.stillCurrent?.() === false) {\n return false;\n }\n for (let attempt = 0; attempt < CHECKPOINT_CAS_ATTEMPTS; attempt += 1) {\n let replaced: boolean;\n try {\n replaced = await tryReplaceCheckpointOnce(tx, scope, input);\n } catch (error) {\n if (error instanceof CheckpointGateRejected) {\n // A fresher checkpoint dominates this candidate: no write, and\n // the caller's covered rows must stay for the covering pane.\n return false;\n }\n throw error;\n }\n if (!replaced) {\n // CAS lost to a concurrent writer — re-read and re-evaluate the\n // gate against the winner's checkpoint.\n continue;\n }\n for (\n let index = 0;\n index < input.coveredTailIds.length;\n index += HISTORY_ROW_CHUNK\n ) {\n // Never a queued row, even if a caller names one: its operations may\n // be in the checkpoint, but it is still the unsent update itself.\n await tx\n .delete(documentHistoryUpdates)\n .where(\n and(\n compactableTailInScope(scope),\n inArray(\n documentHistoryUpdates.id,\n input.coveredTailIds.slice(index, index + HISTORY_ROW_CHUNK),\n ),\n ),\n );\n }\n return true;\n }\n // Exhaustion must not read as durable success: creation and rebuild\n // callers persist record rows assuming the checkpoint landed.\n throw new Error(\n \"Document history checkpoint replacement lost every CAS attempt\",\n );\n });\n}\n\nconst CHECKPOINT_CAS_ATTEMPTS = 16;\n\ntype MutationDb = Parameters<\n Parameters<\n ReturnType<typeof getClientSQLitePersistenceRuntime>[\"runMutation\"]\n >[0]\n>[0];\n\n/**\n * One compare-and-swap attempt. Returns true when this caller's checkpoint\n * became the stored one, false when a concurrent writer won the CAS (the\n * caller re-reads and retries), and throws CheckpointGateRejected when a\n * fresher stored checkpoint dominates the candidate.\n */\nasync function tryReplaceCheckpointOnce(\n tx: MutationDb,\n scope: DocumentScope,\n input: {\n endVersionVector: string;\n force?: boolean;\n snapshot: string;\n },\n): Promise<boolean> {\n const updatedAt = new Date().toISOString();\n const revision = crypto.randomUUID();\n const [stored] = await tx\n .select({\n endVersionVector: documentHistoryCheckpoints.endVersionVector,\n revision: documentHistoryCheckpoints.revision,\n snapshot: documentHistoryCheckpoints.snapshot,\n })\n .from(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, scope.appKind),\n eq(documentHistoryCheckpoints.localId, scope.localId),\n ),\n )\n .limit(1);\n\n if (!stored) {\n const inserted = await tx\n .insert(documentHistoryCheckpoints)\n .values({\n appKind: scope.appKind,\n localId: scope.localId,\n snapshot: input.snapshot,\n endVersionVector: input.endVersionVector,\n revision,\n updatedAt,\n })\n .onConflictDoNothing({\n target: [\n documentHistoryCheckpoints.appKind,\n documentHistoryCheckpoints.localId,\n ],\n })\n .returning({ localId: documentHistoryCheckpoints.localId });\n // Conflict means a concurrent writer inserted first — retry the gate.\n return inserted.length > 0;\n }\n\n // A stale compactor (a pane whose document has not merged another pane's\n // ops) must never replace a checkpoint it does not cover: the covered\n // pane may already have deleted its tail rows, so regressing the\n // checkpoint would leave those ops with no durable copy at all. Vector\n // dominance proves counter coverage; the retained-prefix identity also\n // proves the candidate carries the exact stored operations at those\n // counters rather than a same-frontier fork.\n if (input.force !== true) {\n if (\n !satisfiesVersionVector(input.endVersionVector, stored.endVersionVector)\n ) {\n throw new CheckpointGateRejected();\n }\n if (\n input.snapshot !== stored.snapshot &&\n !(await candidateContainsStoredCheckpointHistory({\n candidateSnapshot: input.snapshot,\n storedEndVersion: stored.endVersionVector,\n storedSnapshot: stored.snapshot,\n }))\n ) {\n throw new CheckpointGateRejected();\n }\n }\n\n const replaced = await tx\n .update(documentHistoryCheckpoints)\n .set({\n snapshot: input.snapshot,\n endVersionVector: input.endVersionVector,\n revision,\n updatedAt,\n })\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, scope.appKind),\n eq(documentHistoryCheckpoints.localId, scope.localId),\n eq(documentHistoryCheckpoints.revision, stored.revision),\n ),\n )\n .returning({ localId: documentHistoryCheckpoints.localId });\n return replaced.length > 0;\n}\n\nasync function candidateContainsStoredCheckpointHistory(input: {\n candidateSnapshot: string;\n storedEndVersion: string;\n storedSnapshot: string;\n}): Promise<boolean> {\n const [candidateDocument, storedDocument] = await Promise.all([\n createDocument(\"checkpoint-candidate-history-gate\"),\n createDocument(\"checkpoint-stored-history-gate\"),\n ]);\n try {\n importSnapshot(candidateDocument, base64ToBytes(input.candidateSnapshot));\n importSnapshot(storedDocument, base64ToBytes(input.storedSnapshot));\n return (\n exportFullHistoryIdentity(candidateDocument, input.storedEndVersion) ===\n exportFullHistoryIdentity(storedDocument)\n );\n } finally {\n candidateDocument.free();\n storedDocument.free();\n }\n}\n\nclass CheckpointGateRejected extends Error {\n constructor() {\n super(\"checkpoint gate rejected\");\n this.name = \"CheckpointGateRejected\";\n }\n}\n\nexport async function deleteDocumentHistory(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await ensureSqlTables(execSql, documentTables);\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (tx) => {\n await tx\n .delete(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, scope.appKind),\n eq(documentHistoryCheckpoints.localId, scope.localId),\n ),\n );\n await tx\n .delete(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n ),\n );\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentOrphanBlobReclaims.js","sourceRoot":"","sources":["documentOrphanBlobReclaims.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,iFAAiF;AACjF,MAAM,CAAC,MAAM,0BAA0B,GAAG,WAAW,CACnD,+BAA+B,EAC/B,EAAE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,UAAU,EAAE,EAAE,CACjD,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAG,oBAAoB,CAChE,0BAA0B,CAC3B,CAAC","sourcesContent":["import { sqliteTable, text } from \"drizzle-orm/sqlite-core\";\nimport { defineSqlTableSchema } from \"../sqlTableSchema\";\n\n/** Durable byte-reclamation queue populated before orphan attachment rows go. */\nexport const documentOrphanBlobReclaims = sqliteTable(\n \"document_orphan_blob_reclaims\",\n { storageKey: text(\"storage_key\").primaryKey() },\n);\n\nexport const documentOrphanBlobReclaimTable = defineSqlTableSchema(\n documentOrphanBlobReclaims,\n);\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentPendingUpdatePersistence.js","sourceRoot":"","sources":["documentPendingUpdatePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n and,\n asc,\n eq,\n inArray,\n isNotNull,\n lt,\n or,\n type SQL,\n sql,\n} from \"drizzle-orm\";\nimport { documentHistoryUpdates, documents } from \"../schema\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlitePersistenceRuntime\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../sqlSchema\";\nimport type {\n DocumentScope,\n PendingUpdateFields,\n PendingUpdateRecord,\n SelectedPendingUpdateRow,\n} from \"./documentPersistenceTypes\";\n\n/**\n * Queued updates are the rows of the local update log that carry an\n * `updateId`. A tail row (origin \"local\") stays in the log after settlement as\n * history until compaction; an \"outbox\" row has no tail role and settlement\n * deletes it.\n */\nconst OUTBOX_ORIGIN = \"outbox\";\n\ntype QueueStatement = Pick<ClientSQLiteTransactionScope, \"delete\" | \"update\">;\ntype QueueRead = Pick<ClientSQLiteTransactionScope, \"selectDistinct\">;\n\nfunction queuedInScope(scope: DocumentScope) {\n return and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n isNotNull(documentHistoryUpdates.updateId),\n );\n}\n\nfunction mapSelectedPendingUpdate(\n row: SelectedPendingUpdateRow,\n): PendingUpdateRecord {\n // A queued row always carries its submission vectors; a row without them\n // cannot be submitted and must fail closed rather than send empty ranges.\n if (\n row.partialStartVersionVector === null ||\n row.partialEndVersionVector === null\n ) {\n throw new Error(\"Queued document update is missing its version vectors\");\n }\n return {\n id: String(row.id ?? \"\"),\n updateData: row.updateData,\n partialStartVersionVector: row.partialStartVersionVector,\n partialEndVersionVector: row.partialEndVersionVector,\n sourceVersionVector: row.sourceVersionVector,\n rekeyCount: row.rekeyCount,\n };\n}\n\n/** The ids among `localIds` (one app kind) with at least one queued update. */\nexport async function listLocalIdsWithQueuedUpdates(\n db: QueueRead,\n appKind: string,\n localIds: readonly string[],\n): Promise<string[]> {\n const uniqueIds = [...new Set(localIds)];\n if (uniqueIds.length === 0) return [];\n const rows = await db\n .selectDistinct({ localId: documentHistoryUpdates.localId })\n .from(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, appKind),\n inArray(documentHistoryUpdates.localId, uniqueIds),\n isNotNull(documentHistoryUpdates.updateId),\n ),\n )\n .orderBy(asc(documentHistoryUpdates.localId));\n return rows.map((row) => row.localId);\n}\n\nexport async function hasQueuedDocumentUpdates(\n db: QueueRead,\n scope: DocumentScope,\n): Promise<boolean> {\n const ids = await listLocalIdsWithQueuedUpdates(db, scope.appKind, [\n scope.localId,\n ]);\n return ids.length > 0;\n}\n\nexport async function listDocumentPendingUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<PendingUpdateRecord[]> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: documentHistoryUpdates.updateId,\n updateData: documentHistoryUpdates.updateData,\n partialStartVersionVector:\n documentHistoryUpdates.partialStartVersionVector,\n partialEndVersionVector: documentHistoryUpdates.partialEndVersionVector,\n sourceVersionVector: documentHistoryUpdates.sourceVersionVector,\n rekeyCount: documentHistoryUpdates.rekeyCount,\n })\n .from(documentHistoryUpdates)\n .where(queuedInScope(scope))\n .orderBy(asc(documentHistoryUpdates.createdAt), asc(sql`rowid`));\n\n return rows.map(mapSelectedPendingUpdate);\n}\n\n/** One log row for a queued update; `origin` decides its tail role. */\nexport function queuedUpdateRow(input: {\n createdAt: string;\n origin: \"local\" | typeof OUTBOX_ORIGIN;\n pendingUpdate: PendingUpdateFields;\n scope: DocumentScope;\n updateId: string;\n}) {\n return {\n id: crypto.randomUUID(),\n appKind: input.scope.appKind,\n localId: input.scope.localId,\n updateData: input.pendingUpdate.updateData,\n origin: input.origin,\n createdAt: input.createdAt,\n updateId: input.updateId,\n partialStartVersionVector: input.pendingUpdate.partialStartVersionVector,\n partialEndVersionVector: input.pendingUpdate.partialEndVersionVector,\n sourceVersionVector: input.pendingUpdate.sourceVersionVector ?? null,\n };\n}\n\n/**\n * Queue an update that has no history-tail role: container metadata (its\n * content is its checkpoint) and full-state re-uploads after a remote reset.\n */\nexport async function enqueueDocumentPendingUpdate(\n execSql: ExecSql,\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n): Promise<string> {\n const updateId = crypto.randomUUID();\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .insert(documentHistoryUpdates)\n .values(\n queuedUpdateRow({\n createdAt: new Date().toISOString(),\n origin: OUTBOX_ORIGIN,\n pendingUpdate,\n scope,\n updateId,\n }),\n )\n .run();\n });\n return updateId;\n}\n\n/**\n * Append a locally authored update to the history tail AND queue it, as one\n * row in one transaction. A crash can therefore never leave the op restorable\n * from history while missing from the outgoing queue, where a null-marker\n * restore would classify it as covered and never send it.\n */\nexport async function enqueueDocumentPendingUpdateWithHistory(\n execSql: ExecSql,\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n options?: {\n expectedDocumentId: string | null;\n expectedRecoveryGeneration: number;\n },\n): Promise<string | null> {\n const createdAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(execSql).transaction(\n async (tx) => {\n if (options) {\n const matchingDocuments = await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n sql`${documents.documentId} IS ${options.expectedDocumentId}`,\n eq(\n documents.recoveryGeneration,\n options.expectedRecoveryGeneration,\n ),\n ),\n )\n .limit(1);\n if (matchingDocuments.length === 0) {\n return null;\n }\n }\n\n return insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt,\n pendingUpdate,\n scope,\n tx,\n });\n },\n { behavior: \"immediate\" },\n );\n}\n\nexport async function insertDocumentPendingUpdateWithHistoryInTransaction(input: {\n createdAt: string;\n pendingUpdate: PendingUpdateFields;\n scope: DocumentScope;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const updateId = crypto.randomUUID();\n await input.tx\n .insert(documentHistoryUpdates)\n .values(\n queuedUpdateRow({\n createdAt: input.createdAt,\n origin: \"local\",\n pendingUpdate: input.pendingUpdate,\n scope: input.scope,\n updateId,\n }),\n )\n .run();\n return updateId;\n}\n\n/**\n * Assign a fresh id to a queued update, keeping every other column. A lost\n * sync ack leaves the server holding the update under the original id with\n * ciphertext a rebuilt submission can never reproduce (each rebuild encrypts\n * with a fresh IV), so the id is permanently poisoned: every resubmission\n * 409s and the whole outgoing batch rolls back. Re-keying lets the next sync\n * pass submit the same ops under a conflict-free id; the server-side copy is\n * harmless because CRDT update import is idempotent.\n *\n * Returns null when no row carries the id, so callers never report progress\n * for a row that lives in some other queue (or nowhere). The UPDATE's own\n * RETURNING row is the progress signal — a pre-flight SELECT would race a\n * second tab sharing the SQLite file, which can settle the row between the\n * read and the write and turn \"rekeyed\" into a spurious re-arm.\n *\n * The persisted per-row bound is enforced here as well: a row already at\n * MAX_PENDING_UPDATE_REKEYS is left untouched and reported as no progress.\n * The in-memory lane counter bounds a busy-loop within one session; this\n * bound survives restarts, so a poisoned row cannot re-key forever at three\n * passes per launch.\n */\nexport const MAX_PENDING_UPDATE_REKEYS = 5;\n\n/**\n * Reset the durable re-key budget for every queued update in a scope. The\n * cap exists to stop a server that keeps conflicting fresh ids from driving\n * a network-speed loop — but a budget burned during an unrelated outage\n * (e.g. yesterday's stale-bundle deadlock 409ing every submit) should not be\n * terminal forever. An explicit manual retry is the deliberate, rate-limited\n * signal that conditions changed, so it gets a fresh budget.\n */\nexport async function resetDocumentPendingUpdateRekeyBudget(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .update(documentHistoryUpdates)\n .set({ rekeyCount: 0 })\n .where(queuedInScope(scope));\n });\n}\n\nexport async function rekeyDocumentPendingUpdate(\n execSql: ExecSql,\n id: string,\n): Promise<string | null> {\n const nextId = crypto.randomUUID();\n let rekeyed = false;\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n const updated = await db\n .update(documentHistoryUpdates)\n .set({\n updateId: nextId,\n rekeyCount: sql`${documentHistoryUpdates.rekeyCount} + 1`,\n })\n .where(\n and(\n eq(documentHistoryUpdates.updateId, id),\n lt(documentHistoryUpdates.rekeyCount, MAX_PENDING_UPDATE_REKEYS),\n ),\n )\n .returning({ id: documentHistoryUpdates.updateId });\n rekeyed = updated.length > 0;\n });\n return rekeyed ? nextId : null;\n}\n\n/**\n * Settle queued updates: an outbox row is deleted, and a tail row stops being\n * queued but stays as history until compaction folds it into a checkpoint.\n */\nexport async function settleQueuedDocumentUpdatesInTransaction(\n tx: QueueStatement,\n scope: DocumentScope,\n updateIds: readonly string[],\n): Promise<void> {\n const uniqueIds = [...new Set(updateIds)];\n if (uniqueIds.length === 0) return;\n const selected = and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n inArray(documentHistoryUpdates.updateId, uniqueIds),\n );\n await unqueueSelectedUpdates(tx, selected);\n}\n\nasync function unqueueSelectedUpdates(\n tx: QueueStatement,\n selected: SQL | undefined,\n): Promise<void> {\n await tx\n .delete(documentHistoryUpdates)\n .where(and(selected, eq(documentHistoryUpdates.origin, OUTBOX_ORIGIN)))\n .run();\n await tx\n .update(documentHistoryUpdates)\n .set({\n updateId: null,\n partialStartVersionVector: null,\n partialEndVersionVector: null,\n sourceVersionVector: null,\n rekeyCount: 0,\n })\n .where(selected)\n .run();\n}\n\n/** Settle one queued update by id, whatever its scope. */\nexport async function settleDocumentPendingUpdate(\n execSql: ExecSql,\n id: string,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await unqueueSelectedUpdates(db, eq(documentHistoryUpdates.updateId, id));\n });\n}\n\n/**\n * Stop queueing every update in the given scopes: outbox rows are dropped,\n * and local tail rows keep their content as history (it is already in the\n * document).\n */\nexport async function unqueueDocumentScopesInTransaction(\n tx: QueueStatement,\n scopes: readonly DocumentScope[],\n): Promise<void> {\n if (scopes.length === 0) return;\n await unqueueSelectedUpdates(tx, or(...scopes.map(queuedInScope)));\n}\n\nexport async function unqueueDocumentPendingUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await unqueueDocumentScopesInTransaction(db, [scope]);\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentPersistenceTypes.js","sourceRoot":"","sources":["documentPersistenceTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { ContainerAccessLevel } from \"@tearleads/crypto\";\nimport type { DocumentSyncPullContinuation } from \"../../documents/shared/sync/pullContinuation\";\n\nexport interface DocumentRecord {\n id: string;\n documentId: string | null;\n /**\n * Durable fence advanced by an atomic raw-history recovery install. Writers\n * capture this before waiting for the mutation queue and must refuse to\n * publish when recovery advanced it first.\n */\n recoveryGeneration?: number;\n /** Former server id reserved for deterministic post-purge recreation. */\n recoveryDocumentId?: string | null;\n /**\n * Encoded end version vector of the persisted content frontier. Content\n * itself lives in the durable history (checkpoint + tail); this column\n * exists so priming and coverage predicates can compare versions from a\n * narrow indexed column. Empty string means \"never hydrated\".\n */\n snapshotEndVersion: string;\n accessEpoch: number;\n accessStateHash?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | null;\n lastCommitLsn?: string | null;\n contentKeyBundle?: string | null;\n documentKekTargets?: string | null;\n documentManifestBundle?: string | null;\n pendingBaseVersion?: string | null;\n pullContinuation?: DocumentSyncPullContinuation | null;\n /**\n * The durable continuation column was non-null but could not be decoded.\n * Keep forcing a page-one pull until a successful settlement replaces the\n * malformed value; ordinary local saves must preserve that recovery signal.\n */\n pullContinuationRecoveryRequired?: true;\n}\n\nexport interface PendingUpdateFields {\n updateData: string;\n partialStartVersionVector: string;\n partialEndVersionVector: string;\n sourceVersionVector?: string | null;\n}\n\nexport interface PendingUpdateRecord extends PendingUpdateFields {\n id: string;\n /**\n * Times this row was assigned a fresh id by lost-ack conflict recovery.\n * Persisted so the bound survives restarts; absent means zero (rows from\n * simple test doubles).\n */\n rekeyCount?: number | undefined;\n}\n\nexport interface DocumentScope {\n appKind: string;\n localId: string;\n}\n\nexport interface SelectedDocumentRecordRow {\n id: string;\n documentId: string | null;\n recoveryGeneration: number;\n recoveryDocumentId: string | null;\n snapshotEndVersion: string;\n accessEpoch: number;\n accessStateHash: string | null;\n effectiveAccessLevel: string | null;\n lastCommitLsn: string | null;\n contentKeyBundle: string | null;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n pendingBaseVersion: string | null;\n pullContinuation: string | null;\n}\n\nexport interface SelectedPendingUpdateRow {\n id: string | null;\n updateData: string;\n partialStartVersionVector: string | null;\n partialEndVersionVector: string | null;\n sourceVersionVector: string | null;\n rekeyCount: number;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentRecordPersistence.js","sourceRoot":"","sources":["documentRecordPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, desc, eq, sql } from \"drizzle-orm\";\nimport { deserializeDocumentSyncPullContinuation } from \"../../documents/shared/sync/pullContinuation\";\nimport { normalizeEffectiveAccessLevel } from \"../../keying/accessLevel\";\nimport { documentHistoryUpdates, documents } from \"../schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../sqlSchema\";\nimport type {\n DocumentRecord,\n DocumentScope,\n SelectedDocumentRecordRow,\n} from \"./documentPersistenceTypes\";\n\n/**\n * The ONE select shape for a full documents-row record: every reader that\n * feeds mapSelectedDocumentRecord spreads this, so a new record column cannot\n * silently miss one of them.\n */\nexport const documentRecordSelection = {\n id: documents.localId,\n documentId: documents.documentId,\n recoveryGeneration: documents.recoveryGeneration,\n recoveryDocumentId: documents.recoveryDocumentId,\n snapshotEndVersion: documents.snapshotEndVersion,\n accessEpoch: documents.accessEpoch,\n accessStateHash: documents.accessStateHash,\n effectiveAccessLevel: documents.effectiveAccessLevel,\n lastCommitLsn: documents.lastCommitLsn,\n documentManifestBundle: documents.documentManifestBundle,\n contentKeyBundle: documents.contentKeyBundle,\n documentKekTargets: documents.documentKekTargets,\n pendingBaseVersion: documents.pendingBaseVersion,\n pullContinuation: documents.pullContinuation,\n};\n\nexport function mapSelectedDocumentRecord(\n row: SelectedDocumentRecordRow,\n): DocumentRecord {\n const record: DocumentRecord = {\n id: row.id,\n documentId: row.documentId,\n recoveryGeneration: row.recoveryGeneration,\n snapshotEndVersion: row.snapshotEndVersion,\n accessEpoch: row.accessEpoch,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n row.effectiveAccessLevel,\n ),\n lastCommitLsn: row.lastCommitLsn,\n contentKeyBundle: row.contentKeyBundle,\n documentKekTargets: row.documentKekTargets,\n documentManifestBundle: row.documentManifestBundle,\n };\n\n if (row.accessStateHash !== null) {\n record.accessStateHash = row.accessStateHash;\n }\n\n if (row.recoveryDocumentId !== null) {\n record.recoveryDocumentId = row.recoveryDocumentId;\n }\n\n // Only surface the marker when one was persisted, so a row that never stored\n // one keeps its prior shape (and init falls through to seeding it).\n if (row.pendingBaseVersion !== null) {\n record.pendingBaseVersion = row.pendingBaseVersion;\n }\n\n const pullContinuation = deserializeDocumentSyncPullContinuation(\n row.pullContinuation,\n );\n if (pullContinuation !== null) {\n record.pullContinuation = pullContinuation;\n } else if (row.pullContinuation !== null) {\n record.pullContinuationRecoveryRequired = true;\n }\n\n return record;\n}\n\nexport async function loadDocumentRecord(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<DocumentRecord | null> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select(documentRecordSelection)\n .from(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n ),\n )\n .limit(1);\n\n return rows[0] ? mapSelectedDocumentRecord(rows[0]) : null;\n}\n\nexport async function findLocalIdByDocumentId(\n execSql: ExecSql,\n appKind: string,\n documentId: string,\n): Promise<string | null> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const hasPendingUpdates = sql<number>`EXISTS (\n SELECT 1\n FROM ${documentHistoryUpdates}\n WHERE ${documentHistoryUpdates.appKind} = ${documents.appKind}\n AND ${documentHistoryUpdates.localId} = ${documents.localId}\n AND ${documentHistoryUpdates.updateId} IS NOT NULL\n )`;\n const hasPendingLocalWork = sql<number>`(\n ${hasPendingUpdates}\n OR (\n ${documents.pendingBaseVersion} IS NOT NULL\n AND ${documents.pendingBaseVersion} <> ${documents.snapshotEndVersion}\n )\n )`;\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(eq(documents.appKind, appKind), eq(documents.documentId, documentId)),\n )\n // Duplicate remote identities can survive an interrupted local adoption.\n // Preserve queued or deferred edits, then make the fallback stable.\n .orderBy(\n desc(hasPendingLocalWork),\n desc(documents.updatedAt),\n desc(documents.localId),\n )\n .limit(1);\n\n return rows[0]?.localId ?? null;\n}\n\nexport async function deleteDocumentRecord(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .delete(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n ),\n )\n .run();\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentSyncFailurePersistence.js","sourceRoot":"","sources":["documentSyncFailurePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, isNotNull } from \"drizzle-orm\";\nimport {\n documents,\n documentTables,\n localIntents,\n localIntentTables,\n} from \"../schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlSchema\";\nimport type { DocumentScope } from \"./documentPersistenceTypes\";\n\ninterface DocumentSyncFailureFields {\n readonly attemptedAt: string;\n readonly message: string;\n readonly status: number | null;\n}\n\n/** The `documents` column values of a scope with no recorded failure. */\nexport const CLEARED_DOCUMENT_SYNC_FAILURE = {\n syncFailureAttemptedAt: null,\n syncFailureMessage: null,\n syncFailureStatus: null,\n} as const;\n\nfunction scopeWhere(scope: DocumentScope) {\n return and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n );\n}\n\n/**\n * Record the last terminal failure or incoming-update quarantine on a document\n * scope's row. The durable pending-update queue has no status columns, so\n * these columns let the write-queue view explain a blocked document. A newer\n * failure replaces the old. A scope with no `documents` row has nothing left\n * to explain, so the update is a no-op there.\n */\nexport async function recordDocumentSyncFailure(\n execSql: ExecSql,\n scope: DocumentScope,\n failure: DocumentSyncFailureFields,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .update(documents)\n .set({\n syncFailureAttemptedAt: failure.attemptedAt,\n syncFailureMessage: failure.message,\n syncFailureStatus: failure.status,\n })\n .where(scopeWhere(scope))\n .run();\n });\n}\n\n/**\n * Whether any queued local write has recorded a terminal failure — a document\n * row carrying a sync failure or an intent row carrying `last_error`. This is\n * the evidence gate for recovery triggers (e.g. re-arming write lanes when org\n * access is restored): without it a transient denial during bootstrap would\n * fire recovery work with nothing to recover, racing the startup sync passes.\n */\nexport async function hasRecordedTerminalSyncFailures(\n execSql: ExecSql,\n): Promise<boolean> {\n await ensureSqlTables(execSql, [...documentTables, ...localIntentTables]);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [failure] = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(isNotNull(documents.syncFailureMessage))\n .limit(1);\n if (failure) {\n return true;\n }\n const [intent] = await db\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(isNotNull(localIntents.lastError))\n .limit(1);\n return intent !== undefined;\n}\n\n/** Clear a scope's recorded failure inside a caller's transaction. */\nexport async function clearDocumentSyncFailureInTransaction(\n tx: ClientSQLiteTransactionScope,\n scope: DocumentScope,\n): Promise<void> {\n await tx\n .update(documents)\n .set(CLEARED_DOCUMENT_SYNC_FAILURE)\n .where(scopeWhere(scope))\n .run();\n}\n\n/**\n * Drop the recorded failure for a scope. Called when a later sync pass for the\n * scope succeeds and whenever the scope's local sync state is torn down, so a\n * stale failure never outlives the condition it describes.\n */\nexport async function clearDocumentSyncFailure(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .update(documents)\n .set(CLEARED_DOCUMENT_SYNC_FAILURE)\n .where(scopeWhere(scope))\n .run();\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport {\n DOCUMENT_SYNC_PULL_RECOVERY_REQUIRED,\n type DocumentSyncPullContinuation,\n serializeDocumentSyncPullContinuation,\n} from \"../../documents/shared/sync/pullContinuation\";\nimport { documentProjectionTables, documents, documentTables } from \"../schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../sqlSchema\";\nimport type { DocumentRecord } from \"./documentPersistenceTypes\";\nimport { loadDocumentRecord } from \"./documentRecordPersistence\";\n\nexport function ensureDocumentTables(execSql: ExecSql): Promise<void> {\n return ensureSqlTables(execSql, documentTables);\n}\n\nexport function ensureDocumentProjectionTables(\n execSql: ExecSql,\n): Promise<void> {\n return ensureSqlTables(execSql, documentProjectionTables);\n}\n\n/** Replace only the exact rejected continuation with a durable recovery marker. */\nexport async function invalidateDocumentSyncPullContinuation(\n execSql: ExecSql,\n input: {\n accessEpoch: number;\n accessStateHash: string | null;\n appKind: string;\n continuation: DocumentSyncPullContinuation;\n contentKeyBundle: string | null;\n documentId: string;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n lastCommitLsn: string | null;\n localId: string;\n },\n): Promise<DocumentRecord | null> {\n await ensureDocumentTables(execSql);\n const expectedContinuation = serializeDocumentSyncPullContinuation(\n input.continuation,\n );\n if (expectedContinuation === null) return null;\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const { db } = getClientSQLitePersistenceRuntime(lockedExecSql);\n await db\n .update(documents)\n .set({ pullContinuation: DOCUMENT_SYNC_PULL_RECOVERY_REQUIRED })\n .where(\n and(\n eq(documents.appKind, input.appKind),\n eq(documents.localId, input.localId),\n eq(documents.documentId, input.documentId),\n eq(documents.accessEpoch, input.accessEpoch),\n sql`${documents.accessStateHash} IS ${input.accessStateHash}`,\n sql`${documents.contentKeyBundle} IS ${input.contentKeyBundle}`,\n sql`${documents.documentKekTargets} IS ${input.documentKekTargets}`,\n sql`${documents.documentManifestBundle} IS ${input.documentManifestBundle}`,\n sql`${documents.lastCommitLsn} IS ${input.lastCommitLsn}`,\n eq(documents.pullContinuation, expectedContinuation),\n ),\n )\n .run();\n return loadDocumentRecord(lockedExecSql, {\n appKind: input.appKind,\n localId: input.localId,\n });\n });\n}\n\nexport {\n enqueueDocumentPendingUpdate,\n enqueueDocumentPendingUpdateWithHistory,\n listDocumentPendingUpdates,\n MAX_PENDING_UPDATE_REKEYS,\n rekeyDocumentPendingUpdate,\n resetDocumentPendingUpdateRekeyBudget,\n settleDocumentPendingUpdate,\n unqueueDocumentPendingUpdates,\n} from \"./documentPendingUpdatePersistence\";\nexport type {\n DocumentRecord,\n DocumentScope,\n PendingUpdateFields,\n PendingUpdateRecord,\n} from \"./documentPersistenceTypes\";\nexport {\n deleteDocumentRecord,\n documentRecordSelection,\n findLocalIdByDocumentId,\n loadDocumentRecord,\n mapSelectedDocumentRecord,\n} from \"./documentRecordPersistence\";\nexport {\n clearDocumentSyncFailure,\n hasRecordedTerminalSyncFailures,\n recordDocumentSyncFailure,\n} from \"./documentSyncFailurePersistence\";\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"remoteResetAttachments.js","sourceRoot":"","sources":["remoteResetAttachments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,kCAAkC,EAAE,MAAM,0DAA0D,CAAC;AAC9G,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,KAIlD;IACC,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,KAAK,CAAC,iBAAiB,CAAC,GAAG,CACzB,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,KAAK,UAAU,CAAC,MAAM,EAAE,CAC9D,CACF,CAAC;IACF,KAAK,MAAM,YAAY,IAAI,kBAAkB,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,EAAE;aACxB,MAAM,CAAC;YACN,OAAO,EAAE,0BAA0B,CAAC,OAAO;YAC3C,MAAM,EAAE,0BAA0B,CAAC,MAAM;YACzC,UAAU,EAAE,0BAA0B,CAAC,UAAU;SAClD,CAAC;aACD,IAAI,CAAC,0BAA0B,CAAC;aAChC,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;QACpE,MAAM,kCAAkC,CACtC,KAAK,CAAC,EAAE,EACR,IAAI;aACD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;aACnE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAChC,CAAC;QACF,MAAM,KAAK,CAAC,EAAE;aACX,MAAM,CAAC,0BAA0B,CAAC;aAClC,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;aAChE,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC","sourcesContent":["import { inArray } from \"drizzle-orm\";\nimport { queueDocumentAttachmentStorageKeys } from \"../../data/persistence/documents/internal/orphanSideRows\";\nimport { documentPendingAttachments } from \"../../data/sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport { remoteResetBatches } from \"./remoteResetBatches\";\nimport type { ResetAttachmentUpload } from \"./remoteResetPlans\";\n\n/** Delete reset-scoped pending rows without abandoning dropped local bytes. */\nexport async function clearResetPendingAttachments(input: {\n readonly attachmentUploads: readonly ResetAttachmentUpload[];\n readonly documentLocalIds: readonly string[];\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const requeuedKeys = new Set(\n input.attachmentUploads.map(\n (attachment) => `${attachment.localId}\\0${attachment.slotId}`,\n ),\n );\n for (const localIdBatch of remoteResetBatches(input.documentLocalIds)) {\n const rows = await input.tx\n .select({\n localId: documentPendingAttachments.localId,\n slotId: documentPendingAttachments.slotId,\n storageKey: documentPendingAttachments.storageKey,\n })\n .from(documentPendingAttachments)\n .where(inArray(documentPendingAttachments.localId, localIdBatch));\n await queueDocumentAttachmentStorageKeys(\n input.tx,\n rows\n .filter((row) => !requeuedKeys.has(`${row.localId}\\0${row.slotId}`))\n .map((row) => row.storageKey),\n );\n await input.tx\n .delete(documentPendingAttachments)\n .where(inArray(documentPendingAttachments.localId, localIdBatch))\n .run();\n }\n}\n"]}
@@ -1,13 +0,0 @@
1
- // Keep bulk inserts, IN predicates, and expanded pair predicates comfortably
2
- // below SQLite's common 999-bind and expression-depth limits. Some queued rows
3
- // consume more than ten binds each, so one conservative size covers every
4
- // reset statement.
5
- export const REMOTE_RESET_SQL_BATCH_SIZE = 50;
6
- export function remoteResetBatches(values) {
7
- const batches = [];
8
- for (let offset = 0; offset < values.length; offset += REMOTE_RESET_SQL_BATCH_SIZE) {
9
- batches.push(values.slice(offset, offset + REMOTE_RESET_SQL_BATCH_SIZE));
10
- }
11
- return batches;
12
- }
13
- //# sourceMappingURL=remoteResetBatches.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"remoteResetBatches.js","sourceRoot":"","sources":["remoteResetBatches.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,0EAA0E;AAC1E,mBAAmB;AACnB,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAE9C,MAAM,UAAU,kBAAkB,CAChC,MAAoB;IAEpB,MAAM,OAAO,GAAU,EAAE,CAAC;IAC1B,KACE,IAAI,MAAM,GAAG,CAAC,EACd,MAAM,GAAG,MAAM,CAAC,MAAM,EACtB,MAAM,IAAI,2BAA2B,EACrC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,2BAA2B,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["// Keep bulk inserts, IN predicates, and expanded pair predicates comfortably\n// below SQLite's common 999-bind and expression-depth limits. Some queued rows\n// consume more than ten binds each, so one conservative size covers every\n// reset statement.\nexport const REMOTE_RESET_SQL_BATCH_SIZE = 50;\n\nexport function remoteResetBatches<T>(\n values: readonly T[],\n): readonly (readonly T[])[] {\n const batches: T[][] = [];\n for (\n let offset = 0;\n offset < values.length;\n offset += REMOTE_RESET_SQL_BATCH_SIZE\n ) {\n batches.push(values.slice(offset, offset + REMOTE_RESET_SQL_BATCH_SIZE));\n }\n return batches;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"remoteResetCursorScope.js","sourceRoot":"","sources":["remoteResetCursorScope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AACvD,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AACjD,6EAA6E;AAC7E,0EAA0E;AAC1E,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAOrC,MAAM,UAAU,uBAAuB,CAAC,KAGvC;IACC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,wBAAwB,EAAE,CAAC;QACpD,OAAO,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,qBAAqB;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,CACL,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC;QAC/C,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KAGjD;IACC,mEAAmE;IACnE,MAAM,KAAK,GAAG,uBAAuB,CAAC;IACtC,MAAM,KAAK,CAAC,EAAE;SACX,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EACzC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAC/B,CACF;SACA,GAAG,EAAE,CAAC;IACT,KAAK,MAAM,cAAc,IAAI,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QACpE,MAAM,aAAa,GAAG,cAAc,CAAC,GAAG,CACtC,CAAC,WAAW,EAAE,EAAE,CAAC,GAAG,kBAAkB,GAAG,WAAW,EAAE,CACvD,CAAC;QACF,MAAM,KAAK,CAAC,EAAE;aACX,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CACJ,EAAE,CACA,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EACzC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,CACrC,EACD,GAAG,CACD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,wBAAwB,CAAC,EAC5C,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,CACtC,CACF,CACF;aACA,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC","sourcesContent":["import { and, eq, inArray, or } from \"drizzle-orm\";\nimport { containerSyncWatermarks } from \"../../data/sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport { remoteResetBatches } from \"./remoteResetBatches\";\n\nconst CONTAINER_DOCUMENTS_LANE = \"container_documents\";\nconst CONTAINER_PARENT_LANE = \"container_parent\";\n// The API root feed lists every accessible organization. Its one cursor must\n// reset on any organization's purge; child feeds use globally unique IDs.\nconst ROOT_LANE_ID = \"root\";\nconst PARENT_LANE_PREFIX = \"parent:\";\n\ninterface SyncCursorRow {\n readonly laneId: string;\n readonly laneKind: string;\n}\n\nexport function isRemoteResetSyncCursor(input: {\n containerIds: ReadonlySet<string>;\n row: SyncCursorRow;\n}): boolean {\n if (input.row.laneKind === CONTAINER_DOCUMENTS_LANE) {\n return input.containerIds.has(input.row.laneId);\n }\n if (input.row.laneKind !== CONTAINER_PARENT_LANE) return false;\n if (input.row.laneId === ROOT_LANE_ID) return true;\n return (\n input.row.laneId.startsWith(PARENT_LANE_PREFIX) &&\n input.containerIds.has(input.row.laneId.slice(PARENT_LANE_PREFIX.length))\n );\n}\n\nexport async function clearRemoteResetSyncCursors(input: {\n containerIds: readonly string[];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n // One row per lane holds both the cursor and its freshness marker.\n const table = containerSyncWatermarks;\n await input.tx\n .delete(table)\n .where(\n and(\n eq(table.laneKind, CONTAINER_PARENT_LANE),\n eq(table.laneId, ROOT_LANE_ID),\n ),\n )\n .run();\n for (const containerBatch of remoteResetBatches(input.containerIds)) {\n const parentLaneIds = containerBatch.map(\n (containerId) => `${PARENT_LANE_PREFIX}${containerId}`,\n );\n await input.tx\n .delete(table)\n .where(\n or(\n and(\n eq(table.laneKind, CONTAINER_PARENT_LANE),\n inArray(table.laneId, parentLaneIds),\n ),\n and(\n eq(table.laneKind, CONTAINER_DOCUMENTS_LANE),\n inArray(table.laneId, containerBatch),\n ),\n ),\n )\n .run();\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"remoteResetPlans.js","sourceRoot":"","sources":["remoteResetPlans.ts"],"names":[],"mappings":"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","sourcesContent":["import { createDocument, exportAllUpdates } from \"@tearleads/loro\";\nimport { and, eq, ne, or, sql } from \"drizzle-orm\";\nimport {\n type DocumentAttachment,\n getDocumentAttachments,\n} from \"../../data/documents\";\nimport { createPendingUpdateFields } from \"../../data/documents/documentSync\";\nimport { DOCUMENTS_APP_KIND } from \"../../data/persistence/documents/documentsPersistence\";\nimport {\n documentAttachmentBlobProjection,\n documentHistoryCheckpoints,\n documentHistoryUpdates,\n documentPendingAttachments,\n documents,\n} from \"../../data/sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../data/sqlite/sqlitePersistenceRuntime\";\nimport { importDocumentHistoryTailUpdates } from \"../documents\";\nimport { remoteResetBatches } from \"./remoteResetBatches\";\n\nexport interface ResetDocumentUpdate {\n readonly appKind: string;\n readonly localId: string;\n readonly updateData: string;\n readonly partialStartVersionVector: string;\n readonly partialEndVersionVector: string;\n readonly sourceVersionVector: string | null;\n}\n\nexport interface ResetAttachmentUpload {\n readonly byteLength: number;\n readonly contentSha256: string;\n readonly localId: string;\n readonly mimeType: string | null;\n readonly name: string;\n readonly slotId: string;\n readonly storageKey: string;\n}\n\ntype ResetContentDoc = Awaited<ReturnType<typeof createDocument>>;\n\nfunction historyScopeKey(appKind: string, localId: string): string {\n return `${appKind} ${localId}`;\n}\n\nfunction attachmentScopeKey(localId: string, slotId: string): string {\n return `${localId}\\0${slotId}`;\n}\n\nfunction buildResetUpdate(input: {\n appKind: string;\n doc: ResetContentDoc;\n localId: string;\n}): ResetDocumentUpdate | null {\n const fields = createPendingUpdateFields(exportAllUpdates(input.doc));\n if (!fields) {\n return null;\n }\n\n return {\n appKind: input.appKind,\n localId: input.localId,\n updateData: fields.updateData,\n partialStartVersionVector: fields.partialStartVersionVector,\n partialEndVersionVector: fields.partialEndVersionVector,\n sourceVersionVector: fields.sourceVersionVector ?? null,\n };\n}\n\ninterface ResetHistoryRows {\n checkpointRows: Array<{\n appKind: string;\n localId: string;\n snapshot: string;\n }>;\n tailRows: Array<{\n appKind: string;\n localId: string;\n updateData: string;\n }>;\n}\n\nasync function loadResetHistoryRows(\n db: ClientSQLiteTransactionScope,\n documentScopes?: readonly ResetDocumentScope[],\n): Promise<ResetHistoryRows> {\n const rows: ResetHistoryRows = { checkpointRows: [], tailRows: [] };\n const scopes = documentScopes\n ? [\n ...new Map(\n documentScopes.map((scope) => [\n historyScopeKey(scope.appKind, scope.localId),\n scope,\n ]),\n ).values(),\n ]\n : null;\n for (const scopeBatch of scopes ? remoteResetBatches(scopes) : [null]) {\n // An outbox row only waits to be sent; the content lives in the\n // checkpoint and tail rows (see `documentHistoryUpdates`).\n const notOutbox = ne(documentHistoryUpdates.origin, \"outbox\");\n const scopeTail = scopeBatch\n ? and(\n notOutbox,\n or(\n ...scopeBatch.map((scope) =>\n and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n ),\n ),\n ),\n )\n : notOutbox;\n const scopeCheckpoints = scopeBatch\n ? or(\n ...scopeBatch.map((scope) =>\n and(\n eq(documentHistoryCheckpoints.appKind, scope.appKind),\n eq(documentHistoryCheckpoints.localId, scope.localId),\n ),\n ),\n )\n : undefined;\n const tailBatch = await db\n .select({\n appKind: documentHistoryUpdates.appKind,\n localId: documentHistoryUpdates.localId,\n updateData: documentHistoryUpdates.updateData,\n })\n .from(documentHistoryUpdates)\n .where(scopeTail)\n .orderBy(sql`rowid`);\n const checkpointBatch = await db\n .select({\n appKind: documentHistoryCheckpoints.appKind,\n localId: documentHistoryCheckpoints.localId,\n snapshot: documentHistoryCheckpoints.snapshot,\n })\n .from(documentHistoryCheckpoints)\n .where(scopeCheckpoints);\n rows.tailRows.push(...tailBatch);\n rows.checkpointRows.push(...checkpointBatch);\n }\n return rows;\n}\n\n/**\n * Reconstruct every persisted document's content from the durable-history\n * tables (checkpoint + tail) — the only content source. A scope without a\n * checkpoint (a discovered shell that never hydrated) gets no doc: it has no\n * content to republish and no attachments to requeue. The mode-sniffing tail\n * import handles both content kinds — full-history snapshots (documents) and\n * exported-updates blobs (container metadata).\n */\nasync function buildResetContentDocs(\n db: ClientSQLiteTransactionScope,\n documentScopes?: readonly ResetDocumentScope[],\n): Promise<Map<string, ResetContentDoc>> {\n // Read the TAIL before the checkpoints (the same order the restore path\n // uses): a compaction landing between the two reads then yields old-tail +\n // new-checkpoint — a safe superset, since replay is idempotent by op\n // identity — whereas the reverse order could yield an old checkpoint plus\n // an already-emptied tail and republish stale content.\n const { checkpointRows, tailRows } = await loadResetHistoryRows(\n db,\n documentScopes,\n );\n\n const tailByScope = new Map<string, string[]>();\n for (const row of tailRows) {\n const key = historyScopeKey(row.appKind, row.localId);\n const tail = tailByScope.get(key);\n if (tail) {\n tail.push(row.updateData);\n } else {\n tailByScope.set(key, [row.updateData]);\n }\n }\n\n // Rebuild the UNION of checkpoint and tail scopes: a tail-only scope (a\n // crash landed the first edit's tail row before the birth checkpoint) may\n // hold the only durable copy of that edit, and dropping it from the reset\n // would discard it.\n const checkpointByScope = new Map(\n checkpointRows.map((row) => [\n historyScopeKey(row.appKind, row.localId),\n row,\n ]),\n );\n const historyScopes = new Map<string, { appKind: string; localId: string }>();\n for (const row of [...checkpointRows, ...tailRows]) {\n historyScopes.set(historyScopeKey(row.appKind, row.localId), {\n appKind: row.appKind,\n localId: row.localId,\n });\n }\n\n const contentDocByScope = new Map<string, ResetContentDoc>();\n await Promise.all(\n [...historyScopes.entries()].map(async ([key, scope]) => {\n const doc = await createDocument(\n `remote-reset:${scope.appKind}:${scope.localId}`,\n );\n const checkpoint = checkpointByScope.get(key);\n // An empty checkpoint blob (e.g. container metadata saved before any\n // update existed) carries no ops — importing it would throw and fail\n // the whole reset.\n importDocumentHistoryTailUpdates(\n doc,\n [\n ...(checkpoint ? [checkpoint.snapshot] : []),\n ...(tailByScope.get(key) ?? []),\n ].filter((blob) => blob.length > 0),\n );\n contentDocByScope.set(key, doc);\n }),\n );\n return contentDocByScope;\n}\n\nexport interface ResetDocumentScope {\n readonly appKind: string;\n readonly localId: string;\n}\n\nasync function loadResetPlanRows(\n db: ClientSQLiteTransactionScope,\n documentScopes?: readonly ResetDocumentScope[],\n) {\n const selectedScopeKeys = documentScopes\n ? new Set(\n documentScopes.map((scope) =>\n historyScopeKey(scope.appKind, scope.localId),\n ),\n )\n : null;\n const allDocumentRows = await db\n .select({ appKind: documents.appKind, localId: documents.localId })\n .from(documents);\n const documentRows = selectedScopeKeys\n ? allDocumentRows.filter((row) =>\n selectedScopeKeys.has(historyScopeKey(row.appKind, row.localId)),\n )\n : allDocumentRows;\n const [allAttachmentRows, pendingAttachmentRows] = await Promise.all([\n db\n .select({\n byteLength: documentAttachmentBlobProjection.byteLength,\n localId: documentAttachmentBlobProjection.localId,\n mimeType: documentAttachmentBlobProjection.mimeType,\n slotId: documentAttachmentBlobProjection.slotId,\n storageKey: documentAttachmentBlobProjection.storageKey,\n })\n .from(documentAttachmentBlobProjection),\n db\n .select({\n byteLength: documentPendingAttachments.byteLength,\n localId: documentPendingAttachments.localId,\n mimeType: documentPendingAttachments.mimeType,\n slotId: documentPendingAttachments.slotId,\n storageKey: documentPendingAttachments.storageKey,\n })\n .from(documentPendingAttachments),\n ]);\n const selectedDocumentLocalIds = new Set(\n documentRows\n .filter((row) => row.appKind === DOCUMENTS_APP_KIND)\n .map((row) => row.localId),\n );\n const attachmentRows = new Map(\n allAttachmentRows\n .filter((row) => selectedDocumentLocalIds.has(row.localId))\n .map((row) => [attachmentScopeKey(row.localId, row.slotId), row]),\n );\n for (const row of pendingAttachmentRows) {\n if (selectedDocumentLocalIds.has(row.localId)) {\n attachmentRows.set(attachmentScopeKey(row.localId, row.slotId), row);\n }\n }\n return {\n attachmentRows: [...attachmentRows.values()],\n documentRows,\n };\n}\n\nexport async function buildResetPlans(\n db: ClientSQLiteTransactionScope,\n documentScopes?: readonly ResetDocumentScope[],\n): Promise<{\n readonly attachmentUploads: ResetAttachmentUpload[];\n readonly documentUpdates: ResetDocumentUpdate[];\n}> {\n const { attachmentRows, documentRows } = await loadResetPlanRows(\n db,\n documentScopes,\n );\n const contentDocByScope = await buildResetContentDocs(db, documentScopes);\n const documentUpdates = documentRows.flatMap((row) => {\n const doc = contentDocByScope.get(\n historyScopeKey(row.appKind, row.localId),\n );\n if (!doc) {\n return [];\n }\n const update = buildResetUpdate({\n appKind: row.appKind,\n doc,\n localId: row.localId,\n });\n return update ? [update] : [];\n });\n const attachmentIntentMaps = new Map<\n string,\n Map<string, DocumentAttachment>\n >();\n const attachmentLocalIds = [\n ...new Set(attachmentRows.map((attachment) => attachment.localId)),\n ];\n for (const localId of attachmentLocalIds) {\n const doc = contentDocByScope.get(\n historyScopeKey(DOCUMENTS_APP_KIND, localId),\n );\n if (!doc) {\n continue;\n }\n attachmentIntentMaps.set(\n localId,\n new Map(\n getDocumentAttachments(doc).map((attachment) => [\n attachment.slotId,\n attachment,\n ]),\n ),\n );\n }\n\n // A reset re-uploads the local attachments as pending work, and the durable\n // document decides which rows those are: a row whose slot the snapshot no\n // longer advertises belongs to an unlink, and re-queueing it would resurrect\n // an attachment the document dropped. Reading the snapshot rather than the\n // detach marker keeps the two halves of an interrupted unlink consistent —\n // there the marker is set but the snapshot still advertises the slot, and the\n // reset has to upload it to match the document it is about to republish.\n const attachmentUploads = attachmentRows.flatMap((attachment) => {\n const intent = attachmentIntentMaps\n .get(attachment.localId)\n ?.get(attachment.slotId);\n if (intent === undefined) {\n return [];\n }\n\n return [\n {\n byteLength: attachment.byteLength,\n contentSha256: intent.contentSha256,\n localId: attachment.localId,\n mimeType: attachment.mimeType,\n name: intent.name,\n slotId: attachment.slotId,\n storageKey: attachment.storageKey,\n },\n ];\n });\n\n return { attachmentUploads, documentUpdates };\n}\n"]}