@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":"documentPendingUpdatePersistence.js","sourceRoot":"","sources":["documentPendingUpdatePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, lt, sql } from \"drizzle-orm\";\nimport type {\n DocumentScope,\n PendingUpdateFields,\n PendingUpdateRecord,\n SelectedPendingUpdateRow,\n} from \"./documentPersistenceTypes\";\nimport {\n documentHistoryUpdates,\n documentPendingUpdates,\n documents,\n} from \"./schema\";\nimport type { ClientSQLiteTransactionScope } from \"./sqlitePersistenceRuntime\";\nimport { getClientSQLitePersistenceRuntime } from \"./sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"./sqlSchema\";\n\nfunction mapSelectedPendingUpdate(\n row: SelectedPendingUpdateRow,\n): PendingUpdateRecord {\n return {\n id: String(row.id ?? \"\"),\n updateData: row.updateData,\n partialStartVersionVector: row.partialStartVersionVector,\n partialEndVersionVector: row.partialEndVersionVector,\n sourceVersionVector: row.sourceVersionVector,\n rekeyCount: row.rekeyCount,\n };\n}\n\nexport async function listDocumentPendingUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<PendingUpdateRecord[]> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: documentPendingUpdates.id,\n updateData: documentPendingUpdates.updateData,\n partialStartVersionVector:\n documentPendingUpdates.partialStartVersionVector,\n partialEndVersionVector: documentPendingUpdates.partialEndVersionVector,\n sourceVersionVector: documentPendingUpdates.sourceVersionVector,\n rekeyCount: documentPendingUpdates.rekeyCount,\n })\n .from(documentPendingUpdates)\n .where(\n and(\n eq(documentPendingUpdates.appKind, scope.appKind),\n eq(documentPendingUpdates.localId, scope.localId),\n ),\n )\n .orderBy(asc(documentPendingUpdates.createdAt), asc(sql`rowid`));\n\n return rows.map(mapSelectedPendingUpdate);\n}\n\nfunction pendingUpdateRow(\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n createdAt: string,\n id = crypto.randomUUID(),\n) {\n return {\n id,\n appKind: scope.appKind,\n localId: scope.localId,\n updateData: pendingUpdate.updateData,\n partialStartVersionVector: pendingUpdate.partialStartVersionVector,\n partialEndVersionVector: pendingUpdate.partialEndVersionVector,\n sourceVersionVector: pendingUpdate.sourceVersionVector ?? null,\n createdAt,\n };\n}\n\nexport async function enqueueDocumentPendingUpdate(\n execSql: ExecSql,\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n): Promise<string> {\n const id = crypto.randomUUID();\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .insert(documentPendingUpdates)\n .values(\n pendingUpdateRow(scope, pendingUpdate, new Date().toISOString(), id),\n )\n .run();\n });\n return id;\n}\n\n/**\n * Enqueue an outgoing update AND append it to the durable-history tail in a\n * single transaction. Serialization alone is not enough: a crash between\n * separate inserts could leave the op restorable from history while missing\n * from the outgoing queue, and a null-marker restore would then classify it\n * as covered and never send it.\n */\nexport async function enqueueDocumentPendingUpdateWithHistory(\n execSql: ExecSql,\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n options?: {\n expectedDocumentId: string | null;\n expectedRecoveryGeneration: number;\n },\n): Promise<string | null> {\n const createdAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(execSql).transaction(\n async (tx) => {\n if (options) {\n const matchingDocuments = await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n sql`${documents.documentId} IS ${options.expectedDocumentId}`,\n eq(\n documents.recoveryGeneration,\n options.expectedRecoveryGeneration,\n ),\n ),\n )\n .limit(1);\n if (matchingDocuments.length === 0) {\n return null;\n }\n }\n\n return insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt,\n pendingUpdate,\n scope,\n tx,\n });\n },\n { behavior: \"immediate\" },\n );\n}\n\nexport async function insertDocumentPendingUpdateWithHistoryInTransaction(input: {\n createdAt: string;\n pendingUpdate: PendingUpdateFields;\n scope: DocumentScope;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const id = crypto.randomUUID();\n await input.tx\n .insert(documentHistoryUpdates)\n .values({\n id: crypto.randomUUID(),\n appKind: input.scope.appKind,\n localId: input.scope.localId,\n updateData: input.pendingUpdate.updateData,\n origin: \"local\",\n createdAt: input.createdAt,\n })\n .run();\n await input.tx\n .insert(documentPendingUpdates)\n .values(\n pendingUpdateRow(input.scope, input.pendingUpdate, input.createdAt, id),\n )\n .run();\n return id;\n}\n\n/**\n * Assign a fresh id to a pending update, keeping every other column. A lost\n * sync ack leaves the server holding the update under the original id with\n * ciphertext a rebuilt submission can never reproduce (each rebuild encrypts\n * with a fresh IV), so the id is permanently poisoned: every resubmission\n * 409s and the whole outgoing batch rolls back. Re-keying lets the next sync\n * pass submit the same ops under a conflict-free id; the server-side copy is\n * harmless because CRDT update import is idempotent.\n *\n * Returns null when no row carries the id, so callers never report progress\n * for a row that lives in some other queue (or nowhere). The UPDATE's own\n * RETURNING row is the progress signal — a pre-flight SELECT would race a\n * second tab sharing the SQLite file, which can settle-delete the row between\n * the read and the write and turn \"rekeyed\" into a spurious re-arm.\n *\n * The persisted per-row bound is enforced here as well: a row already at\n * MAX_PENDING_UPDATE_REKEYS is left untouched and reported as no progress.\n * The in-memory lane counter bounds a busy-loop within one session; this\n * bound survives restarts, so a poisoned row cannot re-key forever at three\n * passes per launch.\n */\nexport const MAX_PENDING_UPDATE_REKEYS = 5;\n\n/**\n * Reset the durable re-key budget for every pending update in a scope. The\n * cap exists to stop a server that keeps conflicting fresh ids from driving\n * a network-speed loop — but a budget burned during an unrelated outage\n * (e.g. yesterday's stale-bundle deadlock 409ing every submit) should not be\n * terminal forever. An explicit manual retry is the deliberate, rate-limited\n * signal that conditions changed, so it gets a fresh budget.\n */\nexport async function resetDocumentPendingUpdateRekeyBudget(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .update(documentPendingUpdates)\n .set({ rekeyCount: 0 })\n .where(\n and(\n eq(documentPendingUpdates.appKind, scope.appKind),\n eq(documentPendingUpdates.localId, scope.localId),\n ),\n );\n });\n}\n\nexport async function rekeyDocumentPendingUpdate(\n execSql: ExecSql,\n id: string,\n): Promise<string | null> {\n const nextId = crypto.randomUUID();\n let rekeyed = false;\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n const updated = await db\n .update(documentPendingUpdates)\n .set({\n id: nextId,\n rekeyCount: sql`${documentPendingUpdates.rekeyCount} + 1`,\n })\n .where(\n and(\n eq(documentPendingUpdates.id, id),\n lt(documentPendingUpdates.rekeyCount, MAX_PENDING_UPDATE_REKEYS),\n ),\n )\n .returning({ id: documentPendingUpdates.id });\n rekeyed = updated.length > 0;\n });\n return rekeyed ? nextId : null;\n}\n\nexport async function deleteDocumentPendingUpdate(\n execSql: ExecSql,\n id: string,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .delete(documentPendingUpdates)\n .where(eq(documentPendingUpdates.id, id))\n .run();\n });\n}\n\nexport async function deleteDocumentPendingUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .delete(documentPendingUpdates)\n .where(\n and(\n eq(documentPendingUpdates.appKind, scope.appKind),\n eq(documentPendingUpdates.localId, scope.localId),\n ),\n )\n .run();\n });\n}\n"]}
1
+ {"version":3,"file":"documentPendingUpdatePersistence.js","sourceRoot":"","sources":["documentPendingUpdatePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n and,\n asc,\n eq,\n inArray,\n isNotNull,\n lt,\n or,\n type SQL,\n sql,\n} from \"drizzle-orm\";\nimport type {\n DocumentScope,\n PendingUpdateFields,\n PendingUpdateRecord,\n SelectedPendingUpdateRow,\n} from \"./documentPersistenceTypes\";\nimport { documentHistoryUpdates, documents } from \"./schema\";\nimport type { ClientSQLiteTransactionScope } from \"./sqlitePersistenceRuntime\";\nimport { getClientSQLitePersistenceRuntime } from \"./sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"./sqlSchema\";\n\n/**\n * Queued updates are the rows of the local update log that carry an\n * `updateId`. A tail row (origin \"local\") stays in the log after settlement as\n * history until compaction; an \"outbox\" row has no tail role and settlement\n * deletes it.\n */\nconst OUTBOX_ORIGIN = \"outbox\";\n\ntype QueueStatement = Pick<ClientSQLiteTransactionScope, \"delete\" | \"update\">;\ntype QueueRead = Pick<ClientSQLiteTransactionScope, \"selectDistinct\">;\n\nfunction queuedInScope(scope: DocumentScope) {\n return and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n isNotNull(documentHistoryUpdates.updateId),\n );\n}\n\nfunction mapSelectedPendingUpdate(\n row: SelectedPendingUpdateRow,\n): PendingUpdateRecord {\n // A queued row always carries its submission vectors; a row without them\n // cannot be submitted and must fail closed rather than send empty ranges.\n if (\n row.partialStartVersionVector === null ||\n row.partialEndVersionVector === null\n ) {\n throw new Error(\"Queued document update is missing its version vectors\");\n }\n return {\n id: String(row.id ?? \"\"),\n updateData: row.updateData,\n partialStartVersionVector: row.partialStartVersionVector,\n partialEndVersionVector: row.partialEndVersionVector,\n sourceVersionVector: row.sourceVersionVector,\n rekeyCount: row.rekeyCount,\n };\n}\n\n/** The ids among `localIds` (one app kind) with at least one queued update. */\nexport async function listLocalIdsWithQueuedUpdates(\n db: QueueRead,\n appKind: string,\n localIds: readonly string[],\n): Promise<string[]> {\n const uniqueIds = [...new Set(localIds)];\n if (uniqueIds.length === 0) return [];\n const rows = await db\n .selectDistinct({ localId: documentHistoryUpdates.localId })\n .from(documentHistoryUpdates)\n .where(\n and(\n eq(documentHistoryUpdates.appKind, appKind),\n inArray(documentHistoryUpdates.localId, uniqueIds),\n isNotNull(documentHistoryUpdates.updateId),\n ),\n )\n .orderBy(asc(documentHistoryUpdates.localId));\n return rows.map((row) => row.localId);\n}\n\nexport async function hasQueuedDocumentUpdates(\n db: QueueRead,\n scope: DocumentScope,\n): Promise<boolean> {\n const ids = await listLocalIdsWithQueuedUpdates(db, scope.appKind, [\n scope.localId,\n ]);\n return ids.length > 0;\n}\n\nexport async function listDocumentPendingUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<PendingUpdateRecord[]> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: documentHistoryUpdates.updateId,\n updateData: documentHistoryUpdates.updateData,\n partialStartVersionVector:\n documentHistoryUpdates.partialStartVersionVector,\n partialEndVersionVector: documentHistoryUpdates.partialEndVersionVector,\n sourceVersionVector: documentHistoryUpdates.sourceVersionVector,\n rekeyCount: documentHistoryUpdates.rekeyCount,\n })\n .from(documentHistoryUpdates)\n .where(queuedInScope(scope))\n .orderBy(asc(documentHistoryUpdates.createdAt), asc(sql`rowid`));\n\n return rows.map(mapSelectedPendingUpdate);\n}\n\n/** One log row for a queued update; `origin` decides its tail role. */\nexport function queuedUpdateRow(input: {\n createdAt: string;\n origin: \"local\" | typeof OUTBOX_ORIGIN;\n pendingUpdate: PendingUpdateFields;\n scope: DocumentScope;\n updateId: string;\n}) {\n return {\n id: crypto.randomUUID(),\n appKind: input.scope.appKind,\n localId: input.scope.localId,\n updateData: input.pendingUpdate.updateData,\n origin: input.origin,\n createdAt: input.createdAt,\n updateId: input.updateId,\n partialStartVersionVector: input.pendingUpdate.partialStartVersionVector,\n partialEndVersionVector: input.pendingUpdate.partialEndVersionVector,\n sourceVersionVector: input.pendingUpdate.sourceVersionVector ?? null,\n };\n}\n\n/**\n * Queue an update that has no history-tail role: container metadata (its\n * content is its checkpoint) and full-state re-uploads after a remote reset.\n */\nexport async function enqueueDocumentPendingUpdate(\n execSql: ExecSql,\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n): Promise<string> {\n const updateId = crypto.randomUUID();\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .insert(documentHistoryUpdates)\n .values(\n queuedUpdateRow({\n createdAt: new Date().toISOString(),\n origin: OUTBOX_ORIGIN,\n pendingUpdate,\n scope,\n updateId,\n }),\n )\n .run();\n });\n return updateId;\n}\n\n/**\n * Append a locally authored update to the history tail AND queue it, as one\n * row in one transaction. A crash can therefore never leave the op restorable\n * from history while missing from the outgoing queue, where a null-marker\n * restore would classify it as covered and never send it.\n */\nexport async function enqueueDocumentPendingUpdateWithHistory(\n execSql: ExecSql,\n scope: DocumentScope,\n pendingUpdate: PendingUpdateFields,\n options?: {\n expectedDocumentId: string | null;\n expectedRecoveryGeneration: number;\n },\n): Promise<string | null> {\n const createdAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(execSql).transaction(\n async (tx) => {\n if (options) {\n const matchingDocuments = await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n sql`${documents.documentId} IS ${options.expectedDocumentId}`,\n eq(\n documents.recoveryGeneration,\n options.expectedRecoveryGeneration,\n ),\n ),\n )\n .limit(1);\n if (matchingDocuments.length === 0) {\n return null;\n }\n }\n\n return insertDocumentPendingUpdateWithHistoryInTransaction({\n createdAt,\n pendingUpdate,\n scope,\n tx,\n });\n },\n { behavior: \"immediate\" },\n );\n}\n\nexport async function insertDocumentPendingUpdateWithHistoryInTransaction(input: {\n createdAt: string;\n pendingUpdate: PendingUpdateFields;\n scope: DocumentScope;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const updateId = crypto.randomUUID();\n await input.tx\n .insert(documentHistoryUpdates)\n .values(\n queuedUpdateRow({\n createdAt: input.createdAt,\n origin: \"local\",\n pendingUpdate: input.pendingUpdate,\n scope: input.scope,\n updateId,\n }),\n )\n .run();\n return updateId;\n}\n\n/**\n * Assign a fresh id to a queued update, keeping every other column. A lost\n * sync ack leaves the server holding the update under the original id with\n * ciphertext a rebuilt submission can never reproduce (each rebuild encrypts\n * with a fresh IV), so the id is permanently poisoned: every resubmission\n * 409s and the whole outgoing batch rolls back. Re-keying lets the next sync\n * pass submit the same ops under a conflict-free id; the server-side copy is\n * harmless because CRDT update import is idempotent.\n *\n * Returns null when no row carries the id, so callers never report progress\n * for a row that lives in some other queue (or nowhere). The UPDATE's own\n * RETURNING row is the progress signal — a pre-flight SELECT would race a\n * second tab sharing the SQLite file, which can settle the row between the\n * read and the write and turn \"rekeyed\" into a spurious re-arm.\n *\n * The persisted per-row bound is enforced here as well: a row already at\n * MAX_PENDING_UPDATE_REKEYS is left untouched and reported as no progress.\n * The in-memory lane counter bounds a busy-loop within one session; this\n * bound survives restarts, so a poisoned row cannot re-key forever at three\n * passes per launch.\n */\nexport const MAX_PENDING_UPDATE_REKEYS = 5;\n\n/**\n * Reset the durable re-key budget for every queued update in a scope. The\n * cap exists to stop a server that keeps conflicting fresh ids from driving\n * a network-speed loop — but a budget burned during an unrelated outage\n * (e.g. yesterday's stale-bundle deadlock 409ing every submit) should not be\n * terminal forever. An explicit manual retry is the deliberate, rate-limited\n * signal that conditions changed, so it gets a fresh budget.\n */\nexport async function resetDocumentPendingUpdateRekeyBudget(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .update(documentHistoryUpdates)\n .set({ rekeyCount: 0 })\n .where(queuedInScope(scope));\n });\n}\n\nexport async function rekeyDocumentPendingUpdate(\n execSql: ExecSql,\n id: string,\n): Promise<string | null> {\n const nextId = crypto.randomUUID();\n let rekeyed = false;\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n const updated = await db\n .update(documentHistoryUpdates)\n .set({\n updateId: nextId,\n rekeyCount: sql`${documentHistoryUpdates.rekeyCount} + 1`,\n })\n .where(\n and(\n eq(documentHistoryUpdates.updateId, id),\n lt(documentHistoryUpdates.rekeyCount, MAX_PENDING_UPDATE_REKEYS),\n ),\n )\n .returning({ id: documentHistoryUpdates.updateId });\n rekeyed = updated.length > 0;\n });\n return rekeyed ? nextId : null;\n}\n\n/**\n * Settle queued updates: an outbox row is deleted, and a tail row stops being\n * queued but stays as history until compaction folds it into a checkpoint.\n */\nexport async function settleQueuedDocumentUpdatesInTransaction(\n tx: QueueStatement,\n scope: DocumentScope,\n updateIds: readonly string[],\n): Promise<void> {\n const uniqueIds = [...new Set(updateIds)];\n if (uniqueIds.length === 0) return;\n const selected = and(\n eq(documentHistoryUpdates.appKind, scope.appKind),\n eq(documentHistoryUpdates.localId, scope.localId),\n inArray(documentHistoryUpdates.updateId, uniqueIds),\n );\n await unqueueSelectedUpdates(tx, selected);\n}\n\nasync function unqueueSelectedUpdates(\n tx: QueueStatement,\n selected: SQL | undefined,\n): Promise<void> {\n await tx\n .delete(documentHistoryUpdates)\n .where(and(selected, eq(documentHistoryUpdates.origin, OUTBOX_ORIGIN)))\n .run();\n await tx\n .update(documentHistoryUpdates)\n .set({\n updateId: null,\n partialStartVersionVector: null,\n partialEndVersionVector: null,\n sourceVersionVector: null,\n rekeyCount: 0,\n })\n .where(selected)\n .run();\n}\n\n/** Settle one queued update by id, whatever its scope. */\nexport async function settleDocumentPendingUpdate(\n execSql: ExecSql,\n id: string,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await unqueueSelectedUpdates(db, eq(documentHistoryUpdates.updateId, id));\n });\n}\n\n/**\n * Stop queueing every update in the given scopes: outbox rows are dropped,\n * and local tail rows keep their content as history (it is already in the\n * document).\n */\nexport async function unqueueDocumentScopesInTransaction(\n tx: QueueStatement,\n scopes: readonly DocumentScope[],\n): Promise<void> {\n if (scopes.length === 0) return;\n await unqueueSelectedUpdates(tx, or(...scopes.map(queuedInScope)));\n}\n\nexport async function unqueueDocumentPendingUpdates(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await unqueueDocumentScopesInTransaction(db, [scope]);\n });\n}\n"]}
@@ -16,7 +16,7 @@ export declare function invalidateDocumentSyncPullContinuation(execSql: ExecSql,
16
16
  lastCommitLsn: string | null;
17
17
  localId: string;
18
18
  }): Promise<DocumentRecord | null>;
19
- export { deleteDocumentPendingUpdate, deleteDocumentPendingUpdates, enqueueDocumentPendingUpdate, enqueueDocumentPendingUpdateWithHistory, listDocumentPendingUpdates, MAX_PENDING_UPDATE_REKEYS, rekeyDocumentPendingUpdate, resetDocumentPendingUpdateRekeyBudget, } from "./documentPendingUpdatePersistence.js";
19
+ export { enqueueDocumentPendingUpdate, enqueueDocumentPendingUpdateWithHistory, listDocumentPendingUpdates, MAX_PENDING_UPDATE_REKEYS, rekeyDocumentPendingUpdate, resetDocumentPendingUpdateRekeyBudget, settleDocumentPendingUpdate, unqueueDocumentPendingUpdates, } from "./documentPendingUpdatePersistence.js";
20
20
  export type { DocumentRecord, DocumentScope, PendingUpdateFields, PendingUpdateRecord, } from "./documentPersistenceTypes.js";
21
21
  export { deleteDocumentRecord, documentRecordSelection, findLocalIdByDocumentId, loadDocumentRecord, mapSelectedDocumentRecord, } from "./documentRecordPersistence.js";
22
22
  export { clearDocumentSyncFailure, hasRecordedTerminalSyncFailures, recordDocumentSyncFailure, } from "./documentSyncFailurePersistence.js";
@@ -29,7 +29,7 @@ export async function invalidateDocumentSyncPullContinuation(execSql, input) {
29
29
  });
30
30
  });
31
31
  }
32
- export { deleteDocumentPendingUpdate, deleteDocumentPendingUpdates, enqueueDocumentPendingUpdate, enqueueDocumentPendingUpdateWithHistory, listDocumentPendingUpdates, MAX_PENDING_UPDATE_REKEYS, rekeyDocumentPendingUpdate, resetDocumentPendingUpdateRekeyBudget, } from "./documentPendingUpdatePersistence.js";
32
+ export { enqueueDocumentPendingUpdate, enqueueDocumentPendingUpdateWithHistory, listDocumentPendingUpdates, MAX_PENDING_UPDATE_REKEYS, rekeyDocumentPendingUpdate, resetDocumentPendingUpdateRekeyBudget, settleDocumentPendingUpdate, unqueueDocumentPendingUpdates, } from "./documentPendingUpdatePersistence.js";
33
33
  export { deleteDocumentRecord, documentRecordSelection, findLocalIdByDocumentId, loadDocumentRecord, mapSelectedDocumentRecord, } from "./documentRecordPersistence.js";
34
34
  export { clearDocumentSyncFailure, hasRecordedTerminalSyncFailures, recordDocumentSyncFailure, } from "./documentSyncFailurePersistence.js";
35
35
  //# sourceMappingURL=documentPersistence.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"documentPersistence.js","sourceRoot":"","sources":["documentPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport {\n DOCUMENT_SYNC_PULL_RECOVERY_REQUIRED,\n type DocumentSyncPullContinuation,\n serializeDocumentSyncPullContinuation,\n} from \"../documents/shared/pullContinuation\";\nimport type { DocumentRecord } from \"./documentPersistenceTypes\";\nimport { loadDocumentRecord } from \"./documentRecordPersistence\";\nimport { documentProjectionTables, documents, documentTables } from \"./schema\";\nimport { getClientSQLitePersistenceRuntime } from \"./sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"./sqlSchema\";\n\nexport function ensureDocumentTables(execSql: ExecSql): Promise<void> {\n return ensureSqlTables(execSql, documentTables);\n}\n\nexport function ensureDocumentProjectionTables(\n execSql: ExecSql,\n): Promise<void> {\n return ensureSqlTables(execSql, documentProjectionTables);\n}\n\n/** Replace only the exact rejected continuation with a durable recovery marker. */\nexport async function invalidateDocumentSyncPullContinuation(\n execSql: ExecSql,\n input: {\n accessEpoch: number;\n accessStateHash: string | null;\n appKind: string;\n continuation: DocumentSyncPullContinuation;\n contentKeyBundle: string | null;\n documentId: string;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n lastCommitLsn: string | null;\n localId: string;\n },\n): Promise<DocumentRecord | null> {\n await ensureDocumentTables(execSql);\n const expectedContinuation = serializeDocumentSyncPullContinuation(\n input.continuation,\n );\n if (expectedContinuation === null) return null;\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const { db } = getClientSQLitePersistenceRuntime(lockedExecSql);\n await db\n .update(documents)\n .set({ pullContinuation: DOCUMENT_SYNC_PULL_RECOVERY_REQUIRED })\n .where(\n and(\n eq(documents.appKind, input.appKind),\n eq(documents.localId, input.localId),\n eq(documents.documentId, input.documentId),\n eq(documents.accessEpoch, input.accessEpoch),\n sql`${documents.accessStateHash} IS ${input.accessStateHash}`,\n sql`${documents.contentKeyBundle} IS ${input.contentKeyBundle}`,\n sql`${documents.documentKekTargets} IS ${input.documentKekTargets}`,\n sql`${documents.documentManifestBundle} IS ${input.documentManifestBundle}`,\n sql`${documents.lastCommitLsn} IS ${input.lastCommitLsn}`,\n eq(documents.pullContinuation, expectedContinuation),\n ),\n )\n .run();\n return loadDocumentRecord(lockedExecSql, {\n appKind: input.appKind,\n localId: input.localId,\n });\n });\n}\n\nexport {\n deleteDocumentPendingUpdate,\n deleteDocumentPendingUpdates,\n enqueueDocumentPendingUpdate,\n enqueueDocumentPendingUpdateWithHistory,\n listDocumentPendingUpdates,\n MAX_PENDING_UPDATE_REKEYS,\n rekeyDocumentPendingUpdate,\n resetDocumentPendingUpdateRekeyBudget,\n} from \"./documentPendingUpdatePersistence\";\nexport type {\n DocumentRecord,\n DocumentScope,\n PendingUpdateFields,\n PendingUpdateRecord,\n} from \"./documentPersistenceTypes\";\nexport {\n deleteDocumentRecord,\n documentRecordSelection,\n findLocalIdByDocumentId,\n loadDocumentRecord,\n mapSelectedDocumentRecord,\n} from \"./documentRecordPersistence\";\nexport {\n clearDocumentSyncFailure,\n hasRecordedTerminalSyncFailures,\n recordDocumentSyncFailure,\n} from \"./documentSyncFailurePersistence\";\n"]}
1
+ {"version":3,"file":"documentPersistence.js","sourceRoot":"","sources":["documentPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport {\n DOCUMENT_SYNC_PULL_RECOVERY_REQUIRED,\n type DocumentSyncPullContinuation,\n serializeDocumentSyncPullContinuation,\n} from \"../documents/shared/pullContinuation\";\nimport type { DocumentRecord } from \"./documentPersistenceTypes\";\nimport { loadDocumentRecord } from \"./documentRecordPersistence\";\nimport { documentProjectionTables, documents, documentTables } from \"./schema\";\nimport { getClientSQLitePersistenceRuntime } from \"./sqlitePersistenceRuntime\";\nimport {\n type ExecSql,\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"./sqlSchema\";\n\nexport function ensureDocumentTables(execSql: ExecSql): Promise<void> {\n return ensureSqlTables(execSql, documentTables);\n}\n\nexport function ensureDocumentProjectionTables(\n execSql: ExecSql,\n): Promise<void> {\n return ensureSqlTables(execSql, documentProjectionTables);\n}\n\n/** Replace only the exact rejected continuation with a durable recovery marker. */\nexport async function invalidateDocumentSyncPullContinuation(\n execSql: ExecSql,\n input: {\n accessEpoch: number;\n accessStateHash: string | null;\n appKind: string;\n continuation: DocumentSyncPullContinuation;\n contentKeyBundle: string | null;\n documentId: string;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n lastCommitLsn: string | null;\n localId: string;\n },\n): Promise<DocumentRecord | null> {\n await ensureDocumentTables(execSql);\n const expectedContinuation = serializeDocumentSyncPullContinuation(\n input.continuation,\n );\n if (expectedContinuation === null) return null;\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const { db } = getClientSQLitePersistenceRuntime(lockedExecSql);\n await db\n .update(documents)\n .set({ pullContinuation: DOCUMENT_SYNC_PULL_RECOVERY_REQUIRED })\n .where(\n and(\n eq(documents.appKind, input.appKind),\n eq(documents.localId, input.localId),\n eq(documents.documentId, input.documentId),\n eq(documents.accessEpoch, input.accessEpoch),\n sql`${documents.accessStateHash} IS ${input.accessStateHash}`,\n sql`${documents.contentKeyBundle} IS ${input.contentKeyBundle}`,\n sql`${documents.documentKekTargets} IS ${input.documentKekTargets}`,\n sql`${documents.documentManifestBundle} IS ${input.documentManifestBundle}`,\n sql`${documents.lastCommitLsn} IS ${input.lastCommitLsn}`,\n eq(documents.pullContinuation, expectedContinuation),\n ),\n )\n .run();\n return loadDocumentRecord(lockedExecSql, {\n appKind: input.appKind,\n localId: input.localId,\n });\n });\n}\n\nexport {\n enqueueDocumentPendingUpdate,\n enqueueDocumentPendingUpdateWithHistory,\n listDocumentPendingUpdates,\n MAX_PENDING_UPDATE_REKEYS,\n rekeyDocumentPendingUpdate,\n resetDocumentPendingUpdateRekeyBudget,\n settleDocumentPendingUpdate,\n unqueueDocumentPendingUpdates,\n} from \"./documentPendingUpdatePersistence\";\nexport type {\n DocumentRecord,\n DocumentScope,\n PendingUpdateFields,\n PendingUpdateRecord,\n} from \"./documentPersistenceTypes\";\nexport {\n deleteDocumentRecord,\n documentRecordSelection,\n findLocalIdByDocumentId,\n loadDocumentRecord,\n mapSelectedDocumentRecord,\n} from \"./documentRecordPersistence\";\nexport {\n clearDocumentSyncFailure,\n hasRecordedTerminalSyncFailures,\n recordDocumentSyncFailure,\n} from \"./documentSyncFailurePersistence\";\n"]}
@@ -72,8 +72,8 @@ export interface SelectedDocumentRecordRow {
72
72
  export interface SelectedPendingUpdateRow {
73
73
  id: string | null;
74
74
  updateData: string;
75
- partialStartVersionVector: string;
76
- partialEndVersionVector: string;
75
+ partialStartVersionVector: string | null;
76
+ partialEndVersionVector: string | null;
77
77
  sourceVersionVector: string | null;
78
78
  rekeyCount: number;
79
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"documentPersistenceTypes.js","sourceRoot":"","sources":["documentPersistenceTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { ContainerAccessLevel } from \"@tearleads/crypto\";\nimport type { DocumentSyncPullContinuation } from \"../documents/shared/pullContinuation\";\n\nexport interface DocumentRecord {\n id: string;\n documentId: string | null;\n /**\n * Durable fence advanced by an atomic raw-history recovery install. Writers\n * capture this before waiting for the mutation queue and must refuse to\n * publish when recovery advanced it first.\n */\n recoveryGeneration?: number;\n /** Former server id reserved for deterministic post-purge recreation. */\n recoveryDocumentId?: string | null;\n /**\n * Encoded end version vector of the persisted content frontier. Content\n * itself lives in the durable history (checkpoint + tail); this column\n * exists so priming and coverage predicates can compare versions from a\n * narrow indexed column. Empty string means \"never hydrated\".\n */\n snapshotEndVersion: string;\n accessEpoch: number;\n accessStateHash?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | null;\n lastCommitLsn?: string | null;\n contentKeyBundle?: string | null;\n documentKekTargets?: string | null;\n documentManifestBundle?: string | null;\n pendingBaseVersion?: string | null;\n pullContinuation?: DocumentSyncPullContinuation | null;\n /**\n * The durable continuation column was non-null but could not be decoded.\n * Keep forcing a page-one pull until a successful settlement replaces the\n * malformed value; ordinary local saves must preserve that recovery signal.\n */\n pullContinuationRecoveryRequired?: true;\n}\n\nexport interface PendingUpdateFields {\n updateData: string;\n partialStartVersionVector: string;\n partialEndVersionVector: string;\n sourceVersionVector?: string | null;\n}\n\nexport interface PendingUpdateRecord extends PendingUpdateFields {\n id: string;\n /**\n * Times this row was assigned a fresh id by lost-ack conflict recovery.\n * Persisted so the bound survives restarts; absent means zero (rows from\n * simple test doubles).\n */\n rekeyCount?: number | undefined;\n}\n\nexport interface DocumentScope {\n appKind: string;\n localId: string;\n}\n\nexport interface SelectedDocumentRecordRow {\n id: string;\n documentId: string | null;\n recoveryGeneration: number;\n recoveryDocumentId: string | null;\n snapshotEndVersion: string;\n accessEpoch: number;\n accessStateHash: string | null;\n effectiveAccessLevel: string | null;\n lastCommitLsn: string | null;\n contentKeyBundle: string | null;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n pendingBaseVersion: string | null;\n pullContinuation: string | null;\n}\n\nexport interface SelectedPendingUpdateRow {\n id: string | null;\n updateData: string;\n partialStartVersionVector: string;\n partialEndVersionVector: string;\n sourceVersionVector: string | null;\n rekeyCount: number;\n}\n"]}
1
+ {"version":3,"file":"documentPersistenceTypes.js","sourceRoot":"","sources":["documentPersistenceTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { ContainerAccessLevel } from \"@tearleads/crypto\";\nimport type { DocumentSyncPullContinuation } from \"../documents/shared/pullContinuation\";\n\nexport interface DocumentRecord {\n id: string;\n documentId: string | null;\n /**\n * Durable fence advanced by an atomic raw-history recovery install. Writers\n * capture this before waiting for the mutation queue and must refuse to\n * publish when recovery advanced it first.\n */\n recoveryGeneration?: number;\n /** Former server id reserved for deterministic post-purge recreation. */\n recoveryDocumentId?: string | null;\n /**\n * Encoded end version vector of the persisted content frontier. Content\n * itself lives in the durable history (checkpoint + tail); this column\n * exists so priming and coverage predicates can compare versions from a\n * narrow indexed column. Empty string means \"never hydrated\".\n */\n snapshotEndVersion: string;\n accessEpoch: number;\n accessStateHash?: string | null;\n effectiveAccessLevel?: ContainerAccessLevel | null;\n lastCommitLsn?: string | null;\n contentKeyBundle?: string | null;\n documentKekTargets?: string | null;\n documentManifestBundle?: string | null;\n pendingBaseVersion?: string | null;\n pullContinuation?: DocumentSyncPullContinuation | null;\n /**\n * The durable continuation column was non-null but could not be decoded.\n * Keep forcing a page-one pull until a successful settlement replaces the\n * malformed value; ordinary local saves must preserve that recovery signal.\n */\n pullContinuationRecoveryRequired?: true;\n}\n\nexport interface PendingUpdateFields {\n updateData: string;\n partialStartVersionVector: string;\n partialEndVersionVector: string;\n sourceVersionVector?: string | null;\n}\n\nexport interface PendingUpdateRecord extends PendingUpdateFields {\n id: string;\n /**\n * Times this row was assigned a fresh id by lost-ack conflict recovery.\n * Persisted so the bound survives restarts; absent means zero (rows from\n * simple test doubles).\n */\n rekeyCount?: number | undefined;\n}\n\nexport interface DocumentScope {\n appKind: string;\n localId: string;\n}\n\nexport interface SelectedDocumentRecordRow {\n id: string;\n documentId: string | null;\n recoveryGeneration: number;\n recoveryDocumentId: string | null;\n snapshotEndVersion: string;\n accessEpoch: number;\n accessStateHash: string | null;\n effectiveAccessLevel: string | null;\n lastCommitLsn: string | null;\n contentKeyBundle: string | null;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n pendingBaseVersion: string | null;\n pullContinuation: string | null;\n}\n\nexport interface SelectedPendingUpdateRow {\n id: string | null;\n updateData: string;\n partialStartVersionVector: string | null;\n partialEndVersionVector: string | null;\n sourceVersionVector: string | null;\n rekeyCount: number;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { and, desc, eq, sql } from "drizzle-orm";
2
2
  import { normalizeEffectiveAccessLevel } from "../accessLevel.js";
3
3
  import { deserializeDocumentSyncPullContinuation } from "../documents/shared/pullContinuation.js";
4
- import { documentPendingUpdates, documents } from "./schema.js";
4
+ import { documentHistoryUpdates, documents } from "./schema.js";
5
5
  import { getClientSQLitePersistenceRuntime } from "./sqlitePersistenceRuntime.js";
6
6
  /**
7
7
  * The ONE select shape for a full documents-row record: every reader that
@@ -70,9 +70,10 @@ export async function findLocalIdByDocumentId(execSql, appKind, documentId) {
70
70
  const { db } = getClientSQLitePersistenceRuntime(execSql);
71
71
  const hasPendingUpdates = sql `EXISTS (
72
72
  SELECT 1
73
- FROM ${documentPendingUpdates}
74
- WHERE ${documentPendingUpdates.appKind} = ${documents.appKind}
75
- AND ${documentPendingUpdates.localId} = ${documents.localId}
73
+ FROM ${documentHistoryUpdates}
74
+ WHERE ${documentHistoryUpdates.appKind} = ${documents.appKind}
75
+ AND ${documentHistoryUpdates.localId} = ${documents.localId}
76
+ AND ${documentHistoryUpdates.updateId} IS NOT NULL
76
77
  )`;
77
78
  const hasPendingLocalWork = sql `(
78
79
  ${hasPendingUpdates}
@@ -1 +1 @@
1
- {"version":3,"file":"documentRecordPersistence.js","sourceRoot":"","sources":["documentRecordPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, desc, eq, sql } from \"drizzle-orm\";\nimport { normalizeEffectiveAccessLevel } from \"../accessLevel\";\nimport { deserializeDocumentSyncPullContinuation } from \"../documents/shared/pullContinuation\";\nimport type {\n DocumentRecord,\n DocumentScope,\n SelectedDocumentRecordRow,\n} from \"./documentPersistenceTypes\";\nimport { documentPendingUpdates, documents } from \"./schema\";\nimport { getClientSQLitePersistenceRuntime } from \"./sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"./sqlSchema\";\n\n/**\n * The ONE select shape for a full documents-row record: every reader that\n * feeds mapSelectedDocumentRecord spreads this, so a new record column cannot\n * silently miss one of them.\n */\nexport const documentRecordSelection = {\n id: documents.localId,\n documentId: documents.documentId,\n recoveryGeneration: documents.recoveryGeneration,\n recoveryDocumentId: documents.recoveryDocumentId,\n snapshotEndVersion: documents.snapshotEndVersion,\n accessEpoch: documents.accessEpoch,\n accessStateHash: documents.accessStateHash,\n effectiveAccessLevel: documents.effectiveAccessLevel,\n lastCommitLsn: documents.lastCommitLsn,\n documentManifestBundle: documents.documentManifestBundle,\n contentKeyBundle: documents.contentKeyBundle,\n documentKekTargets: documents.documentKekTargets,\n pendingBaseVersion: documents.pendingBaseVersion,\n pullContinuation: documents.pullContinuation,\n};\n\nexport function mapSelectedDocumentRecord(\n row: SelectedDocumentRecordRow,\n): DocumentRecord {\n const record: DocumentRecord = {\n id: row.id,\n documentId: row.documentId,\n recoveryGeneration: row.recoveryGeneration,\n snapshotEndVersion: row.snapshotEndVersion,\n accessEpoch: row.accessEpoch,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n row.effectiveAccessLevel,\n ),\n lastCommitLsn: row.lastCommitLsn,\n contentKeyBundle: row.contentKeyBundle,\n documentKekTargets: row.documentKekTargets,\n documentManifestBundle: row.documentManifestBundle,\n };\n\n if (row.accessStateHash !== null) {\n record.accessStateHash = row.accessStateHash;\n }\n\n if (row.recoveryDocumentId !== null) {\n record.recoveryDocumentId = row.recoveryDocumentId;\n }\n\n // Only surface the marker when one was persisted, so a row that never stored\n // one keeps its prior shape (and init falls through to seeding it).\n if (row.pendingBaseVersion !== null) {\n record.pendingBaseVersion = row.pendingBaseVersion;\n }\n\n const pullContinuation = deserializeDocumentSyncPullContinuation(\n row.pullContinuation,\n );\n if (pullContinuation !== null) {\n record.pullContinuation = pullContinuation;\n } else if (row.pullContinuation !== null) {\n record.pullContinuationRecoveryRequired = true;\n }\n\n return record;\n}\n\nexport async function loadDocumentRecord(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<DocumentRecord | null> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select(documentRecordSelection)\n .from(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n ),\n )\n .limit(1);\n\n return rows[0] ? mapSelectedDocumentRecord(rows[0]) : null;\n}\n\nexport async function findLocalIdByDocumentId(\n execSql: ExecSql,\n appKind: string,\n documentId: string,\n): Promise<string | null> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const hasPendingUpdates = sql<number>`EXISTS (\n SELECT 1\n FROM ${documentPendingUpdates}\n WHERE ${documentPendingUpdates.appKind} = ${documents.appKind}\n AND ${documentPendingUpdates.localId} = ${documents.localId}\n )`;\n const hasPendingLocalWork = sql<number>`(\n ${hasPendingUpdates}\n OR (\n ${documents.pendingBaseVersion} IS NOT NULL\n AND ${documents.pendingBaseVersion} <> ${documents.snapshotEndVersion}\n )\n )`;\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(eq(documents.appKind, appKind), eq(documents.documentId, documentId)),\n )\n // Duplicate remote identities can survive an interrupted local adoption.\n // Preserve queued or deferred edits, then make the fallback stable.\n .orderBy(\n desc(hasPendingLocalWork),\n desc(documents.updatedAt),\n desc(documents.localId),\n )\n .limit(1);\n\n return rows[0]?.localId ?? null;\n}\n\nexport async function deleteDocumentRecord(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .delete(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n ),\n )\n .run();\n });\n}\n"]}
1
+ {"version":3,"file":"documentRecordPersistence.js","sourceRoot":"","sources":["documentRecordPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, desc, eq, sql } from \"drizzle-orm\";\nimport { normalizeEffectiveAccessLevel } from \"../accessLevel\";\nimport { deserializeDocumentSyncPullContinuation } from \"../documents/shared/pullContinuation\";\nimport type {\n DocumentRecord,\n DocumentScope,\n SelectedDocumentRecordRow,\n} from \"./documentPersistenceTypes\";\nimport { documentHistoryUpdates, documents } from \"./schema\";\nimport { getClientSQLitePersistenceRuntime } from \"./sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"./sqlSchema\";\n\n/**\n * The ONE select shape for a full documents-row record: every reader that\n * feeds mapSelectedDocumentRecord spreads this, so a new record column cannot\n * silently miss one of them.\n */\nexport const documentRecordSelection = {\n id: documents.localId,\n documentId: documents.documentId,\n recoveryGeneration: documents.recoveryGeneration,\n recoveryDocumentId: documents.recoveryDocumentId,\n snapshotEndVersion: documents.snapshotEndVersion,\n accessEpoch: documents.accessEpoch,\n accessStateHash: documents.accessStateHash,\n effectiveAccessLevel: documents.effectiveAccessLevel,\n lastCommitLsn: documents.lastCommitLsn,\n documentManifestBundle: documents.documentManifestBundle,\n contentKeyBundle: documents.contentKeyBundle,\n documentKekTargets: documents.documentKekTargets,\n pendingBaseVersion: documents.pendingBaseVersion,\n pullContinuation: documents.pullContinuation,\n};\n\nexport function mapSelectedDocumentRecord(\n row: SelectedDocumentRecordRow,\n): DocumentRecord {\n const record: DocumentRecord = {\n id: row.id,\n documentId: row.documentId,\n recoveryGeneration: row.recoveryGeneration,\n snapshotEndVersion: row.snapshotEndVersion,\n accessEpoch: row.accessEpoch,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n row.effectiveAccessLevel,\n ),\n lastCommitLsn: row.lastCommitLsn,\n contentKeyBundle: row.contentKeyBundle,\n documentKekTargets: row.documentKekTargets,\n documentManifestBundle: row.documentManifestBundle,\n };\n\n if (row.accessStateHash !== null) {\n record.accessStateHash = row.accessStateHash;\n }\n\n if (row.recoveryDocumentId !== null) {\n record.recoveryDocumentId = row.recoveryDocumentId;\n }\n\n // Only surface the marker when one was persisted, so a row that never stored\n // one keeps its prior shape (and init falls through to seeding it).\n if (row.pendingBaseVersion !== null) {\n record.pendingBaseVersion = row.pendingBaseVersion;\n }\n\n const pullContinuation = deserializeDocumentSyncPullContinuation(\n row.pullContinuation,\n );\n if (pullContinuation !== null) {\n record.pullContinuation = pullContinuation;\n } else if (row.pullContinuation !== null) {\n record.pullContinuationRecoveryRequired = true;\n }\n\n return record;\n}\n\nexport async function loadDocumentRecord(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<DocumentRecord | null> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select(documentRecordSelection)\n .from(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n ),\n )\n .limit(1);\n\n return rows[0] ? mapSelectedDocumentRecord(rows[0]) : null;\n}\n\nexport async function findLocalIdByDocumentId(\n execSql: ExecSql,\n appKind: string,\n documentId: string,\n): Promise<string | null> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const hasPendingUpdates = sql<number>`EXISTS (\n SELECT 1\n FROM ${documentHistoryUpdates}\n WHERE ${documentHistoryUpdates.appKind} = ${documents.appKind}\n AND ${documentHistoryUpdates.localId} = ${documents.localId}\n AND ${documentHistoryUpdates.updateId} IS NOT NULL\n )`;\n const hasPendingLocalWork = sql<number>`(\n ${hasPendingUpdates}\n OR (\n ${documents.pendingBaseVersion} IS NOT NULL\n AND ${documents.pendingBaseVersion} <> ${documents.snapshotEndVersion}\n )\n )`;\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(eq(documents.appKind, appKind), eq(documents.documentId, documentId)),\n )\n // Duplicate remote identities can survive an interrupted local adoption.\n // Preserve queued or deferred edits, then make the fallback stable.\n .orderBy(\n desc(hasPendingLocalWork),\n desc(documents.updatedAt),\n desc(documents.localId),\n )\n .limit(1);\n\n return rows[0]?.localId ?? null;\n}\n\nexport async function deleteDocumentRecord(\n execSql: ExecSql,\n scope: DocumentScope,\n): Promise<void> {\n await getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n await db\n .delete(documents)\n .where(\n and(\n eq(documents.appKind, scope.appKind),\n eq(documents.localId, scope.localId),\n ),\n )\n .run();\n });\n}\n"]}