@tearleads/client-sdk 0.1.44 → 0.1.46

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 (133) hide show
  1. package/client/Tearleads.js +3 -0
  2. package/client/Tearleads.js.map +1 -1
  3. package/client/userIdentities.d.ts +11 -1
  4. package/client/userIdentities.js +26 -8
  5. package/client/userIdentities.js.map +1 -1
  6. package/client/workflowRuntime.d.ts +2 -1
  7. package/client/workflowRuntime.js +1 -0
  8. package/client/workflowRuntime.js.map +1 -1
  9. package/data/persistence/container-contents/containerContentsPersistence.js +2 -3
  10. package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
  11. package/data/persistence/container-contents/containerCreateIntentSettlement.js +16 -16
  12. package/data/persistence/container-contents/containerCreateIntentSettlement.js.map +1 -1
  13. package/data/persistence/container-contents/containerDeletionPersistence.js +5 -11
  14. package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
  15. package/data/persistence/container-contents/containerDocumentReassignment.js +13 -13
  16. package/data/persistence/container-contents/containerDocumentReassignment.js.map +1 -1
  17. package/data/persistence/container-contents/containerHydrationPersistence.js +7 -4
  18. package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
  19. package/data/persistence/container-contents/containerIntentPersistence.js +43 -42
  20. package/data/persistence/container-contents/containerIntentPersistence.js.map +1 -1
  21. package/data/persistence/container-contents/containerMetadataMutationPersistence.js +15 -20
  22. package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
  23. package/data/persistence/container-contents/containerMoveAbandonPersistence.js +1 -6
  24. package/data/persistence/container-contents/containerMoveAbandonPersistence.js.map +1 -1
  25. package/data/persistence/container-contents/containerMoveIntentRows.js +9 -8
  26. package/data/persistence/container-contents/containerMoveIntentRows.js.map +1 -1
  27. package/data/persistence/container-contents/containerReconcilePersistence.js +4 -8
  28. package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
  29. package/data/persistence/container-contents/containerRecoveryPersistence.js +20 -19
  30. package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
  31. package/data/persistence/container-contents/containerRemovalWork.js +10 -10
  32. package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
  33. package/data/persistence/container-contents/containerStructuralRepair.js +21 -44
  34. package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
  35. package/data/persistence/container-contents/documentLinkRemovalRepair.js +12 -11
  36. package/data/persistence/container-contents/documentLinkRemovalRepair.js.map +1 -1
  37. package/data/persistence/container-contents/documentMoveIntentPersistence.js +53 -28
  38. package/data/persistence/container-contents/documentMoveIntentPersistence.js.map +1 -1
  39. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js +9 -8
  40. package/data/persistence/container-contents/documentPlacementIntentEnqueue.js.map +1 -1
  41. package/data/persistence/container-contents/documentPurgePlacement.js +6 -6
  42. package/data/persistence/container-contents/documentPurgePlacement.js.map +1 -1
  43. package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
  44. package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
  45. package/data/persistence/container-contents/pendingContainerCreate.js +5 -5
  46. package/data/persistence/container-contents/pendingContainerCreate.js.map +1 -1
  47. package/data/persistence/containers/containerPersistence.js +10 -27
  48. package/data/persistence/containers/containerPersistence.js.map +1 -1
  49. package/data/persistence/containers/documentContainerProjectionPersistence.js +2 -2
  50. package/data/persistence/containers/documentContainerProjectionPersistence.js.map +1 -1
  51. package/data/persistence/containers/documentPlacement.js +10 -10
  52. package/data/persistence/containers/documentPlacement.js.map +1 -1
  53. package/data/persistence/documents/internal/discardDocument.js +5 -5
  54. package/data/persistence/documents/internal/discardDocument.js.map +1 -1
  55. package/data/persistence/documents/internal/documentDeletionPersistence.js +7 -9
  56. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  57. package/data/persistence/documents/internal/documentMutationPersistence.js +6 -8
  58. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  59. package/data/persistence/documents/internal/ensureDocumentsSchema.js +2 -2
  60. package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
  61. package/data/persistence/documents/internal/orphanSideRows.js +3 -22
  62. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  63. package/data/persistence/organizations/organizationDataUsagePersistence.js +31 -64
  64. package/data/persistence/organizations/organizationDataUsagePersistence.js.map +1 -1
  65. package/data/persistence/organizations/organizationReadModelPurge.js +1 -5
  66. package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
  67. package/data/persistence/principalCurrentAcknowledgementPersistence.js +24 -17
  68. package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
  69. package/data/persistence/principalHistoryIncompleteRetention.js +3 -9
  70. package/data/persistence/principalHistoryIncompleteRetention.js.map +1 -1
  71. package/data/persistence/principalHistoryStagePersistence.d.ts +3 -9
  72. package/data/persistence/principalHistoryStagePersistence.js +15 -25
  73. package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
  74. package/data/persistence/principalHistoryStageRetention.js +16 -15
  75. package/data/persistence/principalHistoryStageRetention.js.map +1 -1
  76. package/data/persistence/principalHistoryUnpublishedRetention.js +6 -13
  77. package/data/persistence/principalHistoryUnpublishedRetention.js.map +1 -1
  78. package/data/sqlite/containerSchema.d.ts +84 -180
  79. package/data/sqlite/containerSchema.js +14 -23
  80. package/data/sqlite/containerSchema.js.map +1 -1
  81. package/data/sqlite/documentPlacementIntentSchema.js +3 -50
  82. package/data/sqlite/documentPlacementIntentSchema.js.map +1 -1
  83. package/data/sqlite/documentSyncFailurePersistence.d.ts +16 -6
  84. package/data/sqlite/documentSyncFailurePersistence.js +44 -54
  85. package/data/sqlite/documentSyncFailurePersistence.js.map +1 -1
  86. package/data/sqlite/{documentPlacementIntentSchema.d.ts → localIntentSchema.d.ts} +162 -88
  87. package/data/sqlite/localIntentSchema.js +90 -0
  88. package/data/sqlite/localIntentSchema.js.map +1 -0
  89. package/data/sqlite/organizationDataUsageSchema.js +11 -17
  90. package/data/sqlite/organizationDataUsageSchema.js.map +1 -1
  91. package/data/sqlite/principalHistoryRetentionSchema.js +0 -15
  92. package/data/sqlite/principalHistoryRetentionSchema.js.map +1 -1
  93. package/data/sqlite/principalHistoryStageSchema.d.ts +44 -2
  94. package/data/sqlite/principalHistoryStageSchema.js +14 -2
  95. package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
  96. package/data/sqlite/schema.d.ts +947 -2112
  97. package/data/sqlite/schema.js +26 -134
  98. package/data/sqlite/schema.js.map +1 -1
  99. package/data/trustedUserIdentity/identityLink.d.ts +12 -0
  100. package/data/trustedUserIdentity/identityLink.js +117 -0
  101. package/data/trustedUserIdentity/identityLink.js.map +1 -0
  102. package/data/trustedUserIdentity/index.d.ts +2 -1
  103. package/data/trustedUserIdentity/index.js +1 -0
  104. package/data/trustedUserIdentity/index.js.map +1 -1
  105. package/data/trustedUserIdentity/service.js +48 -2
  106. package/data/trustedUserIdentity/service.js.map +1 -1
  107. package/data/trustedUserIdentity/types.d.ts +3 -0
  108. package/data/trustedUserIdentity/types.js.map +1 -1
  109. package/index.js +1 -1
  110. package/index.js.map +1 -1
  111. package/package.json +1 -1
  112. package/workflows/container-contents/documentPriming.js +6 -10
  113. package/workflows/container-contents/documentPriming.js.map +1 -1
  114. package/workflows/container-contents/documentQueries/sql.js +11 -10
  115. package/workflows/container-contents/documentQueries/sql.js.map +1 -1
  116. package/workflows/container-contents/documentQueries.js +2 -2
  117. package/workflows/container-contents/documentQueries.js.map +1 -1
  118. package/workflows/container-contents/pendingDownloads.js +2 -5
  119. package/workflows/container-contents/pendingDownloads.js.map +1 -1
  120. package/workflows/container-contents/pendingWrites/deferredTails.js +3 -11
  121. package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
  122. package/workflows/container-contents/pendingWrites/sources.js +56 -80
  123. package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
  124. package/workflows/container-contents/pendingWrites.js +6 -4
  125. package/workflows/container-contents/pendingWrites.js.map +1 -1
  126. package/workflows/container-contents/remoteContainerState.js +2 -1
  127. package/workflows/container-contents/remoteContainerState.js.map +1 -1
  128. package/workflows/sync/remoteReset.js +16 -23
  129. package/workflows/sync/remoteReset.js.map +1 -1
  130. package/workflows/sync/remoteResetPrincipalScope.js +1 -2
  131. package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
  132. package/workflows/sync/remoteResetScope.js +15 -8
  133. package/workflows/sync/remoteResetScope.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"containerIntentPersistence.js","sourceRoot":"","sources":["containerIntentPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray } from \"drizzle-orm\";\nimport {\n containerCreateIntents,\n containerMoveIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport {\n CONTAINER_CREATE_INTENT_TYPE,\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerContentsPersistence,\n type ContainerCreateIntentErrorInput,\n type ContainerCreateIntentInput,\n type ContainerCreateIntentRecord,\n type ContainerCreateIntentRevisionInput,\n type ContainerCreateIntentSyncStatus,\n type ContainerMoveIntentRecord,\n type ContainerMoveIntentRevisionInput,\n type ContainerMoveIntentSyncStatus,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\n\nfunction parseCreateIntentSyncStatus(\n value: unknown,\n): ContainerCreateIntentSyncStatus {\n return value === \"synced\" ? \"synced\" : \"pending\";\n}\n\nfunction parseMoveIntentSyncStatus(\n value: unknown,\n): ContainerMoveIntentSyncStatus {\n return value === \"blocked\" ? \"blocked\" : \"pending\";\n}\n\ninterface SelectedContainerCreateIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n syncStatus: string;\n remoteContainerId: string | null;\n remoteMetadataDocumentId: string | null;\n remoteMetadataAccessStateHash: string | null;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface SelectedContainerMoveIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n previousParentContainerId: string | null;\n syncStatus: string;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nfunction mapContainerCreateIntentRecord(\n row: SelectedContainerCreateIntentRecord,\n): ContainerCreateIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: parseCreateIntentSyncStatus(row.syncStatus),\n remoteContainerId: row.remoteContainerId,\n remoteMetadataDocumentId: row.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash: row.remoteMetadataAccessStateHash,\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapContainerMoveIntentRecord(\n row: SelectedContainerMoveIntentRecord,\n): ContainerMoveIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n previousParentContainerId: row.previousParentContainerId,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: parseMoveIntentSyncStatus(row.syncStatus),\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport async function saveContainerCreateIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n createIntent: ContainerCreateIntentInput;\n updatedAt: string;\n}) {\n const { containerId, createIntent, tx, updatedAt } = input;\n const id = createIntent.id ?? crypto.randomUUID();\n await tx\n .insert(containerCreateIntents)\n .values({\n id,\n containerId,\n parentContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: containerCreateIntents.containerId,\n set: {\n // Timestamps can collide when a create is re-queued in one clock tick,\n // so every enqueue owns a fresh revision token too.\n id,\n parentContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n updatedAt,\n },\n })\n .run();\n}\n\nexport class ContainerCreateIntentSupersededError extends Error {\n constructor() {\n super(\"Container create intent was superseded before local settlement\");\n }\n}\n\nexport async function deleteContainerMoveIntentRevision(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const deleted = await input.tx\n .delete(containerMoveIntents)\n .where(\n and(\n eq(containerMoveIntents.containerId, input.containerId),\n eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n eq(containerMoveIntents.id, input.expectedIntentId),\n eq(containerMoveIntents.updatedAt, input.expectedUpdatedAt),\n ),\n )\n .returning({ containerId: containerMoveIntents.containerId });\n return deleted.length > 0;\n}\n\nasync function recordCreateIntentErrorAttempt(\n execSql: ExecSql,\n input: ContainerCreateIntentErrorInput,\n): Promise<void> {\n const {\n containerId,\n expectedIntentId,\n expectedUpdatedAt,\n message,\n stillCurrent,\n } = input;\n if (!message) throw new Error(\"Container create intent error is required\");\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(containerCreateIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: message,\n updatedAt,\n })\n .where(\n and(\n eq(containerCreateIntents.containerId, containerId),\n eq(containerCreateIntents.syncStatus, \"pending\"),\n eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(containerCreateIntents.id, expectedIntentId),\n eq(containerCreateIntents.updatedAt, expectedUpdatedAt),\n ),\n )\n .run();\n };\n if (stillCurrent) {\n await runtime.guardedTransaction(record, stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n}\n\nasync function markMoveIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n return deleteContainerMoveIntentRevision({ ...input, tx });\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n\nasync function markCreateIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerCreateIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => settleContainerCreateIntentRevision({ ...input, tx }),\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result !== \"superseded\";\n}\n\ntype ContainerIntentPersistence = Pick<\n ContainerContentsPersistence,\n | \"listPendingCreateIntents\"\n | \"listUnsyncedMoveIntents\"\n | \"recordCreateIntentRevisionError\"\n | \"recordMoveIntentError\"\n | \"markCreateIntentRevisionSynced\"\n | \"markMoveIntentRevisionSynced\"\n>;\n\nexport const containerIntentPersistence = {\n async listPendingCreateIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: containerCreateIntents.id,\n containerId: containerCreateIntents.containerId,\n parentContainerId: containerCreateIntents.parentContainerId,\n syncStatus: containerCreateIntents.syncStatus,\n remoteContainerId: containerCreateIntents.remoteContainerId,\n remoteMetadataDocumentId:\n containerCreateIntents.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash:\n containerCreateIntents.remoteMetadataAccessStateHash,\n lastError: containerCreateIntents.lastError,\n lastAttemptedAt: containerCreateIntents.lastAttemptedAt,\n createdAt: containerCreateIntents.createdAt,\n updatedAt: containerCreateIntents.updatedAt,\n })\n .from(containerCreateIntents)\n .where(\n and(\n eq(containerCreateIntents.syncStatus, \"pending\"),\n eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n ),\n )\n .orderBy(asc(containerCreateIntents.createdAt));\n\n return rows.map((row) => mapContainerCreateIntentRecord(row));\n },\n async listUnsyncedMoveIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n // No status filter: markMoveIntentRevisionSynced deletes settled rows,\n // so every surviving row is unsynced. Blocked intents replay too: \"blocked\"\n // names the reason the last attempt could not proceed, not a terminal\n // verdict — the missing container can appear via hydration, after which\n // the move completes — and hydration must still not revert them.\n const rows = await db\n .select({\n id: containerMoveIntents.id,\n containerId: containerMoveIntents.containerId,\n parentContainerId: containerMoveIntents.parentContainerId,\n previousParentContainerId:\n containerMoveIntents.previousParentContainerId,\n syncStatus: containerMoveIntents.syncStatus,\n lastError: containerMoveIntents.lastError,\n lastAttemptedAt: containerMoveIntents.lastAttemptedAt,\n createdAt: containerMoveIntents.createdAt,\n updatedAt: containerMoveIntents.updatedAt,\n })\n .from(containerMoveIntents)\n .where(eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE))\n .orderBy(asc(containerMoveIntents.createdAt));\n\n return rows.map((row) => mapContainerMoveIntentRecord(row));\n },\n recordCreateIntentRevisionError: (execSql, input) =>\n recordCreateIntentErrorAttempt(execSql, input),\n async recordMoveIntentError(execSql, input) {\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(containerMoveIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: input.message,\n syncStatus: input.blocked ? \"blocked\" : \"pending\",\n updatedAt,\n })\n .where(\n and(\n eq(containerMoveIntents.containerId, input.containerId),\n // Blocked rows stay updatable so a retried intent records its\n // fresh outcome and a transient failure unblocks it.\n inArray(containerMoveIntents.syncStatus, [\"pending\", \"blocked\"]),\n eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n ...(input.expectedIntentId\n ? [eq(containerMoveIntents.id, input.expectedIntentId)]\n : []),\n ...(input.expectedUpdatedAt\n ? [eq(containerMoveIntents.updatedAt, input.expectedUpdatedAt)]\n : []),\n ),\n )\n .run();\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(record, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n },\n markCreateIntentRevisionSynced,\n markMoveIntentRevisionSynced,\n} satisfies ContainerIntentPersistence;\n"]}
1
+ {"version":3,"file":"containerIntentPersistence.js","sourceRoot":"","sources":["containerIntentPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray } from \"drizzle-orm\";\nimport {\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n LOCAL_INTENT_SUBJECT,\n localIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport {\n CONTAINER_CREATE_INTENT_TYPE,\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerContentsPersistence,\n type ContainerCreateIntentErrorInput,\n type ContainerCreateIntentInput,\n type ContainerCreateIntentRecord,\n type ContainerCreateIntentRevisionInput,\n type ContainerCreateIntentSyncStatus,\n type ContainerMoveIntentRecord,\n type ContainerMoveIntentRevisionInput,\n type ContainerMoveIntentSyncStatus,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\n\nfunction parseCreateIntentSyncStatus(\n value: unknown,\n): ContainerCreateIntentSyncStatus {\n return value === \"synced\" ? \"synced\" : \"pending\";\n}\n\nfunction parseMoveIntentSyncStatus(\n value: unknown,\n): ContainerMoveIntentSyncStatus {\n return value === \"blocked\" ? \"blocked\" : \"pending\";\n}\n\ninterface SelectedContainerCreateIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n syncStatus: string;\n remoteContainerId: string | null;\n remoteMetadataDocumentId: string | null;\n remoteMetadataAccessStateHash: string | null;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface SelectedContainerMoveIntentRecord {\n id: string | null;\n containerId: string;\n parentContainerId: string;\n previousParentContainerId: string | null;\n syncStatus: string;\n lastError: string | null;\n lastAttemptedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nfunction mapContainerCreateIntentRecord(\n row: SelectedContainerCreateIntentRecord,\n): ContainerCreateIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: parseCreateIntentSyncStatus(row.syncStatus),\n remoteContainerId: row.remoteContainerId,\n remoteMetadataDocumentId: row.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash: row.remoteMetadataAccessStateHash,\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapContainerMoveIntentRecord(\n row: SelectedContainerMoveIntentRecord,\n): ContainerMoveIntentRecord {\n return {\n id: String(row.id ?? \"\"),\n containerId: row.containerId,\n parentContainerId: row.parentContainerId,\n previousParentContainerId: row.previousParentContainerId,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: parseMoveIntentSyncStatus(row.syncStatus),\n lastError: row.lastError,\n lastAttemptedAt: row.lastAttemptedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport async function saveContainerCreateIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n createIntent: ContainerCreateIntentInput;\n updatedAt: string;\n}) {\n const { containerId, createIntent, tx, updatedAt } = input;\n const id = createIntent.id ?? crypto.randomUUID();\n await tx\n .insert(localIntents)\n .values({\n id,\n lane: LOCAL_INTENT_LANES.containerCreate,\n subjectId: containerId,\n targetContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: LOCAL_INTENT_SUBJECT,\n set: {\n // Timestamps can collide when a create is re-queued in one clock tick,\n // so every enqueue owns a fresh revision token too.\n id,\n targetContainerId: createIntent.parentContainerId,\n intentType: CONTAINER_CREATE_INTENT_TYPE,\n syncStatus: \"pending\",\n remoteContainerId: null,\n remoteMetadataDocumentId: null,\n remoteMetadataAccessStateHash: null,\n lastError: null,\n lastAttemptedAt: null,\n updatedAt,\n },\n })\n .run();\n}\n\nexport class ContainerCreateIntentSupersededError extends Error {\n constructor() {\n super(\"Container create intent was superseded before local settlement\");\n }\n}\n\nexport async function deleteContainerMoveIntentRevision(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const deleted = await input.tx\n .delete(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, input.containerId),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n eq(localIntents.id, input.expectedIntentId),\n eq(localIntents.updatedAt, input.expectedUpdatedAt),\n ),\n )\n .returning({ containerId: localIntents.subjectId });\n return deleted.length > 0;\n}\n\nasync function recordCreateIntentErrorAttempt(\n execSql: ExecSql,\n input: ContainerCreateIntentErrorInput,\n): Promise<void> {\n const {\n containerId,\n expectedIntentId,\n expectedUpdatedAt,\n message,\n stillCurrent,\n } = input;\n if (!message) throw new Error(\"Container create intent error is required\");\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(localIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: message,\n updatedAt,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.subjectId, containerId),\n eq(localIntents.syncStatus, \"pending\"),\n eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(localIntents.id, expectedIntentId),\n eq(localIntents.updatedAt, expectedUpdatedAt),\n ),\n )\n .run();\n };\n if (stillCurrent) {\n await runtime.guardedTransaction(record, stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n}\n\nasync function markMoveIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n return deleteContainerMoveIntentRevision({ ...input, tx });\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n\nasync function markCreateIntentRevisionSynced(\n execSql: ExecSql,\n input: ContainerCreateIntentRevisionInput,\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => settleContainerCreateIntentRevision({ ...input, tx }),\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result !== \"superseded\";\n}\n\ntype ContainerIntentPersistence = Pick<\n ContainerContentsPersistence,\n | \"listPendingCreateIntents\"\n | \"listUnsyncedMoveIntents\"\n | \"recordCreateIntentRevisionError\"\n | \"recordMoveIntentError\"\n | \"markCreateIntentRevisionSynced\"\n | \"markMoveIntentRevisionSynced\"\n>;\n\nexport const containerIntentPersistence = {\n async listPendingCreateIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n id: localIntents.id,\n containerId: localIntents.subjectId,\n parentContainerId: localIntents.targetContainerId,\n syncStatus: localIntents.syncStatus,\n remoteContainerId: localIntents.remoteContainerId,\n remoteMetadataDocumentId: localIntents.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash:\n localIntents.remoteMetadataAccessStateHash,\n lastError: localIntents.lastError,\n lastAttemptedAt: localIntents.lastAttemptedAt,\n createdAt: localIntents.createdAt,\n updatedAt: localIntents.updatedAt,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.syncStatus, \"pending\"),\n eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n ),\n )\n .orderBy(asc(localIntents.createdAt));\n\n return rows.map((row) => mapContainerCreateIntentRecord(row));\n },\n async listUnsyncedMoveIntents(execSql) {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n // No status filter: markMoveIntentRevisionSynced deletes settled rows,\n // so every surviving row is unsynced. Blocked intents replay too: \"blocked\"\n // names the reason the last attempt could not proceed, not a terminal\n // verdict — the missing container can appear via hydration, after which\n // the move completes — and hydration must still not revert them.\n const rows = await db\n .select({\n id: localIntents.id,\n containerId: localIntents.subjectId,\n parentContainerId: localIntents.targetContainerId,\n previousParentContainerId: localIntents.sourceContainerId,\n syncStatus: localIntents.syncStatus,\n lastError: localIntents.lastError,\n lastAttemptedAt: localIntents.lastAttemptedAt,\n createdAt: localIntents.createdAt,\n updatedAt: localIntents.updatedAt,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n ),\n )\n .orderBy(asc(localIntents.createdAt));\n\n return rows.map((row) => mapContainerMoveIntentRecord(row));\n },\n recordCreateIntentRevisionError: (execSql, input) =>\n recordCreateIntentErrorAttempt(execSql, input),\n async recordMoveIntentError(execSql, input) {\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const record = async (tx: ClientSQLiteTransactionScope) => {\n const updatedAt = new Date().toISOString();\n await tx\n .update(localIntents)\n .set({\n lastAttemptedAt: updatedAt,\n lastError: input.message,\n syncStatus: input.blocked ? \"blocked\" : \"pending\",\n updatedAt,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, input.containerId),\n // Blocked rows stay updatable so a retried intent records its\n // fresh outcome and a transient failure unblocks it.\n inArray(localIntents.syncStatus, [\"pending\", \"blocked\"]),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n ...(input.expectedIntentId\n ? [eq(localIntents.id, input.expectedIntentId)]\n : []),\n ...(input.expectedUpdatedAt\n ? [eq(localIntents.updatedAt, input.expectedUpdatedAt)]\n : []),\n ),\n )\n .run();\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(record, input.stillCurrent, {\n behavior: \"immediate\",\n });\n return;\n }\n await runtime.transaction(record, { behavior: \"immediate\" });\n },\n markCreateIntentRevisionSynced,\n markMoveIntentRevisionSynced,\n} satisfies ContainerIntentPersistence;\n"]}
@@ -1,9 +1,10 @@
1
- import { and, eq } from "drizzle-orm";
1
+ import { and, eq, or } from "drizzle-orm";
2
2
  import { assertHeldContainerBinding, heldContainerBinding, } from "../../containers/containerBinding.js";
3
3
  import { documentSyncPullContinuationsEqual } from "../../documents/shared/pullContinuation.js";
4
4
  import { hasQueuedDocumentUpdates, settleQueuedDocumentUpdatesInTransaction, } from "../../sqlite/documentPendingUpdatePersistence.js";
5
5
  import { enqueueDocumentPendingUpdate, } from "../../sqlite/documentPersistence.js";
6
- import { containerCreateIntents, containerMoveIntents, documentSyncFailures, } from "../../sqlite/schema.js";
6
+ import { clearDocumentSyncFailureInTransaction } from "../../sqlite/documentSyncFailurePersistence.js";
7
+ import { inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema.js";
7
8
  import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
8
9
  import { runSerializedSqlMutation } from "../../sqlite/sqlSchema.js";
9
10
  import { loadContainerById, } from "../containers/containerPersistence.js";
@@ -68,29 +69,23 @@ async function loadStoredContainerState(execSql, containerId) {
68
69
  async function deleteAcceptedPendingUpdates(tx, containerId, ids) {
69
70
  await settleQueuedDocumentUpdatesInTransaction(tx, getContainerMetadataScope(containerId), ids);
70
71
  }
71
- async function clearSyncFailure(tx, containerId) {
72
- await tx
73
- .delete(documentSyncFailures)
74
- .where(and(eq(documentSyncFailures.appKind, CONTAINER_METADATA_APP_KIND), eq(documentSyncFailures.localId, containerId)))
75
- .run();
72
+ function clearMetadataSyncFailure(tx, containerId) {
73
+ return clearDocumentSyncFailureInTransaction(tx, {
74
+ appKind: CONTAINER_METADATA_APP_KIND,
75
+ localId: containerId,
76
+ });
76
77
  }
77
78
  async function hasPendingUpdates(tx, containerId) {
78
79
  return hasQueuedDocumentUpdates(tx, getContainerMetadataScope(containerId));
79
80
  }
80
81
  async function hasPendingStructuralIntent(tx, containerId) {
81
- const pendingCreates = await tx
82
- .select({ id: containerCreateIntents.id })
83
- .from(containerCreateIntents)
84
- .where(and(eq(containerCreateIntents.containerId, containerId), eq(containerCreateIntents.syncStatus, "pending")))
85
- .limit(1);
86
- if (pendingCreates.length > 0)
87
- return true;
88
- const unsyncedMoves = await tx
89
- .select({ id: containerMoveIntents.id })
90
- .from(containerMoveIntents)
91
- .where(eq(containerMoveIntents.containerId, containerId))
82
+ // A pending create or any surviving (unsynced) move of this container.
83
+ const structural = await tx
84
+ .select({ id: localIntents.id })
85
+ .from(localIntents)
86
+ .where(and(eq(localIntents.subjectId, containerId), or(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate), eq(localIntents.syncStatus, "pending")), inLocalIntentLane(LOCAL_INTENT_LANES.containerMove))))
92
87
  .limit(1);
93
- return unsyncedMoves.length > 0;
88
+ return structural.length > 0;
94
89
  }
95
90
  async function enqueuePendingUpdate(execSql, containerId, pendingUpdate) {
96
91
  if (!pendingUpdate)
@@ -187,7 +182,7 @@ export async function commitStoredMetadataMutation(execSql, input) {
187
182
  await enqueuePendingUpdate(lockedExecSql, input.container.id, input.pendingUpdate);
188
183
  await deleteAcceptedPendingUpdates(tx, input.container.id, input.acceptedPendingUpdateIds);
189
184
  if (input.clearSyncFailure) {
190
- await clearSyncFailure(tx, input.container.id);
185
+ await clearMetadataSyncFailure(tx, input.container.id);
191
186
  }
192
187
  const { container, localUpdatedAt } = await prepareContainerMutationWrite({
193
188
  currentContainer: currentState.container,
@@ -1 +1 @@
1
- {"version":3,"file":"containerMetadataMutationPersistence.js","sourceRoot":"","sources":["containerMetadataMutationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport {\n assertHeldContainerBinding,\n heldContainerBinding,\n} from \"../../containers/containerBinding\";\nimport { documentSyncPullContinuationsEqual } from \"../../documents/shared/pullContinuation\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../sqlite/documentPendingUpdatePersistence\";\nimport {\n enqueueDocumentPendingUpdate,\n type PendingUpdateFields,\n} from \"../../sqlite/documentPersistence\";\nimport {\n containerCreateIntents,\n containerMoveIntents,\n documentSyncFailures,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport {\n type ContainerRecord,\n loadContainerById,\n} from \"../containers/containerPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\nimport {\n ContainerCreateIntentSupersededError,\n deleteContainerMoveIntentRevision,\n} from \"./containerIntentPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nfunction sameNullableValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nfunction committedMetadataMutationResult(input: {\n container: ContainerRecord;\n createIntentSettled: boolean;\n moveIntentSettled: boolean;\n}) {\n return {\n committed: true as const,\n container: input.container,\n ...(input.createIntentSettled\n ? { createIntentSettled: true as const }\n : {}),\n ...(input.moveIntentSettled ? { moveIntentSettled: true as const } : {}),\n };\n}\n\nfunction sameMetadataSecurityIdentity(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableValue(current.accessStateHash, expected.accessStateHash) &&\n sameNullableValue(current.contentKeyBundle, expected.contentKeyBundle) &&\n sameNullableValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nfunction sameMetadataRecord(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n sameMetadataSecurityIdentity(current, expected) &&\n sameNullableValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n current.metadataUpdates === expected.metadataUpdates &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired)\n );\n}\n\nfunction sameContainerRecord(\n current: ContainerRecord,\n expected: ContainerRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.parentId === expected.parentId &&\n current.organizationId === expected.organizationId &&\n current.metadataDocumentId === expected.metadataDocumentId &&\n (current.systemSlot ?? null) === (expected.systemSlot ?? null) &&\n (current.effectiveAccessLevel ?? null) ===\n (expected.effectiveAccessLevel ?? null) &&\n (current.localUpdatedAt ?? null) === (expected.localUpdatedAt ?? null) &&\n (current.serverCreatedAt ?? null) === (expected.serverCreatedAt ?? null) &&\n (current.serverUpdatedAt ?? null) === (expected.serverUpdatedAt ?? null) &&\n current.name === expected.name &&\n (current.icon ?? null) === (expected.icon ?? null)\n );\n}\n\nasync function loadStoredContainerState(\n execSql: Parameters<\n ContainerContentsPersistence[\"loadContainerMetadataState\"]\n >[0],\n containerId: string,\n): Promise<StoredContainerState | null> {\n const container = await loadContainerById(execSql, containerId);\n if (!container) return null;\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n}\n\nasync function deleteAcceptedPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n ids: readonly string[],\n): Promise<void> {\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n getContainerMetadataScope(containerId),\n ids,\n );\n}\n\nasync function clearSyncFailure(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<void> {\n await tx\n .delete(documentSyncFailures)\n .where(\n and(\n eq(documentSyncFailures.appKind, CONTAINER_METADATA_APP_KIND),\n eq(documentSyncFailures.localId, containerId),\n ),\n )\n .run();\n}\n\nasync function hasPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n return hasQueuedDocumentUpdates(tx, getContainerMetadataScope(containerId));\n}\n\nasync function hasPendingStructuralIntent(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n const pendingCreates = await tx\n .select({ id: containerCreateIntents.id })\n .from(containerCreateIntents)\n .where(\n and(\n eq(containerCreateIntents.containerId, containerId),\n eq(containerCreateIntents.syncStatus, \"pending\"),\n ),\n )\n .limit(1);\n if (pendingCreates.length > 0) return true;\n\n const unsyncedMoves = await tx\n .select({ id: containerMoveIntents.id })\n .from(containerMoveIntents)\n .where(eq(containerMoveIntents.containerId, containerId))\n .limit(1);\n return unsyncedMoves.length > 0;\n}\n\nasync function enqueuePendingUpdate(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n containerId: string,\n pendingUpdate: PendingUpdateFields | undefined,\n): Promise<void> {\n if (!pendingUpdate) return;\n await enqueueDocumentPendingUpdate(\n execSql,\n getContainerMetadataScope(containerId),\n pendingUpdate,\n );\n}\n\ntype CommitMetadataMutationInput = Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n>[1];\n\nfunction staleServerMutationResult(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n) {\n const incomingServerUpdatedAt =\n input.saveOptions?.serverTimestamps?.updatedAt;\n const hasOlderContainerTimestamp =\n incomingServerUpdatedAt != null &&\n currentState?.container.serverUpdatedAt != null &&\n currentState.container.serverUpdatedAt > incomingServerUpdatedAt;\n const hasOlderMetadataAccessEpoch =\n currentState?.record != null &&\n currentState.record.documentId === input.record.documentId &&\n currentState.record.accessEpoch > input.record.accessEpoch;\n return currentState?.record &&\n (hasOlderContainerTimestamp || hasOlderMetadataAccessEpoch)\n ? {\n committed: false as const,\n currentState,\n staleServerState: true as const,\n }\n : null;\n}\n\nfunction metadataMutationStateMatches(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n): currentState is StoredContainerState & {\n record: ContainerMetadataRecord;\n} {\n return Boolean(\n currentState?.record &&\n sameContainerRecord(currentState.container, input.expectedContainer) &&\n sameMetadataRecord(currentState.record, input.expectedRecord),\n );\n}\n\nasync function rejectMetadataMutationConflict(input: {\n currentState: StoredContainerState | null;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}) {\n const { currentState, mutation, tx } = input;\n if (\n currentState?.record &&\n mutation.settleAcceptedPendingOnConflict &&\n sameMetadataSecurityIdentity(currentState.record, mutation.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n mutation.container.id,\n mutation.acceptedPendingUpdateIds,\n );\n }\n return { committed: false as const, currentState };\n}\n\nasync function prepareContainerMutationWrite(input: {\n currentContainer: ContainerRecord;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}): Promise<{ container: ContainerRecord; localUpdatedAt: string }> {\n const { currentContainer, mutation, tx } = input;\n const requestedLocalUpdatedAt =\n mutation.saveOptions?.localUpdatedAt ??\n mutation.saveOptions?.updatedAt ??\n new Date().toISOString();\n const preserveDurableStructure =\n mutation.preserveDurableStructureWhenPending === true &&\n (await hasPendingStructuralIntent(tx, mutation.container.id));\n // Syncing metadata is not a local edit. Preserve the durable edit clock,\n // including an edit another pane made while this request was in flight.\n const localUpdatedAt =\n preserveDurableStructure || mutation.settleAcceptedPendingOnConflict\n ? (currentContainer.localUpdatedAt ?? requestedLocalUpdatedAt)\n : requestedLocalUpdatedAt;\n const structurallyRebasedContainer = preserveDurableStructure\n ? { ...mutation.container, parentId: currentContainer.parentId }\n : mutation.container;\n const didSettleOutgoing =\n mutation.acceptedPendingUpdateIds.length > 0 &&\n !(await hasPendingUpdates(tx, mutation.container.id)) &&\n !(await hasPendingStructuralIntent(tx, mutation.container.id));\n // Only container responses establish the server's structural clock. A\n // metadata acknowledgement supplies no such timestamp; marking it with our\n // wall clock would make later valid listings appear stale forever.\n return {\n container: structurallyRebasedContainer,\n localUpdatedAt: didSettleOutgoing\n ? (currentContainer.serverUpdatedAt ?? localUpdatedAt)\n : localUpdatedAt,\n };\n}\n\n/** Server acknowledgements and listings cannot rebind a held folder. */\nfunction assertMutationKeepsHeldBinding(\n currentState: StoredContainerState & { record: ContainerMetadataRecord },\n input: CommitMetadataMutationInput,\n): void {\n const recordDocumentIds =\n input.record.documentId === currentState.record.documentId\n ? []\n : [input.record.documentId];\n assertHeldContainerBinding(heldContainerBinding(currentState), {\n organizationId: input.container.organizationId,\n metadataDocumentIds: [\n input.container.metadataDocumentId,\n ...recordDocumentIds,\n ],\n });\n}\n\nexport async function commitStoredMetadataMutation(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n input: Parameters<ContainerContentsPersistence[\"commitMetadataMutation\"]>[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n );\n const staleServerResult = staleServerMutationResult(\n currentState,\n input,\n );\n if (staleServerResult) return staleServerResult;\n if (!metadataMutationStateMatches(currentState, input)) {\n return rejectMetadataMutationConflict({\n currentState,\n mutation: input,\n tx,\n });\n }\n assertMutationKeepsHeldBinding(currentState, input);\n\n await enqueuePendingUpdate(\n lockedExecSql,\n input.container.id,\n input.pendingUpdate,\n );\n await deleteAcceptedPendingUpdates(\n tx,\n input.container.id,\n input.acceptedPendingUpdateIds,\n );\n if (input.clearSyncFailure) {\n await clearSyncFailure(tx, input.container.id);\n }\n const { container, localUpdatedAt } =\n await prepareContainerMutationWrite({\n currentContainer: currentState.container,\n mutation: input,\n tx,\n });\n const savedContainer = await saveContainerContentsContainerRows({\n container,\n createIntent: input.saveOptions?.createIntent,\n localUpdatedAt,\n moveIntent: input.saveOptions?.moveIntent,\n record: input.record,\n serverTimestamps: input.saveOptions?.serverTimestamps,\n tx,\n });\n if (\n input.createIntentSettlement &&\n (await settleContainerCreateIntentRevision({\n ...input.createIntentSettlement,\n tx,\n })) === \"superseded\"\n ) {\n throw new ContainerCreateIntentSupersededError();\n }\n if (input.moveIntentSettlement) {\n if (\n !(await deleteContainerMoveIntentRevision({\n ...input.moveIntentSettlement,\n tx,\n }))\n ) {\n throw new Error(\n \"Container move intent was superseded before local settlement\",\n );\n }\n }\n return committedMetadataMutationResult({\n container: savedContainer,\n createIntentSettled: input.createIntentSettlement !== undefined,\n moveIntentSettled: input.moveIntentSettlement !== undefined,\n });\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n if (outcome.committed && outcome.result) {\n return outcome.result;\n }\n return {\n committed: false as const,\n currentState: await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n ),\n };\n });\n}\n\nexport async function settleStoredMetadataPendingUpdates(\n execSql: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[0],\n input: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.containerId,\n );\n if (\n currentState?.record &&\n sameMetadataSecurityIdentity(\n currentState.record,\n input.expectedRecord,\n )\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n input.containerId,\n input.pendingUpdateIds,\n );\n }\n return currentState;\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n return outcome.committed ? outcome.result : null;\n });\n}\n"]}
1
+ {"version":3,"file":"containerMetadataMutationPersistence.js","sourceRoot":"","sources":["containerMetadataMutationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, or } from \"drizzle-orm\";\nimport {\n assertHeldContainerBinding,\n heldContainerBinding,\n} from \"../../containers/containerBinding\";\nimport { documentSyncPullContinuationsEqual } from \"../../documents/shared/pullContinuation\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../sqlite/documentPendingUpdatePersistence\";\nimport {\n enqueueDocumentPendingUpdate,\n type PendingUpdateFields,\n} from \"../../sqlite/documentPersistence\";\nimport { clearDocumentSyncFailureInTransaction } from \"../../sqlite/documentSyncFailurePersistence\";\nimport {\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport {\n type ContainerRecord,\n loadContainerById,\n} from \"../containers/containerPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nimport { settleContainerCreateIntentRevision } from \"./containerCreateIntentSettlement\";\nimport {\n ContainerCreateIntentSupersededError,\n deleteContainerMoveIntentRevision,\n} from \"./containerIntentPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nfunction sameNullableValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nfunction committedMetadataMutationResult(input: {\n container: ContainerRecord;\n createIntentSettled: boolean;\n moveIntentSettled: boolean;\n}) {\n return {\n committed: true as const,\n container: input.container,\n ...(input.createIntentSettled\n ? { createIntentSettled: true as const }\n : {}),\n ...(input.moveIntentSettled ? { moveIntentSettled: true as const } : {}),\n };\n}\n\nfunction sameMetadataSecurityIdentity(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableValue(current.accessStateHash, expected.accessStateHash) &&\n sameNullableValue(current.contentKeyBundle, expected.contentKeyBundle) &&\n sameNullableValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nfunction sameMetadataRecord(\n current: ContainerMetadataRecord,\n expected: ContainerMetadataRecord,\n): boolean {\n return (\n sameMetadataSecurityIdentity(current, expected) &&\n sameNullableValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n current.metadataUpdates === expected.metadataUpdates &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired)\n );\n}\n\nfunction sameContainerRecord(\n current: ContainerRecord,\n expected: ContainerRecord,\n): boolean {\n return (\n current.id === expected.id &&\n current.parentId === expected.parentId &&\n current.organizationId === expected.organizationId &&\n current.metadataDocumentId === expected.metadataDocumentId &&\n (current.systemSlot ?? null) === (expected.systemSlot ?? null) &&\n (current.effectiveAccessLevel ?? null) ===\n (expected.effectiveAccessLevel ?? null) &&\n (current.localUpdatedAt ?? null) === (expected.localUpdatedAt ?? null) &&\n (current.serverCreatedAt ?? null) === (expected.serverCreatedAt ?? null) &&\n (current.serverUpdatedAt ?? null) === (expected.serverUpdatedAt ?? null) &&\n current.name === expected.name &&\n (current.icon ?? null) === (expected.icon ?? null)\n );\n}\n\nasync function loadStoredContainerState(\n execSql: Parameters<\n ContainerContentsPersistence[\"loadContainerMetadataState\"]\n >[0],\n containerId: string,\n): Promise<StoredContainerState | null> {\n const container = await loadContainerById(execSql, containerId);\n if (!container) return null;\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n}\n\nasync function deleteAcceptedPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n ids: readonly string[],\n): Promise<void> {\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n getContainerMetadataScope(containerId),\n ids,\n );\n}\n\nfunction clearMetadataSyncFailure(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<void> {\n return clearDocumentSyncFailureInTransaction(tx, {\n appKind: CONTAINER_METADATA_APP_KIND,\n localId: containerId,\n });\n}\n\nasync function hasPendingUpdates(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n return hasQueuedDocumentUpdates(tx, getContainerMetadataScope(containerId));\n}\n\nasync function hasPendingStructuralIntent(\n tx: ClientSQLiteTransactionScope,\n containerId: string,\n): Promise<boolean> {\n // A pending create or any surviving (unsynced) move of this container.\n const structural = await tx\n .select({ id: localIntents.id })\n .from(localIntents)\n .where(\n and(\n eq(localIntents.subjectId, containerId),\n or(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.syncStatus, \"pending\"),\n ),\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n ),\n ),\n )\n .limit(1);\n return structural.length > 0;\n}\n\nasync function enqueuePendingUpdate(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n containerId: string,\n pendingUpdate: PendingUpdateFields | undefined,\n): Promise<void> {\n if (!pendingUpdate) return;\n await enqueueDocumentPendingUpdate(\n execSql,\n getContainerMetadataScope(containerId),\n pendingUpdate,\n );\n}\n\ntype CommitMetadataMutationInput = Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n>[1];\n\nfunction staleServerMutationResult(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n) {\n const incomingServerUpdatedAt =\n input.saveOptions?.serverTimestamps?.updatedAt;\n const hasOlderContainerTimestamp =\n incomingServerUpdatedAt != null &&\n currentState?.container.serverUpdatedAt != null &&\n currentState.container.serverUpdatedAt > incomingServerUpdatedAt;\n const hasOlderMetadataAccessEpoch =\n currentState?.record != null &&\n currentState.record.documentId === input.record.documentId &&\n currentState.record.accessEpoch > input.record.accessEpoch;\n return currentState?.record &&\n (hasOlderContainerTimestamp || hasOlderMetadataAccessEpoch)\n ? {\n committed: false as const,\n currentState,\n staleServerState: true as const,\n }\n : null;\n}\n\nfunction metadataMutationStateMatches(\n currentState: StoredContainerState | null,\n input: CommitMetadataMutationInput,\n): currentState is StoredContainerState & {\n record: ContainerMetadataRecord;\n} {\n return Boolean(\n currentState?.record &&\n sameContainerRecord(currentState.container, input.expectedContainer) &&\n sameMetadataRecord(currentState.record, input.expectedRecord),\n );\n}\n\nasync function rejectMetadataMutationConflict(input: {\n currentState: StoredContainerState | null;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}) {\n const { currentState, mutation, tx } = input;\n if (\n currentState?.record &&\n mutation.settleAcceptedPendingOnConflict &&\n sameMetadataSecurityIdentity(currentState.record, mutation.expectedRecord)\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n mutation.container.id,\n mutation.acceptedPendingUpdateIds,\n );\n }\n return { committed: false as const, currentState };\n}\n\nasync function prepareContainerMutationWrite(input: {\n currentContainer: ContainerRecord;\n mutation: CommitMetadataMutationInput;\n tx: ClientSQLiteTransactionScope;\n}): Promise<{ container: ContainerRecord; localUpdatedAt: string }> {\n const { currentContainer, mutation, tx } = input;\n const requestedLocalUpdatedAt =\n mutation.saveOptions?.localUpdatedAt ??\n mutation.saveOptions?.updatedAt ??\n new Date().toISOString();\n const preserveDurableStructure =\n mutation.preserveDurableStructureWhenPending === true &&\n (await hasPendingStructuralIntent(tx, mutation.container.id));\n // Syncing metadata is not a local edit. Preserve the durable edit clock,\n // including an edit another pane made while this request was in flight.\n const localUpdatedAt =\n preserveDurableStructure || mutation.settleAcceptedPendingOnConflict\n ? (currentContainer.localUpdatedAt ?? requestedLocalUpdatedAt)\n : requestedLocalUpdatedAt;\n const structurallyRebasedContainer = preserveDurableStructure\n ? { ...mutation.container, parentId: currentContainer.parentId }\n : mutation.container;\n const didSettleOutgoing =\n mutation.acceptedPendingUpdateIds.length > 0 &&\n !(await hasPendingUpdates(tx, mutation.container.id)) &&\n !(await hasPendingStructuralIntent(tx, mutation.container.id));\n // Only container responses establish the server's structural clock. A\n // metadata acknowledgement supplies no such timestamp; marking it with our\n // wall clock would make later valid listings appear stale forever.\n return {\n container: structurallyRebasedContainer,\n localUpdatedAt: didSettleOutgoing\n ? (currentContainer.serverUpdatedAt ?? localUpdatedAt)\n : localUpdatedAt,\n };\n}\n\n/** Server acknowledgements and listings cannot rebind a held folder. */\nfunction assertMutationKeepsHeldBinding(\n currentState: StoredContainerState & { record: ContainerMetadataRecord },\n input: CommitMetadataMutationInput,\n): void {\n const recordDocumentIds =\n input.record.documentId === currentState.record.documentId\n ? []\n : [input.record.documentId];\n assertHeldContainerBinding(heldContainerBinding(currentState), {\n organizationId: input.container.organizationId,\n metadataDocumentIds: [\n input.container.metadataDocumentId,\n ...recordDocumentIds,\n ],\n });\n}\n\nexport async function commitStoredMetadataMutation(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitMetadataMutation\"]\n >[0],\n input: Parameters<ContainerContentsPersistence[\"commitMetadataMutation\"]>[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n );\n const staleServerResult = staleServerMutationResult(\n currentState,\n input,\n );\n if (staleServerResult) return staleServerResult;\n if (!metadataMutationStateMatches(currentState, input)) {\n return rejectMetadataMutationConflict({\n currentState,\n mutation: input,\n tx,\n });\n }\n assertMutationKeepsHeldBinding(currentState, input);\n\n await enqueuePendingUpdate(\n lockedExecSql,\n input.container.id,\n input.pendingUpdate,\n );\n await deleteAcceptedPendingUpdates(\n tx,\n input.container.id,\n input.acceptedPendingUpdateIds,\n );\n if (input.clearSyncFailure) {\n await clearMetadataSyncFailure(tx, input.container.id);\n }\n const { container, localUpdatedAt } =\n await prepareContainerMutationWrite({\n currentContainer: currentState.container,\n mutation: input,\n tx,\n });\n const savedContainer = await saveContainerContentsContainerRows({\n container,\n createIntent: input.saveOptions?.createIntent,\n localUpdatedAt,\n moveIntent: input.saveOptions?.moveIntent,\n record: input.record,\n serverTimestamps: input.saveOptions?.serverTimestamps,\n tx,\n });\n if (\n input.createIntentSettlement &&\n (await settleContainerCreateIntentRevision({\n ...input.createIntentSettlement,\n tx,\n })) === \"superseded\"\n ) {\n throw new ContainerCreateIntentSupersededError();\n }\n if (input.moveIntentSettlement) {\n if (\n !(await deleteContainerMoveIntentRevision({\n ...input.moveIntentSettlement,\n tx,\n }))\n ) {\n throw new Error(\n \"Container move intent was superseded before local settlement\",\n );\n }\n }\n return committedMetadataMutationResult({\n container: savedContainer,\n createIntentSettled: input.createIntentSettlement !== undefined,\n moveIntentSettled: input.moveIntentSettlement !== undefined,\n });\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n if (outcome.committed && outcome.result) {\n return outcome.result;\n }\n return {\n committed: false as const,\n currentState: await loadStoredContainerState(\n lockedExecSql,\n input.container.id,\n ),\n };\n });\n}\n\nexport async function settleStoredMetadataPendingUpdates(\n execSql: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[0],\n input: Parameters<\n ContainerContentsPersistence[\"settleAcceptedMetadataPendingUpdates\"]\n >[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const outcome = await getClientSQLitePersistenceRuntime(\n lockedExecSql,\n ).guardedTransaction(\n async (tx) => {\n const currentState = await loadStoredContainerState(\n lockedExecSql,\n input.containerId,\n );\n if (\n currentState?.record &&\n sameMetadataSecurityIdentity(\n currentState.record,\n input.expectedRecord,\n )\n ) {\n await deleteAcceptedPendingUpdates(\n tx,\n input.containerId,\n input.pendingUpdateIds,\n );\n }\n return currentState;\n },\n () => !input.stillCurrent || input.stillCurrent(),\n { behavior: \"immediate\" },\n );\n return outcome.committed ? outcome.result : null;\n });\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { eq } from "drizzle-orm";
2
- import { containerProjection, containers } from "../../sqlite/schema.js";
2
+ import { containers } from "../../sqlite/schema.js";
3
3
  import { getClientSQLitePersistenceRuntime } from "../../sqlite/sqlitePersistenceRuntime.js";
4
4
  import { deleteContainerMoveIntentRevision } from "./containerIntentPersistence.js";
5
5
  /**
@@ -17,11 +17,6 @@ export async function abandonStoredMoveIntentRevision(execSql, input) {
17
17
  .set({ parentId: input.previousParentContainerId })
18
18
  .where(eq(containers.id, input.containerId))
19
19
  .run();
20
- await tx
21
- .update(containerProjection)
22
- .set({ updatedAt: new Date().toISOString() })
23
- .where(eq(containerProjection.containerId, input.containerId))
24
- .run();
25
20
  return true;
26
21
  }, input.stillCurrent, { behavior: "immediate" });
27
22
  return outcome.committed && outcome.result === true;
@@ -1 +1 @@
1
- {"version":3,"file":"containerMoveAbandonPersistence.js","sourceRoot":"","sources":["containerMoveAbandonPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAG1F,OAAO,EAAE,iCAAiC,EAAE,MAAM,8BAA8B,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,OAAgB,EAChB,KAEC;IAED,MAAM,OAAO,GAAG,MAAM,iCAAiC,CACrD,OAAO,CACR,CAAC,kBAAkB,CAClB,KAAK,EAAE,EAAE,EAAE,EAAE;QACX,IAAI,CAAC,CAAC,MAAM,iCAAiC,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,MAAM,EAAE;aACL,MAAM,CAAC,UAAU,CAAC;aAClB,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,yBAAyB,EAAE,CAAC;aAClD,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;aAC3C,GAAG,EAAE,CAAC;QACT,MAAM,EAAE;aACL,MAAM,CAAC,mBAAmB,CAAC;aAC3B,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;aAC5C,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;aAC7D,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC,EACD,KAAK,CAAC,YAAY,EAClB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;IACF,OAAO,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC;AACtD,CAAC","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport { containerProjection, containers } from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport type { ContainerMoveIntentRevisionInput } from \"./containerContentsPersistenceTypes\";\nimport { deleteContainerMoveIntentRevision } from \"./containerIntentPersistence\";\n\n/**\n * Drop a queued move the server will never accept and put the folder back\n * under the parent it left, atomically. The server row never changed, so no\n * listing would ever restore the placement. Returns false, changing nothing,\n * when a newer local move superseded the revision.\n */\nexport async function abandonStoredMoveIntentRevision(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput & {\n previousParentContainerId: string;\n },\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n if (!(await deleteContainerMoveIntentRevision({ ...input, tx })))\n return false;\n await tx\n .update(containers)\n .set({ parentId: input.previousParentContainerId })\n .where(eq(containers.id, input.containerId))\n .run();\n await tx\n .update(containerProjection)\n .set({ updatedAt: new Date().toISOString() })\n .where(eq(containerProjection.containerId, input.containerId))\n .run();\n return true;\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n"]}
1
+ {"version":3,"file":"containerMoveAbandonPersistence.js","sourceRoot":"","sources":["containerMoveAbandonPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,iCAAiC,EAAE,MAAM,uCAAuC,CAAC;AAG1F,OAAO,EAAE,iCAAiC,EAAE,MAAM,8BAA8B,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,OAAgB,EAChB,KAEC;IAED,MAAM,OAAO,GAAG,MAAM,iCAAiC,CACrD,OAAO,CACR,CAAC,kBAAkB,CAClB,KAAK,EAAE,EAAE,EAAE,EAAE;QACX,IAAI,CAAC,CAAC,MAAM,iCAAiC,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,MAAM,EAAE;aACL,MAAM,CAAC,UAAU,CAAC;aAClB,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,yBAAyB,EAAE,CAAC;aAClD,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;aAC3C,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC,EACD,KAAK,CAAC,YAAY,EAClB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;IACF,OAAO,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC;AACtD,CAAC","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport { containers } from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport type { ContainerMoveIntentRevisionInput } from \"./containerContentsPersistenceTypes\";\nimport { deleteContainerMoveIntentRevision } from \"./containerIntentPersistence\";\n\n/**\n * Drop a queued move the server will never accept and put the folder back\n * under the parent it left, atomically. The server row never changed, so no\n * listing would ever restore the placement. Returns false, changing nothing,\n * when a newer local move superseded the revision.\n */\nexport async function abandonStoredMoveIntentRevision(\n execSql: ExecSql,\n input: ContainerMoveIntentRevisionInput & {\n previousParentContainerId: string;\n },\n): Promise<boolean> {\n const outcome = await getClientSQLitePersistenceRuntime(\n execSql,\n ).guardedTransaction(\n async (tx) => {\n if (!(await deleteContainerMoveIntentRevision({ ...input, tx })))\n return false;\n await tx\n .update(containers)\n .set({ parentId: input.previousParentContainerId })\n .where(eq(containers.id, input.containerId))\n .run();\n return true;\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.committed && outcome.result === true;\n}\n"]}
@@ -1,16 +1,17 @@
1
1
  import { sql } from "drizzle-orm";
2
- import { containerMoveIntents } from "../../sqlite/schema.js";
2
+ import { LOCAL_INTENT_LANES, LOCAL_INTENT_SUBJECT, localIntents, } from "../../sqlite/schema.js";
3
3
  import { CONTAINER_MOVE_INTENT_TYPE, } from "./containerContentsPersistenceTypes.js";
4
4
  export async function saveContainerMoveIntent(input) {
5
5
  const { containerId, moveIntent, tx, updatedAt } = input;
6
6
  const id = moveIntent.id ?? crypto.randomUUID();
7
7
  await tx
8
- .insert(containerMoveIntents)
8
+ .insert(localIntents)
9
9
  .values({
10
10
  id,
11
- containerId,
12
- parentContainerId: moveIntent.parentContainerId,
13
- previousParentContainerId: moveIntent.previousParentContainerId ?? null,
11
+ lane: LOCAL_INTENT_LANES.containerMove,
12
+ subjectId: containerId,
13
+ targetContainerId: moveIntent.parentContainerId,
14
+ sourceContainerId: moveIntent.previousParentContainerId ?? null,
14
15
  intentType: CONTAINER_MOVE_INTENT_TYPE,
15
16
  syncStatus: "pending",
16
17
  lastError: null,
@@ -19,13 +20,13 @@ export async function saveContainerMoveIntent(input) {
19
20
  updatedAt,
20
21
  })
21
22
  .onConflictDoUpdate({
22
- target: containerMoveIntents.containerId,
23
+ target: LOCAL_INTENT_SUBJECT,
23
24
  set: {
24
25
  // The timestamp can collide when two moves are queued in one clock
25
26
  // tick, so every enqueue also owns a fresh revision token.
26
27
  id,
27
- parentContainerId: moveIntent.parentContainerId,
28
- previousParentContainerId: sql `coalesce(${containerMoveIntents.previousParentContainerId}, ${moveIntent.previousParentContainerId ?? null})`,
28
+ targetContainerId: moveIntent.parentContainerId,
29
+ sourceContainerId: sql `coalesce(${localIntents.sourceContainerId}, ${moveIntent.previousParentContainerId ?? null})`,
29
30
  intentType: CONTAINER_MOVE_INTENT_TYPE,
30
31
  syncStatus: "pending",
31
32
  lastError: null,
@@ -1 +1 @@
1
- {"version":3,"file":"containerMoveIntentRows.js","sourceRoot":"","sources":["containerMoveIntentRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EACL,0BAA0B,GAE3B,MAAM,qCAAqC,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAK7C;IACC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACzD,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;IAChD,MAAM,EAAE;SACL,MAAM,CAAC,oBAAoB,CAAC;SAC5B,MAAM,CAAC;QACN,EAAE;QACF,WAAW;QACX,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,yBAAyB,EAAE,UAAU,CAAC,yBAAyB,IAAI,IAAI;QACvE,UAAU,EAAE,0BAA0B;QACtC,UAAU,EAAE,SAAS;QACrB,SAAS,EAAE,IAAI;QACf,eAAe,EAAE,IAAI;QACrB,SAAS,EAAE,SAAS;QACpB,SAAS;KACV,CAAC;SACD,kBAAkB,CAAC;QAClB,MAAM,EAAE,oBAAoB,CAAC,WAAW;QACxC,GAAG,EAAE;YACH,mEAAmE;YACnE,2DAA2D;YAC3D,EAAE;YACF,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;YAC/C,yBAAyB,EAAE,GAAG,CAAA,YAAY,oBAAoB,CAAC,yBAAyB,KAAK,UAAU,CAAC,yBAAyB,IAAI,IAAI,GAAG;YAC5I,UAAU,EAAE,0BAA0B;YACtC,UAAU,EAAE,SAAS;YACrB,SAAS,EAAE,IAAI;YACf,SAAS;SACV;KACF,CAAC;SACD,GAAG,EAAE,CAAC;AACX,CAAC","sourcesContent":["import { sql } from \"drizzle-orm\";\nimport { containerMoveIntents } from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerMoveIntentInput,\n} from \"./containerContentsPersistenceTypes\";\n\nexport async function saveContainerMoveIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n moveIntent: ContainerMoveIntentInput;\n updatedAt: string;\n}) {\n const { containerId, moveIntent, tx, updatedAt } = input;\n const id = moveIntent.id ?? crypto.randomUUID();\n await tx\n .insert(containerMoveIntents)\n .values({\n id,\n containerId,\n parentContainerId: moveIntent.parentContainerId,\n previousParentContainerId: moveIntent.previousParentContainerId ?? null,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: containerMoveIntents.containerId,\n set: {\n // The timestamp can collide when two moves are queued in one clock\n // tick, so every enqueue also owns a fresh revision token.\n id,\n parentContainerId: moveIntent.parentContainerId,\n previousParentContainerId: sql`coalesce(${containerMoveIntents.previousParentContainerId}, ${moveIntent.previousParentContainerId ?? null})`,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n updatedAt,\n },\n })\n .run();\n}\n"]}
1
+ {"version":3,"file":"containerMoveIntentRows.js","sourceRoot":"","sources":["containerMoveIntentRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,0BAA0B,GAE3B,MAAM,qCAAqC,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAK7C;IACC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACzD,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;IAChD,MAAM,EAAE;SACL,MAAM,CAAC,YAAY,CAAC;SACpB,MAAM,CAAC;QACN,EAAE;QACF,IAAI,EAAE,kBAAkB,CAAC,aAAa;QACtC,SAAS,EAAE,WAAW;QACtB,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,iBAAiB,EAAE,UAAU,CAAC,yBAAyB,IAAI,IAAI;QAC/D,UAAU,EAAE,0BAA0B;QACtC,UAAU,EAAE,SAAS;QACrB,SAAS,EAAE,IAAI;QACf,eAAe,EAAE,IAAI;QACrB,SAAS,EAAE,SAAS;QACpB,SAAS;KACV,CAAC;SACD,kBAAkB,CAAC;QAClB,MAAM,EAAE,oBAAoB;QAC5B,GAAG,EAAE;YACH,mEAAmE;YACnE,2DAA2D;YAC3D,EAAE;YACF,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;YAC/C,iBAAiB,EAAE,GAAG,CAAA,YAAY,YAAY,CAAC,iBAAiB,KAAK,UAAU,CAAC,yBAAyB,IAAI,IAAI,GAAG;YACpH,UAAU,EAAE,0BAA0B;YACtC,UAAU,EAAE,SAAS;YACrB,SAAS,EAAE,IAAI;YACf,SAAS;SACV;KACF,CAAC;SACD,GAAG,EAAE,CAAC;AACX,CAAC","sourcesContent":["import { sql } from \"drizzle-orm\";\nimport {\n LOCAL_INTENT_LANES,\n LOCAL_INTENT_SUBJECT,\n localIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerMoveIntentInput,\n} from \"./containerContentsPersistenceTypes\";\n\nexport async function saveContainerMoveIntent(input: {\n tx: ClientSQLiteTransactionScope;\n containerId: string;\n moveIntent: ContainerMoveIntentInput;\n updatedAt: string;\n}) {\n const { containerId, moveIntent, tx, updatedAt } = input;\n const id = moveIntent.id ?? crypto.randomUUID();\n await tx\n .insert(localIntents)\n .values({\n id,\n lane: LOCAL_INTENT_LANES.containerMove,\n subjectId: containerId,\n targetContainerId: moveIntent.parentContainerId,\n sourceContainerId: moveIntent.previousParentContainerId ?? null,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n lastAttemptedAt: null,\n createdAt: updatedAt,\n updatedAt,\n })\n .onConflictDoUpdate({\n target: LOCAL_INTENT_SUBJECT,\n set: {\n // The timestamp can collide when two moves are queued in one clock\n // tick, so every enqueue also owns a fresh revision token.\n id,\n targetContainerId: moveIntent.parentContainerId,\n sourceContainerId: sql`coalesce(${localIntents.sourceContainerId}, ${moveIntent.previousParentContainerId ?? null})`,\n intentType: CONTAINER_MOVE_INTENT_TYPE,\n syncStatus: \"pending\",\n lastError: null,\n updatedAt,\n },\n })\n .run();\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { ensureDocumentTables } from "../../sqlite/documentPersistence.js";
2
- import { containerCreateIntentTables, containerMoveIntentTables, documentContainerProjectionTables, documentMoveIntentTables, documentProjectionTables, } from "../../sqlite/schema.js";
2
+ import { documentContainerProjectionTables, documentPlacementIntentTables, documentProjectionTables, } from "../../sqlite/schema.js";
3
3
  import { getClientSQLitePersistenceRuntime } from "../../sqlite/sqlitePersistenceRuntime.js";
4
4
  import { ensureSqlTables, runSerializedSqlMutation, } from "../../sqlite/sqlSchema.js";
5
5
  import { ensureContainerTables } from "../containers/containerPersistence.js";
@@ -18,7 +18,7 @@ export const containerReconcilePersistence = {
18
18
  const updatedAt = input.updatedAt ?? new Date().toISOString();
19
19
  await ensureSqlTables(lockedExecSql, [
20
20
  ...documentContainerProjectionTables,
21
- ...documentMoveIntentTables,
21
+ ...documentPlacementIntentTables,
22
22
  ...documentProjectionTables,
23
23
  ]);
24
24
  if (input.stillCurrent?.() === false) {
@@ -51,10 +51,8 @@ export const containerReconcilePersistence = {
51
51
  await runSerializedSqlMutation(execSql, async (lockedExecSql) => {
52
52
  const updatedAt = input.updatedAt ?? new Date().toISOString();
53
53
  await ensureSqlTables(lockedExecSql, [
54
- ...containerCreateIntentTables,
55
- ...containerMoveIntentTables,
56
54
  ...documentContainerProjectionTables,
57
- ...documentMoveIntentTables,
55
+ ...documentPlacementIntentTables,
58
56
  ...documentProjectionTables,
59
57
  ]);
60
58
  await ensureContainerTables(lockedExecSql);
@@ -100,10 +98,8 @@ export const containerReconcilePersistence = {
100
98
  await runSerializedSqlMutation(execSql, async (lockedExecSql) => {
101
99
  const updatedAt = input.updatedAt ?? new Date().toISOString();
102
100
  await ensureSqlTables(lockedExecSql, [
103
- ...containerCreateIntentTables,
104
- ...containerMoveIntentTables,
105
101
  ...documentContainerProjectionTables,
106
- ...documentMoveIntentTables,
102
+ ...documentPlacementIntentTables,
107
103
  ...documentProjectionTables,
108
104
  ]);
109
105
  await ensureContainerTables(lockedExecSql);
@@ -1 +1 @@
1
- {"version":3,"file":"containerReconcilePersistence.js","sourceRoot":"","sources":["containerReconcilePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { ensureDocumentTables } from \"../../sqlite/documentPersistence\";\nimport {\n containerCreateIntentTables,\n containerMoveIntentTables,\n documentContainerProjectionTables,\n documentMoveIntentTables,\n documentProjectionTables,\n} from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport { ensureContainerTables } from \"../containers/containerPersistence\";\nimport { sqlContainerSyncWatermarkPersistence } from \"../containers/containerSyncWatermarkPersistence\";\nimport type { ContainerContentsPersistence } from \"./containerContentsPersistenceTypes\";\nimport { reassignContainerDocumentsInTransaction } from \"./containerDocumentReassignment\";\nimport {\n deleteLocalContainerRows,\n reparentLocalContainerChildren,\n updateReparentedDescendantContainers,\n} from \"./containerStructuralRepair\";\n\ntype ContainerReconcilePersistence = Pick<\n ContainerContentsPersistence,\n | \"reassignContainerDocuments\"\n | \"reconcileLocalRootContainer\"\n | \"reconcileLocalSystemContainer\"\n>;\n\nexport const containerReconcilePersistence: ContainerReconcilePersistence = {\n async reassignContainerDocuments(execSql, input) {\n if (input.fromContainerId === input.toContainerId) {\n return;\n }\n if (input.stillCurrent?.() === false) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const updatedAt = input.updatedAt ?? new Date().toISOString();\n await ensureSqlTables(lockedExecSql, [\n ...documentContainerProjectionTables,\n ...documentMoveIntentTables,\n ...documentProjectionTables,\n ]);\n if (input.stillCurrent?.() === false) {\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const reassign = async (\n tx: Parameters<typeof reassignContainerDocumentsInTransaction>[0][\"tx\"],\n ) => {\n await reassignContainerDocumentsInTransaction({\n fromContainerId: input.fromContainerId,\n toContainerId: input.toContainerId,\n tx,\n updatedAt,\n });\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(reassign, input.stillCurrent);\n } else {\n await runtime.transaction(reassign);\n }\n });\n },\n async reconcileLocalRootContainer(execSql, input) {\n if (input.localRootContainerId === input.remoteRootContainerId) {\n return;\n }\n if (input.stillCurrent?.() === false) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const updatedAt = input.updatedAt ?? new Date().toISOString();\n await ensureSqlTables(lockedExecSql, [\n ...containerCreateIntentTables,\n ...containerMoveIntentTables,\n ...documentContainerProjectionTables,\n ...documentMoveIntentTables,\n ...documentProjectionTables,\n ]);\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n if (input.stillCurrent?.() === false) {\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const reconcile = async (\n tx: Parameters<typeof updateReparentedDescendantContainers>[0][\"tx\"],\n ) => {\n await updateReparentedDescendantContainers({\n descendantReparents: input.descendantReparents,\n remoteOrganizationId: input.remoteOrganizationId,\n tx,\n updatedAt,\n });\n await reassignContainerDocumentsInTransaction({\n fromContainerId: input.localRootContainerId,\n toContainerId: input.remoteRootContainerId,\n tx,\n updatedAt,\n });\n await deleteLocalContainerRows({\n containerId: input.localRootContainerId,\n tx,\n });\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(reconcile, input.stillCurrent);\n } else {\n await runtime.transaction(reconcile);\n }\n });\n },\n async reconcileLocalSystemContainer(execSql, input) {\n if (input.localContainerId === input.remoteContainerId) {\n return;\n }\n if (input.stillCurrent?.() === false) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const updatedAt = input.updatedAt ?? new Date().toISOString();\n await ensureSqlTables(lockedExecSql, [\n ...containerCreateIntentTables,\n ...containerMoveIntentTables,\n ...documentContainerProjectionTables,\n ...documentMoveIntentTables,\n ...documentProjectionTables,\n ]);\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n if (input.stillCurrent?.() === false) {\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const reconcile = async (\n tx: Parameters<typeof reparentLocalContainerChildren>[0][\"tx\"],\n ) => {\n await reparentLocalContainerChildren({\n fromContainerId: input.localContainerId,\n remoteOrganizationId: input.remoteOrganizationId,\n toContainerId: input.remoteContainerId,\n tx,\n updatedAt,\n });\n await reassignContainerDocumentsInTransaction({\n fromContainerId: input.localContainerId,\n toContainerId: input.remoteContainerId,\n tx,\n updatedAt,\n });\n await deleteLocalContainerRows({\n containerId: input.localContainerId,\n tx,\n });\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(reconcile, input.stillCurrent);\n } else {\n await runtime.transaction(reconcile);\n }\n });\n },\n};\n"]}
1
+ {"version":3,"file":"containerReconcilePersistence.js","sourceRoot":"","sources":["containerReconcilePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { ensureDocumentTables } from \"../../sqlite/documentPersistence\";\nimport {\n documentContainerProjectionTables,\n documentPlacementIntentTables,\n documentProjectionTables,\n} from \"../../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport { ensureContainerTables } from \"../containers/containerPersistence\";\nimport { sqlContainerSyncWatermarkPersistence } from \"../containers/containerSyncWatermarkPersistence\";\nimport type { ContainerContentsPersistence } from \"./containerContentsPersistenceTypes\";\nimport { reassignContainerDocumentsInTransaction } from \"./containerDocumentReassignment\";\nimport {\n deleteLocalContainerRows,\n reparentLocalContainerChildren,\n updateReparentedDescendantContainers,\n} from \"./containerStructuralRepair\";\n\ntype ContainerReconcilePersistence = Pick<\n ContainerContentsPersistence,\n | \"reassignContainerDocuments\"\n | \"reconcileLocalRootContainer\"\n | \"reconcileLocalSystemContainer\"\n>;\n\nexport const containerReconcilePersistence: ContainerReconcilePersistence = {\n async reassignContainerDocuments(execSql, input) {\n if (input.fromContainerId === input.toContainerId) {\n return;\n }\n if (input.stillCurrent?.() === false) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const updatedAt = input.updatedAt ?? new Date().toISOString();\n await ensureSqlTables(lockedExecSql, [\n ...documentContainerProjectionTables,\n ...documentPlacementIntentTables,\n ...documentProjectionTables,\n ]);\n if (input.stillCurrent?.() === false) {\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const reassign = async (\n tx: Parameters<typeof reassignContainerDocumentsInTransaction>[0][\"tx\"],\n ) => {\n await reassignContainerDocumentsInTransaction({\n fromContainerId: input.fromContainerId,\n toContainerId: input.toContainerId,\n tx,\n updatedAt,\n });\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(reassign, input.stillCurrent);\n } else {\n await runtime.transaction(reassign);\n }\n });\n },\n async reconcileLocalRootContainer(execSql, input) {\n if (input.localRootContainerId === input.remoteRootContainerId) {\n return;\n }\n if (input.stillCurrent?.() === false) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const updatedAt = input.updatedAt ?? new Date().toISOString();\n await ensureSqlTables(lockedExecSql, [\n ...documentContainerProjectionTables,\n ...documentPlacementIntentTables,\n ...documentProjectionTables,\n ]);\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n if (input.stillCurrent?.() === false) {\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const reconcile = async (\n tx: Parameters<typeof updateReparentedDescendantContainers>[0][\"tx\"],\n ) => {\n await updateReparentedDescendantContainers({\n descendantReparents: input.descendantReparents,\n remoteOrganizationId: input.remoteOrganizationId,\n tx,\n updatedAt,\n });\n await reassignContainerDocumentsInTransaction({\n fromContainerId: input.localRootContainerId,\n toContainerId: input.remoteRootContainerId,\n tx,\n updatedAt,\n });\n await deleteLocalContainerRows({\n containerId: input.localRootContainerId,\n tx,\n });\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(reconcile, input.stillCurrent);\n } else {\n await runtime.transaction(reconcile);\n }\n });\n },\n async reconcileLocalSystemContainer(execSql, input) {\n if (input.localContainerId === input.remoteContainerId) {\n return;\n }\n if (input.stillCurrent?.() === false) {\n return;\n }\n\n await runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const updatedAt = input.updatedAt ?? new Date().toISOString();\n await ensureSqlTables(lockedExecSql, [\n ...documentContainerProjectionTables,\n ...documentPlacementIntentTables,\n ...documentProjectionTables,\n ]);\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n if (input.stillCurrent?.() === false) {\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const reconcile = async (\n tx: Parameters<typeof reparentLocalContainerChildren>[0][\"tx\"],\n ) => {\n await reparentLocalContainerChildren({\n fromContainerId: input.localContainerId,\n remoteOrganizationId: input.remoteOrganizationId,\n toContainerId: input.remoteContainerId,\n tx,\n updatedAt,\n });\n await reassignContainerDocumentsInTransaction({\n fromContainerId: input.localContainerId,\n toContainerId: input.remoteContainerId,\n tx,\n updatedAt,\n });\n await deleteLocalContainerRows({\n containerId: input.localContainerId,\n tx,\n });\n };\n if (input.stillCurrent) {\n await runtime.guardedTransaction(reconcile, input.stillCurrent);\n } else {\n await runtime.transaction(reconcile);\n }\n });\n },\n};\n"]}
@@ -1,6 +1,6 @@
1
1
  import { toFingerprint } from "../../../internal/crypto/index.js";
2
- import { eq } from "drizzle-orm";
3
- import { containerCreateIntents, containerMoveIntents, documentMoveIntentTables, } from "../../sqlite/schema.js";
2
+ import { and, eq } from "drizzle-orm";
3
+ import { documentPlacementIntentTables, inContainerIntentLanes, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema.js";
4
4
  import { getClientSQLitePersistenceRuntime } from "../../sqlite/sqlitePersistenceRuntime.js";
5
5
  import { ensureSqlTables, runSerializedSqlMutation, } from "../../sqlite/sqlSchema.js";
6
6
  import { sqlContainerContentsPersistence } from "./containerContentsPersistence.js";
@@ -30,13 +30,18 @@ async function recoverySnapshot(execSql, containerId, organizationId) {
30
30
  ]) {
31
31
  metadata.push(await execSql(`SELECT ${columns} FROM ${table} WHERE app_kind = 'container-metadata' AND local_id = ? ORDER BY rowid`, [containerId]));
32
32
  }
33
- const creates = await execSql("SELECT id, container_id, parent_container_id, intent_type, remote_container_id, remote_metadata_document_id, remote_metadata_access_state_hash FROM container_create_intents WHERE container_id = ? AND sync_status = 'pending' ORDER BY id", [containerId]);
34
- const moves = await execSql("SELECT id, container_id, parent_container_id, previous_parent_container_id, intent_type FROM container_move_intents WHERE container_id = ? ORDER BY id", [containerId]);
35
- const links = await execSql(`SELECT id, local_id, document_id, target_container_id, source_container_id, replace_linked_containers, intent_type FROM document_move_intents WHERE target_container_id = ? OR id IN
36
- (SELECT intent_id FROM document_intent_link_targets WHERE container_id = ?) ORDER BY id`, [containerId, containerId]);
33
+ const creates = await execSql("SELECT id, subject_id, target_container_id, intent_type, remote_container_id, remote_metadata_document_id, remote_metadata_access_state_hash FROM local_intents WHERE lane = ? AND subject_id = ? AND sync_status = 'pending' ORDER BY id", [LOCAL_INTENT_LANES.containerCreate, containerId]);
34
+ const moves = await execSql("SELECT id, subject_id, target_container_id, source_container_id, intent_type FROM local_intents WHERE lane = ? AND subject_id = ? ORDER BY id", [LOCAL_INTENT_LANES.containerMove, containerId]);
35
+ const placementWhere = `lane = ? AND (target_container_id = ? OR id IN
36
+ (SELECT intent_id FROM document_intent_link_targets WHERE container_id = ?))`;
37
+ const placementBind = [
38
+ LOCAL_INTENT_LANES.documentPlacement,
39
+ containerId,
40
+ containerId,
41
+ ];
42
+ const links = await execSql(`SELECT id, local_id, subject_id, target_container_id, source_container_id, replace_linked_containers, intent_type FROM local_intents WHERE ${placementWhere} ORDER BY id`, placementBind);
37
43
  const targets = await execSql(`SELECT intent_id, operation, container_id FROM document_intent_link_targets WHERE intent_id IN
38
- (SELECT id FROM document_move_intents WHERE target_container_id = ? OR id IN
39
- (SELECT intent_id FROM document_intent_link_targets WHERE container_id = ?)) ORDER BY intent_id, container_id, operation`, [containerId, containerId]);
44
+ (SELECT id FROM local_intents WHERE ${placementWhere}) ORDER BY intent_id, container_id, operation`, placementBind);
40
45
  const revision = await toFingerprint(new TextEncoder().encode(JSON.stringify([dormant, metadata, creates, moves, links, targets])));
41
46
  return {
42
47
  revision,
@@ -48,7 +53,7 @@ export async function listRetainedContainerMetadata(execSql, organizationId) {
48
53
  if (!organizationId)
49
54
  return [];
50
55
  await sqlContainerContentsPersistence.ensureSchema(execSql);
51
- await ensureSqlTables(execSql, documentMoveIntentTables);
56
+ await ensureSqlTables(execSql, documentPlacementIntentTables);
52
57
  return runSerializedSqlMutation(execSql, async (locked) => getClientSQLitePersistenceRuntime(locked).transaction(async () => {
53
58
  const rows = await locked(`SELECT container_id FROM dormant_container_metadata
54
59
  WHERE organization_id = ? ORDER BY container_id`, [organizationId]);
@@ -72,7 +77,7 @@ export async function listRetainedContainerMetadata(execSql, organizationId) {
72
77
  /** Explicit local discard, never called by remote discovery. */
73
78
  export async function discardRetainedContainerMetadata(execSql, input) {
74
79
  await sqlContainerContentsPersistence.ensureSchema(execSql);
75
- await ensureSqlTables(execSql, documentMoveIntentTables);
80
+ await ensureSqlTables(execSql, documentPlacementIntentTables);
76
81
  return runSerializedSqlMutation(execSql, async (locked) => getClientSQLitePersistenceRuntime(locked).transaction(async (tx) => {
77
82
  const current = await recoverySnapshot(locked, input.containerId, input.organizationId);
78
83
  if (!current || current.revision !== input.revision)
@@ -102,12 +107,8 @@ export async function discardRetainedContainerMetadata(execSql, input) {
102
107
  containerIds: [input.containerId],
103
108
  });
104
109
  await tx
105
- .delete(containerCreateIntents)
106
- .where(eq(containerCreateIntents.containerId, input.containerId))
107
- .run();
108
- await tx
109
- .delete(containerMoveIntents)
110
- .where(eq(containerMoveIntents.containerId, input.containerId))
110
+ .delete(localIntents)
111
+ .where(and(inContainerIntentLanes(), eq(localIntents.subjectId, input.containerId)))
111
112
  .run();
112
113
  await deleteContainerMetadataDocumentRowsInTransaction(tx, [
113
114
  input.containerId,
@@ -128,11 +129,11 @@ export async function listRecoveryFolderMoveIds(execSql, organizationId) {
128
129
  if (!organizationId)
129
130
  return [];
130
131
  await sqlContainerContentsPersistence.ensureSchema(execSql);
131
- const rows = await execSql(`SELECT c.id FROM containers c JOIN container_move_intents i
132
- ON i.container_id = c.id AND i.parent_container_id = c.parent_id
132
+ const rows = await execSql(`SELECT c.id FROM containers c JOIN local_intents i
133
+ ON i.lane = ? AND i.subject_id = c.id AND i.target_container_id = c.parent_id
133
134
  WHERE c.organization_id = ? AND i.sync_status IN ('pending', 'blocked')
134
135
  AND NOT EXISTS (SELECT 1 FROM containers p WHERE p.id = c.parent_id)
135
- ORDER BY c.id`, [organizationId]);
136
+ ORDER BY c.id`, [LOCAL_INTENT_LANES.containerMove, organizationId]);
136
137
  return rows.map((row) => String(Reflect.get(row, "id")));
137
138
  }
138
139
  //# sourceMappingURL=containerRecoveryPersistence.js.map