@tearleads/client-sdk 0.1.79 → 0.1.80

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 (143) hide show
  1. package/client/deviceFirst/index.d.ts +1 -1
  2. package/client/deviceFirst/index.js +1 -1
  3. package/client/deviceFirst/index.js.map +1 -1
  4. package/client/runtime/principalMutationApi.js +1 -1
  5. package/client/runtime/principalMutationApi.js.map +1 -1
  6. package/client/runtime/principalMutationDispatch.js +1 -1
  7. package/client/runtime/principalMutationDispatch.js.map +1 -1
  8. package/client/runtime/rootContainerAdoption.js.map +1 -1
  9. package/client/runtime/workflowRuntime.d.ts +1 -1
  10. package/client/runtime/workflowRuntime.js.map +1 -1
  11. package/client/session/sessionPurgeRecovery.js +1 -1
  12. package/client/session/sessionPurgeRecovery.js.map +1 -1
  13. package/data/blobs/attachments/projection.js +2 -3
  14. package/data/blobs/attachments/projection.js.map +1 -1
  15. package/data/documents/documentConstants.d.ts +1 -0
  16. package/data/documents/documentConstants.js +1 -0
  17. package/data/documents/documentConstants.js.map +1 -1
  18. package/data/documents/shared/containerKek/containerKekEntryVerification.d.ts +3 -0
  19. package/data/documents/shared/containerKek/index.d.ts +5 -0
  20. package/data/documents/shared/containerKek/index.js +9 -0
  21. package/data/documents/shared/containerKek/index.js.map +1 -0
  22. package/data/documents/shared/projection/index.d.ts +1 -1
  23. package/data/documents/shared/projection/index.js +1 -1
  24. package/data/documents/shared/projection/index.js.map +1 -1
  25. package/data/documents/shared/sync/syncResponseAuthorization.js +1 -1
  26. package/data/documents/shared/sync/syncResponseAuthorization.js.map +1 -1
  27. package/data/keyingProjectionVerification/container/containerCreateManifest.d.ts +12 -0
  28. package/data/keyingProjectionVerification/container/containerDestinationVerification.d.ts +16 -0
  29. package/data/keyingProjectionVerification/index.d.ts +4 -0
  30. package/data/keyingProjectionVerification/index.js +5 -1
  31. package/data/keyingProjectionVerification/index.js.map +1 -1
  32. package/data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence.d.ts +3 -0
  33. package/data/keyingProjectionVerification/principalPolicy/principalPolicyVerification.d.ts +24 -0
  34. package/data/persistence/container-contents/documentPlacement.js +1 -1
  35. package/data/persistence/container-contents/documentPlacement.js.map +1 -1
  36. package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js +1 -1
  37. package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js.map +1 -1
  38. package/data/persistence/documents/documentsPersistence.d.ts +1 -1
  39. package/data/persistence/documents/documentsPersistence.js +2 -3
  40. package/data/persistence/documents/documentsPersistence.js.map +1 -1
  41. package/data/persistence/documents/internal/containerDocumentTombstones.js +1 -1
  42. package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
  43. package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js +1 -1
  44. package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js.map +1 -1
  45. package/data/persistence/documents/internal/documentDeletionPersistence.js +1 -1
  46. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  47. package/data/persistence/documents/internal/documentMutationPersistence.js +1 -1
  48. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  49. package/data/persistence/documents/internal/documentProjectionRows.js +1 -2
  50. package/data/persistence/documents/internal/documentProjectionRows.js.map +1 -1
  51. package/data/persistence/documents/internal/documentPullContinuationPersistence.js +1 -1
  52. package/data/persistence/documents/internal/documentPullContinuationPersistence.js.map +1 -1
  53. package/data/persistence/documents/internal/documentRows.js +1 -2
  54. package/data/persistence/documents/internal/documentRows.js.map +1 -1
  55. package/data/persistence/documents/internal/orphanSideRows.js +1 -1
  56. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  57. package/data/persistence/documents/internal/pendingCreateAdoption.js +1 -1
  58. package/data/persistence/documents/internal/pendingCreateAdoption.js.map +1 -1
  59. package/data/persistence/documents/internal/rowQueryPersistence.js +1 -1
  60. package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
  61. package/package.json +1 -1
  62. package/stores/local-projection/localProjectionStore.d.ts +1 -1
  63. package/stores/local-projection/localProjectionStore.js +1 -1
  64. package/stores/local-projection/localProjectionStore.js.map +1 -1
  65. package/stores/local-projection/registry.d.ts +1 -1
  66. package/stores/local-projection/registry.js.map +1 -1
  67. package/stores/local-projection/types.d.ts +1 -1
  68. package/stores/local-projection/types.js.map +1 -1
  69. package/workflows/blobs/hydration/decrypt.js +1 -2
  70. package/workflows/blobs/hydration/decrypt.js.map +1 -1
  71. package/workflows/blobs/hydration/hydrate.d.ts +1 -1
  72. package/workflows/blobs/hydration/hydrate.js.map +1 -1
  73. package/workflows/container-contents/container-state/create/createAdoption.js +1 -2
  74. package/workflows/container-contents/container-state/create/createAdoption.js.map +1 -1
  75. package/workflows/container-contents/container-state/purge/purgeTreeScope.js +1 -1
  76. package/workflows/container-contents/container-state/purge/purgeTreeScope.js.map +1 -1
  77. package/workflows/container-contents/info/documentInfo.js +1 -1
  78. package/workflows/container-contents/info/documentInfo.js.map +1 -1
  79. package/workflows/container-contents/metadata/index.js +1 -2
  80. package/workflows/container-contents/metadata/index.js.map +1 -1
  81. package/workflows/container-contents/metadata/metadataMutationPreparation.js +1 -1
  82. package/workflows/container-contents/metadata/metadataMutationPreparation.js.map +1 -1
  83. package/workflows/container-contents/metadata/metadataPullContinuationInvalidation.js +1 -1
  84. package/workflows/container-contents/metadata/metadataPullContinuationInvalidation.js.map +1 -1
  85. package/workflows/container-contents/metadata/metadataSyncErrors.js +1 -1
  86. package/workflows/container-contents/metadata/metadataSyncErrors.js.map +1 -1
  87. package/workflows/container-contents/metadata/metadataSyncSettlement.d.ts +1 -1
  88. package/workflows/container-contents/metadata/metadataSyncSettlement.js.map +1 -1
  89. package/workflows/container-contents/metadata/metadataTypes.d.ts +1 -1
  90. package/workflows/container-contents/metadata/metadataTypes.js.map +1 -1
  91. package/workflows/container-contents/pendingWrites/index.js +1 -1
  92. package/workflows/container-contents/pendingWrites/index.js.map +1 -1
  93. package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js +1 -3
  94. package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js.map +1 -1
  95. package/workflows/containers/child/create/index.js +1 -1
  96. package/workflows/containers/child/create/index.js.map +1 -1
  97. package/workflows/containers/child/move/moveRotation.js +1 -1
  98. package/workflows/containers/child/move/moveRotation.js.map +1 -1
  99. package/workflows/containers/child/move/moveWraps.js +1 -1
  100. package/workflows/containers/child/move/moveWraps.js.map +1 -1
  101. package/workflows/containers/child/rekey/rekeyProjection.js +1 -1
  102. package/workflows/containers/child/rekey/rekeyProjection.js.map +1 -1
  103. package/workflows/containers/child/rotation/rotationContext.js +1 -2
  104. package/workflows/containers/child/rotation/rotationContext.js.map +1 -1
  105. package/workflows/containers/child/share/shareAncestorRepair.js +1 -2
  106. package/workflows/containers/child/share/shareAncestorRepair.js.map +1 -1
  107. package/workflows/containers/index.d.ts +2 -3
  108. package/workflows/containers/index.js +1 -2
  109. package/workflows/containers/index.js.map +1 -1
  110. package/workflows/containers/writeRefusal.js +1 -1
  111. package/workflows/containers/writeRefusal.js.map +1 -1
  112. package/workflows/documents/linkSet/linkSetProjectionSeed.js +1 -1
  113. package/workflows/documents/linkSet/linkSetProjectionSeed.js.map +1 -1
  114. package/workflows/documents/syncRekeys/syncAutomaticContainerRekeys.js +1 -1
  115. package/workflows/documents/syncRekeys/syncAutomaticContainerRekeys.js.map +1 -1
  116. package/workflows/organizations/groupMetadata/groupMetadataAccess.js +1 -1
  117. package/workflows/organizations/groupMetadata/groupMetadataAccess.js.map +1 -1
  118. package/workflows/organizations/provisioning/createOrganization.d.ts +1 -1
  119. package/workflows/organizations/provisioning/createOrganization.js +1 -1
  120. package/workflows/organizations/provisioning/createOrganization.js.map +1 -1
  121. package/workflows/organizations/provisioning/organizationProvisioningAttempt.d.ts +1 -1
  122. package/workflows/organizations/provisioning/organizationProvisioningAttempt.js.map +1 -1
  123. package/workflows/organizations/readModel/listLocalOrganizations.js +1 -1
  124. package/workflows/organizations/readModel/listLocalOrganizations.js.map +1 -1
  125. package/workflows/registration/index.d.ts +2 -1
  126. package/workflows/registration/index.js +2 -1
  127. package/workflows/registration/index.js.map +1 -1
  128. package/workflows/registration/organizationProvisioning.d.ts +39 -0
  129. package/workflows/registration/organizationProvisioning.js +211 -0
  130. package/workflows/registration/organizationProvisioning.js.map +1 -0
  131. package/workflows/registration/organizationProvisioningArtifacts.d.ts +2 -3
  132. package/workflows/registration/organizationProvisioningArtifacts.js.map +1 -1
  133. package/workflows/registration/provisioningBootstrapBuilders.d.ts +3 -3
  134. package/workflows/registration/provisioningBootstrapBuilders.js +3 -4
  135. package/workflows/registration/provisioningBootstrapBuilders.js.map +1 -1
  136. package/workflows/registration/registerIdentity.d.ts +2 -39
  137. package/workflows/registration/registerIdentity.js +2 -207
  138. package/workflows/registration/registerIdentity.js.map +1 -1
  139. package/workflows/sync/remoteResetPlans.js +2 -2
  140. package/workflows/sync/remoteResetPlans.js.map +1 -1
  141. package/data/persistence/documents/internal/constants.d.ts +0 -1
  142. package/data/persistence/documents/internal/constants.js +0 -2
  143. package/data/persistence/documents/internal/constants.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"containerDocumentTombstones.js","sourceRoot":"","sources":["containerDocumentTombstones.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EACL,2BAA2B,EAC3B,kBAAkB,EAClB,SAAS,GACV,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,iCAAiC,GAClC,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAAE,gCAAgC,EAAE,MAAM,4CAA4C,CAAC;AAC9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,wCAAwC,EAAE,MAAM,mCAAmC,CAAC;AAC7F,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAElC,SAAS,iCAAiC,CACxC,UAA0D;IAE1D,OAAO,KAAK,CAAC,IAAI,CACf,IAAI,GAAG,CACL,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;QAC5B,GAAG,SAAS,CAAC,UAAU,SAAS,SAAS,CAAC,WAAW,EAAE;QACvD,SAAS;KACV,CAAC,CACH,CAAC,MAAM,EAAE,CACX,CAAC;AACJ,CAAC;AAED,SAAS,oCAAoC,CAC3C,gBAAgE;IAMhE,MAAM,+BAA+B,GAAG,IAAI,GAAG,EAAuB,CAAC;IACvE,MAAM,8BAA8B,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjE,MAAM,sCAAsC,GAAG,IAAI,GAAG,EAGnD,CAAC;IAEJ,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;QACzC,sCAAsC,CAAC,GAAG,CACxC,SAAS,CAAC,UAAU,EACpB,IAAI,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,CACtC,CAAC;QACF,MAAM,mBAAmB,GACvB,+BAA+B,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;QACzE,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC/C,+BAA+B,CAAC,GAAG,CACjC,SAAS,CAAC,UAAU,EACpB,mBAAmB,CACpB,CAAC;QACF,8BAA8B,CAAC,GAAG,CAChC,SAAS,CAAC,UAAU,EACpB,kBAAkB,CAChB,8BAA8B,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EACxD,SAAS,CAAC,SAAS,CACpB,CACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,+BAA+B;QAC/B,8BAA8B;QAC9B,sCAAsC;KACvC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,oCAAoC,CACjD,EAAgC,EAChC,gBAAgE,EAChE,sCAGC;IAED,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;QACzC,MAAM,EAAE;aACL,MAAM,CAAC,2BAA2B,CAAC;aACnC,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,2BAA2B,CAAC,UAAU,EAAE,SAAS,CAAC,UAAU,CAAC,EAChE,EAAE,CAAC,2BAA2B,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,CACnE,CACF;aACA,GAAG,EAAE,CAAC;IACX,CAAC;IACD,KAAK,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,sCAAsC,EAAE,CAAC;QAC1E,MAAM,EAAE;aACL,MAAM,CAAC,2BAA2B,CAAC;aACnC,KAAK,CACJ,MAAM,CAAC,IAAI,KAAK,CAAC;YACf,CAAC,CAAC,EAAE,CAAC,2BAA2B,CAAC,UAAU,EAAE,UAAU,CAAC;YACxD,CAAC,CAAC,GAAG,CACD,EAAE,CAAC,2BAA2B,CAAC,UAAU,EAAE,UAAU,CAAC,EACtD,UAAU,CAAC,2BAA2B,CAAC,WAAW,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CACjE,CACN;aACA,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAC5B,qBAA4C,EAC5C,0BAA+C;IAE/C,OAAO,CACL,qBAAqB,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CACzC,0BAA0B,CAAC,GAAG,CAAC,WAAW,CAAC,CAC5C,IAAI,IAAI,CACV,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,6CAA6C,CAAC,KAM5D;IACC,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IAC1E,yEAAyE;IACzE,wEAAwE;IACxE,6EAA6E;IAC7E,4EAA4E;IAC5E,+EAA+E;IAC/E,4EAA4E;IAC5E,wEAAwE;IACxE,iDAAiD;IACjD,MAAM,QAAQ,GAAG,CACf,MAAM,EAAE;SACL,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;SACtC,IAAI,CAAC,SAAS,CAAC;SACf,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,kBAAkB,CAAC,EACzC,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CACrC,CACF,CACJ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,EAAE;SAC5B,MAAM,CAAC;QACN,OAAO,EAAE,kBAAkB,CAAC,OAAO;QACnC,WAAW,EAAE,kBAAkB,CAAC,WAAW;QAC3C,SAAS,EAAE,kBAAkB,CAAC,SAAS;KACxC,CAAC;SACD,IAAI,CAAC,kBAAkB,CAAC;SACxB,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxD,4EAA4E;IAC5E,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,sBAAsB,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAC5D,GAAG,CAAC,OAAO,KAAK,IAAI;QACpB,GAAG,CAAC,WAAW,KAAK,IAAI;QACxB,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;YACvC,CAAC,KAAK,CAAC,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,SAAS,EAAE,CAAC;QACnE,CAAC,CAAC,EAAE,CACP,CAAC;IACF,IAAI,sBAAsB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,iBAAiB,GAAG,MAAM,EAAE;SAC/B,MAAM,CAAC,EAAE,WAAW,EAAE,2BAA2B,CAAC,WAAW,EAAE,CAAC;SAChE,IAAI,CAAC,2BAA2B,CAAC;SACjC,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;SAC7D,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,WAAW,CAAC,CAAC,CAAC;IACzD,MAAM,eAAe,GAAG,qBAAqB,CAC3C,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,EAC/C,KAAK,CAAC,0BAA0B,CACjC,CAAC;IAEF,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,sBAAsB,EAAE,CAAC;QACzC,MAAM,EAAE;aACL,MAAM,CAAC,kBAAkB,CAAC;aAC1B,GAAG,CAAC;YACH,WAAW,EAAE,eAAe;YAC5B,SAAS,EAAE,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,kBAAkB,CAAC;SACjE,CAAC;aACD,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;aAClD,GAAG,EAAE,CAAC;QACT,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wCAAwC,CAC5D,OAAgB,EAChB,UAA0D;IAE1D,MAAM,gBAAgB,GAAG,iCAAiC,CAAC,UAAU,CAAC,CAAC;IACvE,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,EAAE,EAAE,EAAE,GAAG,iCAAiC,CAAC,OAAO,CAAC,CAAC;IAE1D,OAAO,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACjC,wEAAwE;QACxE,mEAAmE;QACnE,oEAAoE;QACpE,MAAM,QAAQ,GAAG,MAAM,gCAAgC,CACrD,EAAE,EACF,gBAAgB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACnC,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,YAAY,EAAE,EAAE;SACjB,CAAC,CAAC,CACJ,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QACvE,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CACvD,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CACtC,CAAC;QACF,MAAM,EACJ,+BAA+B,EAC/B,8BAA8B,EAC9B,sCAAsC,GACvC,GAAG,oCAAoC,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,oCAAoC,CACxC,EAAE,EACF,UAAU,EACV,sCAAsC,CACvC,CAAC;QACF,MAAM,wCAAwC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAE/D,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,KAAK,MAAM,CACT,UAAU,EACV,mBAAmB,EACpB,IAAI,+BAA+B,EAAE,CAAC;YACrC,eAAe,CAAC,IAAI,CAClB,GAAG,CAAC,MAAM,6CAA6C,CAAC;gBACtD,UAAU;gBACV,mBAAmB;gBACnB,kBAAkB,EAAE,8BAA8B,CAAC,GAAG,CAAC,UAAU,CAAC;gBAClE,EAAE;gBACF,0BAA0B,EACxB,sCAAsC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,GAAG,EAAE;aACtE,CAAC,CAAC,CACJ,CAAC;QACJ,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,EAAE;aAClB,MAAM,CAAC,wBAAwB,CAAC;aAChC,IAAI,CAAC,kBAAkB,CAAC;aACxB,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;aACxC,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;aAC3D,OAAO,CACN,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAClC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CACjC,CAAC;QAEJ,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { and, asc, desc, eq, inArray, notInArray } from \"drizzle-orm\";\nimport {\n documentContainerProjection,\n documentProjection,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport { filterWritableDocumentPlacements } from \"../../container-contents/documentPlacement\";\nimport { getLatestTimestamp } from \"../../latestTimestamp\";\nimport type { ContainerDocumentTombstoneInput } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport { deleteContainerDocumentTombstoneHoldRows } from \"./containerDocumentTombstoneHolds\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n mapDocumentSummary,\n} from \"./documentProjectionRows\";\n\nfunction dedupeContainerDocumentTombstones(\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): ContainerDocumentTombstoneInput[] {\n return Array.from(\n new Map(\n tombstones.map((tombstone) => [\n `${tombstone.documentId}\\u0000${tombstone.containerId}`,\n tombstone,\n ]),\n ).values(),\n );\n}\n\nfunction buildContainerDocumentTombstoneState(\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): {\n removedContainerIdsByDocumentId: Map<string, Set<string>>;\n tombstoneUpdatedAtByDocumentId: Map<string, string>;\n verifiedLinkedContainerIdsByDocumentId: Map<string, ReadonlySet<string>>;\n} {\n const removedContainerIdsByDocumentId = new Map<string, Set<string>>();\n const tombstoneUpdatedAtByDocumentId = new Map<string, string>();\n const verifiedLinkedContainerIdsByDocumentId = new Map<\n string,\n ReadonlySet<string>\n >();\n\n for (const tombstone of uniqueTombstones) {\n verifiedLinkedContainerIdsByDocumentId.set(\n tombstone.documentId,\n new Set(tombstone.linkedContainerIds),\n );\n const removedContainerIds =\n removedContainerIdsByDocumentId.get(tombstone.documentId) ?? new Set();\n removedContainerIds.add(tombstone.containerId);\n removedContainerIdsByDocumentId.set(\n tombstone.documentId,\n removedContainerIds,\n );\n tombstoneUpdatedAtByDocumentId.set(\n tombstone.documentId,\n getLatestTimestamp(\n tombstoneUpdatedAtByDocumentId.get(tombstone.documentId),\n tombstone.updatedAt,\n ),\n );\n }\n\n return {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n };\n}\n\n/**\n * Remove the tombstoned placement and, with the head now verified, every\n * remaining local link row the head does not link: those are listing-seeded\n * rows, and leaving one would keep showing the document in a container the\n * signed link set never named. Rows the head links are kept as they are.\n */\nasync function deleteContainerDocumentTombstoneRows(\n tx: ClientSQLiteTransactionScope,\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n verifiedLinkedContainerIdsByDocumentId: ReadonlyMap<\n string,\n ReadonlySet<string>\n >,\n): Promise<void> {\n for (const tombstone of uniqueTombstones) {\n await tx\n .delete(documentContainerProjection)\n .where(\n and(\n eq(documentContainerProjection.documentId, tombstone.documentId),\n eq(documentContainerProjection.containerId, tombstone.containerId),\n ),\n )\n .run();\n }\n for (const [documentId, linked] of verifiedLinkedContainerIdsByDocumentId) {\n await tx\n .delete(documentContainerProjection)\n .where(\n linked.size === 0\n ? eq(documentContainerProjection.documentId, documentId)\n : and(\n eq(documentContainerProjection.documentId, documentId),\n notInArray(documentContainerProjection.containerId, [...linked]),\n ),\n )\n .run();\n }\n}\n\n/**\n * The primary container after a removal: the first remaining local row the\n * verified head links. A remaining row the head does not link is a\n * listing-seeded row and never becomes the primary, so a listing cannot\n * re-home the document. With no such row the document is unplaced (`null`)\n * and reachable through orphan recovery, rather than pointed at a head\n * container this device may not be able to read.\n */\nfunction selectNextContainerId(\n remainingContainerIds: ReadonlyArray<string>,\n verifiedLinkedContainerIds: ReadonlySet<string>,\n): string | null {\n return (\n remainingContainerIds.find((containerId) =>\n verifiedLinkedContainerIds.has(containerId),\n ) ?? null\n );\n}\n\nasync function updateSelectedContainersForDocumentTombstones(input: {\n documentId: string;\n removedContainerIds: ReadonlySet<string>;\n tombstoneUpdatedAt: string | undefined;\n tx: ClientSQLiteTransactionScope;\n verifiedLinkedContainerIds: ReadonlySet<string>;\n}): Promise<string[]> {\n const { documentId, removedContainerIds, tombstoneUpdatedAt, tx } = input;\n // A server document can own more than one local projection row: identity\n // recovery legitimately rematerializes a second projection for the same\n // documentId before semantic convergence completes. The link delete above is\n // keyed by (documentId, containerId) and the container item view surfaces a\n // document by its primary container_id, so EVERY projection row still pointing\n // at a removed container must be repaired here — resolving a single localId\n // left a duplicate row stranded at the source, keeping a moved document\n // visible in the container it was unlinked from.\n const localIds = (\n await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.documentId, documentId),\n ),\n )\n ).map((row) => row.localId);\n if (localIds.length === 0) {\n return [];\n }\n\n const projectionRows = await tx\n .select({\n localId: documentProjection.localId,\n containerId: documentProjection.containerId,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.localId, localIds));\n // Every projection row whose primary container is tombstoned OR outside the\n // verified link set is repointed: a primary at a listing-seeded row would\n // otherwise keep showing the document in a container the head never named.\n const rowsAtRemovedContainer = projectionRows.flatMap((row) =>\n row.localId !== null &&\n row.containerId !== null &&\n (removedContainerIds.has(row.containerId) ||\n !input.verifiedLinkedContainerIds.has(row.containerId))\n ? [{ localId: row.localId, updatedAt: row.updatedAt ?? undefined }]\n : [],\n );\n if (rowsAtRemovedContainer.length === 0) {\n return [];\n }\n\n const remainingLinkRows = await tx\n .select({ containerId: documentContainerProjection.containerId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, documentId))\n .orderBy(asc(documentContainerProjection.containerId));\n const nextContainerId = selectNextContainerId(\n remainingLinkRows.map((row) => row.containerId),\n input.verifiedLinkedContainerIds,\n );\n\n const changedLocalIds: string[] = [];\n for (const row of rowsAtRemovedContainer) {\n await tx\n .update(documentProjection)\n .set({\n containerId: nextContainerId,\n updatedAt: getLatestTimestamp(row.updatedAt, tombstoneUpdatedAt),\n })\n .where(eq(documentProjection.localId, row.localId))\n .run();\n changedLocalIds.push(row.localId);\n }\n\n return changedLocalIds;\n}\n\nexport async function applyContainerDocumentTombstonesWithExec(\n execSql: ExecSql,\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n) {\n const uniqueTombstones = dedupeContainerDocumentTombstones(tombstones);\n if (uniqueTombstones.length === 0) {\n return [];\n }\n\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return db.transaction(async (tx) => {\n // Besides the pending-intent guard, the verified head must not be older\n // than local document state: a lagging or replayed head must never\n // delete rows a newer listing or settled move wrote (`CheckEpoch`).\n const writable = await filterWritableDocumentPlacements(\n tx,\n uniqueTombstones.map((tombstone) => ({\n accessEpoch: tombstone.accessEpoch,\n documentId: tombstone.documentId,\n containerIds: [],\n })),\n );\n const writableIds = new Set(writable.map((input) => input.documentId));\n const applicable = uniqueTombstones.filter((tombstone) =>\n writableIds.has(tombstone.documentId),\n );\n const {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n } = buildContainerDocumentTombstoneState(applicable);\n await deleteContainerDocumentTombstoneRows(\n tx,\n applicable,\n verifiedLinkedContainerIdsByDocumentId,\n );\n await deleteContainerDocumentTombstoneHoldRows(tx, applicable);\n\n const changedLocalIds: string[] = [];\n for (const [\n documentId,\n removedContainerIds,\n ] of removedContainerIdsByDocumentId) {\n changedLocalIds.push(\n ...(await updateSelectedContainersForDocumentTombstones({\n documentId,\n removedContainerIds,\n tombstoneUpdatedAt: tombstoneUpdatedAtByDocumentId.get(documentId),\n tx,\n verifiedLinkedContainerIds:\n verifiedLinkedContainerIdsByDocumentId.get(documentId) ?? new Set(),\n })),\n );\n }\n\n if (changedLocalIds.length === 0) {\n return [];\n }\n\n const rows = await tx\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(inArray(documentProjection.localId, changedLocalIds))\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n });\n}\n"]}
1
+ {"version":3,"file":"containerDocumentTombstones.js","sourceRoot":"","sources":["containerDocumentTombstones.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, desc, eq, inArray, notInArray } from \"drizzle-orm\";\nimport { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport {\n documentContainerProjection,\n documentProjection,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport { filterWritableDocumentPlacements } from \"../../container-contents/documentPlacement\";\nimport { getLatestTimestamp } from \"../../latestTimestamp\";\nimport type { ContainerDocumentTombstoneInput } from \"../types\";\nimport { deleteContainerDocumentTombstoneHoldRows } from \"./containerDocumentTombstoneHolds\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n mapDocumentSummary,\n} from \"./documentProjectionRows\";\n\nfunction dedupeContainerDocumentTombstones(\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): ContainerDocumentTombstoneInput[] {\n return Array.from(\n new Map(\n tombstones.map((tombstone) => [\n `${tombstone.documentId}\\u0000${tombstone.containerId}`,\n tombstone,\n ]),\n ).values(),\n );\n}\n\nfunction buildContainerDocumentTombstoneState(\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): {\n removedContainerIdsByDocumentId: Map<string, Set<string>>;\n tombstoneUpdatedAtByDocumentId: Map<string, string>;\n verifiedLinkedContainerIdsByDocumentId: Map<string, ReadonlySet<string>>;\n} {\n const removedContainerIdsByDocumentId = new Map<string, Set<string>>();\n const tombstoneUpdatedAtByDocumentId = new Map<string, string>();\n const verifiedLinkedContainerIdsByDocumentId = new Map<\n string,\n ReadonlySet<string>\n >();\n\n for (const tombstone of uniqueTombstones) {\n verifiedLinkedContainerIdsByDocumentId.set(\n tombstone.documentId,\n new Set(tombstone.linkedContainerIds),\n );\n const removedContainerIds =\n removedContainerIdsByDocumentId.get(tombstone.documentId) ?? new Set();\n removedContainerIds.add(tombstone.containerId);\n removedContainerIdsByDocumentId.set(\n tombstone.documentId,\n removedContainerIds,\n );\n tombstoneUpdatedAtByDocumentId.set(\n tombstone.documentId,\n getLatestTimestamp(\n tombstoneUpdatedAtByDocumentId.get(tombstone.documentId),\n tombstone.updatedAt,\n ),\n );\n }\n\n return {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n };\n}\n\n/**\n * Remove the tombstoned placement and, with the head now verified, every\n * remaining local link row the head does not link: those are listing-seeded\n * rows, and leaving one would keep showing the document in a container the\n * signed link set never named. Rows the head links are kept as they are.\n */\nasync function deleteContainerDocumentTombstoneRows(\n tx: ClientSQLiteTransactionScope,\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n verifiedLinkedContainerIdsByDocumentId: ReadonlyMap<\n string,\n ReadonlySet<string>\n >,\n): Promise<void> {\n for (const tombstone of uniqueTombstones) {\n await tx\n .delete(documentContainerProjection)\n .where(\n and(\n eq(documentContainerProjection.documentId, tombstone.documentId),\n eq(documentContainerProjection.containerId, tombstone.containerId),\n ),\n )\n .run();\n }\n for (const [documentId, linked] of verifiedLinkedContainerIdsByDocumentId) {\n await tx\n .delete(documentContainerProjection)\n .where(\n linked.size === 0\n ? eq(documentContainerProjection.documentId, documentId)\n : and(\n eq(documentContainerProjection.documentId, documentId),\n notInArray(documentContainerProjection.containerId, [...linked]),\n ),\n )\n .run();\n }\n}\n\n/**\n * The primary container after a removal: the first remaining local row the\n * verified head links. A remaining row the head does not link is a\n * listing-seeded row and never becomes the primary, so a listing cannot\n * re-home the document. With no such row the document is unplaced (`null`)\n * and reachable through orphan recovery, rather than pointed at a head\n * container this device may not be able to read.\n */\nfunction selectNextContainerId(\n remainingContainerIds: ReadonlyArray<string>,\n verifiedLinkedContainerIds: ReadonlySet<string>,\n): string | null {\n return (\n remainingContainerIds.find((containerId) =>\n verifiedLinkedContainerIds.has(containerId),\n ) ?? null\n );\n}\n\nasync function updateSelectedContainersForDocumentTombstones(input: {\n documentId: string;\n removedContainerIds: ReadonlySet<string>;\n tombstoneUpdatedAt: string | undefined;\n tx: ClientSQLiteTransactionScope;\n verifiedLinkedContainerIds: ReadonlySet<string>;\n}): Promise<string[]> {\n const { documentId, removedContainerIds, tombstoneUpdatedAt, tx } = input;\n // A server document can own more than one local projection row: identity\n // recovery legitimately rematerializes a second projection for the same\n // documentId before semantic convergence completes. The link delete above is\n // keyed by (documentId, containerId) and the container item view surfaces a\n // document by its primary container_id, so EVERY projection row still pointing\n // at a removed container must be repaired here — resolving a single localId\n // left a duplicate row stranded at the source, keeping a moved document\n // visible in the container it was unlinked from.\n const localIds = (\n await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.documentId, documentId),\n ),\n )\n ).map((row) => row.localId);\n if (localIds.length === 0) {\n return [];\n }\n\n const projectionRows = await tx\n .select({\n localId: documentProjection.localId,\n containerId: documentProjection.containerId,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.localId, localIds));\n // Every projection row whose primary container is tombstoned OR outside the\n // verified link set is repointed: a primary at a listing-seeded row would\n // otherwise keep showing the document in a container the head never named.\n const rowsAtRemovedContainer = projectionRows.flatMap((row) =>\n row.localId !== null &&\n row.containerId !== null &&\n (removedContainerIds.has(row.containerId) ||\n !input.verifiedLinkedContainerIds.has(row.containerId))\n ? [{ localId: row.localId, updatedAt: row.updatedAt ?? undefined }]\n : [],\n );\n if (rowsAtRemovedContainer.length === 0) {\n return [];\n }\n\n const remainingLinkRows = await tx\n .select({ containerId: documentContainerProjection.containerId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, documentId))\n .orderBy(asc(documentContainerProjection.containerId));\n const nextContainerId = selectNextContainerId(\n remainingLinkRows.map((row) => row.containerId),\n input.verifiedLinkedContainerIds,\n );\n\n const changedLocalIds: string[] = [];\n for (const row of rowsAtRemovedContainer) {\n await tx\n .update(documentProjection)\n .set({\n containerId: nextContainerId,\n updatedAt: getLatestTimestamp(row.updatedAt, tombstoneUpdatedAt),\n })\n .where(eq(documentProjection.localId, row.localId))\n .run();\n changedLocalIds.push(row.localId);\n }\n\n return changedLocalIds;\n}\n\nexport async function applyContainerDocumentTombstonesWithExec(\n execSql: ExecSql,\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n) {\n const uniqueTombstones = dedupeContainerDocumentTombstones(tombstones);\n if (uniqueTombstones.length === 0) {\n return [];\n }\n\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return db.transaction(async (tx) => {\n // Besides the pending-intent guard, the verified head must not be older\n // than local document state: a lagging or replayed head must never\n // delete rows a newer listing or settled move wrote (`CheckEpoch`).\n const writable = await filterWritableDocumentPlacements(\n tx,\n uniqueTombstones.map((tombstone) => ({\n accessEpoch: tombstone.accessEpoch,\n documentId: tombstone.documentId,\n containerIds: [],\n })),\n );\n const writableIds = new Set(writable.map((input) => input.documentId));\n const applicable = uniqueTombstones.filter((tombstone) =>\n writableIds.has(tombstone.documentId),\n );\n const {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n } = buildContainerDocumentTombstoneState(applicable);\n await deleteContainerDocumentTombstoneRows(\n tx,\n applicable,\n verifiedLinkedContainerIdsByDocumentId,\n );\n await deleteContainerDocumentTombstoneHoldRows(tx, applicable);\n\n const changedLocalIds: string[] = [];\n for (const [\n documentId,\n removedContainerIds,\n ] of removedContainerIdsByDocumentId) {\n changedLocalIds.push(\n ...(await updateSelectedContainersForDocumentTombstones({\n documentId,\n removedContainerIds,\n tombstoneUpdatedAt: tombstoneUpdatedAtByDocumentId.get(documentId),\n tx,\n verifiedLinkedContainerIds:\n verifiedLinkedContainerIdsByDocumentId.get(documentId) ?? new Set(),\n })),\n );\n }\n\n if (changedLocalIds.length === 0) {\n return [];\n }\n\n const rows = await tx\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(inArray(documentProjection.localId, changedLocalIds))\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n });\n}\n"]}
@@ -1,8 +1,8 @@
1
+ import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
1
2
  import { insertDocumentPendingUpdateWithHistoryInTransaction } from "../../../sqlite/documentPersistence/documentPendingUpdatePersistence.js";
2
3
  import { documentHistoryCheckpoints } from "../../../sqlite/schema/index.js";
3
4
  import { getClientSQLitePersistenceRuntime } from "../../../sqlite/sqlitePersistenceRuntime.js";
4
5
  import { runSerializedSqlMutation } from "../../../sqlite/sqlSchema.js";
5
- import { DOCUMENTS_APP_KIND } from "./constants.js";
6
6
  import { createDocumentRowsIfAbsent, resolveDocumentSaveTimestamp, } from "./documentRows.js";
7
7
  export async function createStoredDocumentWithHistoryCheckpoint(execSql, document, historyCheckpoint, options, saveClientProjection) {
8
8
  return runSerializedSqlMutation(execSql, async (lockedExecSql) => getClientSQLitePersistenceRuntime(lockedExecSql).transaction(async (tx) => {
@@ -1 +1 @@
1
- {"version":3,"file":"createDocumentWithHistoryCheckpoint.js","sourceRoot":"","sources":["createDocumentWithHistoryCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mDAAmD,EAAE,MAAM,sEAAsE,CAAC;AAC3I,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAC7F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,yCAAyC,CAC7D,OAEI,EACJ,QAEI,EACJ,iBAEI,EACJ,OAEI,EACJ,oBAEI;IAEJ,OAAO,wBAAwB,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,CAC/D,iCAAiC,CAAC,aAAa,CAAC,CAAC,WAAW,CAC1D,KAAK,EAAE,EAAE,EAAE,EAAE;QACX,MAAM,SAAS,GAAG,MAAM,4BAA4B,CAAC;YACnD,QAAQ;YACR,OAAO;YACP,EAAE;SACH,CAAC,CAAC;QACH,IAAI,OAAO,EAAE,YAAY,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC;YAC/C,QAAQ;YACR,EAAE;YACF,SAAS;SACV,CAAC,CAAC;QACH,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,EAAE;aACL,MAAM,CAAC,0BAA0B,CAAC;aAClC,MAAM,CAAC;YACN,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,QAAQ,CAAC,EAAE;YACpB,QAAQ,EAAE,iBAAiB,CAAC,QAAQ;YACpC,gBAAgB,EAAE,iBAAiB,CAAC,gBAAgB;YACpD,QAAQ;YACR,SAAS;SACV,CAAC;aACD,kBAAkB,CAAC;YAClB,MAAM,EAAE;gBACN,0BAA0B,CAAC,OAAO;gBAClC,0BAA0B,CAAC,OAAO;aACnC;YACD,GAAG,EAAE;gBACH,QAAQ,EAAE,iBAAiB,CAAC,QAAQ;gBACpC,gBAAgB,EAAE,iBAAiB,CAAC,gBAAgB;gBACpD,QAAQ;gBACR,SAAS;aACV;SACF,CAAC;aACD,GAAG,EAAE,CAAC;QACT,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;YAC3B,MAAM,mDAAmD,CAAC;gBACxD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,KAAK,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE;gBAC5D,EAAE;aACH,CAAC,CAAC;QACL,CAAC;QACD,MAAM,oBAAoB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QACrD,OAAO,SAAS,CAAC;IACnB,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CACF,CAAC;AACJ,CAAC","sourcesContent":["import { insertDocumentPendingUpdateWithHistoryInTransaction } from \"../../../sqlite/documentPersistence/documentPendingUpdatePersistence\";\nimport { documentHistoryCheckpoints } from \"../../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentsPersistence } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport {\n createDocumentRowsIfAbsent,\n resolveDocumentSaveTimestamp,\n} from \"./documentRows\";\n\nexport async function createStoredDocumentWithHistoryCheckpoint(\n execSql: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[0],\n document: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[1],\n historyCheckpoint: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[2],\n options: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[3],\n saveClientProjection: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[4],\n): Promise<string | null> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const updatedAt = await resolveDocumentSaveTimestamp({\n document,\n options,\n tx,\n });\n if (options?.stillCurrent && !options.stillCurrent()) {\n return null;\n }\n const created = await createDocumentRowsIfAbsent({\n document,\n tx,\n updatedAt,\n });\n if (!created) return null;\n const revision = crypto.randomUUID();\n await tx\n .insert(documentHistoryCheckpoints)\n .values({\n appKind: DOCUMENTS_APP_KIND,\n localId: document.id,\n snapshot: historyCheckpoint.snapshot,\n endVersionVector: historyCheckpoint.endVersionVector,\n revision,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: [\n documentHistoryCheckpoints.appKind,\n documentHistoryCheckpoints.localId,\n ],\n set: {\n snapshot: historyCheckpoint.snapshot,\n endVersionVector: historyCheckpoint.endVersionVector,\n revision,\n updatedAt,\n },\n })\n .run();\n if (options?.pendingUpdate) {\n await insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt: new Date().toISOString(),\n pendingUpdate: options.pendingUpdate,\n scope: { appKind: DOCUMENTS_APP_KIND, localId: document.id },\n tx,\n });\n }\n await saveClientProjection(lockedExecSql, updatedAt);\n return updatedAt;\n },\n { behavior: \"immediate\" },\n ),\n );\n}\n"]}
1
+ {"version":3,"file":"createDocumentWithHistoryCheckpoint.js","sourceRoot":"","sources":["createDocumentWithHistoryCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,mDAAmD,EAAE,MAAM,sEAAsE,CAAC;AAC3I,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAC7F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,yCAAyC,CAC7D,OAEI,EACJ,QAEI,EACJ,iBAEI,EACJ,OAEI,EACJ,oBAEI;IAEJ,OAAO,wBAAwB,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,CAC/D,iCAAiC,CAAC,aAAa,CAAC,CAAC,WAAW,CAC1D,KAAK,EAAE,EAAE,EAAE,EAAE;QACX,MAAM,SAAS,GAAG,MAAM,4BAA4B,CAAC;YACnD,QAAQ;YACR,OAAO;YACP,EAAE;SACH,CAAC,CAAC;QACH,IAAI,OAAO,EAAE,YAAY,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC;YAC/C,QAAQ;YACR,EAAE;YACF,SAAS;SACV,CAAC,CAAC;QACH,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,EAAE;aACL,MAAM,CAAC,0BAA0B,CAAC;aAClC,MAAM,CAAC;YACN,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,QAAQ,CAAC,EAAE;YACpB,QAAQ,EAAE,iBAAiB,CAAC,QAAQ;YACpC,gBAAgB,EAAE,iBAAiB,CAAC,gBAAgB;YACpD,QAAQ;YACR,SAAS;SACV,CAAC;aACD,kBAAkB,CAAC;YAClB,MAAM,EAAE;gBACN,0BAA0B,CAAC,OAAO;gBAClC,0BAA0B,CAAC,OAAO;aACnC;YACD,GAAG,EAAE;gBACH,QAAQ,EAAE,iBAAiB,CAAC,QAAQ;gBACpC,gBAAgB,EAAE,iBAAiB,CAAC,gBAAgB;gBACpD,QAAQ;gBACR,SAAS;aACV;SACF,CAAC;aACD,GAAG,EAAE,CAAC;QACT,IAAI,OAAO,EAAE,aAAa,EAAE,CAAC;YAC3B,MAAM,mDAAmD,CAAC;gBACxD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,KAAK,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE;gBAC5D,EAAE;aACH,CAAC,CAAC;QACL,CAAC;QACD,MAAM,oBAAoB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QACrD,OAAO,SAAS,CAAC;IACnB,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CACF,CAAC;AACJ,CAAC","sourcesContent":["import { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport { insertDocumentPendingUpdateWithHistoryInTransaction } from \"../../../sqlite/documentPersistence/documentPendingUpdatePersistence\";\nimport { documentHistoryCheckpoints } from \"../../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentsPersistence } from \"../types\";\nimport {\n createDocumentRowsIfAbsent,\n resolveDocumentSaveTimestamp,\n} from \"./documentRows\";\n\nexport async function createStoredDocumentWithHistoryCheckpoint(\n execSql: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[0],\n document: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[1],\n historyCheckpoint: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[2],\n options: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[3],\n saveClientProjection: Parameters<\n DocumentsPersistence[\"createDocumentWithHistoryCheckpoint\"]\n >[4],\n): Promise<string | null> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const updatedAt = await resolveDocumentSaveTimestamp({\n document,\n options,\n tx,\n });\n if (options?.stillCurrent && !options.stillCurrent()) {\n return null;\n }\n const created = await createDocumentRowsIfAbsent({\n document,\n tx,\n updatedAt,\n });\n if (!created) return null;\n const revision = crypto.randomUUID();\n await tx\n .insert(documentHistoryCheckpoints)\n .values({\n appKind: DOCUMENTS_APP_KIND,\n localId: document.id,\n snapshot: historyCheckpoint.snapshot,\n endVersionVector: historyCheckpoint.endVersionVector,\n revision,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: [\n documentHistoryCheckpoints.appKind,\n documentHistoryCheckpoints.localId,\n ],\n set: {\n snapshot: historyCheckpoint.snapshot,\n endVersionVector: historyCheckpoint.endVersionVector,\n revision,\n updatedAt,\n },\n })\n .run();\n if (options?.pendingUpdate) {\n await insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt: new Date().toISOString(),\n pendingUpdate: options.pendingUpdate,\n scope: { appKind: DOCUMENTS_APP_KIND, localId: document.id },\n tx,\n });\n }\n await saveClientProjection(lockedExecSql, updatedAt);\n return updatedAt;\n },\n { behavior: \"immediate\" },\n ),\n );\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import { and, eq, inArray, ne } from "drizzle-orm";
2
+ import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
2
3
  import { clearDocumentSyncFailure, deleteDocumentRecord, loadDocumentRecord, } from "../../../sqlite/documentPersistence/index.js";
3
4
  import { deleteDocumentHistory } from "../../../sqlite/documentPersistence/documentHistoryPersistence.js";
4
5
  import { documentAttachmentBlobProjection, documentContainerProjection, documentPendingAttachments, documentPlacementIntentTables, documentProjection, documentProjectionText, documents, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../../sqlite/schema/index.js";
5
6
  import { documentIntentLinkTargets } from "../../../sqlite/schema/documentPlacementIntentSchema.js";
6
7
  import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
7
8
  import { ensureSqlTables, runSerializedSqlMutation, } from "../../../sqlite/sqlSchema.js";
8
- import { DOCUMENTS_APP_KIND } from "./constants.js";
9
9
  import { deleteContainerDocumentTombstoneHoldsForDocuments } from "./containerDocumentTombstoneHolds.js";
10
10
  import { sameCanonicalDocumentSecurityIdentity } from "./documentRecordIdentity.js";
11
11
  import { getDocumentScope } from "./documentRows.js";
@@ -1 +1 @@
1
- {"version":3,"file":"documentDeletionPersistence.js","sourceRoot":"","sources":["documentDeletionPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, ne } from \"drizzle-orm\";\nimport {\n clearDocumentSyncFailure,\n deleteDocumentRecord,\n loadDocumentRecord,\n} from \"../../../sqlite/documentPersistence\";\nimport { deleteDocumentHistory } from \"../../../sqlite/documentPersistence/documentHistoryPersistence\";\nimport {\n documentAttachmentBlobProjection,\n documentContainerProjection,\n documentPendingAttachments,\n documentPlacementIntentTables,\n documentProjection,\n documentProjectionText,\n documents,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../../sqlite/schema\";\nimport { documentIntentLinkTargets } from \"../../../sqlite/schema/documentPlacementIntentSchema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../../sqlite/sqlSchema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport { deleteContainerDocumentTombstoneHoldsForDocuments } from \"./containerDocumentTombstoneHolds\";\nimport { sameCanonicalDocumentSecurityIdentity } from \"./documentRecordIdentity\";\nimport { getDocumentScope } from \"./documentRows\";\nimport { queueDocumentAttachmentBlobReclaims } from \"./orphanSideRows\";\n\nasync function deleteStoredDocumentRows(input: {\n existingDocumentId: string | null;\n localId: string;\n lockedExecSql: ExecSql;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { existingDocumentId, localId, lockedExecSql, tx } = input;\n await queueDocumentAttachmentBlobReclaims({\n localWhere: eq(documentAttachmentBlobProjection.localId, localId),\n pendingWhere: eq(documentPendingAttachments.localId, localId),\n tx,\n });\n await tx\n .delete(documentProjection)\n .where(eq(documentProjection.localId, localId))\n .run();\n await tx\n .delete(documentProjectionText)\n .where(eq(documentProjectionText.localId, localId))\n .run();\n await tx\n .delete(documentPendingAttachments)\n .where(eq(documentPendingAttachments.localId, localId))\n .run();\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(eq(documentAttachmentBlobProjection.localId, localId))\n .run();\n if (existingDocumentId) {\n await tx\n .delete(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, existingDocumentId))\n .run();\n await deleteContainerDocumentTombstoneHoldsForDocuments(tx, [\n existingDocumentId,\n ]);\n const placementIntent = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n eq(localIntents.subjectId, existingDocumentId),\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(placementIntent),\n ),\n )\n .run();\n await tx.delete(localIntents).where(placementIntent).run();\n }\n const scope = getDocumentScope(localId);\n await deleteDocumentHistory(lockedExecSql, scope);\n await clearDocumentSyncFailure(lockedExecSql, scope);\n await deleteDocumentRecord(lockedExecSql, scope);\n}\n\nasync function ensureDocumentDeletionTables(execSql: ExecSql): Promise<void> {\n // Move intents live in the container-contents schema, which document-only\n // callers may not have initialized yet.\n await ensureSqlTables(execSql, documentPlacementIntentTables);\n}\n\nasync function hasAnotherDocumentAlias(input: {\n documentId: string;\n localId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const rows = await input.tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.documentId, input.documentId),\n ne(documents.localId, input.localId),\n ),\n )\n .limit(1);\n return rows.length > 0;\n}\n\nexport async function deleteStoredDocument(\n execSql: ExecSql,\n localId: string,\n): Promise<void> {\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureDocumentDeletionTables(lockedExecSql);\n await getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const existingDocument = await loadDocumentRecord(lockedExecSql, {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n });\n await deleteStoredDocumentRows({\n existingDocumentId: existingDocument?.documentId ?? null,\n localId,\n lockedExecSql,\n tx,\n });\n },\n { behavior: \"immediate\" },\n );\n });\n}\n\nexport async function deleteStoredDocumentIfMatches(\n execSql: ExecSql,\n expectedRecord: StoredDocumentRecord,\n deleteClientProjection: (transactionExecSql: ExecSql) => Promise<void>,\n): Promise<boolean> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureDocumentDeletionTables(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const existingDocument = await loadDocumentRecord(lockedExecSql, {\n appKind: DOCUMENTS_APP_KIND,\n localId: expectedRecord.id,\n });\n if (\n !existingDocument ||\n !sameCanonicalDocumentSecurityIdentity(\n existingDocument,\n expectedRecord,\n )\n ) {\n return false;\n }\n const [placement] = await tx\n .select({ containerId: documentProjection.containerId })\n .from(documentProjection)\n .where(eq(documentProjection.localId, expectedRecord.id))\n .limit(1);\n if ((placement?.containerId ?? null) !== expectedRecord.containerId)\n return false;\n if (\n existingDocument.documentId &&\n (await hasAnotherDocumentAlias({\n documentId: existingDocument.documentId,\n localId: expectedRecord.id,\n tx,\n }))\n ) {\n return false;\n }\n await deleteStoredDocumentRows({\n existingDocumentId: existingDocument.documentId ?? null,\n localId: expectedRecord.id,\n lockedExecSql,\n tx,\n });\n await deleteClientProjection(lockedExecSql);\n return true;\n },\n { behavior: \"immediate\" },\n );\n });\n}\n\nexport async function deleteStoredDocumentSideRowsIfAbsent(\n execSql: ExecSql,\n localId: string,\n expectedDocumentId: string | null,\n deleteClientProjection: (transactionExecSql: ExecSql) => Promise<void>,\n): Promise<boolean> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureDocumentDeletionTables(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const existingDocument = await loadDocumentRecord(lockedExecSql, {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n });\n if (existingDocument) return false;\n if (\n expectedDocumentId &&\n (await hasAnotherDocumentAlias({\n documentId: expectedDocumentId,\n localId,\n tx,\n }))\n ) {\n return false;\n }\n\n await deleteStoredDocumentRows({\n existingDocumentId: expectedDocumentId,\n localId,\n lockedExecSql,\n tx,\n });\n await deleteClientProjection(lockedExecSql);\n return true;\n },\n { behavior: \"immediate\" },\n );\n });\n}\n"]}
1
+ {"version":3,"file":"documentDeletionPersistence.js","sourceRoot":"","sources":["documentDeletionPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, ne } from \"drizzle-orm\";\nimport { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport {\n clearDocumentSyncFailure,\n deleteDocumentRecord,\n loadDocumentRecord,\n} from \"../../../sqlite/documentPersistence\";\nimport { deleteDocumentHistory } from \"../../../sqlite/documentPersistence/documentHistoryPersistence\";\nimport {\n documentAttachmentBlobProjection,\n documentContainerProjection,\n documentPendingAttachments,\n documentPlacementIntentTables,\n documentProjection,\n documentProjectionText,\n documents,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../../sqlite/schema\";\nimport { documentIntentLinkTargets } from \"../../../sqlite/schema/documentPlacementIntentSchema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../../sqlite/sqlSchema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { deleteContainerDocumentTombstoneHoldsForDocuments } from \"./containerDocumentTombstoneHolds\";\nimport { sameCanonicalDocumentSecurityIdentity } from \"./documentRecordIdentity\";\nimport { getDocumentScope } from \"./documentRows\";\nimport { queueDocumentAttachmentBlobReclaims } from \"./orphanSideRows\";\n\nasync function deleteStoredDocumentRows(input: {\n existingDocumentId: string | null;\n localId: string;\n lockedExecSql: ExecSql;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { existingDocumentId, localId, lockedExecSql, tx } = input;\n await queueDocumentAttachmentBlobReclaims({\n localWhere: eq(documentAttachmentBlobProjection.localId, localId),\n pendingWhere: eq(documentPendingAttachments.localId, localId),\n tx,\n });\n await tx\n .delete(documentProjection)\n .where(eq(documentProjection.localId, localId))\n .run();\n await tx\n .delete(documentProjectionText)\n .where(eq(documentProjectionText.localId, localId))\n .run();\n await tx\n .delete(documentPendingAttachments)\n .where(eq(documentPendingAttachments.localId, localId))\n .run();\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(eq(documentAttachmentBlobProjection.localId, localId))\n .run();\n if (existingDocumentId) {\n await tx\n .delete(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, existingDocumentId))\n .run();\n await deleteContainerDocumentTombstoneHoldsForDocuments(tx, [\n existingDocumentId,\n ]);\n const placementIntent = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n eq(localIntents.subjectId, existingDocumentId),\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(placementIntent),\n ),\n )\n .run();\n await tx.delete(localIntents).where(placementIntent).run();\n }\n const scope = getDocumentScope(localId);\n await deleteDocumentHistory(lockedExecSql, scope);\n await clearDocumentSyncFailure(lockedExecSql, scope);\n await deleteDocumentRecord(lockedExecSql, scope);\n}\n\nasync function ensureDocumentDeletionTables(execSql: ExecSql): Promise<void> {\n // Move intents live in the container-contents schema, which document-only\n // callers may not have initialized yet.\n await ensureSqlTables(execSql, documentPlacementIntentTables);\n}\n\nasync function hasAnotherDocumentAlias(input: {\n documentId: string;\n localId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const rows = await input.tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.documentId, input.documentId),\n ne(documents.localId, input.localId),\n ),\n )\n .limit(1);\n return rows.length > 0;\n}\n\nexport async function deleteStoredDocument(\n execSql: ExecSql,\n localId: string,\n): Promise<void> {\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureDocumentDeletionTables(lockedExecSql);\n await getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const existingDocument = await loadDocumentRecord(lockedExecSql, {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n });\n await deleteStoredDocumentRows({\n existingDocumentId: existingDocument?.documentId ?? null,\n localId,\n lockedExecSql,\n tx,\n });\n },\n { behavior: \"immediate\" },\n );\n });\n}\n\nexport async function deleteStoredDocumentIfMatches(\n execSql: ExecSql,\n expectedRecord: StoredDocumentRecord,\n deleteClientProjection: (transactionExecSql: ExecSql) => Promise<void>,\n): Promise<boolean> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureDocumentDeletionTables(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const existingDocument = await loadDocumentRecord(lockedExecSql, {\n appKind: DOCUMENTS_APP_KIND,\n localId: expectedRecord.id,\n });\n if (\n !existingDocument ||\n !sameCanonicalDocumentSecurityIdentity(\n existingDocument,\n expectedRecord,\n )\n ) {\n return false;\n }\n const [placement] = await tx\n .select({ containerId: documentProjection.containerId })\n .from(documentProjection)\n .where(eq(documentProjection.localId, expectedRecord.id))\n .limit(1);\n if ((placement?.containerId ?? null) !== expectedRecord.containerId)\n return false;\n if (\n existingDocument.documentId &&\n (await hasAnotherDocumentAlias({\n documentId: existingDocument.documentId,\n localId: expectedRecord.id,\n tx,\n }))\n ) {\n return false;\n }\n await deleteStoredDocumentRows({\n existingDocumentId: existingDocument.documentId ?? null,\n localId: expectedRecord.id,\n lockedExecSql,\n tx,\n });\n await deleteClientProjection(lockedExecSql);\n return true;\n },\n { behavior: \"immediate\" },\n );\n });\n}\n\nexport async function deleteStoredDocumentSideRowsIfAbsent(\n execSql: ExecSql,\n localId: string,\n expectedDocumentId: string | null,\n deleteClientProjection: (transactionExecSql: ExecSql) => Promise<void>,\n): Promise<boolean> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureDocumentDeletionTables(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const existingDocument = await loadDocumentRecord(lockedExecSql, {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n });\n if (existingDocument) return false;\n if (\n expectedDocumentId &&\n (await hasAnotherDocumentAlias({\n documentId: expectedDocumentId,\n localId,\n tx,\n }))\n ) {\n return false;\n }\n\n await deleteStoredDocumentRows({\n existingDocumentId: expectedDocumentId,\n localId,\n lockedExecSql,\n tx,\n });\n await deleteClientProjection(lockedExecSql);\n return true;\n },\n { behavior: \"immediate\" },\n );\n });\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { base64ToBytes } from "../../../../internal/encoding/index.js";
2
2
  import { createDocument, importSnapshot, updateMatchesDocumentHistory, } from "../../../../internal/loro/index.js";
3
3
  import { and, eq } from "drizzle-orm";
4
+ import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
4
5
  import { documentSyncPullContinuationsEqual } from "../../../documents/shared/sync/pullContinuation.js";
5
6
  import { appendDocumentHistoryUpdates, replaceDocumentHistoryCheckpoint, } from "../../../sqlite/documentPersistence/documentHistoryPersistence.js";
6
7
  import { insertDocumentPendingUpdateWithHistoryInTransaction, settleQueuedDocumentUpdatesInTransaction, } from "../../../sqlite/documentPersistence/documentPendingUpdatePersistence.js";
@@ -9,7 +10,6 @@ import { documentHistoryUpdates } from "../../../sqlite/schema/index.js";
9
10
  import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
10
11
  import { runSerializedSqlMutation } from "../../../sqlite/sqlSchema.js";
11
12
  import { applyStoredAttachmentRemoval, upsertStoredAttachmentStagingRows, } from "./attachmentStagingPersistence.js";
12
- import { DOCUMENTS_APP_KIND } from "./constants.js";
13
13
  import { sameDocumentSecurityIdentity, sameNullableDocumentValue, } from "./documentRecordIdentity.js";
14
14
  import { resolveDocumentSaveTimestamp, saveDocumentRows } from "./documentRows.js";
15
15
  function sameRecoveryGeneration(current, expected) {
@@ -1 +1 @@
1
- {"version":3,"file":"documentMutationPersistence.js","sourceRoot":"","sources":["documentMutationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes } from \"@tearleads/encoding\";\nimport {\n createDocument,\n importSnapshot,\n updateMatchesDocumentHistory,\n} from \"@tearleads/loro\";\nimport { and, eq } from \"drizzle-orm\";\nimport { documentSyncPullContinuationsEqual } from \"../../../documents/shared/sync/pullContinuation\";\nimport {\n appendDocumentHistoryUpdates,\n replaceDocumentHistoryCheckpoint,\n} from \"../../../sqlite/documentPersistence/documentHistoryPersistence\";\nimport {\n insertDocumentPendingUpdateWithHistoryInTransaction,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../../sqlite/documentPersistence/documentPendingUpdatePersistence\";\nimport { clearDocumentSyncFailureInTransaction } from \"../../../sqlite/documentPersistence/documentSyncFailurePersistence\";\nimport { documentHistoryUpdates } from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentsPersistence, StoredDocumentRecord } from \"../types\";\nimport {\n applyStoredAttachmentRemoval,\n upsertStoredAttachmentStagingRows,\n} from \"./attachmentStagingPersistence\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport {\n sameDocumentSecurityIdentity,\n sameNullableDocumentValue,\n} from \"./documentRecordIdentity\";\nimport { resolveDocumentSaveTimestamp, saveDocumentRows } from \"./documentRows\";\n\nfunction sameRecoveryGeneration(\n current: StoredDocumentRecord,\n expected: StoredDocumentRecord,\n): boolean {\n return (\n (current.recoveryGeneration ?? 0) === (expected.recoveryGeneration ?? 0)\n );\n}\n\nfunction sameExpectedDocumentRecord(\n current: StoredDocumentRecord,\n expected: StoredDocumentRecord,\n): boolean {\n return (\n sameDocumentSecurityIdentity(current, expected) &&\n sameRecoveryGeneration(current, expected) &&\n sameNullableDocumentValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n sameNullableDocumentValue(\n current.pendingBaseVersion,\n expected.pendingBaseVersion,\n ) &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired) &&\n (current.documentKind ?? null) === (expected.documentKind ?? null) &&\n current.text === expected.text &&\n (current.title ?? null) === (expected.title ?? null)\n );\n}\n\nasync function deleteAcceptedPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n localId: string,\n ids: readonly string[],\n): Promise<void> {\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n { appKind: DOCUMENTS_APP_KIND, localId },\n ids,\n );\n}\n\nasync function insertPendingUpdate(\n tx: ClientSQLiteTransactionScope,\n documentId: string,\n pendingUpdate: Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"pendingUpdate\"],\n): Promise<void> {\n if (!pendingUpdate) return;\n await insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt: new Date().toISOString(),\n pendingUpdate,\n scope: { appKind: DOCUMENTS_APP_KIND, localId: documentId },\n tx,\n });\n}\n\nasync function settleMutationConflict(input: {\n currentRecord: StoredDocumentRecord | null;\n mutation: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[1];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n if (\n input.currentRecord &&\n input.mutation.settleAcceptedPendingOnConflict &&\n sameDocumentSecurityIdentity(\n input.currentRecord,\n input.mutation.expectedRecord,\n ) &&\n sameRecoveryGeneration(input.currentRecord, input.mutation.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n input.tx,\n input.mutation.document.id,\n input.mutation.acceptedPendingUpdateIds,\n );\n }\n}\n\nasync function appendMutationHistory(\n execSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0],\n input: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[1],\n tx: ClientSQLiteTransactionScope,\n): Promise<void> {\n if (input.historyCheckpoint) {\n const coveredLocalState = input.historyCheckpoint.pruneCoveredLocalState\n ? await findCoveredRecoveryLocalState(\n tx,\n input.document.id,\n input.historyCheckpoint.snapshot,\n )\n : {\n checkpointIds: [],\n hasOrdinaryPendingUpdates: false,\n hasUnprunablePendingUpdates: false,\n hasUnverifiedHistoryTail: false,\n tailIds: [],\n };\n if (\n input.historyCheckpoint.pruneCoveredLocalState &&\n (coveredLocalState.hasOrdinaryPendingUpdates ||\n coveredLocalState.hasUnprunablePendingUpdates)\n ) {\n throw new Error(\n \"Document recovery found unproven pending updates before installation\",\n );\n }\n if (\n input.historyCheckpoint.pruneCoveredLocalState &&\n coveredLocalState.hasUnverifiedHistoryTail\n ) {\n throw new Error(\n \"Document recovery found unverified history tail before installation\",\n );\n }\n // A queued rotation baseline the recovery snapshot covers is unqueued\n // first so the replacement below can delete it with the covered tail.\n await deleteAcceptedPendingUpdates(\n tx,\n input.document.id,\n coveredLocalState.checkpointIds,\n );\n const checkpointReplaced = await replaceDocumentHistoryCheckpoint(\n execSql,\n { appKind: DOCUMENTS_APP_KIND, localId: input.document.id },\n {\n ...input.historyCheckpoint,\n coveredTailIds: input.historyCheckpoint.pruneCoveredLocalState\n ? coveredLocalState.tailIds\n : input.historyCheckpoint.coveredTailIds,\n },\n );\n if (input.historyCheckpoint.pruneCoveredLocalState && !checkpointReplaced) {\n throw new Error(\n \"Document recovery checkpoint was superseded before installation\",\n );\n }\n }\n if (input.historyUpdates && input.historyUpdates.length > 0) {\n await appendDocumentHistoryUpdates(\n execSql,\n { appKind: DOCUMENTS_APP_KIND, localId: input.document.id },\n input.historyUpdates,\n input.historyUpdateOrigin ?? \"local\",\n );\n }\n}\n\nasync function findCoveredRecoveryLocalState(\n tx: ClientSQLiteTransactionScope,\n localId: string,\n recoverySnapshot: string,\n): Promise<{\n checkpointIds: string[];\n hasOrdinaryPendingUpdates: boolean;\n hasUnprunablePendingUpdates: boolean;\n hasUnverifiedHistoryTail: boolean;\n tailIds: string[];\n}> {\n const recoveredDocument = await createDocument(\n `recovery-tail-verification:${localId}`,\n );\n try {\n importSnapshot(recoveredDocument, base64ToBytes(recoverySnapshot));\n const rows = await tx\n .select({\n id: documentHistoryUpdates.id,\n origin: documentHistoryUpdates.origin,\n sourceVersionVector: documentHistoryUpdates.sourceVersionVector,\n updateData: documentHistoryUpdates.updateData,\n updateId: documentHistoryUpdates.updateId,\n })\n .from(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, DOCUMENTS_APP_KIND),\n eq(documentHistoryUpdates.localId, localId),\n ),\n );\n const pendingUpdates = rows.filter((row) => row.updateId !== null);\n const tail = rows.filter((row) => row.origin !== \"outbox\");\n const checkpointUpdateData = new Set(\n pendingUpdates.flatMap((row) =>\n row.sourceVersionVector === null ? [] : [row.updateData],\n ),\n );\n let hasUnverifiedHistoryTail = false;\n const tailIds = tail.flatMap((row) => {\n if (row.id === null) {\n // An unverifiable row identity cannot participate in the guarded\n // delete, so accepting it would leave a stale recovery redirect.\n hasUnverifiedHistoryTail = true;\n return [];\n }\n if (checkpointUpdateData.has(row.updateData)) return [row.id];\n try {\n if (\n updateMatchesDocumentHistory(\n recoveredDocument,\n base64ToBytes(row.updateData),\n )\n ) {\n return [row.id];\n }\n } catch {\n // Fall through: malformed history is not proven by the rebuild.\n }\n hasUnverifiedHistoryTail = true;\n return [];\n });\n return {\n checkpointIds: pendingUpdates.flatMap((row) =>\n row.updateId !== null && row.sourceVersionVector !== null\n ? [row.updateId]\n : [],\n ),\n hasOrdinaryPendingUpdates: pendingUpdates.some(\n (row) => row.sourceVersionVector === null,\n ),\n hasUnprunablePendingUpdates: pendingUpdates.some(\n (row) => row.id === null,\n ),\n hasUnverifiedHistoryTail,\n tailIds,\n };\n } finally {\n recoveredDocument.free();\n }\n}\n\ntype CommitDocumentMutationInput = Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n>[1];\ntype SaveClientProjection = Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n>[2];\n\nasync function applyStoredDocumentMutation(input: {\n lockedExecSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0];\n mutation: CommitDocumentMutationInput;\n saveClientProjection: SaveClientProjection;\n tx: ClientSQLiteTransactionScope;\n loadDocument: DocumentsPersistence[\"loadDocument\"];\n}) {\n const { lockedExecSql, mutation, tx } = input;\n const currentRecord = await input.loadDocument(\n lockedExecSql,\n mutation.document.id,\n );\n if (mutation.stillCurrent && !mutation.stillCurrent()) {\n return { committed: false as const, currentRecord };\n }\n if (\n !currentRecord ||\n !sameExpectedDocumentRecord(currentRecord, mutation.expectedRecord)\n ) {\n await settleMutationConflict({ currentRecord, mutation, tx });\n return { committed: false as const, currentRecord };\n }\n\n if (mutation.attachmentRemoval) {\n await applyStoredAttachmentRemoval({\n localId: mutation.document.id,\n removal: mutation.attachmentRemoval,\n tx,\n });\n }\n if (mutation.attachmentStaging) {\n await upsertStoredAttachmentStagingRows({\n createdAt: new Date().toISOString(),\n localId: mutation.document.id,\n staging: mutation.attachmentStaging,\n tx,\n });\n }\n await appendMutationHistory(lockedExecSql, mutation, tx);\n await insertPendingUpdate(tx, mutation.document.id, mutation.pendingUpdate);\n await deleteAcceptedPendingUpdates(\n tx,\n mutation.document.id,\n mutation.acceptedPendingUpdateIds,\n );\n if (mutation.clearSyncFailure) {\n await clearDocumentSyncFailureInTransaction(tx, {\n appKind: DOCUMENTS_APP_KIND,\n localId: mutation.document.id,\n });\n }\n const updatedAt = await resolveDocumentSaveTimestamp({\n document: mutation.document,\n options:\n mutation.updatedAt === undefined\n ? undefined\n : { updatedAt: mutation.updatedAt },\n tx,\n });\n if (\n !(await saveDocumentRows({ document: mutation.document, tx, updatedAt }))\n ) {\n throw new Error(\n \"Document recovery generation changed before mutation save\",\n );\n }\n await input.saveClientProjection(lockedExecSql, updatedAt);\n return { committed: true as const, updatedAt };\n}\n\nasync function runStoredDocumentMutationTransaction(input: {\n lockedExecSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0];\n mutation: CommitDocumentMutationInput;\n saveClientProjection: SaveClientProjection;\n loadDocument: DocumentsPersistence[\"loadDocument\"];\n}) {\n const outcome = await getClientSQLitePersistenceRuntime(\n input.lockedExecSql,\n ).guardedTransaction(\n (tx) => applyStoredDocumentMutation({ ...input, tx }),\n () => !input.mutation.stillCurrent || input.mutation.stillCurrent(),\n { behavior: \"immediate\" },\n );\n if (outcome.committed && outcome.result) {\n return outcome.result;\n }\n return {\n committed: false as const,\n currentRecord: await input.loadDocument(\n input.lockedExecSql,\n input.mutation.document.id,\n ),\n };\n}\n\nexport async function commitStoredDocumentMutation(\n execSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0],\n input: CommitDocumentMutationInput,\n saveClientProjection: SaveClientProjection,\n loadDocument: DocumentsPersistence[\"loadDocument\"],\n) {\n return runSerializedSqlMutation(execSql, (lockedExecSql) =>\n runStoredDocumentMutationTransaction({\n lockedExecSql,\n loadDocument,\n mutation: input,\n saveClientProjection,\n }),\n );\n}\n\nexport async function settleStoredDocumentPendingUpdates(\n execSql: Parameters<DocumentsPersistence[\"settleAcceptedPendingUpdates\"]>[0],\n input: Parameters<DocumentsPersistence[\"settleAcceptedPendingUpdates\"]>[1],\n loadDocument: DocumentsPersistence[\"loadDocument\"],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const currentRecord = await loadDocument(\n lockedExecSql,\n input.expectedRecord.id,\n );\n if (\n currentRecord &&\n sameDocumentSecurityIdentity(currentRecord, input.expectedRecord) &&\n sameRecoveryGeneration(currentRecord, input.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n input.expectedRecord.id,\n input.pendingUpdateIds,\n );\n }\n return currentRecord;\n },\n { behavior: \"immediate\" },\n ),\n );\n}\n"]}
1
+ {"version":3,"file":"documentMutationPersistence.js","sourceRoot":"","sources":["documentMutationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes } from \"@tearleads/encoding\";\nimport {\n createDocument,\n importSnapshot,\n updateMatchesDocumentHistory,\n} from \"@tearleads/loro\";\nimport { and, eq } from \"drizzle-orm\";\nimport { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport { documentSyncPullContinuationsEqual } from \"../../../documents/shared/sync/pullContinuation\";\nimport {\n appendDocumentHistoryUpdates,\n replaceDocumentHistoryCheckpoint,\n} from \"../../../sqlite/documentPersistence/documentHistoryPersistence\";\nimport {\n insertDocumentPendingUpdateWithHistoryInTransaction,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../../sqlite/documentPersistence/documentPendingUpdatePersistence\";\nimport { clearDocumentSyncFailureInTransaction } from \"../../../sqlite/documentPersistence/documentSyncFailurePersistence\";\nimport { documentHistoryUpdates } from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentsPersistence, StoredDocumentRecord } from \"../types\";\nimport {\n applyStoredAttachmentRemoval,\n upsertStoredAttachmentStagingRows,\n} from \"./attachmentStagingPersistence\";\nimport {\n sameDocumentSecurityIdentity,\n sameNullableDocumentValue,\n} from \"./documentRecordIdentity\";\nimport { resolveDocumentSaveTimestamp, saveDocumentRows } from \"./documentRows\";\n\nfunction sameRecoveryGeneration(\n current: StoredDocumentRecord,\n expected: StoredDocumentRecord,\n): boolean {\n return (\n (current.recoveryGeneration ?? 0) === (expected.recoveryGeneration ?? 0)\n );\n}\n\nfunction sameExpectedDocumentRecord(\n current: StoredDocumentRecord,\n expected: StoredDocumentRecord,\n): boolean {\n return (\n sameDocumentSecurityIdentity(current, expected) &&\n sameRecoveryGeneration(current, expected) &&\n sameNullableDocumentValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n sameNullableDocumentValue(\n current.pendingBaseVersion,\n expected.pendingBaseVersion,\n ) &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired) &&\n (current.documentKind ?? null) === (expected.documentKind ?? null) &&\n current.text === expected.text &&\n (current.title ?? null) === (expected.title ?? null)\n );\n}\n\nasync function deleteAcceptedPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n localId: string,\n ids: readonly string[],\n): Promise<void> {\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n { appKind: DOCUMENTS_APP_KIND, localId },\n ids,\n );\n}\n\nasync function insertPendingUpdate(\n tx: ClientSQLiteTransactionScope,\n documentId: string,\n pendingUpdate: Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n >[1][\"pendingUpdate\"],\n): Promise<void> {\n if (!pendingUpdate) return;\n await insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt: new Date().toISOString(),\n pendingUpdate,\n scope: { appKind: DOCUMENTS_APP_KIND, localId: documentId },\n tx,\n });\n}\n\nasync function settleMutationConflict(input: {\n currentRecord: StoredDocumentRecord | null;\n mutation: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[1];\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n if (\n input.currentRecord &&\n input.mutation.settleAcceptedPendingOnConflict &&\n sameDocumentSecurityIdentity(\n input.currentRecord,\n input.mutation.expectedRecord,\n ) &&\n sameRecoveryGeneration(input.currentRecord, input.mutation.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n input.tx,\n input.mutation.document.id,\n input.mutation.acceptedPendingUpdateIds,\n );\n }\n}\n\nasync function appendMutationHistory(\n execSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0],\n input: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[1],\n tx: ClientSQLiteTransactionScope,\n): Promise<void> {\n if (input.historyCheckpoint) {\n const coveredLocalState = input.historyCheckpoint.pruneCoveredLocalState\n ? await findCoveredRecoveryLocalState(\n tx,\n input.document.id,\n input.historyCheckpoint.snapshot,\n )\n : {\n checkpointIds: [],\n hasOrdinaryPendingUpdates: false,\n hasUnprunablePendingUpdates: false,\n hasUnverifiedHistoryTail: false,\n tailIds: [],\n };\n if (\n input.historyCheckpoint.pruneCoveredLocalState &&\n (coveredLocalState.hasOrdinaryPendingUpdates ||\n coveredLocalState.hasUnprunablePendingUpdates)\n ) {\n throw new Error(\n \"Document recovery found unproven pending updates before installation\",\n );\n }\n if (\n input.historyCheckpoint.pruneCoveredLocalState &&\n coveredLocalState.hasUnverifiedHistoryTail\n ) {\n throw new Error(\n \"Document recovery found unverified history tail before installation\",\n );\n }\n // A queued rotation baseline the recovery snapshot covers is unqueued\n // first so the replacement below can delete it with the covered tail.\n await deleteAcceptedPendingUpdates(\n tx,\n input.document.id,\n coveredLocalState.checkpointIds,\n );\n const checkpointReplaced = await replaceDocumentHistoryCheckpoint(\n execSql,\n { appKind: DOCUMENTS_APP_KIND, localId: input.document.id },\n {\n ...input.historyCheckpoint,\n coveredTailIds: input.historyCheckpoint.pruneCoveredLocalState\n ? coveredLocalState.tailIds\n : input.historyCheckpoint.coveredTailIds,\n },\n );\n if (input.historyCheckpoint.pruneCoveredLocalState && !checkpointReplaced) {\n throw new Error(\n \"Document recovery checkpoint was superseded before installation\",\n );\n }\n }\n if (input.historyUpdates && input.historyUpdates.length > 0) {\n await appendDocumentHistoryUpdates(\n execSql,\n { appKind: DOCUMENTS_APP_KIND, localId: input.document.id },\n input.historyUpdates,\n input.historyUpdateOrigin ?? \"local\",\n );\n }\n}\n\nasync function findCoveredRecoveryLocalState(\n tx: ClientSQLiteTransactionScope,\n localId: string,\n recoverySnapshot: string,\n): Promise<{\n checkpointIds: string[];\n hasOrdinaryPendingUpdates: boolean;\n hasUnprunablePendingUpdates: boolean;\n hasUnverifiedHistoryTail: boolean;\n tailIds: string[];\n}> {\n const recoveredDocument = await createDocument(\n `recovery-tail-verification:${localId}`,\n );\n try {\n importSnapshot(recoveredDocument, base64ToBytes(recoverySnapshot));\n const rows = await tx\n .select({\n id: documentHistoryUpdates.id,\n origin: documentHistoryUpdates.origin,\n sourceVersionVector: documentHistoryUpdates.sourceVersionVector,\n updateData: documentHistoryUpdates.updateData,\n updateId: documentHistoryUpdates.updateId,\n })\n .from(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, DOCUMENTS_APP_KIND),\n eq(documentHistoryUpdates.localId, localId),\n ),\n );\n const pendingUpdates = rows.filter((row) => row.updateId !== null);\n const tail = rows.filter((row) => row.origin !== \"outbox\");\n const checkpointUpdateData = new Set(\n pendingUpdates.flatMap((row) =>\n row.sourceVersionVector === null ? [] : [row.updateData],\n ),\n );\n let hasUnverifiedHistoryTail = false;\n const tailIds = tail.flatMap((row) => {\n if (row.id === null) {\n // An unverifiable row identity cannot participate in the guarded\n // delete, so accepting it would leave a stale recovery redirect.\n hasUnverifiedHistoryTail = true;\n return [];\n }\n if (checkpointUpdateData.has(row.updateData)) return [row.id];\n try {\n if (\n updateMatchesDocumentHistory(\n recoveredDocument,\n base64ToBytes(row.updateData),\n )\n ) {\n return [row.id];\n }\n } catch {\n // Fall through: malformed history is not proven by the rebuild.\n }\n hasUnverifiedHistoryTail = true;\n return [];\n });\n return {\n checkpointIds: pendingUpdates.flatMap((row) =>\n row.updateId !== null && row.sourceVersionVector !== null\n ? [row.updateId]\n : [],\n ),\n hasOrdinaryPendingUpdates: pendingUpdates.some(\n (row) => row.sourceVersionVector === null,\n ),\n hasUnprunablePendingUpdates: pendingUpdates.some(\n (row) => row.id === null,\n ),\n hasUnverifiedHistoryTail,\n tailIds,\n };\n } finally {\n recoveredDocument.free();\n }\n}\n\ntype CommitDocumentMutationInput = Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n>[1];\ntype SaveClientProjection = Parameters<\n DocumentsPersistence[\"commitDocumentMutation\"]\n>[2];\n\nasync function applyStoredDocumentMutation(input: {\n lockedExecSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0];\n mutation: CommitDocumentMutationInput;\n saveClientProjection: SaveClientProjection;\n tx: ClientSQLiteTransactionScope;\n loadDocument: DocumentsPersistence[\"loadDocument\"];\n}) {\n const { lockedExecSql, mutation, tx } = input;\n const currentRecord = await input.loadDocument(\n lockedExecSql,\n mutation.document.id,\n );\n if (mutation.stillCurrent && !mutation.stillCurrent()) {\n return { committed: false as const, currentRecord };\n }\n if (\n !currentRecord ||\n !sameExpectedDocumentRecord(currentRecord, mutation.expectedRecord)\n ) {\n await settleMutationConflict({ currentRecord, mutation, tx });\n return { committed: false as const, currentRecord };\n }\n\n if (mutation.attachmentRemoval) {\n await applyStoredAttachmentRemoval({\n localId: mutation.document.id,\n removal: mutation.attachmentRemoval,\n tx,\n });\n }\n if (mutation.attachmentStaging) {\n await upsertStoredAttachmentStagingRows({\n createdAt: new Date().toISOString(),\n localId: mutation.document.id,\n staging: mutation.attachmentStaging,\n tx,\n });\n }\n await appendMutationHistory(lockedExecSql, mutation, tx);\n await insertPendingUpdate(tx, mutation.document.id, mutation.pendingUpdate);\n await deleteAcceptedPendingUpdates(\n tx,\n mutation.document.id,\n mutation.acceptedPendingUpdateIds,\n );\n if (mutation.clearSyncFailure) {\n await clearDocumentSyncFailureInTransaction(tx, {\n appKind: DOCUMENTS_APP_KIND,\n localId: mutation.document.id,\n });\n }\n const updatedAt = await resolveDocumentSaveTimestamp({\n document: mutation.document,\n options:\n mutation.updatedAt === undefined\n ? undefined\n : { updatedAt: mutation.updatedAt },\n tx,\n });\n if (\n !(await saveDocumentRows({ document: mutation.document, tx, updatedAt }))\n ) {\n throw new Error(\n \"Document recovery generation changed before mutation save\",\n );\n }\n await input.saveClientProjection(lockedExecSql, updatedAt);\n return { committed: true as const, updatedAt };\n}\n\nasync function runStoredDocumentMutationTransaction(input: {\n lockedExecSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0];\n mutation: CommitDocumentMutationInput;\n saveClientProjection: SaveClientProjection;\n loadDocument: DocumentsPersistence[\"loadDocument\"];\n}) {\n const outcome = await getClientSQLitePersistenceRuntime(\n input.lockedExecSql,\n ).guardedTransaction(\n (tx) => applyStoredDocumentMutation({ ...input, tx }),\n () => !input.mutation.stillCurrent || input.mutation.stillCurrent(),\n { behavior: \"immediate\" },\n );\n if (outcome.committed && outcome.result) {\n return outcome.result;\n }\n return {\n committed: false as const,\n currentRecord: await input.loadDocument(\n input.lockedExecSql,\n input.mutation.document.id,\n ),\n };\n}\n\nexport async function commitStoredDocumentMutation(\n execSql: Parameters<DocumentsPersistence[\"commitDocumentMutation\"]>[0],\n input: CommitDocumentMutationInput,\n saveClientProjection: SaveClientProjection,\n loadDocument: DocumentsPersistence[\"loadDocument\"],\n) {\n return runSerializedSqlMutation(execSql, (lockedExecSql) =>\n runStoredDocumentMutationTransaction({\n lockedExecSql,\n loadDocument,\n mutation: input,\n saveClientProjection,\n }),\n );\n}\n\nexport async function settleStoredDocumentPendingUpdates(\n execSql: Parameters<DocumentsPersistence[\"settleAcceptedPendingUpdates\"]>[0],\n input: Parameters<DocumentsPersistence[\"settleAcceptedPendingUpdates\"]>[1],\n loadDocument: DocumentsPersistence[\"loadDocument\"],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const currentRecord = await loadDocument(\n lockedExecSql,\n input.expectedRecord.id,\n );\n if (\n currentRecord &&\n sameDocumentSecurityIdentity(currentRecord, input.expectedRecord) &&\n sameRecoveryGeneration(currentRecord, input.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n input.expectedRecord.id,\n input.pendingUpdateIds,\n );\n }\n return currentRecord;\n },\n { behavior: \"immediate\" },\n ),\n );\n}\n"]}
@@ -1,9 +1,8 @@
1
1
  import { and, eq } from "drizzle-orm";
2
- import { DEFAULT_DOCUMENT_KIND } from "../../../documents/documentConstants.js";
2
+ import { DEFAULT_DOCUMENT_KIND, DOCUMENTS_APP_KIND, } from "../../../documents/documentConstants.js";
3
3
  import { deriveStoredDocumentTitle, getUntitledDocumentTitle, } from "../../../documents/documentKinds.js";
4
4
  import { normalizeEffectiveAccessLevel } from "../../../keying/accessLevel.js";
5
5
  import { documentProjection, documents } from "../../../sqlite/schema/index.js";
6
- import { DOCUMENTS_APP_KIND } from "./constants.js";
7
6
  // Deliberately excludes the projected text (`documentProjectionText`): the
8
7
  // title fallback is derived at write time, so summary listings never need to
9
8
  // haul content-sized values through the worker.
@@ -1 +1 @@
1
- {"version":3,"file":"documentProjectionRows.js","sourceRoot":"","sources":["documentProjectionRows.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../documents/documentConstants\";\nimport {\n deriveStoredDocumentTitle,\n getUntitledDocumentTitle,\n type StoredDocumentKind,\n} from \"../../../documents/documentKinds\";\nimport type { DocumentSummary } from \"../../../documents/documentSummary\";\nimport { normalizeEffectiveAccessLevel } from \"../../../keying/accessLevel\";\nimport { documentProjection, documents } from \"../../../sqlite/schema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\n\ninterface SelectedDocumentProjection {\n localId: string | null;\n documentId: string | null;\n containerId: string | null;\n documentKind: StoredDocumentKind;\n title: string;\n updatedAt: string;\n accessStateHash: string | null;\n effectiveAccessLevel: string | null;\n}\n\ninterface SelectedDocumentProjectionDetail {\n text: string | null;\n containerId: string | null;\n documentKind: StoredDocumentKind;\n title: string;\n}\n\ninterface SelectedDocumentProjectionTimestamp {\n documentKind?: StoredDocumentKind;\n text?: string | null;\n title?: string;\n updatedAt: string;\n}\n\n// Deliberately excludes the projected text (`documentProjectionText`): the\n// title fallback is derived at write time, so summary listings never need to\n// haul content-sized values through the worker.\nexport const documentSummarySelection = {\n localId: documentProjection.localId,\n documentId: documentProjection.documentId,\n containerId: documentProjection.containerId,\n documentKind: documentProjection.documentKind,\n title: documentProjection.title,\n updatedAt: documentProjection.updatedAt,\n accessStateHash: documents.accessStateHash,\n effectiveAccessLevel: documents.effectiveAccessLevel,\n};\n\nexport const documentSummaryJoin = and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, documentProjection.localId),\n);\n\nexport function mapDocumentSummary(\n row: SelectedDocumentProjection,\n): DocumentSummary {\n return {\n accessStateHash: row.accessStateHash,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n row.effectiveAccessLevel,\n ),\n id: row.localId ?? \"\",\n containerId: row.containerId,\n documentKind: row.documentKind,\n documentId: row.documentId,\n title: getProjectionTitle(row),\n updatedAt: row.updatedAt,\n };\n}\n\nexport function toDocumentSummary(\n record: StoredDocumentRecord,\n updatedAt: string,\n): DocumentSummary {\n return {\n accessStateHash: record.accessStateHash ?? null,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n record.effectiveAccessLevel,\n ),\n id: record.id,\n containerId: record.containerId,\n documentKind: record.documentKind ?? DEFAULT_DOCUMENT_KIND,\n documentId: record.documentId,\n title: record.title ?? deriveStoredDocumentTitle(record.text),\n updatedAt,\n };\n}\n\nexport function getProjectionText(\n row:\n | SelectedDocumentProjectionDetail\n | SelectedDocumentProjectionTimestamp\n | undefined,\n): string {\n return row?.text ?? \"\";\n}\n\nexport function getProjectionContainerId(\n row: SelectedDocumentProjectionDetail | undefined,\n): string | null {\n return row?.containerId ?? null;\n}\n\nexport function getProjectionDocumentKind(\n row:\n | SelectedDocumentProjectionDetail\n | SelectedDocumentProjectionTimestamp\n | undefined,\n): StoredDocumentKind {\n return row?.documentKind ?? DEFAULT_DOCUMENT_KIND;\n}\n\nexport function getProjectionTitle(\n row:\n | SelectedDocumentProjectionDetail\n | SelectedDocumentProjectionTimestamp\n | undefined,\n): string {\n const title = row?.title ?? \"\";\n if (\n title.length > 0 &&\n title !== getUntitledDocumentTitle(DEFAULT_DOCUMENT_KIND)\n ) {\n return title;\n }\n\n return deriveStoredDocumentTitle(row?.text ?? \"\");\n}\n\nexport function getProjectionUpdatedAt(\n row: SelectedDocumentProjectionTimestamp | undefined,\n): string {\n return row?.updatedAt ?? \"\";\n}\n"]}
1
+ {"version":3,"file":"documentProjectionRows.js","sourceRoot":"","sources":["documentProjectionRows.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport {\n DEFAULT_DOCUMENT_KIND,\n DOCUMENTS_APP_KIND,\n} from \"../../../documents/documentConstants\";\nimport {\n deriveStoredDocumentTitle,\n getUntitledDocumentTitle,\n type StoredDocumentKind,\n} from \"../../../documents/documentKinds\";\nimport type { DocumentSummary } from \"../../../documents/documentSummary\";\nimport { normalizeEffectiveAccessLevel } from \"../../../keying/accessLevel\";\nimport { documentProjection, documents } from \"../../../sqlite/schema\";\nimport type { StoredDocumentRecord } from \"../types\";\n\ninterface SelectedDocumentProjection {\n localId: string | null;\n documentId: string | null;\n containerId: string | null;\n documentKind: StoredDocumentKind;\n title: string;\n updatedAt: string;\n accessStateHash: string | null;\n effectiveAccessLevel: string | null;\n}\n\ninterface SelectedDocumentProjectionDetail {\n text: string | null;\n containerId: string | null;\n documentKind: StoredDocumentKind;\n title: string;\n}\n\ninterface SelectedDocumentProjectionTimestamp {\n documentKind?: StoredDocumentKind;\n text?: string | null;\n title?: string;\n updatedAt: string;\n}\n\n// Deliberately excludes the projected text (`documentProjectionText`): the\n// title fallback is derived at write time, so summary listings never need to\n// haul content-sized values through the worker.\nexport const documentSummarySelection = {\n localId: documentProjection.localId,\n documentId: documentProjection.documentId,\n containerId: documentProjection.containerId,\n documentKind: documentProjection.documentKind,\n title: documentProjection.title,\n updatedAt: documentProjection.updatedAt,\n accessStateHash: documents.accessStateHash,\n effectiveAccessLevel: documents.effectiveAccessLevel,\n};\n\nexport const documentSummaryJoin = and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, documentProjection.localId),\n);\n\nexport function mapDocumentSummary(\n row: SelectedDocumentProjection,\n): DocumentSummary {\n return {\n accessStateHash: row.accessStateHash,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n row.effectiveAccessLevel,\n ),\n id: row.localId ?? \"\",\n containerId: row.containerId,\n documentKind: row.documentKind,\n documentId: row.documentId,\n title: getProjectionTitle(row),\n updatedAt: row.updatedAt,\n };\n}\n\nexport function toDocumentSummary(\n record: StoredDocumentRecord,\n updatedAt: string,\n): DocumentSummary {\n return {\n accessStateHash: record.accessStateHash ?? null,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n record.effectiveAccessLevel,\n ),\n id: record.id,\n containerId: record.containerId,\n documentKind: record.documentKind ?? DEFAULT_DOCUMENT_KIND,\n documentId: record.documentId,\n title: record.title ?? deriveStoredDocumentTitle(record.text),\n updatedAt,\n };\n}\n\nexport function getProjectionText(\n row:\n | SelectedDocumentProjectionDetail\n | SelectedDocumentProjectionTimestamp\n | undefined,\n): string {\n return row?.text ?? \"\";\n}\n\nexport function getProjectionContainerId(\n row: SelectedDocumentProjectionDetail | undefined,\n): string | null {\n return row?.containerId ?? null;\n}\n\nexport function getProjectionDocumentKind(\n row:\n | SelectedDocumentProjectionDetail\n | SelectedDocumentProjectionTimestamp\n | undefined,\n): StoredDocumentKind {\n return row?.documentKind ?? DEFAULT_DOCUMENT_KIND;\n}\n\nexport function getProjectionTitle(\n row:\n | SelectedDocumentProjectionDetail\n | SelectedDocumentProjectionTimestamp\n | undefined,\n): string {\n const title = row?.title ?? \"\";\n if (\n title.length > 0 &&\n title !== getUntitledDocumentTitle(DEFAULT_DOCUMENT_KIND)\n ) {\n return title;\n }\n\n return deriveStoredDocumentTitle(row?.text ?? \"\");\n}\n\nexport function getProjectionUpdatedAt(\n row: SelectedDocumentProjectionTimestamp | undefined,\n): string {\n return row?.updatedAt ?? \"\";\n}\n"]}
@@ -1,7 +1,7 @@
1
+ import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
1
2
  import { invalidateDocumentSyncPullContinuation } from "../../../sqlite/documentPersistence/index.js";
2
3
  import { getClientSQLitePersistenceRuntime } from "../../../sqlite/sqlitePersistenceRuntime.js";
3
4
  import { runSerializedSqlMutation } from "../../../sqlite/sqlSchema.js";
4
- import { DOCUMENTS_APP_KIND } from "./constants.js";
5
5
  export async function invalidateStoredDocumentPullContinuation(execSql, input, loadDocument, loadHistoryRestoreState) {
6
6
  return runSerializedSqlMutation(execSql, async (lockedExecSql) => getClientSQLitePersistenceRuntime(lockedExecSql).transaction(async () => {
7
7
  const invalidated = await invalidateDocumentSyncPullContinuation(lockedExecSql, {
@@ -1 +1 @@
1
- {"version":3,"file":"documentPullContinuationPersistence.js","sourceRoot":"","sources":["documentPullContinuationPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sCAAsC,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAC7F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,wCAAwC,CAC5D,OAA0E,EAC1E,KAAwE,EACxE,YAAkD,EAClD,uBAAwE;IAExE,OAAO,wBAAwB,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,CAC/D,iCAAiC,CAAC,aAAa,CAAC,CAAC,WAAW,CAC1D,KAAK,IAAI,EAAE;QACT,MAAM,WAAW,GAAG,MAAM,sCAAsC,CAC9D,aAAa,EACb;YACE,GAAG,KAAK;YACR,OAAO,EAAE,kBAAkB;SAC5B,CACF,CAAC;QACF,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,mBAAmB,GAAG,MAAM,uBAAuB,CACvD,aAAa,EACb,KAAK,CAAC,OAAO,CACd,CAAC;QACF,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CACF,CAAC;AACJ,CAAC","sourcesContent":["import { invalidateDocumentSyncPullContinuation } from \"../../../sqlite/documentPersistence\";\nimport { getClientSQLitePersistenceRuntime } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentsPersistence } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\n\nexport async function invalidateStoredDocumentPullContinuation(\n execSql: Parameters<DocumentsPersistence[\"invalidatePullContinuation\"]>[0],\n input: Parameters<DocumentsPersistence[\"invalidatePullContinuation\"]>[1],\n loadDocument: DocumentsPersistence[\"loadDocument\"],\n loadHistoryRestoreState: DocumentsPersistence[\"loadHistoryRestoreState\"],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async () => {\n const invalidated = await invalidateDocumentSyncPullContinuation(\n lockedExecSql,\n {\n ...input,\n appKind: DOCUMENTS_APP_KIND,\n },\n );\n if (!invalidated) return null;\n const record = await loadDocument(lockedExecSql, input.localId);\n if (!record) return null;\n const historyRestoreState = await loadHistoryRestoreState(\n lockedExecSql,\n input.localId,\n );\n return { historyRestoreState, record };\n },\n { behavior: \"immediate\" },\n ),\n );\n}\n"]}
1
+ {"version":3,"file":"documentPullContinuationPersistence.js","sourceRoot":"","sources":["documentPullContinuationPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,sCAAsC,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,EAAE,iCAAiC,EAAE,MAAM,0CAA0C,CAAC;AAC7F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAGrE,MAAM,CAAC,KAAK,UAAU,wCAAwC,CAC5D,OAA0E,EAC1E,KAAwE,EACxE,YAAkD,EAClD,uBAAwE;IAExE,OAAO,wBAAwB,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,CAC/D,iCAAiC,CAAC,aAAa,CAAC,CAAC,WAAW,CAC1D,KAAK,IAAI,EAAE;QACT,MAAM,WAAW,GAAG,MAAM,sCAAsC,CAC9D,aAAa,EACb;YACE,GAAG,KAAK;YACR,OAAO,EAAE,kBAAkB;SAC5B,CACF,CAAC;QACF,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,mBAAmB,GAAG,MAAM,uBAAuB,CACvD,aAAa,EACb,KAAK,CAAC,OAAO,CACd,CAAC;QACF,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CACF,CAAC;AACJ,CAAC","sourcesContent":["import { DOCUMENTS_APP_KIND } from \"../../../documents/documentConstants\";\nimport { invalidateDocumentSyncPullContinuation } from \"../../../sqlite/documentPersistence\";\nimport { getClientSQLitePersistenceRuntime } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../../sqlite/sqlSchema\";\nimport type { DocumentsPersistence } from \"../types\";\n\nexport async function invalidateStoredDocumentPullContinuation(\n execSql: Parameters<DocumentsPersistence[\"invalidatePullContinuation\"]>[0],\n input: Parameters<DocumentsPersistence[\"invalidatePullContinuation\"]>[1],\n loadDocument: DocumentsPersistence[\"loadDocument\"],\n loadHistoryRestoreState: DocumentsPersistence[\"loadHistoryRestoreState\"],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) =>\n getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async () => {\n const invalidated = await invalidateDocumentSyncPullContinuation(\n lockedExecSql,\n {\n ...input,\n appKind: DOCUMENTS_APP_KIND,\n },\n );\n if (!invalidated) return null;\n const record = await loadDocument(lockedExecSql, input.localId);\n if (!record) return null;\n const historyRestoreState = await loadHistoryRestoreState(\n lockedExecSql,\n input.localId,\n );\n return { historyRestoreState, record };\n },\n { behavior: \"immediate\" },\n ),\n );\n}\n"]}
@@ -1,11 +1,10 @@
1
1
  import { and, eq, lte } from "drizzle-orm";
2
- import { DEFAULT_DOCUMENT_KIND } from "../../../documents/documentConstants.js";
2
+ import { DEFAULT_DOCUMENT_KIND, DOCUMENTS_APP_KIND, } from "../../../documents/documentConstants.js";
3
3
  import { deriveStoredDocumentTitle } from "../../../documents/documentKinds.js";
4
4
  import { serializeDocumentSyncPullContinuation } from "../../../documents/shared/sync/pullContinuation.js";
5
5
  import { normalizeEffectiveAccessLevel } from "../../../keying/accessLevel.js";
6
6
  import { documentProjection, documentProjectionText, documents, } from "../../../sqlite/schema/index.js";
7
7
  import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
8
- import { DOCUMENTS_APP_KIND } from "./constants.js";
9
8
  import { getProjectionDocumentKind, getProjectionText, getProjectionTitle, getProjectionUpdatedAt, } from "./documentProjectionRows.js";
10
9
  export function getDocumentScope(localId) {
11
10
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"documentRows.js","sourceRoot":"","sources":["documentRows.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, lte } from \"drizzle-orm\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../documents/documentConstants\";\nimport { deriveStoredDocumentTitle } from \"../../../documents/documentKinds\";\nimport { serializeDocumentSyncPullContinuation } from \"../../../documents/shared/sync/pullContinuation\";\nimport { normalizeEffectiveAccessLevel } from \"../../../keying/accessLevel\";\nimport type { DocumentScope } from \"../../../sqlite/documentPersistence\";\nimport {\n documentProjection,\n documentProjectionText,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport {\n getProjectionDocumentKind,\n getProjectionText,\n getProjectionTitle,\n getProjectionUpdatedAt,\n} from \"./documentProjectionRows\";\n\nexport function getDocumentScope(localId: string): DocumentScope {\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n };\n}\n\nexport async function hasDocumentRow(\n execSql: ExecSql,\n localId: string,\n): Promise<boolean> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, localId),\n ),\n )\n .limit(1);\n return rows.length > 0;\n}\n\nfunction toDocumentRecordRow(input: {\n document: StoredDocumentRecord;\n updatedAt: string;\n}) {\n const { document, updatedAt } = input;\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId: document.id,\n documentId: document.documentId,\n recoveryGeneration: document.recoveryGeneration ?? 0,\n recoveryDocumentId: document.documentId\n ? null\n : (document.recoveryDocumentId ?? null),\n snapshotEndVersion: document.snapshotEndVersion,\n accessEpoch: document.accessEpoch,\n accessStateHash: document.accessStateHash ?? null,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n document.effectiveAccessLevel,\n ),\n lastCommitLsn: document.lastCommitLsn ?? null,\n documentManifestBundle: document.documentManifestBundle ?? null,\n contentKeyBundle: document.contentKeyBundle ?? null,\n documentKekTargets: document.documentKekTargets ?? null,\n // Only touch the outgoing-delta marker when the caller manages it. Callers\n // that leave it undefined (e.g. discovery upserts, registration bootstrap)\n // must not clobber a marker a device-first deferRemoteSync write persisted.\n ...(document.pendingBaseVersion === undefined\n ? {}\n : { pendingBaseVersion: document.pendingBaseVersion }),\n ...(document.pullContinuation === undefined\n ? {}\n : {\n pullContinuation: serializeDocumentSyncPullContinuation(\n document.pullContinuation,\n ),\n }),\n updatedAt,\n };\n}\n\nasync function saveDocumentProjectionRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const { document, tx, updatedAt } = input;\n const projectionRow = {\n localId: document.id,\n documentId: document.documentId,\n containerId: document.containerId,\n documentKind: document.documentKind ?? DEFAULT_DOCUMENT_KIND,\n title: document.title ?? deriveStoredDocumentTitle(document.text),\n updatedAt,\n };\n await tx\n .insert(documentProjection)\n .values(projectionRow)\n .onConflictDoUpdate({\n target: documentProjection.localId,\n set: projectionRow,\n })\n .run();\n\n const projectionTextRow = {\n localId: document.id,\n text: document.text,\n };\n await tx\n .insert(documentProjectionText)\n .values(projectionTextRow)\n .onConflictDoUpdate({\n target: documentProjectionText.localId,\n set: projectionTextRow,\n })\n .run();\n}\n\nexport async function createDocumentRowsIfAbsent(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n const inserted = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoNothing({\n target: [documents.appKind, documents.localId],\n })\n .returning({ localId: documents.localId });\n if (inserted.length === 0) {\n return false;\n }\n\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nexport async function saveDocumentRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n // The recovery-generation fence rides on the upsert: a stored row from a\n // newer recovery generation is left untouched and returns no row, so a\n // stale writer skips the projection writes without a separate read.\n const saved = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoUpdate({\n target: [documents.appKind, documents.localId],\n set: documentRow,\n setWhere: lte(\n documents.recoveryGeneration,\n documentRow.recoveryGeneration,\n ),\n })\n .returning({ localId: documents.localId });\n if (saved.length === 0) {\n return false;\n }\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nfunction didStoredDocumentContentChange(\n existing: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n > | null,\n next: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n >,\n): boolean {\n return (\n existing === null ||\n existing.documentKind !== (next.documentKind ?? DEFAULT_DOCUMENT_KIND) ||\n existing.snapshotEndVersion !== next.snapshotEndVersion ||\n existing.text !== next.text ||\n existing.title !== (next.title ?? deriveStoredDocumentTitle(next.text))\n );\n}\n\nexport async function resolveDocumentSaveTimestamp(input: {\n document: StoredDocumentRecord;\n options?: { updatedAt?: string } | undefined;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const { document, options, tx } = input;\n if (options?.updatedAt) {\n return options.updatedAt;\n }\n\n // One read for the stored row and its projection; the projection columns\n // are not nullable, so they are null exactly when the projection is absent.\n const [existing] = await tx\n .select({\n snapshotEndVersion: documents.snapshotEndVersion,\n documentKind: documentProjection.documentKind,\n text: documentProjectionText.text,\n title: documentProjection.title,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documents)\n .leftJoin(\n documentProjection,\n eq(documentProjection.localId, documents.localId),\n )\n .leftJoin(\n documentProjectionText,\n eq(documentProjectionText.localId, documentProjection.localId),\n )\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, document.id),\n ),\n )\n .limit(1);\n const existingProjection =\n existing?.documentKind != null &&\n existing.title != null &&\n existing.updatedAt != null\n ? {\n documentKind: existing.documentKind,\n text: existing.text,\n title: existing.title,\n updatedAt: existing.updatedAt,\n }\n : undefined;\n const now = new Date().toISOString();\n return didStoredDocumentContentChange(\n existing\n ? {\n documentKind: getProjectionDocumentKind(existingProjection),\n snapshotEndVersion: existing.snapshotEndVersion,\n text: getProjectionText(existingProjection),\n title: getProjectionTitle(existingProjection),\n }\n : null,\n document,\n )\n ? now\n : getProjectionUpdatedAt(existingProjection) || now;\n}\n"]}
1
+ {"version":3,"file":"documentRows.js","sourceRoot":"","sources":["documentRows.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, lte } from \"drizzle-orm\";\nimport {\n DEFAULT_DOCUMENT_KIND,\n DOCUMENTS_APP_KIND,\n} from \"../../../documents/documentConstants\";\nimport { deriveStoredDocumentTitle } from \"../../../documents/documentKinds\";\nimport { serializeDocumentSyncPullContinuation } from \"../../../documents/shared/sync/pullContinuation\";\nimport { normalizeEffectiveAccessLevel } from \"../../../keying/accessLevel\";\nimport type { DocumentScope } from \"../../../sqlite/documentPersistence\";\nimport {\n documentProjection,\n documentProjectionText,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport {\n getProjectionDocumentKind,\n getProjectionText,\n getProjectionTitle,\n getProjectionUpdatedAt,\n} from \"./documentProjectionRows\";\n\nexport function getDocumentScope(localId: string): DocumentScope {\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n };\n}\n\nexport async function hasDocumentRow(\n execSql: ExecSql,\n localId: string,\n): Promise<boolean> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, localId),\n ),\n )\n .limit(1);\n return rows.length > 0;\n}\n\nfunction toDocumentRecordRow(input: {\n document: StoredDocumentRecord;\n updatedAt: string;\n}) {\n const { document, updatedAt } = input;\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId: document.id,\n documentId: document.documentId,\n recoveryGeneration: document.recoveryGeneration ?? 0,\n recoveryDocumentId: document.documentId\n ? null\n : (document.recoveryDocumentId ?? null),\n snapshotEndVersion: document.snapshotEndVersion,\n accessEpoch: document.accessEpoch,\n accessStateHash: document.accessStateHash ?? null,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n document.effectiveAccessLevel,\n ),\n lastCommitLsn: document.lastCommitLsn ?? null,\n documentManifestBundle: document.documentManifestBundle ?? null,\n contentKeyBundle: document.contentKeyBundle ?? null,\n documentKekTargets: document.documentKekTargets ?? null,\n // Only touch the outgoing-delta marker when the caller manages it. Callers\n // that leave it undefined (e.g. discovery upserts, registration bootstrap)\n // must not clobber a marker a device-first deferRemoteSync write persisted.\n ...(document.pendingBaseVersion === undefined\n ? {}\n : { pendingBaseVersion: document.pendingBaseVersion }),\n ...(document.pullContinuation === undefined\n ? {}\n : {\n pullContinuation: serializeDocumentSyncPullContinuation(\n document.pullContinuation,\n ),\n }),\n updatedAt,\n };\n}\n\nasync function saveDocumentProjectionRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const { document, tx, updatedAt } = input;\n const projectionRow = {\n localId: document.id,\n documentId: document.documentId,\n containerId: document.containerId,\n documentKind: document.documentKind ?? DEFAULT_DOCUMENT_KIND,\n title: document.title ?? deriveStoredDocumentTitle(document.text),\n updatedAt,\n };\n await tx\n .insert(documentProjection)\n .values(projectionRow)\n .onConflictDoUpdate({\n target: documentProjection.localId,\n set: projectionRow,\n })\n .run();\n\n const projectionTextRow = {\n localId: document.id,\n text: document.text,\n };\n await tx\n .insert(documentProjectionText)\n .values(projectionTextRow)\n .onConflictDoUpdate({\n target: documentProjectionText.localId,\n set: projectionTextRow,\n })\n .run();\n}\n\nexport async function createDocumentRowsIfAbsent(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n const inserted = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoNothing({\n target: [documents.appKind, documents.localId],\n })\n .returning({ localId: documents.localId });\n if (inserted.length === 0) {\n return false;\n }\n\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nexport async function saveDocumentRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n // The recovery-generation fence rides on the upsert: a stored row from a\n // newer recovery generation is left untouched and returns no row, so a\n // stale writer skips the projection writes without a separate read.\n const saved = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoUpdate({\n target: [documents.appKind, documents.localId],\n set: documentRow,\n setWhere: lte(\n documents.recoveryGeneration,\n documentRow.recoveryGeneration,\n ),\n })\n .returning({ localId: documents.localId });\n if (saved.length === 0) {\n return false;\n }\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nfunction didStoredDocumentContentChange(\n existing: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n > | null,\n next: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n >,\n): boolean {\n return (\n existing === null ||\n existing.documentKind !== (next.documentKind ?? DEFAULT_DOCUMENT_KIND) ||\n existing.snapshotEndVersion !== next.snapshotEndVersion ||\n existing.text !== next.text ||\n existing.title !== (next.title ?? deriveStoredDocumentTitle(next.text))\n );\n}\n\nexport async function resolveDocumentSaveTimestamp(input: {\n document: StoredDocumentRecord;\n options?: { updatedAt?: string } | undefined;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const { document, options, tx } = input;\n if (options?.updatedAt) {\n return options.updatedAt;\n }\n\n // One read for the stored row and its projection; the projection columns\n // are not nullable, so they are null exactly when the projection is absent.\n const [existing] = await tx\n .select({\n snapshotEndVersion: documents.snapshotEndVersion,\n documentKind: documentProjection.documentKind,\n text: documentProjectionText.text,\n title: documentProjection.title,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documents)\n .leftJoin(\n documentProjection,\n eq(documentProjection.localId, documents.localId),\n )\n .leftJoin(\n documentProjectionText,\n eq(documentProjectionText.localId, documentProjection.localId),\n )\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, document.id),\n ),\n )\n .limit(1);\n const existingProjection =\n existing?.documentKind != null &&\n existing.title != null &&\n existing.updatedAt != null\n ? {\n documentKind: existing.documentKind,\n text: existing.text,\n title: existing.title,\n updatedAt: existing.updatedAt,\n }\n : undefined;\n const now = new Date().toISOString();\n return didStoredDocumentContentChange(\n existing\n ? {\n documentKind: getProjectionDocumentKind(existingProjection),\n snapshotEndVersion: existing.snapshotEndVersion,\n text: getProjectionText(existingProjection),\n title: getProjectionTitle(existingProjection),\n }\n : null,\n document,\n )\n ? now\n : getProjectionUpdatedAt(existingProjection) || now;\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  import { and, asc, eq, inArray, isNotNull, lt, notExists, or, } from "drizzle-orm";
2
+ import { DOCUMENTS_APP_KIND } from "../../../documents/documentConstants.js";
2
3
  import { documentOrphanBlobReclaims } from "../../../sqlite/documentPersistence/documentOrphanBlobReclaims.js";
3
4
  import { documentAttachmentBlobProjection, documentHistoryCheckpoints, documentHistoryUpdates, documentPendingAttachments, documents, } from "../../../sqlite/schema/index.js";
4
5
  import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
5
6
  import { runSerializedSqlMutation, } from "../../../sqlite/sqlSchema.js";
6
- import { DOCUMENTS_APP_KIND } from "./constants.js";
7
7
  // Crash residue gets a full day to outlive slow devices and wall-clock skew;
8
8
  // canonical-row absence is necessary but never sufficient for fresh writes.
9
9
  const DOCUMENT_ORPHAN_SWEEP_MIN_AGE_MS = 24 * 60 * 60 * 1000;