@tearleads/client-sdk 0.1.42 → 0.1.44

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 (224) hide show
  1. package/client/containerDocumentDiscovery.js +71 -29
  2. package/client/containerDocumentDiscovery.js.map +1 -1
  3. package/client/deviceFirst.js +4 -5
  4. package/client/deviceFirst.js.map +1 -1
  5. package/data/blobs/transferPool.js +35 -8
  6. package/data/blobs/transferPool.js.map +1 -1
  7. package/data/containers/shared/projection.js +12 -0
  8. package/data/containers/shared/projection.js.map +1 -1
  9. package/data/documents/blob/shared/types.d.ts +2 -3
  10. package/data/documents/blob/shared/types.js.map +1 -1
  11. package/data/documents/shared/events.js +0 -1
  12. package/data/documents/shared/events.js.map +1 -1
  13. package/data/persistence/container-contents/containerContentsPersistence.js +6 -22
  14. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  15. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +5 -15
  16. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  17. package/data/persistence/container-contents/containerPendingUpdatePersistence.js +6 -15
  18. package/data/persistence/container-contents/containerPendingUpdatePersistence.js.map +1 -1
  19. package/data/persistence/container-contents/containerRecoveryPersistence.js +3 -4
  20. package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
  21. package/data/persistence/container-contents/containerRemovalWork.js +3 -5
  22. package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
  23. package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
  24. package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
  25. package/data/persistence/containers/containerSyncWatermarkPersistence.d.ts +11 -3
  26. package/data/persistence/containers/containerSyncWatermarkPersistence.js +46 -58
  27. package/data/persistence/containers/containerSyncWatermarkPersistence.js.map +1 -1
  28. package/data/persistence/documents/documentsPersistence.js +4 -9
  29. package/data/persistence/documents/documentsPersistence.js.map +1 -1
  30. package/data/persistence/documents/internal/discardDocument.js +1 -2
  31. package/data/persistence/documents/internal/discardDocument.js.map +1 -1
  32. package/data/persistence/documents/internal/documentDeletionPersistence.js +1 -2
  33. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  34. package/data/persistence/documents/internal/documentMutationPersistence.js +17 -25
  35. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  36. package/data/persistence/documents/internal/orphanSideRows.js +2 -14
  37. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  38. package/data/persistence/documents/internal/syncQueuePersistence.js +3 -3
  39. package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
  40. package/data/sqlite/documentHistoryPersistence.d.ts +9 -3
  41. package/data/sqlite/documentHistoryPersistence.js +31 -8
  42. package/data/sqlite/documentHistoryPersistence.js.map +1 -1
  43. package/data/sqlite/documentPendingUpdatePersistence.d.ts +58 -11
  44. package/data/sqlite/documentPendingUpdatePersistence.js +137 -63
  45. package/data/sqlite/documentPendingUpdatePersistence.js.map +1 -1
  46. package/data/sqlite/documentPersistence.d.ts +1 -1
  47. package/data/sqlite/documentPersistence.js +1 -1
  48. package/data/sqlite/documentPersistence.js.map +1 -1
  49. package/data/sqlite/documentPersistenceTypes.d.ts +2 -2
  50. package/data/sqlite/documentPersistenceTypes.js.map +1 -1
  51. package/data/sqlite/documentRecordPersistence.js +5 -4
  52. package/data/sqlite/documentRecordPersistence.js.map +1 -1
  53. package/data/sqlite/schema.d.ts +167 -517
  54. package/data/sqlite/schema.js +68 -82
  55. package/data/sqlite/schema.js.map +1 -1
  56. package/internal/api-client/ApiClient.d.ts +18 -41
  57. package/internal/api-client/ApiClient.js +9 -14
  58. package/internal/api-client/ApiClient.js.map +1 -1
  59. package/internal/api-client/apiRequestRuntime.d.ts +2 -0
  60. package/internal/api-client/apiRequestRuntime.js +4 -0
  61. package/internal/api-client/apiRequestRuntime.js.map +1 -1
  62. package/internal/api-client/binaryRequestOperationTransport.d.ts +18 -0
  63. package/internal/api-client/index.d.ts +1 -0
  64. package/internal/api-client/index.js +1 -0
  65. package/internal/api-client/index.js.map +1 -1
  66. package/internal/api-client/operationTransportFactory.d.ts +6 -0
  67. package/internal/api-client/requestInternals.js +7 -7
  68. package/internal/api-client/requestInternals.js.map +1 -1
  69. package/internal/api-client/routes/blobs/get.d.ts +7 -0
  70. package/internal/api-client/routes/blobs/get.js.map +1 -1
  71. package/internal/api-client/routes/blobs/multipart.js +1 -11
  72. package/internal/api-client/routes/blobs/multipart.js.map +1 -1
  73. package/internal/api-client/routes/blobs/multipartUpload.d.ts +14 -0
  74. package/internal/api-client/routes/blobs/multipartUpload.js +94 -43
  75. package/internal/api-client/routes/blobs/multipartUpload.js.map +1 -1
  76. package/internal/api-client/routes/containers/reads.d.ts +13 -7
  77. package/internal/api-client/routes/containers/reads.js +36 -15
  78. package/internal/api-client/routes/containers/reads.js.map +1 -1
  79. package/internal/api-client/types.d.ts +1 -5
  80. package/internal/api-client/types.js.map +1 -1
  81. package/internal/validators/containerReadRefinements.js +15 -5
  82. package/internal/validators/containerReadRefinements.js.map +1 -1
  83. package/internal/validators/containerReadSchemas.d.ts +36 -0
  84. package/internal/validators/containerReadSchemas.js +64 -1
  85. package/internal/validators/containerReadSchemas.js.map +1 -1
  86. package/internal/validators/operation/attachments.d.ts +80 -160
  87. package/internal/validators/operation/auth.d.ts +760 -1664
  88. package/internal/validators/operation/blobDownloads.js +1 -1
  89. package/internal/validators/operation/blobDownloads.js.map +1 -1
  90. package/internal/validators/operation/containerMutations.d.ts +416 -856
  91. package/internal/validators/operation/containerReads.d.ts +118 -182
  92. package/internal/validators/operation/containerReads.js +20 -54
  93. package/internal/validators/operation/containerReads.js.map +1 -1
  94. package/internal/validators/operation/documentMutations.d.ts +120 -264
  95. package/internal/validators/operation/documentSync.d.ts +40 -80
  96. package/internal/validators/operation/index.d.ts +2 -2
  97. package/internal/validators/operation/index.js +2 -2
  98. package/internal/validators/operation/index.js.map +1 -1
  99. package/internal/validators/operation/multipartBlobs.d.ts +70 -190
  100. package/internal/validators/operation/multipartBlobs.js +2 -24
  101. package/internal/validators/operation/multipartBlobs.js.map +1 -1
  102. package/internal/validators/operation/multipartPartUploads.d.ts +5 -5
  103. package/internal/validators/operation/multipartPartUploads.js +6 -20
  104. package/internal/validators/operation/multipartPartUploads.js.map +1 -1
  105. package/internal/validators/operation/organizations.d.ts +882 -1906
  106. package/internal/validators/operation/principals.d.ts +120 -240
  107. package/internal/validators/operation/registry.d.ts +3 -4
  108. package/internal/validators/operation/registry.js +3 -4
  109. package/internal/validators/operation/registry.js.map +1 -1
  110. package/internal/validators/request/blob.d.ts +100 -201
  111. package/internal/validators/request/blob.js +6 -13
  112. package/internal/validators/request/blob.js.map +1 -1
  113. package/internal/validators/request/container.d.ts +136 -272
  114. package/internal/validators/request/container.js +16 -10
  115. package/internal/validators/request/container.js.map +1 -1
  116. package/internal/validators/request/containerDocumentLanes.d.ts +23 -0
  117. package/internal/validators/request/containerDocumentLanes.js +23 -0
  118. package/internal/validators/request/containerDocumentLanes.js.map +1 -0
  119. package/internal/validators/request/containerManifestRef.d.ts +54 -0
  120. package/internal/validators/request/containerManifestRef.js +28 -0
  121. package/internal/validators/request/containerManifestRef.js.map +1 -0
  122. package/internal/validators/request/containerMetadata.d.ts +160 -368
  123. package/internal/validators/request/containerParentLanes.js +5 -35
  124. package/internal/validators/request/containerParentLanes.js.map +1 -1
  125. package/internal/validators/request/document.d.ts +100 -245
  126. package/internal/validators/request/document.js +1 -2
  127. package/internal/validators/request/document.js.map +1 -1
  128. package/internal/validators/request/documentSyncSchema.d.ts +42 -109
  129. package/internal/validators/request/documentSyncSchema.js +8 -25
  130. package/internal/validators/request/documentSyncSchema.js.map +1 -1
  131. package/internal/validators/request/index.d.ts +2 -1
  132. package/internal/validators/request/index.js +2 -1
  133. package/internal/validators/request/index.js.map +1 -1
  134. package/internal/validators/request/organization.d.ts +160 -320
  135. package/internal/validators/request/organizationProvisioning.d.ts +2424 -5312
  136. package/internal/validators/request/principal.d.ts +160 -320
  137. package/internal/validators/request/registration.d.ts +760 -1664
  138. package/internal/validators/response/blob.d.ts +48 -27
  139. package/internal/validators/response/blob.js +3 -10
  140. package/internal/validators/response/blob.js.map +1 -1
  141. package/internal/validators/response/containerDocumentLanes.d.ts +82 -0
  142. package/internal/validators/response/containerDocumentLanes.js +35 -0
  143. package/internal/validators/response/containerDocumentLanes.js.map +1 -0
  144. package/internal/validators/response/containerParentLanes.js +3 -15
  145. package/internal/validators/response/containerParentLanes.js.map +1 -1
  146. package/internal/validators/response/index.d.ts +3 -2
  147. package/internal/validators/response/index.js +2 -2
  148. package/internal/validators/response/index.js.map +1 -1
  149. package/internal/validators/util/blob.d.ts +7 -0
  150. package/internal/validators/util/blob.js +7 -0
  151. package/internal/validators/util/blob.js.map +1 -1
  152. package/internal/validators/util/blobTransferSchemas.d.ts +41 -0
  153. package/internal/validators/util/blobTransferSchemas.js +39 -0
  154. package/internal/validators/util/blobTransferSchemas.js.map +1 -0
  155. package/internal/validators/util/containerLimits.d.ts +7 -0
  156. package/internal/validators/util/containerLimits.js +7 -0
  157. package/internal/validators/util/containerLimits.js.map +1 -1
  158. package/internal/validators/util/index.d.ts +2 -1
  159. package/internal/validators/util/index.js +2 -1
  160. package/internal/validators/util/index.js.map +1 -1
  161. package/package.json +1 -1
  162. package/sync/reconciliation/knownContainerSweep.js +57 -54
  163. package/sync/reconciliation/knownContainerSweep.js.map +1 -1
  164. package/sync/reconciliation/reconcileContainer.js +49 -17
  165. package/sync/reconciliation/reconcileContainer.js.map +1 -1
  166. package/sync/reconciliation/service.js +44 -16
  167. package/sync/reconciliation/service.js.map +1 -1
  168. package/sync/reconciliation/serviceTypes.d.ts +23 -2
  169. package/sync/reconciliation/serviceTypes.js.map +1 -1
  170. package/workflows/blobs/multipartFirstParts.js +82 -0
  171. package/workflows/blobs/multipartFirstParts.js.map +1 -0
  172. package/workflows/blobs/multipartStageResolution.js +83 -0
  173. package/workflows/blobs/multipartStageResolution.js.map +1 -0
  174. package/workflows/blobs/multipartUpload.js +45 -89
  175. package/workflows/blobs/multipartUpload.js.map +1 -1
  176. package/workflows/container-contents/containerDocumentListing.js +92 -38
  177. package/workflows/container-contents/containerDocumentListing.js.map +1 -1
  178. package/workflows/container-contents/containerPersistence.d.ts +8 -2
  179. package/workflows/container-contents/containerPersistence.js +6 -7
  180. package/workflows/container-contents/containerPersistence.js.map +1 -1
  181. package/workflows/container-contents/documentDiscovery.d.ts +3 -3
  182. package/workflows/container-contents/documentDiscovery.js +24 -96
  183. package/workflows/container-contents/documentDiscovery.js.map +1 -1
  184. package/workflows/container-contents/documentDiscoveryApply.js +65 -0
  185. package/workflows/container-contents/documentDiscoveryApply.js.map +1 -0
  186. package/workflows/container-contents/documentDiscoveryLanes.js +53 -0
  187. package/workflows/container-contents/documentDiscoveryLanes.js.map +1 -0
  188. package/workflows/container-contents/documentDiscoveryTypes.d.ts +25 -19
  189. package/workflows/container-contents/documentDiscoveryTypes.js.map +1 -1
  190. package/workflows/container-contents/documentPriming.js +2 -1
  191. package/workflows/container-contents/documentPriming.js.map +1 -1
  192. package/workflows/container-contents/documentQueries/sql.js +4 -4
  193. package/workflows/container-contents/documentQueries/sql.js.map +1 -1
  194. package/workflows/container-contents/pendingWrites/deferredTails.js +6 -3
  195. package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
  196. package/workflows/container-contents/pendingWrites/sources.js +2 -1
  197. package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
  198. package/workflows/container-contents/pendingWrites.js +2 -1
  199. package/workflows/container-contents/pendingWrites.js.map +1 -1
  200. package/workflows/container-contents/remoteHydration/laneFetchMarkers.js +11 -17
  201. package/workflows/container-contents/remoteHydration/laneFetchMarkers.js.map +1 -1
  202. package/workflows/containers/child/create.js +3 -3
  203. package/workflows/containers/child/create.js.map +1 -1
  204. package/workflows/containers/child/move.js +2 -2
  205. package/workflows/containers/child/move.js.map +1 -1
  206. package/workflows/containers/child/mutationRequestCore.js +5 -4
  207. package/workflows/containers/child/mutationRequestCore.js.map +1 -1
  208. package/workflows/containers/child/recitePlan.js +3 -2
  209. package/workflows/containers/child/recitePlan.js.map +1 -1
  210. package/workflows/containers/child/sharePlanCore.js +2 -2
  211. package/workflows/containers/child/sharePlanCore.js.map +1 -1
  212. package/workflows/containers/root/create.js +2 -2
  213. package/workflows/containers/root/create.js.map +1 -1
  214. package/workflows/registration/provisioningBootstrapBuilders.d.ts +20 -46
  215. package/workflows/sync/remoteReset.js +9 -9
  216. package/workflows/sync/remoteReset.js.map +1 -1
  217. package/workflows/sync/remoteResetCursorScope.js +10 -18
  218. package/workflows/sync/remoteResetCursorScope.js.map +1 -1
  219. package/workflows/sync/remoteResetPlans.js +6 -3
  220. package/workflows/sync/remoteResetPlans.js.map +1 -1
  221. package/workflows/sync/remoteResetScope.js +4 -11
  222. package/workflows/sync/remoteResetScope.js.map +1 -1
  223. package/internal/validators/operation/blobTransferSchemas.js +0 -11
  224. package/internal/validators/operation/blobTransferSchemas.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dormantContainerMetadata.js","sourceRoot":"","sources":["dormantContainerMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n documentHistoryCheckpoints,\n documentHistoryUpdates,\n documentPendingUpdates,\n documentSyncFailures,\n documents,\n dormantContainerMetadata,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\n\nexport const CONTAINER_METADATA_APP_KIND = \"container-metadata\";\n\ninterface DormantContainerMetadataRetention {\n readonly containerId: string;\n readonly organizationId: string;\n readonly retainedAt: string;\n}\n\nexport async function retainDormantContainerMetadataInTransaction(\n tx: ClientSQLiteTransactionScope,\n retained: ReadonlyArray<DormantContainerMetadataRetention>,\n): Promise<void> {\n if (retained.length === 0) {\n return;\n }\n\n await tx\n .insert(dormantContainerMetadata)\n .values([...retained])\n .onConflictDoUpdate({\n target: dormantContainerMetadata.containerId,\n set: {\n organizationId: sql`excluded.organization_id`,\n retainedAt: sql`excluded.retained_at`,\n },\n })\n .run();\n}\n\nexport async function clearDormantContainerMetadataInTransaction(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n if (containerIds.length === 0) {\n return;\n }\n await tx\n .delete(dormantContainerMetadata)\n .where(inArray(dormantContainerMetadata.containerId, [...containerIds]))\n .run();\n}\n\n/** Delete every durable row owned by a container-metadata document scope. */\nexport async function deleteContainerMetadataDocumentRowsInTransaction(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n const ids = [...containerIds];\n if (ids.length === 0) {\n return;\n }\n await tx\n .delete(documents)\n .where(\n and(\n eq(documents.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documents.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentHistoryCheckpoints.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentHistoryUpdates.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentPendingUpdates)\n .where(\n and(\n eq(documentPendingUpdates.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentPendingUpdates.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentSyncFailures)\n .where(\n and(\n eq(documentSyncFailures.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentSyncFailures.localId, ids),\n ),\n )\n .run();\n await clearDormantContainerMetadataInTransaction(tx, ids);\n}\n"]}
1
+ {"version":3,"file":"dormantContainerMetadata.js","sourceRoot":"","sources":["dormantContainerMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,EACpB,SAAS,EACT,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,CAAC,MAAM,2BAA2B,GAAG,oBAAoB,CAAC;AAQhE,MAAM,CAAC,KAAK,UAAU,2CAA2C,CAC/D,EAAgC,EAChC,QAA0D;IAE1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,MAAM,EAAE;SACL,MAAM,CAAC,wBAAwB,CAAC;SAChC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;SACrB,kBAAkB,CAAC;QAClB,MAAM,EAAE,wBAAwB,CAAC,WAAW;QAC5C,GAAG,EAAE;YACH,cAAc,EAAE,GAAG,CAAA,0BAA0B;YAC7C,UAAU,EAAE,GAAG,CAAA,sBAAsB;SACtC;KACF,CAAC;SACD,GAAG,EAAE,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0CAA0C,CAC9D,EAAgC,EAChC,YAAmC;IAEnC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,MAAM,EAAE;SACL,MAAM,CAAC,wBAAwB,CAAC;SAChC,KAAK,CAAC,OAAO,CAAC,wBAAwB,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;SACvE,GAAG,EAAE,CAAC;AACX,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,gDAAgD,CACpE,EAAgC,EAChC,YAAmC;IAEnC,MAAM,GAAG,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC;IAC9B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO;IACT,CAAC;IACD,MAAM,EAAE;SACL,MAAM,CAAC,SAAS,CAAC;SACjB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,2BAA2B,CAAC,EAClD,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAChC,CACF;SACA,GAAG,EAAE,CAAC;IACT,MAAM,EAAE;SACL,MAAM,CAAC,0BAA0B,CAAC;SAClC,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,CAAC,EACnE,OAAO,CAAC,0BAA0B,CAAC,OAAO,EAAE,GAAG,CAAC,CACjD,CACF;SACA,GAAG,EAAE,CAAC;IACT,MAAM,EAAE;SACL,MAAM,CAAC,sBAAsB,CAAC;SAC9B,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,sBAAsB,CAAC,OAAO,EAAE,2BAA2B,CAAC,EAC/D,OAAO,CAAC,sBAAsB,CAAC,OAAO,EAAE,GAAG,CAAC,CAC7C,CACF;SACA,GAAG,EAAE,CAAC;IACT,MAAM,EAAE;SACL,MAAM,CAAC,oBAAoB,CAAC;SAC5B,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,CAAC,EAC7D,OAAO,CAAC,oBAAoB,CAAC,OAAO,EAAE,GAAG,CAAC,CAC3C,CACF;SACA,GAAG,EAAE,CAAC;IACT,MAAM,0CAA0C,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AAC5D,CAAC","sourcesContent":["import { and, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n documentHistoryCheckpoints,\n documentHistoryUpdates,\n documentSyncFailures,\n documents,\n dormantContainerMetadata,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\n\nexport const CONTAINER_METADATA_APP_KIND = \"container-metadata\";\n\ninterface DormantContainerMetadataRetention {\n readonly containerId: string;\n readonly organizationId: string;\n readonly retainedAt: string;\n}\n\nexport async function retainDormantContainerMetadataInTransaction(\n tx: ClientSQLiteTransactionScope,\n retained: ReadonlyArray<DormantContainerMetadataRetention>,\n): Promise<void> {\n if (retained.length === 0) {\n return;\n }\n\n await tx\n .insert(dormantContainerMetadata)\n .values([...retained])\n .onConflictDoUpdate({\n target: dormantContainerMetadata.containerId,\n set: {\n organizationId: sql`excluded.organization_id`,\n retainedAt: sql`excluded.retained_at`,\n },\n })\n .run();\n}\n\nexport async function clearDormantContainerMetadataInTransaction(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n if (containerIds.length === 0) {\n return;\n }\n await tx\n .delete(dormantContainerMetadata)\n .where(inArray(dormantContainerMetadata.containerId, [...containerIds]))\n .run();\n}\n\n/** Delete every durable row owned by a container-metadata document scope. */\nexport async function deleteContainerMetadataDocumentRowsInTransaction(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n const ids = [...containerIds];\n if (ids.length === 0) {\n return;\n }\n await tx\n .delete(documents)\n .where(\n and(\n eq(documents.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documents.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentHistoryCheckpoints)\n .where(\n and(\n eq(documentHistoryCheckpoints.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentHistoryCheckpoints.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentHistoryUpdates.localId, ids),\n ),\n )\n .run();\n await tx\n .delete(documentSyncFailures)\n .where(\n and(\n eq(documentSyncFailures.appKind, CONTAINER_METADATA_APP_KIND),\n inArray(documentSyncFailures.localId, ids),\n ),\n )\n .run();\n await clearDormantContainerMetadataInTransaction(tx, ids);\n}\n"]}
@@ -31,9 +31,9 @@ export declare function containerSyncWatermarkLaneKey(lane: ContainerSyncWaterma
31
31
  laneKind: string;
32
32
  };
33
33
  /**
34
- * The watermark half of the container-delete cascade, statement-only so the
35
- * caller can run it inside one atomic transaction alongside the rest of the
36
- * cascade.
34
+ * The lane-state half of the container-delete cascade (cursor and freshness
35
+ * marker share one row), statement-only so the caller can run it inside one
36
+ * atomic transaction alongside the rest of the cascade.
37
37
  */
38
38
  export declare function deleteContainerWatermarksInTransaction(tx: ClientSQLiteDatabase | ClientSQLiteTransactionScope, containerIds: ReadonlyArray<string>): Promise<void>;
39
39
  export declare const sqlContainerSyncWatermarkPersistence: {
@@ -43,6 +43,14 @@ export declare const sqlContainerSyncWatermarkPersistence: {
43
43
  loadCheckRecords(execSql: ExecSql, lanes: ReadonlyArray<ContainerSyncWatermarkLane>): Promise<Array<ContainerSyncLaneCheckRecord | null>>;
44
44
  markChecked(execSql: ExecSql, lane: ContainerSyncWatermarkLane, options?: ContainerSyncMarkerMutationOptions): Promise<boolean>;
45
45
  saveWatermark(execSql: ExecSql, lane: ContainerSyncWatermarkLane, watermark: SyncWatermark, options?: ContainerSyncMarkerMutationOptions): Promise<boolean>;
46
+ /**
47
+ * Upserts one lane row in a single statement: the cursor when `watermark`
48
+ * is set and the freshness marker when `checked`; the other half is kept.
49
+ */
50
+ recordLaneFetch(execSql: ExecSql, lane: ContainerSyncWatermarkLane, fetch: {
51
+ readonly checked: boolean;
52
+ readonly watermark: SyncWatermark | null;
53
+ }, options?: ContainerSyncMarkerMutationOptions): Promise<boolean>;
46
54
  deleteWatermarksForContainers(execSql: ExecSql, containerIds: ReadonlyArray<string>): Promise<void>;
47
55
  };
48
56
  export {};
@@ -1,5 +1,5 @@
1
- import { and, eq, inArray, or } from "drizzle-orm";
2
- import { containerSyncLaneChecks, containerSyncWatermarks, containerSyncWatermarkTables, } from "../../sqlite/schema.js";
1
+ import { and, eq, inArray, isNotNull, or } from "drizzle-orm";
2
+ import { containerSyncWatermarks, containerSyncWatermarkTables, } from "../../sqlite/schema.js";
3
3
  import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
4
4
  import { ensureSqlTables } from "../../sqlite/sqlSchema.js";
5
5
  const CONTAINER_PARENT_LANE = "container_parent";
@@ -37,9 +37,9 @@ function containerParentLaneId(parentId) {
37
37
  : `${CONTAINER_PARENT_LANE_ID_PREFIX}${parentId}`;
38
38
  }
39
39
  /**
40
- * The watermark half of the container-delete cascade, statement-only so the
41
- * caller can run it inside one atomic transaction alongside the rest of the
42
- * cascade.
40
+ * The lane-state half of the container-delete cascade (cursor and freshness
41
+ * marker share one row), statement-only so the caller can run it inside one
42
+ * atomic transaction alongside the rest of the cascade.
43
43
  */
44
44
  export async function deleteContainerWatermarksInTransaction(tx, containerIds) {
45
45
  const uniqueContainerIds = Array.from(new Set(containerIds));
@@ -52,12 +52,14 @@ export async function deleteContainerWatermarksInTransaction(tx, containerIds) {
52
52
  .delete(containerSyncWatermarks)
53
53
  .where(or(and(eq(containerSyncWatermarks.laneKind, CONTAINER_PARENT_LANE), inArray(containerSyncWatermarks.laneId, parentLaneIds)), and(eq(containerSyncWatermarks.laneKind, CONTAINER_DOCUMENTS_LANE), inArray(containerSyncWatermarks.laneId, documentLaneIds))))
54
54
  .run();
55
- await tx
56
- .delete(containerSyncLaneChecks)
57
- .where(or(and(eq(containerSyncLaneChecks.laneKind, CONTAINER_PARENT_LANE), inArray(containerSyncLaneChecks.laneId, parentLaneIds)), and(eq(containerSyncLaneChecks.laneKind, CONTAINER_DOCUMENTS_LANE), inArray(containerSyncLaneChecks.laneId, documentLaneIds))))
58
- .run();
59
55
  }
60
56
  function mapSelectedWatermarkRecord(row) {
57
+ // A lane checked before any cursor was saved has no watermark yet.
58
+ if (row.watermarkId === null ||
59
+ row.watermarkUpdatedAt === null ||
60
+ row.updatedAt === null) {
61
+ return null;
62
+ }
61
63
  return {
62
64
  laneId: row.laneId,
63
65
  laneKind: row.laneKind,
@@ -121,14 +123,14 @@ async function selectWatermarkRows(execSql, lanes) {
121
123
  async function selectCheckRows(execSql, lanes) {
122
124
  await ensureSqlTables(execSql, containerSyncWatermarkTables);
123
125
  const { db } = getClientSQLitePersistenceRuntime(execSql);
124
- return selectLaneRowsInBatches(lanes, ({ laneId, laneKind }) => and(eq(containerSyncLaneChecks.laneKind, laneKind), eq(containerSyncLaneChecks.laneId, laneId)), (whereClause) => db
126
+ return selectLaneRowsInBatches(lanes, ({ laneId, laneKind }) => and(eq(containerSyncWatermarks.laneKind, laneKind), eq(containerSyncWatermarks.laneId, laneId)), async (whereClause) => (await db
125
127
  .select({
126
- checkedAt: containerSyncLaneChecks.checkedAt,
127
- laneId: containerSyncLaneChecks.laneId,
128
- laneKind: containerSyncLaneChecks.laneKind,
128
+ checkedAt: containerSyncWatermarks.checkedAt,
129
+ laneId: containerSyncWatermarks.laneId,
130
+ laneKind: containerSyncWatermarks.laneKind,
129
131
  })
130
- .from(containerSyncLaneChecks)
131
- .where(whereClause));
132
+ .from(containerSyncWatermarks)
133
+ .where(and(whereClause, isNotNull(containerSyncWatermarks.checkedAt)))).flatMap(({ checkedAt, laneId, laneKind }) => checkedAt === null ? [] : [{ checkedAt, laneId, laneKind }]));
132
134
  }
133
135
  export const sqlContainerSyncWatermarkPersistence = {
134
136
  async ensureSchema(execSql) {
@@ -145,7 +147,8 @@ export const sqlContainerSyncWatermarkPersistence = {
145
147
  const recordsByKey = new Map();
146
148
  for (const row of rows) {
147
149
  const record = mapSelectedWatermarkRecord(row);
148
- recordsByKey.set(laneKeyString(record), record);
150
+ if (record)
151
+ recordsByKey.set(laneKeyString(record), record);
149
152
  }
150
153
  return lanes.map((lane) => {
151
154
  const laneKey = containerSyncWatermarkLaneKey(lane);
@@ -163,65 +166,50 @@ export const sqlContainerSyncWatermarkPersistence = {
163
166
  return recordsByKey.get(laneKeyString(laneKey)) ?? null;
164
167
  });
165
168
  },
166
- async markChecked(execSql, lane, options) {
167
- await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);
168
- const { laneId, laneKind } = containerSyncWatermarkLaneKey(lane);
169
- const row = {
170
- checkedAt: new Date().toISOString(),
171
- laneId,
172
- laneKind,
173
- };
174
- const mark = async (db) => {
175
- await db
176
- .insert(containerSyncLaneChecks)
177
- .values(row)
178
- .onConflictDoUpdate({
179
- target: [
180
- containerSyncLaneChecks.laneKind,
181
- containerSyncLaneChecks.laneId,
182
- ],
183
- set: row,
184
- })
185
- .run();
186
- };
187
- const runtime = getClientSQLitePersistenceRuntime(execSql);
188
- if (!options?.stillCurrent) {
189
- await runtime.runMutation(mark);
190
- return true;
191
- }
192
- return (await runtime.guardedTransaction(mark, options.stillCurrent))
193
- .committed;
169
+ markChecked(execSql, lane, options) {
170
+ return sqlContainerSyncWatermarkPersistence.recordLaneFetch(execSql, lane, { checked: true, watermark: null }, options);
194
171
  },
195
- async saveWatermark(execSql, lane, watermark, options) {
172
+ saveWatermark(execSql, lane, watermark, options) {
173
+ return sqlContainerSyncWatermarkPersistence.recordLaneFetch(execSql, lane, { checked: false, watermark }, options);
174
+ },
175
+ /**
176
+ * Upserts one lane row in a single statement: the cursor when `watermark`
177
+ * is set and the freshness marker when `checked`; the other half is kept.
178
+ */
179
+ async recordLaneFetch(execSql, lane, fetch, options) {
180
+ if (!fetch.checked && !fetch.watermark)
181
+ return true;
196
182
  await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);
197
- const { laneId, laneKind } = containerSyncWatermarkLaneKey(lane);
198
- const updatedAt = new Date().toISOString();
199
- const row = {
200
- laneId,
201
- laneKind,
202
- watermarkId: watermark.id,
203
- watermarkUpdatedAt: watermark.updatedAt,
204
- updatedAt,
183
+ const now = new Date().toISOString();
184
+ const changed = {
185
+ ...(fetch.watermark
186
+ ? {
187
+ updatedAt: now,
188
+ watermarkId: fetch.watermark.id,
189
+ watermarkUpdatedAt: fetch.watermark.updatedAt,
190
+ }
191
+ : {}),
192
+ ...(fetch.checked ? { checkedAt: now } : {}),
205
193
  };
206
- const save = async (db) => {
194
+ const record = async (db) => {
207
195
  await db
208
196
  .insert(containerSyncWatermarks)
209
- .values(row)
197
+ .values({ ...containerSyncWatermarkLaneKey(lane), ...changed })
210
198
  .onConflictDoUpdate({
211
199
  target: [
212
200
  containerSyncWatermarks.laneKind,
213
201
  containerSyncWatermarks.laneId,
214
202
  ],
215
- set: row,
203
+ set: changed,
216
204
  })
217
205
  .run();
218
206
  };
219
207
  const runtime = getClientSQLitePersistenceRuntime(execSql);
220
208
  if (!options?.stillCurrent) {
221
- await runtime.runMutation(save);
209
+ await runtime.runMutation(record);
222
210
  return true;
223
211
  }
224
- return (await runtime.guardedTransaction(save, options.stillCurrent))
212
+ return (await runtime.guardedTransaction(record, options.stillCurrent))
225
213
  .committed;
226
214
  },
227
215
  async deleteWatermarksForContainers(execSql, containerIds) {
@@ -1 +1 @@
1
- {"version":3,"file":"containerSyncWatermarkPersistence.js","sourceRoot":"","sources":["containerSyncWatermarkPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SyncWatermark } from \"@tearleads/validators/response\";\nimport { and, eq, inArray, or, type SQL } from \"drizzle-orm\";\nimport {\n containerSyncLaneChecks,\n containerSyncWatermarks,\n containerSyncWatermarkTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteDatabase,\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../../sqlite/sqlSchema\";\n\nconst CONTAINER_PARENT_LANE = \"container_parent\";\nconst CONTAINER_DOCUMENTS_LANE = \"container_documents\";\nconst ROOT_CONTAINER_PARENT_LANE_ID = \"root\";\nconst CONTAINER_PARENT_LANE_ID_PREFIX = \"parent:\";\n// Each lane predicate binds two values, so keep batches comfortably under\n// SQLite's variable limit when a caller reads many lanes at once.\nconst LANE_SELECT_BATCH_SIZE = 100;\n\nexport type ContainerSyncWatermarkLane =\n | {\n kind: typeof CONTAINER_PARENT_LANE;\n parentId: string | null;\n }\n | {\n kind: typeof CONTAINER_DOCUMENTS_LANE;\n containerId: string;\n };\n\ninterface SelectedContainerSyncWatermark {\n laneId: string;\n laneKind: string;\n updatedAt: string;\n watermarkId: string;\n watermarkUpdatedAt: string;\n}\n\ninterface ContainerSyncWatermarkRecord {\n laneId: string;\n laneKind: string;\n updatedAt: string;\n watermark: SyncWatermark;\n}\n\nexport interface ContainerSyncLaneCheckRecord {\n checkedAt: string;\n laneId: string;\n laneKind: string;\n}\n\ninterface ContainerSyncMarkerMutationOptions {\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport const containerParentSyncLane = (\n parentId: string | null,\n): ContainerSyncWatermarkLane => ({\n kind: CONTAINER_PARENT_LANE,\n parentId,\n});\n\nexport const containerContentsSyncLane = (\n containerId: string,\n): ContainerSyncWatermarkLane => ({\n kind: CONTAINER_DOCUMENTS_LANE,\n containerId,\n});\n\nexport function containerSyncWatermarkLaneKey(\n lane: ContainerSyncWatermarkLane,\n): {\n laneId: string;\n laneKind: string;\n} {\n switch (lane.kind) {\n case CONTAINER_PARENT_LANE:\n return {\n laneKind: lane.kind,\n laneId: containerParentLaneId(lane.parentId),\n };\n case CONTAINER_DOCUMENTS_LANE:\n return {\n laneKind: lane.kind,\n laneId: lane.containerId,\n };\n }\n}\n\nfunction containerParentLaneId(parentId: string | null): string {\n return parentId === null\n ? ROOT_CONTAINER_PARENT_LANE_ID\n : `${CONTAINER_PARENT_LANE_ID_PREFIX}${parentId}`;\n}\n\n/**\n * The watermark half of the container-delete cascade, statement-only so the\n * caller can run it inside one atomic transaction alongside the rest of the\n * cascade.\n */\nexport async function deleteContainerWatermarksInTransaction(\n tx: ClientSQLiteDatabase | ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n const uniqueContainerIds = Array.from(new Set(containerIds));\n if (uniqueContainerIds.length === 0) {\n return;\n }\n const parentLaneIds = uniqueContainerIds.map(containerParentLaneId);\n const documentLaneIds = uniqueContainerIds;\n await tx\n .delete(containerSyncWatermarks)\n .where(\n or(\n and(\n eq(containerSyncWatermarks.laneKind, CONTAINER_PARENT_LANE),\n inArray(containerSyncWatermarks.laneId, parentLaneIds),\n ),\n and(\n eq(containerSyncWatermarks.laneKind, CONTAINER_DOCUMENTS_LANE),\n inArray(containerSyncWatermarks.laneId, documentLaneIds),\n ),\n ),\n )\n .run();\n await tx\n .delete(containerSyncLaneChecks)\n .where(\n or(\n and(\n eq(containerSyncLaneChecks.laneKind, CONTAINER_PARENT_LANE),\n inArray(containerSyncLaneChecks.laneId, parentLaneIds),\n ),\n and(\n eq(containerSyncLaneChecks.laneKind, CONTAINER_DOCUMENTS_LANE),\n inArray(containerSyncLaneChecks.laneId, documentLaneIds),\n ),\n ),\n )\n .run();\n}\n\nfunction mapSelectedWatermarkRecord(\n row: SelectedContainerSyncWatermark,\n): ContainerSyncWatermarkRecord {\n return {\n laneId: row.laneId,\n laneKind: row.laneKind,\n updatedAt: row.updatedAt,\n watermark: {\n id: row.watermarkId,\n updatedAt: row.watermarkUpdatedAt,\n },\n };\n}\n\nfunction laneKeyString(input: { laneId: string; laneKind: string }): string {\n return `${input.laneKind}\\0${input.laneId}`;\n}\n\nfunction uniqueLaneKeys(\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Array<{ laneId: string; laneKind: string }> {\n const seen = new Set<string>();\n const laneKeys: Array<{ laneId: string; laneKind: string }> = [];\n\n for (const lane of lanes) {\n const laneKey = containerSyncWatermarkLaneKey(lane);\n const key = laneKeyString(laneKey);\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n laneKeys.push(laneKey);\n }\n\n return laneKeys;\n}\n\n// The ONE batched lane-select shape for this file: both row readers must\n// chunk, because a caller may pass unboundedly many lanes and each lane\n// predicate binds two variables.\nasync function selectLaneRowsInBatches<TRow>(\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n buildLanePredicate: (laneKey: {\n laneId: string;\n laneKind: string;\n }) => SQL | undefined,\n selectBatch: (whereClause: SQL) => Promise<TRow[]>,\n): Promise<TRow[]> {\n const laneKeys = uniqueLaneKeys(lanes);\n const rows: TRow[] = [];\n\n for (\n let index = 0;\n index < laneKeys.length;\n index += LANE_SELECT_BATCH_SIZE\n ) {\n const lanePredicates = laneKeys\n .slice(index, index + LANE_SELECT_BATCH_SIZE)\n .map(buildLanePredicate)\n .filter((predicate): predicate is SQL => predicate !== undefined);\n const whereClause =\n lanePredicates.length === 1 ? lanePredicates[0] : or(...lanePredicates);\n if (!whereClause) {\n continue;\n }\n\n rows.push(...(await selectBatch(whereClause)));\n }\n\n return rows;\n}\n\nasync function selectWatermarkRows(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Promise<SelectedContainerSyncWatermark[]> {\n await ensureSqlTables(execSql, containerSyncWatermarkTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return selectLaneRowsInBatches(\n lanes,\n ({ laneId, laneKind }) =>\n and(\n eq(containerSyncWatermarks.laneKind, laneKind),\n eq(containerSyncWatermarks.laneId, laneId),\n ),\n (whereClause) =>\n db\n .select({\n laneId: containerSyncWatermarks.laneId,\n laneKind: containerSyncWatermarks.laneKind,\n updatedAt: containerSyncWatermarks.updatedAt,\n watermarkId: containerSyncWatermarks.watermarkId,\n watermarkUpdatedAt: containerSyncWatermarks.watermarkUpdatedAt,\n })\n .from(containerSyncWatermarks)\n .where(whereClause),\n );\n}\n\nasync function selectCheckRows(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Promise<ContainerSyncLaneCheckRecord[]> {\n await ensureSqlTables(execSql, containerSyncWatermarkTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return selectLaneRowsInBatches(\n lanes,\n ({ laneId, laneKind }) =>\n and(\n eq(containerSyncLaneChecks.laneKind, laneKind),\n eq(containerSyncLaneChecks.laneId, laneId),\n ),\n (whereClause) =>\n db\n .select({\n checkedAt: containerSyncLaneChecks.checkedAt,\n laneId: containerSyncLaneChecks.laneId,\n laneKind: containerSyncLaneChecks.laneKind,\n })\n .from(containerSyncLaneChecks)\n .where(whereClause),\n );\n}\n\nexport const sqlContainerSyncWatermarkPersistence = {\n async ensureSchema(execSql: ExecSql): Promise<void> {\n await ensureSqlTables(execSql, containerSyncWatermarkTables);\n },\n\n async loadWatermark(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n ): Promise<SyncWatermark | null> {\n const [record] =\n await sqlContainerSyncWatermarkPersistence.loadWatermarkRecords(execSql, [\n lane,\n ]);\n return record?.watermark ?? null;\n },\n\n async loadWatermarkRecords(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n ): Promise<Array<ContainerSyncWatermarkRecord | null>> {\n const rows = await selectWatermarkRows(execSql, lanes);\n const recordsByKey = new Map<string, ContainerSyncWatermarkRecord>();\n\n for (const row of rows) {\n const record = mapSelectedWatermarkRecord(row);\n recordsByKey.set(laneKeyString(record), record);\n }\n\n return lanes.map((lane) => {\n const laneKey = containerSyncWatermarkLaneKey(lane);\n return recordsByKey.get(laneKeyString(laneKey)) ?? null;\n });\n },\n\n async loadCheckRecords(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n ): Promise<Array<ContainerSyncLaneCheckRecord | null>> {\n const rows = await selectCheckRows(execSql, lanes);\n const recordsByKey = new Map<string, ContainerSyncLaneCheckRecord>();\n\n for (const row of rows) {\n recordsByKey.set(laneKeyString(row), row);\n }\n\n return lanes.map((lane) => {\n const laneKey = containerSyncWatermarkLaneKey(lane);\n return recordsByKey.get(laneKeyString(laneKey)) ?? null;\n });\n },\n\n async markChecked(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n options?: ContainerSyncMarkerMutationOptions,\n ): Promise<boolean> {\n await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);\n const { laneId, laneKind } = containerSyncWatermarkLaneKey(lane);\n const row = {\n checkedAt: new Date().toISOString(),\n laneId,\n laneKind,\n };\n\n const mark = async (\n db: ClientSQLiteDatabase | ClientSQLiteTransactionScope,\n ) => {\n await db\n .insert(containerSyncLaneChecks)\n .values(row)\n .onConflictDoUpdate({\n target: [\n containerSyncLaneChecks.laneKind,\n containerSyncLaneChecks.laneId,\n ],\n set: row,\n })\n .run();\n };\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n if (!options?.stillCurrent) {\n await runtime.runMutation(mark);\n return true;\n }\n return (await runtime.guardedTransaction(mark, options.stillCurrent))\n .committed;\n },\n\n async saveWatermark(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n watermark: SyncWatermark,\n options?: ContainerSyncMarkerMutationOptions,\n ): Promise<boolean> {\n await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);\n const { laneId, laneKind } = containerSyncWatermarkLaneKey(lane);\n const updatedAt = new Date().toISOString();\n const row = {\n laneId,\n laneKind,\n watermarkId: watermark.id,\n watermarkUpdatedAt: watermark.updatedAt,\n updatedAt,\n };\n\n const save = async (\n db: ClientSQLiteDatabase | ClientSQLiteTransactionScope,\n ) => {\n await db\n .insert(containerSyncWatermarks)\n .values(row)\n .onConflictDoUpdate({\n target: [\n containerSyncWatermarks.laneKind,\n containerSyncWatermarks.laneId,\n ],\n set: row,\n })\n .run();\n };\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n if (!options?.stillCurrent) {\n await runtime.runMutation(save);\n return true;\n }\n return (await runtime.guardedTransaction(save, options.stillCurrent))\n .committed;\n },\n\n async deleteWatermarksForContainers(\n execSql: ExecSql,\n containerIds: ReadonlyArray<string>,\n ): Promise<void> {\n const uniqueContainerIds = Array.from(new Set(containerIds));\n if (uniqueContainerIds.length === 0) {\n return;\n }\n\n await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await deleteContainerWatermarksInTransaction(db, uniqueContainerIds);\n });\n },\n};\n"]}
1
+ {"version":3,"file":"containerSyncWatermarkPersistence.js","sourceRoot":"","sources":["containerSyncWatermarkPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SyncWatermark } from \"@tearleads/validators/response\";\nimport { and, eq, inArray, isNotNull, or, type SQL } from \"drizzle-orm\";\nimport {\n containerSyncWatermarks,\n containerSyncWatermarkTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteDatabase,\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../../sqlite/sqlSchema\";\n\nconst CONTAINER_PARENT_LANE = \"container_parent\";\nconst CONTAINER_DOCUMENTS_LANE = \"container_documents\";\nconst ROOT_CONTAINER_PARENT_LANE_ID = \"root\";\nconst CONTAINER_PARENT_LANE_ID_PREFIX = \"parent:\";\n// Each lane predicate binds two values, so keep batches comfortably under\n// SQLite's variable limit when a caller reads many lanes at once.\nconst LANE_SELECT_BATCH_SIZE = 100;\n\nexport type ContainerSyncWatermarkLane =\n | {\n kind: typeof CONTAINER_PARENT_LANE;\n parentId: string | null;\n }\n | {\n kind: typeof CONTAINER_DOCUMENTS_LANE;\n containerId: string;\n };\n\ninterface SelectedContainerSyncWatermark {\n laneId: string;\n laneKind: string;\n updatedAt: string | null;\n watermarkId: string | null;\n watermarkUpdatedAt: string | null;\n}\n\ninterface ContainerSyncWatermarkRecord {\n laneId: string;\n laneKind: string;\n updatedAt: string;\n watermark: SyncWatermark;\n}\n\nexport interface ContainerSyncLaneCheckRecord {\n checkedAt: string;\n laneId: string;\n laneKind: string;\n}\n\ninterface ContainerSyncMarkerMutationOptions {\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport const containerParentSyncLane = (\n parentId: string | null,\n): ContainerSyncWatermarkLane => ({\n kind: CONTAINER_PARENT_LANE,\n parentId,\n});\n\nexport const containerContentsSyncLane = (\n containerId: string,\n): ContainerSyncWatermarkLane => ({\n kind: CONTAINER_DOCUMENTS_LANE,\n containerId,\n});\n\nexport function containerSyncWatermarkLaneKey(\n lane: ContainerSyncWatermarkLane,\n): {\n laneId: string;\n laneKind: string;\n} {\n switch (lane.kind) {\n case CONTAINER_PARENT_LANE:\n return {\n laneKind: lane.kind,\n laneId: containerParentLaneId(lane.parentId),\n };\n case CONTAINER_DOCUMENTS_LANE:\n return {\n laneKind: lane.kind,\n laneId: lane.containerId,\n };\n }\n}\n\nfunction containerParentLaneId(parentId: string | null): string {\n return parentId === null\n ? ROOT_CONTAINER_PARENT_LANE_ID\n : `${CONTAINER_PARENT_LANE_ID_PREFIX}${parentId}`;\n}\n\n/**\n * The lane-state half of the container-delete cascade (cursor and freshness\n * marker share one row), statement-only so the caller can run it inside one\n * atomic transaction alongside the rest of the cascade.\n */\nexport async function deleteContainerWatermarksInTransaction(\n tx: ClientSQLiteDatabase | ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n const uniqueContainerIds = Array.from(new Set(containerIds));\n if (uniqueContainerIds.length === 0) {\n return;\n }\n const parentLaneIds = uniqueContainerIds.map(containerParentLaneId);\n const documentLaneIds = uniqueContainerIds;\n await tx\n .delete(containerSyncWatermarks)\n .where(\n or(\n and(\n eq(containerSyncWatermarks.laneKind, CONTAINER_PARENT_LANE),\n inArray(containerSyncWatermarks.laneId, parentLaneIds),\n ),\n and(\n eq(containerSyncWatermarks.laneKind, CONTAINER_DOCUMENTS_LANE),\n inArray(containerSyncWatermarks.laneId, documentLaneIds),\n ),\n ),\n )\n .run();\n}\n\nfunction mapSelectedWatermarkRecord(\n row: SelectedContainerSyncWatermark,\n): ContainerSyncWatermarkRecord | null {\n // A lane checked before any cursor was saved has no watermark yet.\n if (\n row.watermarkId === null ||\n row.watermarkUpdatedAt === null ||\n row.updatedAt === null\n ) {\n return null;\n }\n return {\n laneId: row.laneId,\n laneKind: row.laneKind,\n updatedAt: row.updatedAt,\n watermark: {\n id: row.watermarkId,\n updatedAt: row.watermarkUpdatedAt,\n },\n };\n}\n\nfunction laneKeyString(input: { laneId: string; laneKind: string }): string {\n return `${input.laneKind}\\0${input.laneId}`;\n}\n\nfunction uniqueLaneKeys(\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Array<{ laneId: string; laneKind: string }> {\n const seen = new Set<string>();\n const laneKeys: Array<{ laneId: string; laneKind: string }> = [];\n\n for (const lane of lanes) {\n const laneKey = containerSyncWatermarkLaneKey(lane);\n const key = laneKeyString(laneKey);\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n laneKeys.push(laneKey);\n }\n\n return laneKeys;\n}\n\n// The ONE batched lane-select shape for this file: both row readers must\n// chunk, because a caller may pass unboundedly many lanes and each lane\n// predicate binds two variables.\nasync function selectLaneRowsInBatches<TRow>(\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n buildLanePredicate: (laneKey: {\n laneId: string;\n laneKind: string;\n }) => SQL | undefined,\n selectBatch: (whereClause: SQL) => Promise<TRow[]>,\n): Promise<TRow[]> {\n const laneKeys = uniqueLaneKeys(lanes);\n const rows: TRow[] = [];\n\n for (\n let index = 0;\n index < laneKeys.length;\n index += LANE_SELECT_BATCH_SIZE\n ) {\n const lanePredicates = laneKeys\n .slice(index, index + LANE_SELECT_BATCH_SIZE)\n .map(buildLanePredicate)\n .filter((predicate): predicate is SQL => predicate !== undefined);\n const whereClause =\n lanePredicates.length === 1 ? lanePredicates[0] : or(...lanePredicates);\n if (!whereClause) {\n continue;\n }\n\n rows.push(...(await selectBatch(whereClause)));\n }\n\n return rows;\n}\n\nasync function selectWatermarkRows(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Promise<SelectedContainerSyncWatermark[]> {\n await ensureSqlTables(execSql, containerSyncWatermarkTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return selectLaneRowsInBatches(\n lanes,\n ({ laneId, laneKind }) =>\n and(\n eq(containerSyncWatermarks.laneKind, laneKind),\n eq(containerSyncWatermarks.laneId, laneId),\n ),\n (whereClause) =>\n db\n .select({\n laneId: containerSyncWatermarks.laneId,\n laneKind: containerSyncWatermarks.laneKind,\n updatedAt: containerSyncWatermarks.updatedAt,\n watermarkId: containerSyncWatermarks.watermarkId,\n watermarkUpdatedAt: containerSyncWatermarks.watermarkUpdatedAt,\n })\n .from(containerSyncWatermarks)\n .where(whereClause),\n );\n}\n\nasync function selectCheckRows(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Promise<ContainerSyncLaneCheckRecord[]> {\n await ensureSqlTables(execSql, containerSyncWatermarkTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return selectLaneRowsInBatches(\n lanes,\n ({ laneId, laneKind }) =>\n and(\n eq(containerSyncWatermarks.laneKind, laneKind),\n eq(containerSyncWatermarks.laneId, laneId),\n ),\n async (whereClause) =>\n (\n await db\n .select({\n checkedAt: containerSyncWatermarks.checkedAt,\n laneId: containerSyncWatermarks.laneId,\n laneKind: containerSyncWatermarks.laneKind,\n })\n .from(containerSyncWatermarks)\n .where(and(whereClause, isNotNull(containerSyncWatermarks.checkedAt)))\n ).flatMap(({ checkedAt, laneId, laneKind }) =>\n checkedAt === null ? [] : [{ checkedAt, laneId, laneKind }],\n ),\n );\n}\n\nexport const sqlContainerSyncWatermarkPersistence = {\n async ensureSchema(execSql: ExecSql): Promise<void> {\n await ensureSqlTables(execSql, containerSyncWatermarkTables);\n },\n\n async loadWatermark(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n ): Promise<SyncWatermark | null> {\n const [record] =\n await sqlContainerSyncWatermarkPersistence.loadWatermarkRecords(execSql, [\n lane,\n ]);\n return record?.watermark ?? null;\n },\n\n async loadWatermarkRecords(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n ): Promise<Array<ContainerSyncWatermarkRecord | null>> {\n const rows = await selectWatermarkRows(execSql, lanes);\n const recordsByKey = new Map<string, ContainerSyncWatermarkRecord>();\n\n for (const row of rows) {\n const record = mapSelectedWatermarkRecord(row);\n if (record) recordsByKey.set(laneKeyString(record), record);\n }\n\n return lanes.map((lane) => {\n const laneKey = containerSyncWatermarkLaneKey(lane);\n return recordsByKey.get(laneKeyString(laneKey)) ?? null;\n });\n },\n\n async loadCheckRecords(\n execSql: ExecSql,\n lanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n ): Promise<Array<ContainerSyncLaneCheckRecord | null>> {\n const rows = await selectCheckRows(execSql, lanes);\n const recordsByKey = new Map<string, ContainerSyncLaneCheckRecord>();\n\n for (const row of rows) {\n recordsByKey.set(laneKeyString(row), row);\n }\n\n return lanes.map((lane) => {\n const laneKey = containerSyncWatermarkLaneKey(lane);\n return recordsByKey.get(laneKeyString(laneKey)) ?? null;\n });\n },\n\n markChecked(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n options?: ContainerSyncMarkerMutationOptions,\n ): Promise<boolean> {\n return sqlContainerSyncWatermarkPersistence.recordLaneFetch(\n execSql,\n lane,\n { checked: true, watermark: null },\n options,\n );\n },\n\n saveWatermark(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n watermark: SyncWatermark,\n options?: ContainerSyncMarkerMutationOptions,\n ): Promise<boolean> {\n return sqlContainerSyncWatermarkPersistence.recordLaneFetch(\n execSql,\n lane,\n { checked: false, watermark },\n options,\n );\n },\n\n /**\n * Upserts one lane row in a single statement: the cursor when `watermark`\n * is set and the freshness marker when `checked`; the other half is kept.\n */\n async recordLaneFetch(\n execSql: ExecSql,\n lane: ContainerSyncWatermarkLane,\n fetch: {\n readonly checked: boolean;\n readonly watermark: SyncWatermark | null;\n },\n options?: ContainerSyncMarkerMutationOptions,\n ): Promise<boolean> {\n if (!fetch.checked && !fetch.watermark) return true;\n await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);\n const now = new Date().toISOString();\n const changed = {\n ...(fetch.watermark\n ? {\n updatedAt: now,\n watermarkId: fetch.watermark.id,\n watermarkUpdatedAt: fetch.watermark.updatedAt,\n }\n : {}),\n ...(fetch.checked ? { checkedAt: now } : {}),\n };\n const record = async (\n db: ClientSQLiteDatabase | ClientSQLiteTransactionScope,\n ) => {\n await db\n .insert(containerSyncWatermarks)\n .values({ ...containerSyncWatermarkLaneKey(lane), ...changed })\n .onConflictDoUpdate({\n target: [\n containerSyncWatermarks.laneKind,\n containerSyncWatermarks.laneId,\n ],\n set: changed,\n })\n .run();\n };\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n if (!options?.stillCurrent) {\n await runtime.runMutation(record);\n return true;\n }\n return (await runtime.guardedTransaction(record, options.stillCurrent))\n .committed;\n },\n\n async deleteWatermarksForContainers(\n execSql: ExecSql,\n containerIds: ReadonlyArray<string>,\n ): Promise<void> {\n const uniqueContainerIds = Array.from(new Set(containerIds));\n if (uniqueContainerIds.length === 0) {\n return;\n }\n\n await sqlContainerSyncWatermarkPersistence.ensureSchema(execSql);\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await deleteContainerWatermarksInTransaction(db, uniqueContainerIds);\n });\n },\n};\n"]}
@@ -2,8 +2,9 @@ import { KeyingVerificationError } from "../../../internal/crypto/index.js";
2
2
  import { and, desc, eq, inArray, notInArray, or } from "drizzle-orm";
3
3
  import { DEFAULT_DOCUMENT_KIND } from "../../documents/documentConstants.js";
4
4
  import { HIDDEN_DOCUMENT_SUMMARY_KINDS, } from "../../documents/documentSummary.js";
5
+ import { settleQueuedDocumentUpdatesInTransaction } from "../../sqlite/documentPendingUpdatePersistence.js";
5
6
  import { findLocalIdByDocumentId } from "../../sqlite/documentPersistence.js";
6
- import { documentPendingUpdates, documentProjection, documentPurgeCheckpoints, documents, } from "../../sqlite/schema.js";
7
+ import { documentProjection, documentPurgeCheckpoints, documents, } from "../../sqlite/schema.js";
7
8
  import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
8
9
  import { runSerializedSqlMutation } from "../../sqlite/sqlSchema.js";
9
10
  import { DOCUMENTS_APP_KIND } from "./internal/constants.js";
@@ -16,7 +17,7 @@ import { loadStoredDocumentWithHistoryRestoreState } from "./internal/documentHi
16
17
  import { commitStoredDocumentMutation, settleStoredDocumentPendingUpdates, } from "./internal/documentMutationPersistence.js";
17
18
  import { documentSummaryJoin, documentSummarySelection, getProjectionUpdatedAt, mapDocumentSummary, toDocumentSummary, } from "./internal/documentProjectionRows.js";
18
19
  import { invalidateStoredDocumentPullContinuation } from "./internal/documentPullContinuationPersistence.js";
19
- import { resolveDocumentSaveTimestamp, saveDocumentRows, } from "./internal/documentRows.js";
20
+ import { getDocumentScope, resolveDocumentSaveTimestamp, saveDocumentRows, } from "./internal/documentRows.js";
20
21
  import { resolvePersistedAccessStateHash, resolvePersistedDocumentRuntimeState, } from "./internal/documentRuntimeState.js";
21
22
  import { loadStoredDocumentStoreState } from "./internal/documentStoreStatePersistence.js";
22
23
  import { listDocumentSummaries } from "./internal/documentSummaryQueries.js";
@@ -188,7 +189,6 @@ export const sqlDocumentsPersistence = {
188
189
  }, { behavior: "immediate" }));
189
190
  },
190
191
  async saveDocumentAndDeletePendingUpdates(execSql, document, pendingUpdateIds, options) {
191
- const uniquePendingUpdateIds = [...new Set(pendingUpdateIds)];
192
192
  return runSerializedSqlMutation(execSql, async (lockedExecSql) => getClientSQLitePersistenceRuntime(lockedExecSql).transaction(async (tx) => {
193
193
  const updatedAt = await resolveDocumentSaveTimestamp({
194
194
  document,
@@ -202,12 +202,7 @@ export const sqlDocumentsPersistence = {
202
202
  });
203
203
  if (!saved)
204
204
  return updatedAt;
205
- if (uniquePendingUpdateIds.length > 0) {
206
- await tx
207
- .delete(documentPendingUpdates)
208
- .where(and(eq(documentPendingUpdates.appKind, DOCUMENTS_APP_KIND), eq(documentPendingUpdates.localId, document.id), inArray(documentPendingUpdates.id, uniquePendingUpdateIds)))
209
- .run();
210
- }
205
+ await settleQueuedDocumentUpdatesInTransaction(tx, getDocumentScope(document.id), pendingUpdateIds);
211
206
  return updatedAt;
212
207
  }, { behavior: "immediate" }));
213
208
  },
@@ -1 +1 @@
1
- {"version":3,"file":"documentsPersistence.js","sourceRoot":"","sources":["documentsPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { and, desc, eq, inArray, notInArray, or, type SQL } from \"drizzle-orm\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../documents/documentConstants\";\nimport {\n type DiscoveredDocumentInput,\n type DocumentSummary,\n HIDDEN_DOCUMENT_SUMMARY_KINDS,\n} from \"../../documents/documentSummary\";\nimport { findLocalIdByDocumentId } from \"../../sqlite/documentPersistence\";\nimport {\n documentPendingUpdates,\n documentProjection,\n documentPurgeCheckpoints,\n documents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport { DOCUMENTS_APP_KIND } from \"./internal/constants\";\nimport { applyContainerDocumentTombstonesWithExec } from \"./internal/containerDocumentTombstones\";\nimport { createStoredDocumentWithHistoryCheckpoint } from \"./internal/createDocumentWithHistoryCheckpoint\";\nimport { discardStoredDocumentToShell } from \"./internal/discardDocument\";\nimport { resolveDiscoveredDocumentPlacement } from \"./internal/discoveredDocumentPlacement\";\nimport {\n deleteStoredDocument,\n deleteStoredDocumentIfMatches,\n deleteStoredDocumentSideRowsIfAbsent,\n} from \"./internal/documentDeletionPersistence\";\nimport { loadStoredDocumentWithHistoryRestoreState } from \"./internal/documentHistoryStatePersistence\";\nimport {\n commitStoredDocumentMutation,\n settleStoredDocumentPendingUpdates,\n} from \"./internal/documentMutationPersistence\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n getProjectionUpdatedAt,\n mapDocumentSummary,\n toDocumentSummary,\n} from \"./internal/documentProjectionRows\";\nimport { invalidateStoredDocumentPullContinuation } from \"./internal/documentPullContinuationPersistence\";\nimport {\n resolveDocumentSaveTimestamp,\n saveDocumentRows,\n} from \"./internal/documentRows\";\nimport {\n resolvePersistedAccessStateHash,\n resolvePersistedDocumentRuntimeState,\n} from \"./internal/documentRuntimeState\";\nimport { loadStoredDocumentStoreState } from \"./internal/documentStoreStatePersistence\";\nimport { listDocumentSummaries } from \"./internal/documentSummaryQueries\";\nimport { ensureDocumentsSchema } from \"./internal/ensureDocumentsSchema\";\nimport { saveHydratedAttachment } from \"./internal/hydratedAttachmentPersistence\";\nimport {\n acknowledgeDocumentOrphanBlobReclaim,\n deleteOrphanedDocumentSideRows,\n isDocumentBlobStorageKeyReferenced,\n listDocumentOrphanBlobReclaims,\n} from \"./internal/orphanSideRows\";\nimport {\n loadPendingCreateSummary,\n mapPendingCreateLocalIds,\n} from \"./internal/pendingCreateAdoption\";\nimport { documentRowQueryPersistence } from \"./internal/rowQueryPersistence\";\nimport { documentSyncQueuePersistence } from \"./internal/syncQueuePersistence\";\nimport type {\n ContainerDocumentTombstoneInput,\n DiscardDocumentToShellResult,\n DocumentsPersistence,\n RelinkPersistedDocumentInput,\n StoredDocumentRecord,\n} from \"./types\";\n\nexport { DOCUMENTS_APP_KIND } from \"./internal/constants\";\nexport type {\n AttachmentRemovalRows,\n AttachmentStagingRows,\n ContainerDocumentTombstoneInput,\n DiscardDocumentToShellResult,\n DocumentsPersistence,\n LocalAttachmentRecord,\n PendingAttachmentRecord,\n PendingAttachmentUploadIdentity,\n PendingUpdateInsert,\n PendingUpdateRecord,\n RelinkPersistedDocumentInput,\n StoredDocumentRecord,\n} from \"./types\";\n\nconst DISCOVERED_DOCUMENT_PLACEHOLDER_TITLE = \"Syncing document...\";\n\nasync function upsertDiscoveredDocumentWithExec(\n execSql: ExecSql,\n input: DiscoveredDocumentInput,\n pendingCreates: ReadonlyMap<string, string>,\n tx: ClientSQLiteTransactionScope,\n): Promise<DocumentSummary> {\n const [purgeCheckpoint] = await tx\n .select({ documentId: documentPurgeCheckpoints.documentId })\n .from(documentPurgeCheckpoints)\n .where(eq(documentPurgeCheckpoints.documentId, input.documentId))\n .limit(1);\n if (purgeCheckpoint) {\n throw new KeyingVerificationError(\n \"rollback\",\n \"Document discovery targets a permanently purged document\",\n );\n }\n const existingLocalId = await findLocalIdByDocumentId(\n execSql,\n DOCUMENTS_APP_KIND,\n input.documentId,\n );\n const localId = existingLocalId ?? input.documentId;\n const pendingLocalId = pendingCreates.get(input.documentId);\n if (!existingLocalId && pendingLocalId) {\n const pending = await loadPendingCreateSummary(execSql, pendingLocalId);\n if (!pending) throw new Error(\"Pending create projection is unavailable\");\n return pending;\n }\n const existingDocument = await sqlDocumentsPersistence.loadDocument(\n execSql,\n localId,\n );\n const placement = await resolveDiscoveredDocumentPlacement(\n tx,\n existingDocument,\n input,\n );\n\n const nextDocument: StoredDocumentRecord = {\n id: localId,\n documentId: input.documentId,\n documentKind: existingDocument?.documentKind ?? DEFAULT_DOCUMENT_KIND,\n text: existingDocument?.text ?? \"\",\n title: existingDocument?.title ?? DISCOVERED_DOCUMENT_PLACEHOLDER_TITLE,\n snapshotEndVersion: existingDocument?.snapshotEndVersion ?? \"\",\n recoveryGeneration: existingDocument?.recoveryGeneration ?? 0,\n ...placement,\n effectiveAccessLevel:\n input.effectiveAccessLevel ??\n existingDocument?.effectiveAccessLevel ??\n null,\n ...resolvePersistedDocumentRuntimeState(existingDocument, {\n accessEpoch: placement.accessEpoch,\n documentId: input.documentId,\n }),\n };\n\n const saveOptions =\n existingDocument === null || existingDocument === undefined\n ? { updatedAt: input.createdAt }\n : undefined;\n const updatedAt = await resolveDocumentSaveTimestamp({\n document: nextDocument,\n options: saveOptions,\n tx,\n });\n if (!(await saveDocumentRows({ document: nextDocument, tx, updatedAt }))) {\n throw new Error(\"Document recovery generation changed during discovery\");\n }\n\n return toDocumentSummary(nextDocument, updatedAt);\n}\n\nasync function relinkPersistedDocumentWithExec(\n execSql: ExecSql,\n input: RelinkPersistedDocumentInput,\n): Promise<DocumentSummary | null> {\n const existingDocument = await sqlDocumentsPersistence.loadDocument(\n execSql,\n input.localId,\n );\n if (!existingDocument) {\n return null;\n }\n\n const nextAccessEpoch = Math.max(\n existingDocument.accessEpoch,\n input.accessEpoch,\n );\n const nextDocument: StoredDocumentRecord = {\n ...existingDocument,\n accessEpoch: nextAccessEpoch,\n accessStateHash: resolvePersistedAccessStateHash(existingDocument, {\n accessEpoch: nextAccessEpoch,\n accessStateHash: input.accessStateHash,\n documentId: input.documentId,\n }),\n containerId: input.containerId,\n documentId: input.documentId,\n ...resolvePersistedDocumentRuntimeState(existingDocument, {\n accessEpoch: nextAccessEpoch,\n documentId: input.documentId,\n }),\n };\n\n await sqlDocumentsPersistence.saveDocument(execSql, nextDocument);\n\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const updatedAtRows = await db\n .select({ updatedAt: documentProjection.updatedAt })\n .from(documentProjection)\n .where(eq(documentProjection.localId, input.localId))\n .limit(1);\n\n return toDocumentSummary(\n nextDocument,\n getProjectionUpdatedAt(updatedAtRows[0]),\n );\n}\n\nexport async function upsertDiscoveredDocuments(\n execSql: ExecSql,\n inputs: ReadonlyArray<DiscoveredDocumentInput>,\n): Promise<DocumentSummary[]> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const pendingCreates = await mapPendingCreateLocalIds(lockedExecSql);\n const nextSummaries: DocumentSummary[] = [];\n\n for (const input of inputs) {\n nextSummaries.push(\n await upsertDiscoveredDocumentWithExec(\n lockedExecSql,\n input,\n pendingCreates,\n tx,\n ),\n );\n }\n\n return nextSummaries;\n },\n { behavior: \"immediate\" },\n );\n });\n}\n\nexport async function applyContainerDocumentTombstones(\n execSql: ExecSql,\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): Promise<DocumentSummary[]> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n return applyContainerDocumentTombstonesWithExec(lockedExecSql, tombstones);\n });\n}\n\nexport async function listDocumentsByContainerIdsOrDocumentIds(\n execSql: ExecSql,\n input: {\n containerIds: ReadonlyArray<string>;\n documentIds: ReadonlyArray<string>;\n },\n): Promise<DocumentSummary[]> {\n const uniqueContainerIds = Array.from(new Set(input.containerIds));\n const uniqueDocumentIds = Array.from(new Set(input.documentIds));\n if (uniqueContainerIds.length === 0 && uniqueDocumentIds.length === 0) {\n return [];\n }\n\n const filters: SQL[] = [];\n if (uniqueContainerIds.length > 0) {\n filters.push(inArray(documentProjection.containerId, uniqueContainerIds));\n }\n\n if (uniqueDocumentIds.length > 0) {\n filters.push(inArray(documentProjection.documentId, uniqueDocumentIds));\n }\n\n const whereCondition = filters.length === 1 ? filters[0] : or(...filters);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(\n and(\n whereCondition,\n notInArray(documentProjection.documentKind, [\n ...HIDDEN_DOCUMENT_SUMMARY_KINDS,\n ]),\n ),\n )\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n}\n\nexport const sqlDocumentsPersistence: DocumentsPersistence = {\n orphanBlobs: {\n acknowledge: acknowledgeDocumentOrphanBlobReclaim,\n isReferenced: isDocumentBlobStorageKeyReferenced,\n list: listDocumentOrphanBlobReclaims,\n sweep: deleteOrphanedDocumentSideRows,\n },\n ...documentRowQueryPersistence,\n ...documentSyncQueuePersistence,\n supportsAtomicRecoveryHistoryPruning: true,\n saveHydratedAttachment,\n createDocumentWithHistoryCheckpoint:\n createStoredDocumentWithHistoryCheckpoint,\n commitDocumentMutation: (execSql, input, saveClientProjection) =>\n commitStoredDocumentMutation(\n execSql,\n input,\n saveClientProjection,\n sqlDocumentsPersistence.loadDocument,\n ),\n settleAcceptedPendingUpdates: (execSql, input) =>\n settleStoredDocumentPendingUpdates(\n execSql,\n input,\n sqlDocumentsPersistence.loadDocument,\n ),\n ensureSchema: ensureDocumentsSchema,\n listDocumentSummaries,\n listDocumentsByContainerIdsOrDocumentIds,\n invalidatePullContinuation: (execSql, input) =>\n invalidateStoredDocumentPullContinuation(\n execSql,\n input,\n sqlDocumentsPersistence.loadDocument,\n sqlDocumentsPersistence.loadHistoryRestoreState,\n ),\n loadDocumentWithHistoryRestoreState: (execSql, localId) =>\n loadStoredDocumentWithHistoryRestoreState(\n execSql,\n localId,\n sqlDocumentsPersistence,\n ),\n loadDocumentStoreState: (execSql, localId) =>\n loadStoredDocumentStoreState(execSql, localId, sqlDocumentsPersistence),\n async saveDocument(execSql, document, options) {\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 await saveDocumentRows({\n document,\n tx,\n updatedAt,\n });\n\n return updatedAt;\n },\n { behavior: \"immediate\" },\n ),\n );\n },\n async saveDocumentAndDeletePendingUpdates(\n execSql,\n document,\n pendingUpdateIds,\n options,\n ) {\n const uniquePendingUpdateIds = [...new Set(pendingUpdateIds)];\n\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 const saved = await saveDocumentRows({\n document,\n tx,\n updatedAt,\n });\n if (!saved) return updatedAt;\n if (uniquePendingUpdateIds.length > 0) {\n await tx\n .delete(documentPendingUpdates)\n .where(\n and(\n eq(documentPendingUpdates.appKind, DOCUMENTS_APP_KIND),\n eq(documentPendingUpdates.localId, document.id),\n inArray(documentPendingUpdates.id, uniquePendingUpdateIds),\n ),\n )\n .run();\n }\n return updatedAt;\n },\n { behavior: \"immediate\" },\n ),\n );\n },\n deleteDocument: deleteStoredDocument,\n deleteDocumentIfMatches: deleteStoredDocumentIfMatches,\n deleteDocumentSideRowsIfAbsent: deleteStoredDocumentSideRowsIfAbsent,\n async discardDocumentToShell(\n execSql,\n localId,\n expectedDocumentId,\n documentProjectors,\n ): Promise<DiscardDocumentToShellResult> {\n return discardStoredDocumentToShell({\n documentProjectors,\n execSql,\n expectedDocumentId,\n localId,\n persistence: sqlDocumentsPersistence,\n });\n },\n async upsertDiscoveredDocument(execSql, input) {\n const [nextSummary] = await upsertDiscoveredDocuments(execSql, [input]);\n if (!nextSummary) {\n throw new Error(\"Failed to upsert discovered document\");\n }\n\n return nextSummary;\n },\n async relinkPersistedDocument(execSql, input) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n () => relinkPersistedDocumentWithExec(lockedExecSql, input),\n { behavior: \"immediate\" },\n );\n });\n },\n};\n"]}
1
+ {"version":3,"file":"documentsPersistence.js","sourceRoot":"","sources":["documentsPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { and, desc, eq, inArray, notInArray, or, type SQL } from \"drizzle-orm\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../documents/documentConstants\";\nimport {\n type DiscoveredDocumentInput,\n type DocumentSummary,\n HIDDEN_DOCUMENT_SUMMARY_KINDS,\n} from \"../../documents/documentSummary\";\nimport { settleQueuedDocumentUpdatesInTransaction } from \"../../sqlite/documentPendingUpdatePersistence\";\nimport { findLocalIdByDocumentId } from \"../../sqlite/documentPersistence\";\nimport {\n documentProjection,\n documentPurgeCheckpoints,\n documents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport { DOCUMENTS_APP_KIND } from \"./internal/constants\";\nimport { applyContainerDocumentTombstonesWithExec } from \"./internal/containerDocumentTombstones\";\nimport { createStoredDocumentWithHistoryCheckpoint } from \"./internal/createDocumentWithHistoryCheckpoint\";\nimport { discardStoredDocumentToShell } from \"./internal/discardDocument\";\nimport { resolveDiscoveredDocumentPlacement } from \"./internal/discoveredDocumentPlacement\";\nimport {\n deleteStoredDocument,\n deleteStoredDocumentIfMatches,\n deleteStoredDocumentSideRowsIfAbsent,\n} from \"./internal/documentDeletionPersistence\";\nimport { loadStoredDocumentWithHistoryRestoreState } from \"./internal/documentHistoryStatePersistence\";\nimport {\n commitStoredDocumentMutation,\n settleStoredDocumentPendingUpdates,\n} from \"./internal/documentMutationPersistence\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n getProjectionUpdatedAt,\n mapDocumentSummary,\n toDocumentSummary,\n} from \"./internal/documentProjectionRows\";\nimport { invalidateStoredDocumentPullContinuation } from \"./internal/documentPullContinuationPersistence\";\nimport {\n getDocumentScope,\n resolveDocumentSaveTimestamp,\n saveDocumentRows,\n} from \"./internal/documentRows\";\nimport {\n resolvePersistedAccessStateHash,\n resolvePersistedDocumentRuntimeState,\n} from \"./internal/documentRuntimeState\";\nimport { loadStoredDocumentStoreState } from \"./internal/documentStoreStatePersistence\";\nimport { listDocumentSummaries } from \"./internal/documentSummaryQueries\";\nimport { ensureDocumentsSchema } from \"./internal/ensureDocumentsSchema\";\nimport { saveHydratedAttachment } from \"./internal/hydratedAttachmentPersistence\";\nimport {\n acknowledgeDocumentOrphanBlobReclaim,\n deleteOrphanedDocumentSideRows,\n isDocumentBlobStorageKeyReferenced,\n listDocumentOrphanBlobReclaims,\n} from \"./internal/orphanSideRows\";\nimport {\n loadPendingCreateSummary,\n mapPendingCreateLocalIds,\n} from \"./internal/pendingCreateAdoption\";\nimport { documentRowQueryPersistence } from \"./internal/rowQueryPersistence\";\nimport { documentSyncQueuePersistence } from \"./internal/syncQueuePersistence\";\nimport type {\n ContainerDocumentTombstoneInput,\n DiscardDocumentToShellResult,\n DocumentsPersistence,\n RelinkPersistedDocumentInput,\n StoredDocumentRecord,\n} from \"./types\";\n\nexport { DOCUMENTS_APP_KIND } from \"./internal/constants\";\nexport type {\n AttachmentRemovalRows,\n AttachmentStagingRows,\n ContainerDocumentTombstoneInput,\n DiscardDocumentToShellResult,\n DocumentsPersistence,\n LocalAttachmentRecord,\n PendingAttachmentRecord,\n PendingAttachmentUploadIdentity,\n PendingUpdateInsert,\n PendingUpdateRecord,\n RelinkPersistedDocumentInput,\n StoredDocumentRecord,\n} from \"./types\";\n\nconst DISCOVERED_DOCUMENT_PLACEHOLDER_TITLE = \"Syncing document...\";\n\nasync function upsertDiscoveredDocumentWithExec(\n execSql: ExecSql,\n input: DiscoveredDocumentInput,\n pendingCreates: ReadonlyMap<string, string>,\n tx: ClientSQLiteTransactionScope,\n): Promise<DocumentSummary> {\n const [purgeCheckpoint] = await tx\n .select({ documentId: documentPurgeCheckpoints.documentId })\n .from(documentPurgeCheckpoints)\n .where(eq(documentPurgeCheckpoints.documentId, input.documentId))\n .limit(1);\n if (purgeCheckpoint) {\n throw new KeyingVerificationError(\n \"rollback\",\n \"Document discovery targets a permanently purged document\",\n );\n }\n const existingLocalId = await findLocalIdByDocumentId(\n execSql,\n DOCUMENTS_APP_KIND,\n input.documentId,\n );\n const localId = existingLocalId ?? input.documentId;\n const pendingLocalId = pendingCreates.get(input.documentId);\n if (!existingLocalId && pendingLocalId) {\n const pending = await loadPendingCreateSummary(execSql, pendingLocalId);\n if (!pending) throw new Error(\"Pending create projection is unavailable\");\n return pending;\n }\n const existingDocument = await sqlDocumentsPersistence.loadDocument(\n execSql,\n localId,\n );\n const placement = await resolveDiscoveredDocumentPlacement(\n tx,\n existingDocument,\n input,\n );\n\n const nextDocument: StoredDocumentRecord = {\n id: localId,\n documentId: input.documentId,\n documentKind: existingDocument?.documentKind ?? DEFAULT_DOCUMENT_KIND,\n text: existingDocument?.text ?? \"\",\n title: existingDocument?.title ?? DISCOVERED_DOCUMENT_PLACEHOLDER_TITLE,\n snapshotEndVersion: existingDocument?.snapshotEndVersion ?? \"\",\n recoveryGeneration: existingDocument?.recoveryGeneration ?? 0,\n ...placement,\n effectiveAccessLevel:\n input.effectiveAccessLevel ??\n existingDocument?.effectiveAccessLevel ??\n null,\n ...resolvePersistedDocumentRuntimeState(existingDocument, {\n accessEpoch: placement.accessEpoch,\n documentId: input.documentId,\n }),\n };\n\n const saveOptions =\n existingDocument === null || existingDocument === undefined\n ? { updatedAt: input.createdAt }\n : undefined;\n const updatedAt = await resolveDocumentSaveTimestamp({\n document: nextDocument,\n options: saveOptions,\n tx,\n });\n if (!(await saveDocumentRows({ document: nextDocument, tx, updatedAt }))) {\n throw new Error(\"Document recovery generation changed during discovery\");\n }\n\n return toDocumentSummary(nextDocument, updatedAt);\n}\n\nasync function relinkPersistedDocumentWithExec(\n execSql: ExecSql,\n input: RelinkPersistedDocumentInput,\n): Promise<DocumentSummary | null> {\n const existingDocument = await sqlDocumentsPersistence.loadDocument(\n execSql,\n input.localId,\n );\n if (!existingDocument) {\n return null;\n }\n\n const nextAccessEpoch = Math.max(\n existingDocument.accessEpoch,\n input.accessEpoch,\n );\n const nextDocument: StoredDocumentRecord = {\n ...existingDocument,\n accessEpoch: nextAccessEpoch,\n accessStateHash: resolvePersistedAccessStateHash(existingDocument, {\n accessEpoch: nextAccessEpoch,\n accessStateHash: input.accessStateHash,\n documentId: input.documentId,\n }),\n containerId: input.containerId,\n documentId: input.documentId,\n ...resolvePersistedDocumentRuntimeState(existingDocument, {\n accessEpoch: nextAccessEpoch,\n documentId: input.documentId,\n }),\n };\n\n await sqlDocumentsPersistence.saveDocument(execSql, nextDocument);\n\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const updatedAtRows = await db\n .select({ updatedAt: documentProjection.updatedAt })\n .from(documentProjection)\n .where(eq(documentProjection.localId, input.localId))\n .limit(1);\n\n return toDocumentSummary(\n nextDocument,\n getProjectionUpdatedAt(updatedAtRows[0]),\n );\n}\n\nexport async function upsertDiscoveredDocuments(\n execSql: ExecSql,\n inputs: ReadonlyArray<DiscoveredDocumentInput>,\n): Promise<DocumentSummary[]> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const pendingCreates = await mapPendingCreateLocalIds(lockedExecSql);\n const nextSummaries: DocumentSummary[] = [];\n\n for (const input of inputs) {\n nextSummaries.push(\n await upsertDiscoveredDocumentWithExec(\n lockedExecSql,\n input,\n pendingCreates,\n tx,\n ),\n );\n }\n\n return nextSummaries;\n },\n { behavior: \"immediate\" },\n );\n });\n}\n\nexport async function applyContainerDocumentTombstones(\n execSql: ExecSql,\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): Promise<DocumentSummary[]> {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n return applyContainerDocumentTombstonesWithExec(lockedExecSql, tombstones);\n });\n}\n\nexport async function listDocumentsByContainerIdsOrDocumentIds(\n execSql: ExecSql,\n input: {\n containerIds: ReadonlyArray<string>;\n documentIds: ReadonlyArray<string>;\n },\n): Promise<DocumentSummary[]> {\n const uniqueContainerIds = Array.from(new Set(input.containerIds));\n const uniqueDocumentIds = Array.from(new Set(input.documentIds));\n if (uniqueContainerIds.length === 0 && uniqueDocumentIds.length === 0) {\n return [];\n }\n\n const filters: SQL[] = [];\n if (uniqueContainerIds.length > 0) {\n filters.push(inArray(documentProjection.containerId, uniqueContainerIds));\n }\n\n if (uniqueDocumentIds.length > 0) {\n filters.push(inArray(documentProjection.documentId, uniqueDocumentIds));\n }\n\n const whereCondition = filters.length === 1 ? filters[0] : or(...filters);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(\n and(\n whereCondition,\n notInArray(documentProjection.documentKind, [\n ...HIDDEN_DOCUMENT_SUMMARY_KINDS,\n ]),\n ),\n )\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n}\n\nexport const sqlDocumentsPersistence: DocumentsPersistence = {\n orphanBlobs: {\n acknowledge: acknowledgeDocumentOrphanBlobReclaim,\n isReferenced: isDocumentBlobStorageKeyReferenced,\n list: listDocumentOrphanBlobReclaims,\n sweep: deleteOrphanedDocumentSideRows,\n },\n ...documentRowQueryPersistence,\n ...documentSyncQueuePersistence,\n supportsAtomicRecoveryHistoryPruning: true,\n saveHydratedAttachment,\n createDocumentWithHistoryCheckpoint:\n createStoredDocumentWithHistoryCheckpoint,\n commitDocumentMutation: (execSql, input, saveClientProjection) =>\n commitStoredDocumentMutation(\n execSql,\n input,\n saveClientProjection,\n sqlDocumentsPersistence.loadDocument,\n ),\n settleAcceptedPendingUpdates: (execSql, input) =>\n settleStoredDocumentPendingUpdates(\n execSql,\n input,\n sqlDocumentsPersistence.loadDocument,\n ),\n ensureSchema: ensureDocumentsSchema,\n listDocumentSummaries,\n listDocumentsByContainerIdsOrDocumentIds,\n invalidatePullContinuation: (execSql, input) =>\n invalidateStoredDocumentPullContinuation(\n execSql,\n input,\n sqlDocumentsPersistence.loadDocument,\n sqlDocumentsPersistence.loadHistoryRestoreState,\n ),\n loadDocumentWithHistoryRestoreState: (execSql, localId) =>\n loadStoredDocumentWithHistoryRestoreState(\n execSql,\n localId,\n sqlDocumentsPersistence,\n ),\n loadDocumentStoreState: (execSql, localId) =>\n loadStoredDocumentStoreState(execSql, localId, sqlDocumentsPersistence),\n async saveDocument(execSql, document, options) {\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 await saveDocumentRows({\n document,\n tx,\n updatedAt,\n });\n\n return updatedAt;\n },\n { behavior: \"immediate\" },\n ),\n );\n },\n async saveDocumentAndDeletePendingUpdates(\n execSql,\n document,\n pendingUpdateIds,\n options,\n ) {\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 const saved = await saveDocumentRows({\n document,\n tx,\n updatedAt,\n });\n if (!saved) return updatedAt;\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n getDocumentScope(document.id),\n pendingUpdateIds,\n );\n return updatedAt;\n },\n { behavior: \"immediate\" },\n ),\n );\n },\n deleteDocument: deleteStoredDocument,\n deleteDocumentIfMatches: deleteStoredDocumentIfMatches,\n deleteDocumentSideRowsIfAbsent: deleteStoredDocumentSideRowsIfAbsent,\n async discardDocumentToShell(\n execSql,\n localId,\n expectedDocumentId,\n documentProjectors,\n ): Promise<DiscardDocumentToShellResult> {\n return discardStoredDocumentToShell({\n documentProjectors,\n execSql,\n expectedDocumentId,\n localId,\n persistence: sqlDocumentsPersistence,\n });\n },\n async upsertDiscoveredDocument(execSql, input) {\n const [nextSummary] = await upsertDiscoveredDocuments(execSql, [input]);\n if (!nextSummary) {\n throw new Error(\"Failed to upsert discovered document\");\n }\n\n return nextSummary;\n },\n async relinkPersistedDocument(execSql, input) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await sqlDocumentsPersistence.ensureSchema(lockedExecSql);\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n () => relinkPersistedDocumentWithExec(lockedExecSql, input),\n { behavior: \"immediate\" },\n );\n });\n },\n};\n"]}
@@ -2,7 +2,7 @@ import { and, eq, isNotNull } from "drizzle-orm";
2
2
  import { DEFAULT_DOCUMENT_KIND } from "../../../documents/documentConstants.js";
3
3
  import { resolveDocumentProjectorRegistry, } from "../../../documents/documentKinds.js";
4
4
  import { deleteDocumentHistory } from "../../../sqlite/documentHistoryPersistence.js";
5
- import { clearDocumentSyncFailure, deleteDocumentPendingUpdates, } from "../../../sqlite/documentPersistence.js";
5
+ import { clearDocumentSyncFailure } from "../../../sqlite/documentPersistence.js";
6
6
  import { documentAttachmentBlobProjection, documentMoveIntents, documentMoveIntentTables, documentPendingAttachments, } from "../../../sqlite/schema.js";
7
7
  import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
8
8
  import { ensureSqlTables, runSerializedSqlMutation, } from "../../../sqlite/sqlSchema.js";
@@ -64,7 +64,6 @@ async function loadDiscardCandidate(input) {
64
64
  // after a re-pull restores it, leaving the attachment permanently invisible.
65
65
  async function clearDiscardedDocumentRows(input) {
66
66
  const { candidate, localId, lockedExecSql, tx } = input;
67
- await deleteDocumentPendingUpdates(lockedExecSql, getDocumentScope(localId));
68
67
  await tx
69
68
  .delete(documentPendingAttachments)
70
69
  .where(eq(documentPendingAttachments.localId, localId))
@@ -1 +1 @@
1
- {"version":3,"file":"discardDocument.js","sourceRoot":"","sources":["discardDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAGL,gCAAgC,GACjC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EACL,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,gCAAgC,EAChC,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAEL,iCAAiC,GAClC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAEL,eAAe,EACf,wBAAwB,GACzB,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EACL,gBAAgB,EAChB,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAC;AAEtE,SAAS,yBAAyB,CAChC,OAAe,EACf,gBAAsC;IAEtC,OAAO;QACL,EAAE,EAAE,OAAO;QACX,WAAW,EAAE,gBAAgB,CAAC,WAAW;QACzC,eAAe,EAAE,gBAAgB,CAAC,eAAe,IAAI,IAAI;QACzD,WAAW,EAAE,gBAAgB,CAAC,WAAW;QACzC,gBAAgB,EAAE,IAAI;QACtB,UAAU,EAAE,gBAAgB,CAAC,UAAU;QACvC,kBAAkB,EAAE,IAAI;QACxB,sBAAsB,EAAE,IAAI;QAC5B,oBAAoB,EAAE,gBAAgB,CAAC,oBAAoB,IAAI,IAAI;QACnE,aAAa,EAAE,IAAI;QACnB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE,IAAI;QACtB,kBAAkB,EAAE,gBAAgB,CAAC,kBAAkB,IAAI,CAAC;QAC5D,kBAAkB,EAAE,EAAE;QACtB,IAAI,EAAE,EAAE;QACR,GAAG,CAAC,gBAAgB,CAAC,YAAY,KAAK,SAAS;YAC7C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,YAAY,EAAE,gBAAgB,CAAC,YAAY,EAAE,CAAC;QACpD,GAAG,CAAC,gBAAgB,CAAC,KAAK,KAAK,SAAS;YACtC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,KAAK,EAAE,CAAC;KACvC,CAAC;AACJ,CAAC;AAQD,KAAK,UAAU,oBAAoB,CAAC,KASnC;IACC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IAC9E,MAAM,gBAAgB,GAAG,MAAM,WAAW,CAAC,YAAY,CACrD,aAAa,EACb,OAAO,CACR,CAAC;IACF,IACE,CAAC,gBAAgB,EAAE,UAAU;QAC7B,gBAAgB,CAAC,UAAU,KAAK,kBAAkB;QAClD,CAAC,gBAAgB,CAAC,WAAW,EAC7B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,EAAE;SAC5B,MAAM,CAAC,EAAE,EAAE,EAAE,mBAAmB,CAAC,EAAE,EAAE,CAAC;SACtC,IAAI,CAAC,mBAAmB,CAAC;SACzB,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SAC/C,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3C,MAAM,kBAAkB,GAAG,MAAM,WAAW,CAAC,sBAAsB,CACjE,aAAa,EACb,OAAO,CACR,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,EAAE;SAC1B,MAAM,CAAC,EAAE,UAAU,EAAE,gCAAgC,CAAC,UAAU,EAAE,CAAC;SACnE,IAAI,CAAC,gCAAgC,CAAC;SACtC,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,gCAAgC,CAAC,OAAO,EAAE,OAAO,CAAC,EACrD,SAAS,CAAC,gCAAgC,CAAC,UAAU,CAAC,CACvD,CACF,CAAC;IACJ,OAAO;QACL,mBAAmB,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC;QAC9D,gBAAgB;QAChB,kBAAkB;KACnB,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,KAAK,UAAU,0BAA0B,CAAC,KAKzC;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IACxD,MAAM,4BAA4B,CAAC,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7E,MAAM,EAAE;SACL,MAAM,CAAC,0BAA0B,CAAC;SAClC,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;SACtD,GAAG,EAAE,CAAC;IACT,KAAK,MAAM,iBAAiB,IAAI,SAAS,CAAC,kBAAkB,EAAE,CAAC;QAC7D,MAAM,EAAE;aACL,MAAM,CAAC,gCAAgC,CAAC;aACxC,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,gCAAgC,CAAC,OAAO,EAAE,OAAO,CAAC,EACrD,EAAE,CAAC,gCAAgC,CAAC,MAAM,EAAE,iBAAiB,CAAC,MAAM,CAAC,EACrE,EAAE,CACA,gCAAgC,CAAC,UAAU,EAC3C,iBAAiB,CAAC,UAAU,CAC7B,CACF,CACF;aACA,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,EAAE;SACL,MAAM,CAAC,gCAAgC,CAAC;SACxC,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,gCAAgC,CAAC,OAAO,EAAE,OAAO,CAAC,EACrD,SAAS,CAAC,gCAAgC,CAAC,UAAU,CAAC,CACvD,CACF;SACA,GAAG,EAAE,CAAC;IACT,MAAM,qBAAqB,CAAC,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,MAAM,wBAAwB,CAAC,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,KAM/B;IACC,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IAC5E,MAAM,aAAa,GAAG,yBAAyB,CAC7C,OAAO,EACP,SAAS,CAAC,gBAAgB,CAC3B,CAAC;IACF,2EAA2E;IAC3E,2DAA2D;IAC3D,MAAM,kBAAkB,CAAC,oCAAoC,CAAC;QAC5D,YAAY,EAAE,aAAa,CAAC,YAAY,IAAI,qBAAqB;QACjE,OAAO,EAAE,aAAa;QACtB,OAAO;KACR,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,4BAA4B,CAAC;QACnD,QAAQ,EAAE,aAAa;QACvB,EAAE;KACH,CAAC,CAAC;IACH,IAAI,CAAC,CAAC,MAAM,gBAAgB,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,4EAA4E;AAC5E,+DAA+D;AAC/D,KAAK,UAAU,0BAA0B,CAAC,KASzC;IACC,MAAM,sBAAsB,GAC1B,KAAK,CAAC,kBAAkB,CAAC,yBAAyB,EAAE,CAAC;IACvD,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,eAAe,CAAC,KAAK,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,iCAAiC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,WAAW,CACvE,KAAK,EAAE,EAAE,EAAE,EAAE;QACX,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC5C,MAAM,0BAA0B,CAAC;YAC/B,SAAS;YACT,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,EAAE;SACH,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACpD,uEAAuE;QACvE,qEAAqE;QACrE,oEAAoE;QACpE,MAAM,kCAAkC,CAAC,EAAE,EAAE;YAC3C,GAAG,IAAI,GAAG,CAAC;gBACT,GAAG,SAAS,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC;gBAC5D,GAAG,SAAS,CAAC,mBAAmB;aACjC,CAAC;SACH,CAAC,CAAC;QACH,OAAO;YACL,SAAS,EAAE,IAAI;YACf,YAAY,EACV,SAAS,CAAC,gBAAgB,CAAC,YAAY,IAAI,qBAAqB;SACnE,CAAC;IACJ,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,KASlD;IACC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAC3D,OAAO,wBAAwB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE;QACrE,MAAM,eAAe,CAAC,aAAa,EAAE,wBAAwB,CAAC,CAAC;QAC/D,OAAO,0BAA0B,CAAC;YAChC,kBAAkB,EAAE,gCAAgC,CAClD,KAAK,CAAC,kBAAkB,CACzB;YACD,kBAAkB;YAClB,OAAO;YACP,aAAa;YACb,WAAW;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { and, eq, isNotNull } from \"drizzle-orm\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../documents/documentConstants\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n resolveDocumentProjectorRegistry,\n} from \"../../../documents/documentKinds\";\nimport { deleteDocumentHistory } from \"../../../sqlite/documentHistoryPersistence\";\nimport {\n clearDocumentSyncFailure,\n deleteDocumentPendingUpdates,\n} from \"../../../sqlite/documentPersistence\";\nimport {\n documentAttachmentBlobProjection,\n documentMoveIntents,\n documentMoveIntentTables,\n documentPendingAttachments,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../../sqlite/sqlSchema\";\nimport type {\n DiscardDocumentToShellResult,\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../types\";\nimport {\n getDocumentScope,\n resolveDocumentSaveTimestamp,\n saveDocumentRows,\n} from \"./documentRows\";\nimport { queueDocumentAttachmentStorageKeys } from \"./orphanSideRows\";\n\nfunction buildDiscardShellDocument(\n localId: string,\n existingDocument: StoredDocumentRecord,\n): StoredDocumentRecord {\n return {\n id: localId,\n accessEpoch: existingDocument.accessEpoch,\n accessStateHash: existingDocument.accessStateHash ?? null,\n containerId: existingDocument.containerId,\n contentKeyBundle: null,\n documentId: existingDocument.documentId,\n documentKekTargets: null,\n documentManifestBundle: null,\n effectiveAccessLevel: existingDocument.effectiveAccessLevel ?? null,\n lastCommitLsn: null,\n pendingBaseVersion: null,\n pullContinuation: null,\n recoveryGeneration: existingDocument.recoveryGeneration ?? 0,\n snapshotEndVersion: \"\",\n text: \"\",\n ...(existingDocument.documentKind === undefined\n ? {}\n : { documentKind: existingDocument.documentKind }),\n ...(existingDocument.title === undefined\n ? {}\n : { title: existingDocument.title }),\n };\n}\n\ninterface DiscardCandidate {\n detachedStorageKeys: string[];\n existingDocument: StoredDocumentRecord;\n pendingAttachments: ReadonlyArray<{ slotId: string; storageKey: string }>;\n}\n\nasync function loadDiscardCandidate(input: {\n expectedDocumentId: string;\n localId: string;\n lockedExecSql: ExecSql;\n persistence: Pick<\n DocumentsPersistence,\n \"listPendingAttachments\" | \"loadDocument\"\n >;\n tx: ClientSQLiteTransactionScope;\n}): Promise<DiscardCandidate | null> {\n const { expectedDocumentId, localId, lockedExecSql, persistence, tx } = input;\n const existingDocument = await persistence.loadDocument(\n lockedExecSql,\n localId,\n );\n if (\n !existingDocument?.documentId ||\n existingDocument.documentId !== expectedDocumentId ||\n !existingDocument.containerId\n ) {\n return null;\n }\n const moveIntentRows = await tx\n .select({ id: documentMoveIntents.id })\n .from(documentMoveIntents)\n .where(eq(documentMoveIntents.localId, localId))\n .limit(1);\n if (moveIntentRows.length > 0) return null;\n\n const pendingAttachments = await persistence.listPendingAttachments(\n lockedExecSql,\n localId,\n );\n const detachedRows = await tx\n .select({ storageKey: documentAttachmentBlobProjection.storageKey })\n .from(documentAttachmentBlobProjection)\n .where(\n and(\n eq(documentAttachmentBlobProjection.localId, localId),\n isNotNull(documentAttachmentBlobProjection.detachedAt),\n ),\n );\n return {\n detachedStorageKeys: detachedRows.map((row) => row.storageKey),\n existingDocument,\n pendingAttachments,\n };\n}\n\n// Staged-upload rows AND detached local-attachment markers both go: a marker\n// for a locally-discarded detach would otherwise keep filtering the slot out\n// after a re-pull restores it, leaving the attachment permanently invisible.\nasync function clearDiscardedDocumentRows(input: {\n candidate: DiscardCandidate;\n localId: string;\n lockedExecSql: ExecSql;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { candidate, localId, lockedExecSql, tx } = input;\n await deleteDocumentPendingUpdates(lockedExecSql, getDocumentScope(localId));\n await tx\n .delete(documentPendingAttachments)\n .where(eq(documentPendingAttachments.localId, localId))\n .run();\n for (const pendingAttachment of candidate.pendingAttachments) {\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(\n and(\n eq(documentAttachmentBlobProjection.localId, localId),\n eq(documentAttachmentBlobProjection.slotId, pendingAttachment.slotId),\n eq(\n documentAttachmentBlobProjection.storageKey,\n pendingAttachment.storageKey,\n ),\n ),\n )\n .run();\n }\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(\n and(\n eq(documentAttachmentBlobProjection.localId, localId),\n isNotNull(documentAttachmentBlobProjection.detachedAt),\n ),\n )\n .run();\n await deleteDocumentHistory(lockedExecSql, getDocumentScope(localId));\n await clearDocumentSyncFailure(lockedExecSql, getDocumentScope(localId));\n}\n\nasync function saveDiscardShell(input: {\n candidate: DiscardCandidate;\n documentProjectors: DocumentProjectorRegistry;\n localId: string;\n lockedExecSql: ExecSql;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { candidate, documentProjectors, localId, lockedExecSql, tx } = input;\n const shellDocument = buildDiscardShellDocument(\n localId,\n candidate.existingDocument,\n );\n // The document-kind projection derives from discarded content, so clear it\n // inside the transaction and let the next pull rebuild it.\n await documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: shellDocument.documentKind ?? DEFAULT_DOCUMENT_KIND,\n execSql: lockedExecSql,\n localId,\n });\n const updatedAt = await resolveDocumentSaveTimestamp({\n document: shellDocument,\n tx,\n });\n if (!(await saveDocumentRows({ document: shellDocument, tx, updatedAt }))) {\n throw new Error(\"Document recovery generation changed during discard\");\n }\n}\n\n// Eligibility, teardown, client-projection clearing, and shell replacement\n// share one immediate transaction, so a second connection cannot relink the\n// local id between identity validation and destructive writes.\nasync function discardDocumentRowsToShell(input: {\n documentProjectors: DocumentProjectorRegistry;\n expectedDocumentId: string;\n localId: string;\n lockedExecSql: ExecSql;\n persistence: Pick<\n DocumentsPersistence,\n \"listPendingAttachments\" | \"loadDocument\"\n >;\n}): Promise<DiscardDocumentToShellResult> {\n const clientProjectionTables =\n input.documentProjectors.getClientProjectionTables();\n if (clientProjectionTables.length > 0) {\n await ensureSqlTables(input.lockedExecSql, clientProjectionTables);\n }\n return getClientSQLitePersistenceRuntime(input.lockedExecSql).transaction(\n async (tx) => {\n const candidate = await loadDiscardCandidate({ ...input, tx });\n if (!candidate) return { discarded: false };\n await clearDiscardedDocumentRows({\n candidate,\n localId: input.localId,\n lockedExecSql: input.lockedExecSql,\n tx,\n });\n await saveDiscardShell({ ...input, candidate, tx });\n // The deleted rows were these bytes' only pointers from this document,\n // but a hydrated copy is shared by every slot holding the same blob.\n // Queue them for the reference-checked reclaim instead of deleting.\n await queueDocumentAttachmentStorageKeys(tx, [\n ...new Set([\n ...candidate.pendingAttachments.map((row) => row.storageKey),\n ...candidate.detachedStorageKeys,\n ]),\n ]);\n return {\n discarded: true,\n documentKind:\n candidate.existingDocument.documentKind ?? DEFAULT_DOCUMENT_KIND,\n };\n },\n { behavior: \"immediate\" },\n );\n}\n\n/**\n * Atomically convert a stuck document's local state to the\n * freshly-discovered-share shell: drop its queued updates, staged attachment\n * rows (and their settled local-attachment halves, which share the staged\n * storage keys the caller reclaims), detached attachment markers, durable\n * history, recorded sync failure, and document-kind client projection, then\n * overwrite the record with an empty snapshot that keeps its identity,\n * placement, title, and kind. Everything commits in ONE transaction.\n *\n * Refused under the serialized mutation when the document is local-only or\n * unlinked (its rows are the only copy), when its documentId no longer\n * matches the caller's expectation (a stale caller or racing relink must not\n * discard a different identity's edits), or when any move intent references\n * it (the local containerId is then the move's optimistic placement, and\n * reseeding it as server truth would silently commit the move locally while\n * discarding the intent that was meant to perform it).\n */\nexport async function discardStoredDocumentToShell(input: {\n documentProjectors: DocumentProjectorRegistryInput;\n execSql: ExecSql;\n expectedDocumentId: string;\n localId: string;\n persistence: Pick<\n DocumentsPersistence,\n \"listPendingAttachments\" | \"loadDocument\"\n >;\n}): Promise<DiscardDocumentToShellResult> {\n const { expectedDocumentId, localId, persistence } = input;\n return runSerializedSqlMutation(input.execSql, async (lockedExecSql) => {\n await ensureSqlTables(lockedExecSql, documentMoveIntentTables);\n return discardDocumentRowsToShell({\n documentProjectors: resolveDocumentProjectorRegistry(\n input.documentProjectors,\n ),\n expectedDocumentId,\n localId,\n lockedExecSql,\n persistence,\n });\n });\n}\n"]}
1
+ {"version":3,"file":"discardDocument.js","sourceRoot":"","sources":["discardDocument.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, isNotNull } from \"drizzle-orm\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../documents/documentConstants\";\nimport {\n type DocumentProjectorRegistry,\n type DocumentProjectorRegistryInput,\n resolveDocumentProjectorRegistry,\n} from \"../../../documents/documentKinds\";\nimport { deleteDocumentHistory } from \"../../../sqlite/documentHistoryPersistence\";\nimport { clearDocumentSyncFailure } from \"../../../sqlite/documentPersistence\";\nimport {\n documentAttachmentBlobProjection,\n documentMoveIntents,\n documentMoveIntentTables,\n documentPendingAttachments,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../../sqlite/sqlSchema\";\nimport type {\n DiscardDocumentToShellResult,\n DocumentsPersistence,\n StoredDocumentRecord,\n} from \"../types\";\nimport {\n getDocumentScope,\n resolveDocumentSaveTimestamp,\n saveDocumentRows,\n} from \"./documentRows\";\nimport { queueDocumentAttachmentStorageKeys } from \"./orphanSideRows\";\n\nfunction buildDiscardShellDocument(\n localId: string,\n existingDocument: StoredDocumentRecord,\n): StoredDocumentRecord {\n return {\n id: localId,\n accessEpoch: existingDocument.accessEpoch,\n accessStateHash: existingDocument.accessStateHash ?? null,\n containerId: existingDocument.containerId,\n contentKeyBundle: null,\n documentId: existingDocument.documentId,\n documentKekTargets: null,\n documentManifestBundle: null,\n effectiveAccessLevel: existingDocument.effectiveAccessLevel ?? null,\n lastCommitLsn: null,\n pendingBaseVersion: null,\n pullContinuation: null,\n recoveryGeneration: existingDocument.recoveryGeneration ?? 0,\n snapshotEndVersion: \"\",\n text: \"\",\n ...(existingDocument.documentKind === undefined\n ? {}\n : { documentKind: existingDocument.documentKind }),\n ...(existingDocument.title === undefined\n ? {}\n : { title: existingDocument.title }),\n };\n}\n\ninterface DiscardCandidate {\n detachedStorageKeys: string[];\n existingDocument: StoredDocumentRecord;\n pendingAttachments: ReadonlyArray<{ slotId: string; storageKey: string }>;\n}\n\nasync function loadDiscardCandidate(input: {\n expectedDocumentId: string;\n localId: string;\n lockedExecSql: ExecSql;\n persistence: Pick<\n DocumentsPersistence,\n \"listPendingAttachments\" | \"loadDocument\"\n >;\n tx: ClientSQLiteTransactionScope;\n}): Promise<DiscardCandidate | null> {\n const { expectedDocumentId, localId, lockedExecSql, persistence, tx } = input;\n const existingDocument = await persistence.loadDocument(\n lockedExecSql,\n localId,\n );\n if (\n !existingDocument?.documentId ||\n existingDocument.documentId !== expectedDocumentId ||\n !existingDocument.containerId\n ) {\n return null;\n }\n const moveIntentRows = await tx\n .select({ id: documentMoveIntents.id })\n .from(documentMoveIntents)\n .where(eq(documentMoveIntents.localId, localId))\n .limit(1);\n if (moveIntentRows.length > 0) return null;\n\n const pendingAttachments = await persistence.listPendingAttachments(\n lockedExecSql,\n localId,\n );\n const detachedRows = await tx\n .select({ storageKey: documentAttachmentBlobProjection.storageKey })\n .from(documentAttachmentBlobProjection)\n .where(\n and(\n eq(documentAttachmentBlobProjection.localId, localId),\n isNotNull(documentAttachmentBlobProjection.detachedAt),\n ),\n );\n return {\n detachedStorageKeys: detachedRows.map((row) => row.storageKey),\n existingDocument,\n pendingAttachments,\n };\n}\n\n// Staged-upload rows AND detached local-attachment markers both go: a marker\n// for a locally-discarded detach would otherwise keep filtering the slot out\n// after a re-pull restores it, leaving the attachment permanently invisible.\nasync function clearDiscardedDocumentRows(input: {\n candidate: DiscardCandidate;\n localId: string;\n lockedExecSql: ExecSql;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { candidate, localId, lockedExecSql, tx } = input;\n await tx\n .delete(documentPendingAttachments)\n .where(eq(documentPendingAttachments.localId, localId))\n .run();\n for (const pendingAttachment of candidate.pendingAttachments) {\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(\n and(\n eq(documentAttachmentBlobProjection.localId, localId),\n eq(documentAttachmentBlobProjection.slotId, pendingAttachment.slotId),\n eq(\n documentAttachmentBlobProjection.storageKey,\n pendingAttachment.storageKey,\n ),\n ),\n )\n .run();\n }\n await tx\n .delete(documentAttachmentBlobProjection)\n .where(\n and(\n eq(documentAttachmentBlobProjection.localId, localId),\n isNotNull(documentAttachmentBlobProjection.detachedAt),\n ),\n )\n .run();\n await deleteDocumentHistory(lockedExecSql, getDocumentScope(localId));\n await clearDocumentSyncFailure(lockedExecSql, getDocumentScope(localId));\n}\n\nasync function saveDiscardShell(input: {\n candidate: DiscardCandidate;\n documentProjectors: DocumentProjectorRegistry;\n localId: string;\n lockedExecSql: ExecSql;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { candidate, documentProjectors, localId, lockedExecSql, tx } = input;\n const shellDocument = buildDiscardShellDocument(\n localId,\n candidate.existingDocument,\n );\n // The document-kind projection derives from discarded content, so clear it\n // inside the transaction and let the next pull rebuild it.\n await documentProjectors.deleteStoredDocumentClientProjection({\n documentKind: shellDocument.documentKind ?? DEFAULT_DOCUMENT_KIND,\n execSql: lockedExecSql,\n localId,\n });\n const updatedAt = await resolveDocumentSaveTimestamp({\n document: shellDocument,\n tx,\n });\n if (!(await saveDocumentRows({ document: shellDocument, tx, updatedAt }))) {\n throw new Error(\"Document recovery generation changed during discard\");\n }\n}\n\n// Eligibility, teardown, client-projection clearing, and shell replacement\n// share one immediate transaction, so a second connection cannot relink the\n// local id between identity validation and destructive writes.\nasync function discardDocumentRowsToShell(input: {\n documentProjectors: DocumentProjectorRegistry;\n expectedDocumentId: string;\n localId: string;\n lockedExecSql: ExecSql;\n persistence: Pick<\n DocumentsPersistence,\n \"listPendingAttachments\" | \"loadDocument\"\n >;\n}): Promise<DiscardDocumentToShellResult> {\n const clientProjectionTables =\n input.documentProjectors.getClientProjectionTables();\n if (clientProjectionTables.length > 0) {\n await ensureSqlTables(input.lockedExecSql, clientProjectionTables);\n }\n return getClientSQLitePersistenceRuntime(input.lockedExecSql).transaction(\n async (tx) => {\n const candidate = await loadDiscardCandidate({ ...input, tx });\n if (!candidate) return { discarded: false };\n await clearDiscardedDocumentRows({\n candidate,\n localId: input.localId,\n lockedExecSql: input.lockedExecSql,\n tx,\n });\n await saveDiscardShell({ ...input, candidate, tx });\n // The deleted rows were these bytes' only pointers from this document,\n // but a hydrated copy is shared by every slot holding the same blob.\n // Queue them for the reference-checked reclaim instead of deleting.\n await queueDocumentAttachmentStorageKeys(tx, [\n ...new Set([\n ...candidate.pendingAttachments.map((row) => row.storageKey),\n ...candidate.detachedStorageKeys,\n ]),\n ]);\n return {\n discarded: true,\n documentKind:\n candidate.existingDocument.documentKind ?? DEFAULT_DOCUMENT_KIND,\n };\n },\n { behavior: \"immediate\" },\n );\n}\n\n/**\n * Atomically convert a stuck document's local state to the\n * freshly-discovered-share shell: drop its queued updates, staged attachment\n * rows (and their settled local-attachment halves, which share the staged\n * storage keys the caller reclaims), detached attachment markers, durable\n * history, recorded sync failure, and document-kind client projection, then\n * overwrite the record with an empty snapshot that keeps its identity,\n * placement, title, and kind. Everything commits in ONE transaction.\n *\n * Refused under the serialized mutation when the document is local-only or\n * unlinked (its rows are the only copy), when its documentId no longer\n * matches the caller's expectation (a stale caller or racing relink must not\n * discard a different identity's edits), or when any move intent references\n * it (the local containerId is then the move's optimistic placement, and\n * reseeding it as server truth would silently commit the move locally while\n * discarding the intent that was meant to perform it).\n */\nexport async function discardStoredDocumentToShell(input: {\n documentProjectors: DocumentProjectorRegistryInput;\n execSql: ExecSql;\n expectedDocumentId: string;\n localId: string;\n persistence: Pick<\n DocumentsPersistence,\n \"listPendingAttachments\" | \"loadDocument\"\n >;\n}): Promise<DiscardDocumentToShellResult> {\n const { expectedDocumentId, localId, persistence } = input;\n return runSerializedSqlMutation(input.execSql, async (lockedExecSql) => {\n await ensureSqlTables(lockedExecSql, documentMoveIntentTables);\n return discardDocumentRowsToShell({\n documentProjectors: resolveDocumentProjectorRegistry(\n input.documentProjectors,\n ),\n expectedDocumentId,\n localId,\n lockedExecSql,\n persistence,\n });\n });\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { and, eq, inArray, ne } from "drizzle-orm";
2
2
  import { deleteDocumentHistory } from "../../../sqlite/documentHistoryPersistence.js";
3
- import { clearDocumentSyncFailure, deleteDocumentPendingUpdates, deleteDocumentRecord, loadDocumentRecord, } from "../../../sqlite/documentPersistence.js";
3
+ import { clearDocumentSyncFailure, deleteDocumentRecord, loadDocumentRecord, } from "../../../sqlite/documentPersistence.js";
4
4
  import { documentIntentLinkTargets } from "../../../sqlite/documentPlacementIntentSchema.js";
5
5
  import { documentAttachmentBlobProjection, documentContainerProjection, documentMoveIntents, documentMoveIntentTables, documentPendingAttachments, documentProjection, documentProjectionText, documents, } from "../../../sqlite/schema.js";
6
6
  import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
@@ -54,7 +54,6 @@ async function deleteStoredDocumentRows(input) {
54
54
  .run();
55
55
  }
56
56
  const scope = getDocumentScope(localId);
57
- await deleteDocumentPendingUpdates(lockedExecSql, scope);
58
57
  await deleteDocumentHistory(lockedExecSql, scope);
59
58
  await clearDocumentSyncFailure(lockedExecSql, scope);
60
59
  await deleteDocumentRecord(lockedExecSql, scope);