@tearleads/client-sdk 0.1.76 → 0.1.78
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.
- package/data/{documents/blob/shared → blobs/attachments}/blobEnvelopeStream.js +1 -1
- package/data/{documents/blob/shared → blobs/attachments}/blobEnvelopeStream.js.map +1 -1
- package/data/blobs/attachments/blobRecordCrypto.d.ts +26 -0
- package/data/{documents/blob/shared → blobs/attachments}/blobRecordCrypto.js +2 -2
- package/data/{documents/blob/shared → blobs/attachments}/blobSourceSnapshot.d.ts +1 -1
- package/data/{documents/blob/shared → blobs/attachments}/blobSourceSnapshot.js +2 -2
- package/data/blobs/attachments/blobSourceSnapshot.js.map +1 -0
- package/data/blobs/attachments/chunkedBlobCrypto.d.ts +17 -0
- package/data/{documents/blob/shared → blobs/attachments}/chunkedBlobCrypto.js +3 -3
- package/data/blobs/attachments/chunkedBlobCrypto.js.map +1 -0
- package/data/blobs/attachments/crypto.d.ts +3 -0
- package/data/blobs/attachments/encryptedUploadParts.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/events.js +3 -3
- package/data/blobs/attachments/events.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/projection.js +8 -8
- package/data/blobs/attachments/projection.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/readers.js +3 -3
- package/data/blobs/attachments/readers.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/responses.js +2 -2
- package/data/blobs/attachments/responses.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/types.d.ts +8 -8
- package/data/blobs/attachments/types.js.map +1 -0
- package/data/{containers → persistence/container-contents}/containerBinding.js +1 -1
- package/data/persistence/container-contents/containerContentsPersistence.js +2 -2
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.d.ts +2 -2
- package/data/persistence/container-contents/containerContentsPersistenceTypes.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +2 -2
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerHydrationPersistence.js +2 -2
- package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +2 -2
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
- package/data/persistence/container-contents/containerRebindPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +2 -2
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/dormantMetadataSweep.js +1 -1
- package/data/persistence/container-contents/dormantMetadataSweep.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
- package/data/persistence/documents/internal/discoveredDocumentPlacement.js +1 -1
- package/data/persistence/documents/internal/discoveredDocumentPlacement.js.map +1 -1
- package/package.json +1 -1
- package/stores/container-contents/systemContainers/systemContainerIcon.js +1 -1
- package/stores/container-contents/systemContainers/systemContainerIcon.js.map +1 -1
- package/stores/documents/documentStore/attachmentUpload/attachmentSourceUpload.js +1 -2
- package/stores/documents/documentStore/attachmentUpload/attachmentSourceUpload.js.map +1 -1
- package/stores/documents/documentStore/sync/syncAttachments.js.map +1 -1
- package/workflows/blobs/detach.js +2 -2
- package/workflows/blobs/detach.js.map +1 -1
- package/workflows/blobs/hydration/blobChunkDecryption.js +1 -1
- package/workflows/blobs/hydration/blobChunkDecryption.js.map +1 -1
- package/workflows/blobs/hydration/decrypt.d.ts +1 -1
- package/workflows/blobs/hydration/decrypt.js +4 -4
- package/workflows/blobs/hydration/decrypt.js.map +1 -1
- package/workflows/blobs/index.d.ts +3 -1
- package/workflows/blobs/index.js +3 -0
- package/workflows/blobs/index.js.map +1 -1
- package/workflows/blobs/upload/automaticMultipartUpload.js +1 -1
- package/workflows/blobs/upload/automaticMultipartUpload.js.map +1 -1
- package/workflows/blobs/upload/index.d.ts +2 -2
- package/workflows/blobs/upload/index.js +4 -4
- package/workflows/blobs/upload/index.js.map +1 -1
- package/workflows/blobs/upload/multipartFirstParts.js.map +1 -1
- package/workflows/blobs/upload/multipartStageFailures.js.map +1 -1
- package/workflows/blobs/upload/multipartStageResolution.js.map +1 -1
- package/workflows/blobs/upload/multipartUpload.js.map +1 -1
- package/workflows/blobs/verification/attachmentBindingVerification.js.map +1 -1
- package/workflows/blobs/verification/attachmentKeyAuthenticator.js +1 -1
- package/workflows/blobs/verification/attachmentKeyAuthenticator.js.map +1 -1
- package/workflows/blobs/verification/retainedAttachmentVerification.js +1 -1
- package/workflows/blobs/verification/retainedAttachmentVerification.js.map +1 -1
- package/workflows/blobs/verification/writerProjection.js +1 -1
- package/workflows/blobs/verification/writerProjection.js.map +1 -1
- package/workflows/container-contents/container-state/create/createChild.js +1 -1
- package/workflows/container-contents/container-state/create/createChild.js.map +1 -1
- package/workflows/container-contents/container-state/purge/purgeTree.js +1 -1
- package/workflows/container-contents/container-state/purge/purgeTree.js.map +1 -1
- package/workflows/container-contents/container-state/types.js.map +1 -1
- package/workflows/container-contents/containerPersistence.d.ts +3 -3
- package/workflows/container-contents/containerPersistence.js +1 -1
- package/workflows/container-contents/containerPersistence.js.map +1 -1
- package/workflows/container-contents/documentLinks/documentLinkIntent.js +1 -1
- package/workflows/container-contents/documentLinks/documentLinkIntent.js.map +1 -1
- package/workflows/container-contents/documentLinks/index.js +1 -1
- package/workflows/container-contents/documentLinks/index.js.map +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntent.js +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntent.js.map +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntentSettlement.js +2 -2
- package/workflows/container-contents/documentMove/documentMoveIntentSettlement.js.map +1 -1
- package/workflows/container-contents/documentQueries/documentSubtreeQueries.js +1 -1
- package/workflows/container-contents/documentQueries/documentSubtreeQueries.js.map +1 -1
- package/workflows/container-contents/documentQueries/index.js +3 -3
- package/workflows/container-contents/documentQueries/index.js.map +1 -1
- package/workflows/container-contents/documentQueries/pendingDownloads.js +1 -1
- package/workflows/container-contents/documentQueries/pendingDownloads.js.map +1 -1
- package/workflows/container-contents/index.d.ts +1 -1
- package/workflows/container-contents/index.js +1 -1
- package/workflows/container-contents/index.js.map +1 -1
- package/workflows/container-contents/info/blobInfo.js +1 -1
- package/workflows/container-contents/info/blobInfo.js.map +1 -1
- package/workflows/container-contents/info/containerInfo.js +2 -2
- package/workflows/container-contents/info/containerInfo.js.map +1 -1
- package/{data/containers → workflows/container-contents/metadata}/containerMetadataDocument.d.ts +1 -1
- package/{data/containers → workflows/container-contents/metadata}/containerMetadataDocument.js +2 -2
- package/workflows/container-contents/metadata/containerMetadataDocument.js.map +1 -0
- package/workflows/container-contents/metadata/metadataMutationPreparation.js +1 -1
- package/workflows/container-contents/metadata/metadataMutationPreparation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataPersistence.js +1 -1
- package/workflows/container-contents/metadata/metadataPersistence.js.map +1 -1
- package/workflows/container-contents/metadata/metadataRecord.js.map +1 -1
- package/workflows/container-contents/metadata/metadataStateIsolation.js +1 -1
- package/workflows/container-contents/metadata/metadataStateIsolation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js.map +1 -1
- package/workflows/container-contents/metadata/metadataTypes.d.ts +2 -2
- package/workflows/container-contents/metadata/metadataTypes.js.map +1 -1
- package/workflows/container-contents/recovery/folderRecovery.js +1 -1
- package/workflows/container-contents/recovery/folderRecovery.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/replacementBinding.js +1 -1
- package/workflows/container-contents/remoteHydration/destination/replacementBinding.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js.map +1 -1
- package/workflows/container-contents/remoteHydration/heldContainerRebind.js +1 -1
- package/workflows/container-contents/remoteHydration/heldContainerRebind.js.map +1 -1
- package/workflows/container-contents/remoteHydration/reattachMetadata.js +1 -1
- package/workflows/container-contents/remoteHydration/reattachMetadata.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js +2 -2
- package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js.map +1 -1
- package/workflows/container-contents/remoteHydration/types.d.ts +1 -1
- package/workflows/container-contents/remoteHydration/types.js.map +1 -1
- package/workflows/container-contents/storedContainerState.js +1 -1
- package/workflows/container-contents/storedContainerState.js.map +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js.map +1 -1
- package/workflows/organizations/readModel/localReadModelDetails.js +1 -1
- package/workflows/organizations/readModel/localReadModelDetails.js.map +1 -1
- package/workflows/registration/bootstrapRootContainer.js +1 -1
- package/workflows/registration/bootstrapRootContainer.js.map +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.js +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.js.map +1 -1
- package/workflows/registration/rootMetadataBootstrap.js +1 -1
- package/workflows/registration/rootMetadataBootstrap.js.map +1 -1
- package/workflows/sync/remoteReset.js +1 -1
- package/workflows/sync/remoteReset.js.map +1 -1
- package/data/containers/containerMetadataDocument.js.map +0 -1
- package/data/documents/blob/shared/blobSourceSnapshot.js.map +0 -1
- package/data/documents/blob/shared/chunkedBlobCrypto.js.map +0 -1
- package/data/documents/blob/shared/encryptedUploadParts.js.map +0 -1
- package/data/documents/blob/shared/events.js.map +0 -1
- package/data/documents/blob/shared/projection.js.map +0 -1
- package/data/documents/blob/shared/readers.js.map +0 -1
- package/data/documents/blob/shared/responses.js.map +0 -1
- package/data/documents/blob/shared/types.js.map +0 -1
- /package/data/{documents/blob/shared → blobs/attachments}/blobRecordCrypto.js.map +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/crypto.js +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/crypto.js.map +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/encryptedUploadParts.js +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/types.js +0 -0
- /package/data/{containers → persistence/container-contents}/containerBinding.d.ts +0 -0
- /package/data/{containers → persistence/container-contents}/containerBinding.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.d.ts +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.d.ts +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/documentContainerProjectionPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/documentContainerProjectionPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/documentPlacement.js +0 -0
- /package/data/persistence/{containers → container-contents}/documentPlacement.js.map +0 -0
|
@@ -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 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
|
+
{"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 type { ContainerContentsPersistence } from \"./containerContentsPersistenceTypes\";\nimport { reassignContainerDocumentsInTransaction } from \"./containerDocumentReassignment\";\nimport { ensureContainerTables } from \"./containerPersistence\";\nimport {\n deleteLocalContainerRows,\n reparentLocalContainerChildren,\n updateReparentedDescendantContainers,\n} from \"./containerStructuralRepair\";\nimport { sqlContainerSyncWatermarkPersistence } from \"./containerSyncWatermarkPersistence\";\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,9 +1,9 @@
|
|
|
1
1
|
import { and, asc, eq, inArray } from "drizzle-orm";
|
|
2
2
|
import { containers, documentContainerProjection, documentProjection, inContainerIntentLanes, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema/index.js";
|
|
3
|
-
import { deleteContainerWatermarksInTransaction } from "../containers/containerSyncWatermarkPersistence.js";
|
|
4
3
|
import { deleteContainerDocumentTombstoneHoldsForContainers } from "../documents/containerDocumentTombstoneHoldsPersistence.js";
|
|
5
4
|
import { getLatestTimestamp } from "../latestTimestamp.js";
|
|
6
5
|
import { saveContainerCreateIntent } from "./containerIntentPersistence.js";
|
|
6
|
+
import { deleteContainerWatermarksInTransaction } from "./containerSyncWatermarkPersistence.js";
|
|
7
7
|
import { deleteContainerMetadataDocumentRowsInTransaction } from "./dormantContainerMetadata.js";
|
|
8
8
|
// The containers being removed still exist when repair runs (deletion follows
|
|
9
9
|
// it). Capture their org attribution so a detached document's pending writes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerStructuralRepair.js","sourceRoot":"","sources":["containerStructuralRepair.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,UAAU,EACV,2BAA2B,EAC3B,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,sCAAsC,EAAE,MAAM,iDAAiD,CAAC;AACzG,OAAO,EAAE,kDAAkD,EAAE,MAAM,yDAAyD,CAAC;AAC7H,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAKxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,gDAAgD,EAAE,MAAM,4BAA4B,CAAC;AAE9F,8EAA8E;AAC9E,6EAA6E;AAC7E,8EAA8E;AAC9E,8CAA8C;AAC9C,KAAK,UAAU,gCAAgC,CAC7C,EAAgC,EAChC,YAAmC;IAEnC,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,MAAM,CAAC;QACN,EAAE,EAAE,UAAU,CAAC,EAAE;QACjB,cAAc,EAAE,UAAU,CAAC,cAAc;KAC1C,CAAC;SACD,IAAI,CAAC,UAAU,CAAC;SAChB,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;IAC/C,MAAM,2BAA2B,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9D,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,SAAS,CAAC,EAAE,IAAI,SAAS,CAAC,cAAc,EAAE,CAAC;YAC7C,2BAA2B,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,OAAO,2BAA2B,CAAC;AACrC,CAAC;AAED,8EAA8E;AAC9E,6EAA6E;AAC7E,+BAA+B;AAC/B,KAAK,UAAU,yCAAyC,CACtD,EAAgC,EAChC,WAAkC;IAElC,MAAM,qCAAqC,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxE,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,qCAAqC,CAAC;IAC/C,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,EAAE;SAC5B,MAAM,CAAC;QACN,WAAW,EAAE,2BAA2B,CAAC,WAAW;QACpD,UAAU,EAAE,2BAA2B,CAAC,UAAU;KACnD,CAAC;SACD,IAAI,CAAC,2BAA2B,CAAC;SACjC,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;SACnE,OAAO,CACN,GAAG,CAAC,2BAA2B,CAAC,UAAU,CAAC,EAC3C,GAAG,CAAC,2BAA2B,CAAC,WAAW,CAAC,CAC7C,CAAC;IACJ,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC,qCAAqC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAChE,qCAAqC,CAAC,GAAG,CACvC,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,WAAW,CACjB,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,qCAAqC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gDAAgD,CAAC,KAGtE;IACC,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IACrB,MAAM,sBAAsB,GAAG,IAAI,GAAG,CACpC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAC1E,CAAC;IACF,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,CAAC;QACC,MAAM,YAAY,GAAG,MAAM,EAAE;aAC1B,MAAM,CAAC;YACN,WAAW,EAAE,kBAAkB,CAAC,WAAW;YAC3C,UAAU,EAAE,kBAAkB,CAAC,UAAU;YACzC,OAAO,EAAE,kBAAkB,CAAC,OAAO;YACnC,SAAS,EAAE,kBAAkB,CAAC,SAAS;SACxC,CAAC;aACD,IAAI,CAAC,kBAAkB,CAAC;aACxB,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;QAEhE,MAAM,2BAA2B,GAAG,MAAM,gCAAgC,CACxE,EAAE,EACF,YAAY,CACb,CAAC;QAEF,MAAM,EAAE;aACL,MAAM,CAAC,2BAA2B,CAAC;aACnC,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;aACrE,GAAG,EAAE,CAAC;QACT,MAAM,kDAAkD,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAE3E,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAC5B,IAAI,GAAG,CACL,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACxE,CACF,CAAC;QACF,MAAM,qCAAqC,GACzC,MAAM,yCAAyC,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QAEnE,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YAED,MAAM,qBAAqB,GAAG,GAAG,CAAC,WAAW;gBAC3C,CAAC,CAAC,2BAA2B,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;gBAClD,CAAC,CAAC,SAAS,CAAC;YACd,MAAM,EAAE;iBACL,MAAM,CAAC,kBAAkB,CAAC;iBAC1B,GAAG,CAAC;gBACH,WAAW,EAAE,GAAG,CAAC,UAAU;oBACzB,CAAC,CAAC,CAAC,qCAAqC,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;wBAC1D,IAAI,CAAC;oBACP,CAAC,CAAC,IAAI;gBACR,GAAG,CAAC,qBAAqB;oBACvB,CAAC,CAAC,EAAE,cAAc,EAAE,qBAAqB,EAAE;oBAC3C,CAAC,CAAC,EAAE,CAAC;gBACP,SAAS,EAAE,kBAAkB,CAC3B,GAAG,CAAC,SAAS,EACb,GAAG,CAAC,WAAW;oBACb,CAAC,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC;oBAChE,CAAC,CAAC,GAAG,CAAC,SAAS,CAClB;aACF,CAAC;iBACD,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;iBAClD,GAAG,EAAE,CAAC;QACX,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oCAAoC,CAAC,KAK1D;IACC,MAAM,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC3E,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAC9B,IAAI,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CACrE,CAAC;IACF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,MAAM,EAAE;SACL,MAAM,CAAC,UAAU,CAAC;SAClB,GAAG,CAAC;QACH,cAAc,EAAE,oBAAoB;QACpC,cAAc,EAAE,SAAS;KAC1B,CAAC;SACD,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;SAC5C,GAAG,EAAE,CAAC;IAET,KAAK,MAAM,QAAQ,IAAI,mBAAmB,EAAE,CAAC;QAC3C,MAAM,EAAE;aACL,MAAM,CAAC,UAAU,CAAC;aAClB,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,EAAE,CAAC;aAC7C,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;aAC9C,GAAG,EAAE,CAAC;QAET,IAAI,QAAQ,CAAC,kBAAkB,IAAI,QAAQ,CAAC,iBAAiB,EAAE,CAAC;YAC9D,MAAM,yBAAyB,CAAC;gBAC9B,WAAW,EAAE,QAAQ,CAAC,WAAW;gBACjC,YAAY,EAAE,EAAE,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB,EAAE;gBAC/D,EAAE;gBACF,SAAS;aACV,CAAC,CAAC;QACL,CAAC;QAED,IAAI,QAAQ,CAAC,iBAAiB,EAAE,CAAC;YAC/B,MAAM,EAAE;iBACL,MAAM,CAAC,YAAY,CAAC;iBACpB,GAAG,CAAC;gBACH,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;gBACvB,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;gBAC7C,UAAU,EAAE,SAAS;gBACrB,SAAS;aACV,CAAC;iBACD,KAAK,CACJ,GAAG,CACD,iBAAiB,CAAC,kBAAkB,CAAC,aAAa,CAAC,EACnD,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,CACjD,CACF;iBACA,GAAG,EAAE,CAAC;QACX,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,KAMpD;IACC,MAAM,EACJ,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,EAAE,EACF,SAAS,GACV,GAAG,KAAK,CAAC;IACV,MAAM,EAAE;SACL,MAAM,CAAC,UAAU,CAAC;SAClB,GAAG,CAAC;QACH,cAAc,EAAE,oBAAoB;QACpC,QAAQ,EAAE,aAAa;QACvB,cAAc,EAAE,SAAS;KAC1B,CAAC;SACD,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;SAC/C,GAAG,EAAE,CAAC;IACT,MAAM,UAAU,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACzE,MAAM,gBAAgB,GAAG,MAAM,EAAE;SAC9B,MAAM,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC;SAC/C,IAAI,CAAC,YAAY,CAAC;SAClB,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,CAAC;SAC3E,GAAG,EAAE,CAAC;IACT,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;QACtC,MAAM,EAAE;aACL,MAAM,CAAC,YAAY,CAAC;aACpB,GAAG,CAAC;YACH,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;YACvB,iBAAiB,EAAE,aAAa;YAChC,SAAS;SACV,CAAC;aACD,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;aACtE,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;IACrE,MAAM,cAAc,GAAG,MAAM,EAAE;SAC5B,MAAM,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC;SAC/C,IAAI,CAAC,YAAY,CAAC;SAClB,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,CAAC;SACzE,GAAG,EAAE,CAAC;IACT,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;QACpC,MAAM,EAAE;aACL,MAAM,CAAC,YAAY,CAAC;aACpB,GAAG,CAAC;YACH,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;YACvB,iBAAiB,EAAE,aAAa;YAChC,UAAU,EAAE,SAAS;YACrB,SAAS;SACV,CAAC;aACD,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;aACpE,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAG9C;IACC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IAClC,MAAM,EAAE;SACL,MAAM,CAAC,YAAY,CAAC;SACpB,KAAK,CACJ,GAAG,CAAC,sBAAsB,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CACvE;SACA,GAAG,EAAE,CAAC;IACT,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACxE,MAAM,gDAAgD,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,MAAM,sCAAsC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import { and, asc, eq, inArray } from \"drizzle-orm\";\nimport {\n containers,\n documentContainerProjection,\n documentProjection,\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { deleteContainerWatermarksInTransaction } from \"../containers/containerSyncWatermarkPersistence\";\nimport { deleteContainerDocumentTombstoneHoldsForContainers } from \"../documents/containerDocumentTombstoneHoldsPersistence\";\nimport { getLatestTimestamp } from \"../latestTimestamp\";\nimport type {\n ContainerRemoval,\n LocalRootDescendantReparentInput,\n} from \"./containerContentsPersistenceTypes\";\nimport { saveContainerCreateIntent } from \"./containerIntentPersistence\";\nimport { deleteContainerMetadataDocumentRowsInTransaction } from \"./dormantContainerMetadata\";\n\n// The containers being removed still exist when repair runs (deletion follows\n// it). Capture their org attribution so a detached document's pending writes\n// keep a resolvable organization id after the join source is gone — e.g. when\n// access to a shared org is revoked mid-sync.\nasync function loadOrganizationIdsForContainers(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<Map<string, string>> {\n const rows = await tx\n .select({\n id: containers.id,\n organizationId: containers.organizationId,\n })\n .from(containers)\n .where(inArray(containers.id, containerIds));\n const organizationIdByContainerId = new Map<string, string>();\n for (const container of rows) {\n if (container.id && container.organizationId) {\n organizationIdByContainerId.set(container.id, container.organizationId);\n }\n }\n return organizationIdByContainerId;\n}\n\n// A document unlinked from a removed container may keep other live links; its\n// projection then re-homes to the first remaining link (deterministic order)\n// instead of dropping to null.\nasync function loadFirstRemainingContainerIdByDocumentId(\n tx: ClientSQLiteTransactionScope,\n documentIds: ReadonlyArray<string>,\n): Promise<Map<string, string>> {\n const firstRemainingContainerIdByDocumentId = new Map<string, string>();\n if (documentIds.length === 0) {\n return firstRemainingContainerIdByDocumentId;\n }\n const remainingLinks = await tx\n .select({\n containerId: documentContainerProjection.containerId,\n documentId: documentContainerProjection.documentId,\n })\n .from(documentContainerProjection)\n .where(inArray(documentContainerProjection.documentId, documentIds))\n .orderBy(\n asc(documentContainerProjection.documentId),\n asc(documentContainerProjection.containerId),\n );\n for (const link of remainingLinks) {\n if (!firstRemainingContainerIdByDocumentId.has(link.documentId)) {\n firstRemainingContainerIdByDocumentId.set(\n link.documentId,\n link.containerId,\n );\n }\n }\n return firstRemainingContainerIdByDocumentId;\n}\n\nexport async function repairDocumentsForRemovedContainersInTransaction(input: {\n removals: ReadonlyArray<ContainerRemoval>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { tx } = input;\n const updatedAtByContainerId = new Map(\n input.removals.map((removal) => [removal.containerId, removal.updatedAt]),\n );\n const containerIds = Array.from(updatedAtByContainerId.keys());\n if (containerIds.length === 0) {\n return;\n }\n\n {\n const selectedRows = await tx\n .select({\n containerId: documentProjection.containerId,\n documentId: documentProjection.documentId,\n localId: documentProjection.localId,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.containerId, containerIds));\n\n const organizationIdByContainerId = await loadOrganizationIdsForContainers(\n tx,\n containerIds,\n );\n\n await tx\n .delete(documentContainerProjection)\n .where(inArray(documentContainerProjection.containerId, containerIds))\n .run();\n await deleteContainerDocumentTombstoneHoldsForContainers(tx, containerIds);\n\n const documentIds = Array.from(\n new Set(\n selectedRows.flatMap((row) => (row.documentId ? [row.documentId] : [])),\n ),\n );\n const firstRemainingContainerIdByDocumentId =\n await loadFirstRemainingContainerIdByDocumentId(tx, documentIds);\n\n for (const row of selectedRows) {\n if (!row.localId) {\n continue;\n }\n\n const removedOrganizationId = row.containerId\n ? organizationIdByContainerId.get(row.containerId)\n : undefined;\n await tx\n .update(documentProjection)\n .set({\n containerId: row.documentId\n ? (firstRemainingContainerIdByDocumentId.get(row.documentId) ??\n null)\n : null,\n ...(removedOrganizationId\n ? { organizationId: removedOrganizationId }\n : {}),\n updatedAt: getLatestTimestamp(\n row.updatedAt,\n row.containerId\n ? (updatedAtByContainerId.get(row.containerId) ?? row.updatedAt)\n : row.updatedAt,\n ),\n })\n .where(eq(documentProjection.localId, row.localId))\n .run();\n }\n }\n}\n\nexport async function updateReparentedDescendantContainers(input: {\n descendantReparents: ReadonlyArray<LocalRootDescendantReparentInput>;\n remoteOrganizationId: string;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const { descendantReparents, remoteOrganizationId, tx, updatedAt } = input;\n const descendantIds = Array.from(\n new Set(descendantReparents.map((reparent) => reparent.containerId)),\n );\n if (descendantIds.length === 0) {\n return;\n }\n\n await tx\n .update(containers)\n .set({\n organizationId: remoteOrganizationId,\n localUpdatedAt: updatedAt,\n })\n .where(inArray(containers.id, descendantIds))\n .run();\n\n for (const reparent of descendantReparents) {\n await tx\n .update(containers)\n .set({ parentId: reparent.parentContainerId })\n .where(eq(containers.id, reparent.containerId))\n .run();\n\n if (reparent.updateCreateIntent && reparent.parentContainerId) {\n await saveContainerCreateIntent({\n containerId: reparent.containerId,\n createIntent: { parentContainerId: reparent.parentContainerId },\n tx,\n updatedAt,\n });\n }\n\n if (reparent.parentContainerId) {\n await tx\n .update(localIntents)\n .set({\n id: crypto.randomUUID(),\n targetContainerId: reparent.parentContainerId,\n syncStatus: \"pending\",\n updatedAt,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, reparent.containerId),\n ),\n )\n .run();\n }\n }\n}\n\nexport async function reparentLocalContainerChildren(input: {\n fromContainerId: string;\n remoteOrganizationId: string;\n toContainerId: string;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const {\n fromContainerId,\n remoteOrganizationId,\n toContainerId,\n tx,\n updatedAt,\n } = input;\n await tx\n .update(containers)\n .set({\n organizationId: remoteOrganizationId,\n parentId: toContainerId,\n localUpdatedAt: updatedAt,\n })\n .where(eq(containers.parentId, fromContainerId))\n .run();\n const createLane = inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate);\n const createIntentRows = await tx\n .select({ containerId: localIntents.subjectId })\n .from(localIntents)\n .where(and(createLane, eq(localIntents.targetContainerId, fromContainerId)))\n .all();\n for (const intent of createIntentRows) {\n await tx\n .update(localIntents)\n .set({\n id: crypto.randomUUID(),\n targetContainerId: toContainerId,\n updatedAt,\n })\n .where(and(createLane, eq(localIntents.subjectId, intent.containerId)))\n .run();\n }\n const moveLane = inLocalIntentLane(LOCAL_INTENT_LANES.containerMove);\n const moveIntentRows = await tx\n .select({ containerId: localIntents.subjectId })\n .from(localIntents)\n .where(and(moveLane, eq(localIntents.targetContainerId, fromContainerId)))\n .all();\n for (const intent of moveIntentRows) {\n await tx\n .update(localIntents)\n .set({\n id: crypto.randomUUID(),\n targetContainerId: toContainerId,\n syncStatus: \"pending\",\n updatedAt,\n })\n .where(and(moveLane, eq(localIntents.subjectId, intent.containerId)))\n .run();\n }\n}\n\nexport async function deleteLocalContainerRows(input: {\n containerId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { containerId, tx } = input;\n await tx\n .delete(localIntents)\n .where(\n and(inContainerIntentLanes(), eq(localIntents.subjectId, containerId)),\n )\n .run();\n await tx.delete(containers).where(eq(containers.id, containerId)).run();\n await deleteContainerMetadataDocumentRowsInTransaction(tx, [containerId]);\n await deleteContainerWatermarksInTransaction(tx, [containerId]);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerStructuralRepair.js","sourceRoot":"","sources":["containerStructuralRepair.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray } from \"drizzle-orm\";\nimport {\n containers,\n documentContainerProjection,\n documentProjection,\n inContainerIntentLanes,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { deleteContainerDocumentTombstoneHoldsForContainers } from \"../documents/containerDocumentTombstoneHoldsPersistence\";\nimport { getLatestTimestamp } from \"../latestTimestamp\";\nimport type {\n ContainerRemoval,\n LocalRootDescendantReparentInput,\n} from \"./containerContentsPersistenceTypes\";\nimport { saveContainerCreateIntent } from \"./containerIntentPersistence\";\nimport { deleteContainerWatermarksInTransaction } from \"./containerSyncWatermarkPersistence\";\nimport { deleteContainerMetadataDocumentRowsInTransaction } from \"./dormantContainerMetadata\";\n\n// The containers being removed still exist when repair runs (deletion follows\n// it). Capture their org attribution so a detached document's pending writes\n// keep a resolvable organization id after the join source is gone — e.g. when\n// access to a shared org is revoked mid-sync.\nasync function loadOrganizationIdsForContainers(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<Map<string, string>> {\n const rows = await tx\n .select({\n id: containers.id,\n organizationId: containers.organizationId,\n })\n .from(containers)\n .where(inArray(containers.id, containerIds));\n const organizationIdByContainerId = new Map<string, string>();\n for (const container of rows) {\n if (container.id && container.organizationId) {\n organizationIdByContainerId.set(container.id, container.organizationId);\n }\n }\n return organizationIdByContainerId;\n}\n\n// A document unlinked from a removed container may keep other live links; its\n// projection then re-homes to the first remaining link (deterministic order)\n// instead of dropping to null.\nasync function loadFirstRemainingContainerIdByDocumentId(\n tx: ClientSQLiteTransactionScope,\n documentIds: ReadonlyArray<string>,\n): Promise<Map<string, string>> {\n const firstRemainingContainerIdByDocumentId = new Map<string, string>();\n if (documentIds.length === 0) {\n return firstRemainingContainerIdByDocumentId;\n }\n const remainingLinks = await tx\n .select({\n containerId: documentContainerProjection.containerId,\n documentId: documentContainerProjection.documentId,\n })\n .from(documentContainerProjection)\n .where(inArray(documentContainerProjection.documentId, documentIds))\n .orderBy(\n asc(documentContainerProjection.documentId),\n asc(documentContainerProjection.containerId),\n );\n for (const link of remainingLinks) {\n if (!firstRemainingContainerIdByDocumentId.has(link.documentId)) {\n firstRemainingContainerIdByDocumentId.set(\n link.documentId,\n link.containerId,\n );\n }\n }\n return firstRemainingContainerIdByDocumentId;\n}\n\nexport async function repairDocumentsForRemovedContainersInTransaction(input: {\n removals: ReadonlyArray<ContainerRemoval>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { tx } = input;\n const updatedAtByContainerId = new Map(\n input.removals.map((removal) => [removal.containerId, removal.updatedAt]),\n );\n const containerIds = Array.from(updatedAtByContainerId.keys());\n if (containerIds.length === 0) {\n return;\n }\n\n {\n const selectedRows = await tx\n .select({\n containerId: documentProjection.containerId,\n documentId: documentProjection.documentId,\n localId: documentProjection.localId,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.containerId, containerIds));\n\n const organizationIdByContainerId = await loadOrganizationIdsForContainers(\n tx,\n containerIds,\n );\n\n await tx\n .delete(documentContainerProjection)\n .where(inArray(documentContainerProjection.containerId, containerIds))\n .run();\n await deleteContainerDocumentTombstoneHoldsForContainers(tx, containerIds);\n\n const documentIds = Array.from(\n new Set(\n selectedRows.flatMap((row) => (row.documentId ? [row.documentId] : [])),\n ),\n );\n const firstRemainingContainerIdByDocumentId =\n await loadFirstRemainingContainerIdByDocumentId(tx, documentIds);\n\n for (const row of selectedRows) {\n if (!row.localId) {\n continue;\n }\n\n const removedOrganizationId = row.containerId\n ? organizationIdByContainerId.get(row.containerId)\n : undefined;\n await tx\n .update(documentProjection)\n .set({\n containerId: row.documentId\n ? (firstRemainingContainerIdByDocumentId.get(row.documentId) ??\n null)\n : null,\n ...(removedOrganizationId\n ? { organizationId: removedOrganizationId }\n : {}),\n updatedAt: getLatestTimestamp(\n row.updatedAt,\n row.containerId\n ? (updatedAtByContainerId.get(row.containerId) ?? row.updatedAt)\n : row.updatedAt,\n ),\n })\n .where(eq(documentProjection.localId, row.localId))\n .run();\n }\n }\n}\n\nexport async function updateReparentedDescendantContainers(input: {\n descendantReparents: ReadonlyArray<LocalRootDescendantReparentInput>;\n remoteOrganizationId: string;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const { descendantReparents, remoteOrganizationId, tx, updatedAt } = input;\n const descendantIds = Array.from(\n new Set(descendantReparents.map((reparent) => reparent.containerId)),\n );\n if (descendantIds.length === 0) {\n return;\n }\n\n await tx\n .update(containers)\n .set({\n organizationId: remoteOrganizationId,\n localUpdatedAt: updatedAt,\n })\n .where(inArray(containers.id, descendantIds))\n .run();\n\n for (const reparent of descendantReparents) {\n await tx\n .update(containers)\n .set({ parentId: reparent.parentContainerId })\n .where(eq(containers.id, reparent.containerId))\n .run();\n\n if (reparent.updateCreateIntent && reparent.parentContainerId) {\n await saveContainerCreateIntent({\n containerId: reparent.containerId,\n createIntent: { parentContainerId: reparent.parentContainerId },\n tx,\n updatedAt,\n });\n }\n\n if (reparent.parentContainerId) {\n await tx\n .update(localIntents)\n .set({\n id: crypto.randomUUID(),\n targetContainerId: reparent.parentContainerId,\n syncStatus: \"pending\",\n updatedAt,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, reparent.containerId),\n ),\n )\n .run();\n }\n }\n}\n\nexport async function reparentLocalContainerChildren(input: {\n fromContainerId: string;\n remoteOrganizationId: string;\n toContainerId: string;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const {\n fromContainerId,\n remoteOrganizationId,\n toContainerId,\n tx,\n updatedAt,\n } = input;\n await tx\n .update(containers)\n .set({\n organizationId: remoteOrganizationId,\n parentId: toContainerId,\n localUpdatedAt: updatedAt,\n })\n .where(eq(containers.parentId, fromContainerId))\n .run();\n const createLane = inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate);\n const createIntentRows = await tx\n .select({ containerId: localIntents.subjectId })\n .from(localIntents)\n .where(and(createLane, eq(localIntents.targetContainerId, fromContainerId)))\n .all();\n for (const intent of createIntentRows) {\n await tx\n .update(localIntents)\n .set({\n id: crypto.randomUUID(),\n targetContainerId: toContainerId,\n updatedAt,\n })\n .where(and(createLane, eq(localIntents.subjectId, intent.containerId)))\n .run();\n }\n const moveLane = inLocalIntentLane(LOCAL_INTENT_LANES.containerMove);\n const moveIntentRows = await tx\n .select({ containerId: localIntents.subjectId })\n .from(localIntents)\n .where(and(moveLane, eq(localIntents.targetContainerId, fromContainerId)))\n .all();\n for (const intent of moveIntentRows) {\n await tx\n .update(localIntents)\n .set({\n id: crypto.randomUUID(),\n targetContainerId: toContainerId,\n syncStatus: \"pending\",\n updatedAt,\n })\n .where(and(moveLane, eq(localIntents.subjectId, intent.containerId)))\n .run();\n }\n}\n\nexport async function deleteLocalContainerRows(input: {\n containerId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n const { containerId, tx } = input;\n await tx\n .delete(localIntents)\n .where(\n and(inContainerIntentLanes(), eq(localIntents.subjectId, containerId)),\n )\n .run();\n await tx.delete(containers).where(eq(containers.id, containerId)).run();\n await deleteContainerMetadataDocumentRowsInTransaction(tx, [containerId]);\n await deleteContainerWatermarksInTransaction(tx, [containerId]);\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { and, eq, sql } from "drizzle-orm";
|
|
2
2
|
import { dormantContainerMetadata, dormantMetadataSweepRequests, } from "../../sqlite/schema/index.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
|
-
import { ensureContainerTables } from "
|
|
4
|
+
import { ensureContainerTables } from "./containerPersistence.js";
|
|
5
5
|
export async function requestDormantMetadataRestorationSweeps(execSql, input) {
|
|
6
6
|
await ensureContainerTables(execSql);
|
|
7
7
|
const requestedAt = new Date().toISOString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dormantMetadataSweep.js","sourceRoot":"","sources":["dormantMetadataSweep.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport {\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport { ensureContainerTables } from \"../containers/containerPersistence\";\n\nexport interface DormantMetadataSweepRequest {\n readonly attemptCount: number;\n readonly generation: number;\n readonly lastAttemptedAt: string | null;\n readonly organizationId: string;\n readonly requestedAt: string;\n readonly requesterUserId: string;\n}\n\nexport interface DormantMetadataSweepPersistence {\n claimDormantMetadataSweepAttempt: (\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n attemptedAt: string,\n stillCurrent?: (() => boolean) | undefined,\n ) => Promise<boolean>;\n completeDormantMetadataSweepRequest: (\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n stillCurrent?: (() => boolean) | undefined,\n ) => Promise<void>;\n listDormantMetadataSweepRequests: (\n execSql: ExecSql,\n requesterUserId: string,\n ) => Promise<readonly DormantMetadataSweepRequest[]>;\n}\n\nexport async function requestDormantMetadataRestorationSweeps(\n execSql: ExecSql,\n input: { requesterUserId: string },\n): Promise<number> {\n await ensureContainerTables(execSql);\n const requestedAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n const organizations = await db\n .selectDistinct({\n organizationId: dormantContainerMetadata.organizationId,\n })\n .from(dormantContainerMetadata)\n .orderBy(dormantContainerMetadata.organizationId);\n if (organizations.length === 0) {\n return 0;\n }\n\n await db\n .insert(dormantMetadataSweepRequests)\n .values(\n organizations.map(({ organizationId }) => ({\n attemptCount: 0,\n generation: 1,\n lastAttemptedAt: null,\n organizationId,\n requestedAt,\n requesterUserId: input.requesterUserId,\n })),\n )\n .onConflictDoUpdate({\n target: [\n dormantMetadataSweepRequests.organizationId,\n dormantMetadataSweepRequests.requesterUserId,\n ],\n set: {\n attemptCount: 0,\n generation: sql`${dormantMetadataSweepRequests.generation} + 1`,\n lastAttemptedAt: null,\n requestedAt: sql`excluded.requested_at`,\n },\n })\n .run();\n return organizations.length;\n });\n}\n\nexport async function listDormantMetadataSweepRequests(\n execSql: ExecSql,\n requesterUserId: string,\n): Promise<readonly DormantMetadataSweepRequest[]> {\n await ensureContainerTables(execSql);\n return getClientSQLitePersistenceRuntime(execSql)\n .db.select({\n attemptCount: dormantMetadataSweepRequests.attemptCount,\n generation: dormantMetadataSweepRequests.generation,\n lastAttemptedAt: dormantMetadataSweepRequests.lastAttemptedAt,\n organizationId: dormantMetadataSweepRequests.organizationId,\n requestedAt: dormantMetadataSweepRequests.requestedAt,\n requesterUserId: dormantMetadataSweepRequests.requesterUserId,\n })\n .from(dormantMetadataSweepRequests)\n .where(eq(dormantMetadataSweepRequests.requesterUserId, requesterUserId))\n .orderBy(dormantMetadataSweepRequests.organizationId);\n}\n\nexport async function claimDormantMetadataSweepAttempt(\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n attemptedAt: string,\n stillCurrent?: (() => boolean) | undefined,\n): Promise<boolean> {\n await ensureContainerTables(execSql);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const claim = async (tx: ClientSQLiteTransactionScope) => {\n const [current] = await tx\n .select({ attemptCount: dormantMetadataSweepRequests.attemptCount })\n .from(dormantMetadataSweepRequests)\n .where(\n and(\n eq(dormantMetadataSweepRequests.organizationId, sweep.organizationId),\n eq(\n dormantMetadataSweepRequests.requesterUserId,\n sweep.requesterUserId,\n ),\n eq(dormantMetadataSweepRequests.generation, sweep.generation),\n ),\n )\n .limit(1);\n if (!current || current.attemptCount !== sweep.attemptCount) {\n return false;\n }\n await tx\n .update(dormantMetadataSweepRequests)\n .set({\n attemptCount: current.attemptCount + 1,\n lastAttemptedAt: attemptedAt,\n })\n .where(\n and(\n eq(dormantMetadataSweepRequests.organizationId, sweep.organizationId),\n eq(\n dormantMetadataSweepRequests.requesterUserId,\n sweep.requesterUserId,\n ),\n eq(dormantMetadataSweepRequests.generation, sweep.generation),\n eq(dormantMetadataSweepRequests.attemptCount, current.attemptCount),\n ),\n )\n .run();\n return true;\n };\n if (!stillCurrent) {\n return runtime.transaction(claim);\n }\n const outcome = await runtime.guardedTransaction(claim, stillCurrent);\n return outcome.committed && outcome.result === true;\n}\n\nexport async function completeDormantMetadataSweepRequest(\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n stillCurrent?: (() => boolean) | undefined,\n): Promise<void> {\n await ensureContainerTables(execSql);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const complete = async (tx: ClientSQLiteTransactionScope) => {\n await tx\n .delete(dormantMetadataSweepRequests)\n .where(\n and(\n eq(dormantMetadataSweepRequests.organizationId, sweep.organizationId),\n eq(\n dormantMetadataSweepRequests.requesterUserId,\n sweep.requesterUserId,\n ),\n eq(dormantMetadataSweepRequests.generation, sweep.generation),\n ),\n )\n .run();\n };\n if (stillCurrent) {\n await runtime.guardedTransaction(complete, stillCurrent);\n return;\n }\n await runtime.transaction(complete);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dormantMetadataSweep.js","sourceRoot":"","sources":["dormantMetadataSweep.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, sql } from \"drizzle-orm\";\nimport {\n dormantContainerMetadata,\n dormantMetadataSweepRequests,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../sqlite/sqlSchema\";\nimport { ensureContainerTables } from \"./containerPersistence\";\n\nexport interface DormantMetadataSweepRequest {\n readonly attemptCount: number;\n readonly generation: number;\n readonly lastAttemptedAt: string | null;\n readonly organizationId: string;\n readonly requestedAt: string;\n readonly requesterUserId: string;\n}\n\nexport interface DormantMetadataSweepPersistence {\n claimDormantMetadataSweepAttempt: (\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n attemptedAt: string,\n stillCurrent?: (() => boolean) | undefined,\n ) => Promise<boolean>;\n completeDormantMetadataSweepRequest: (\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n stillCurrent?: (() => boolean) | undefined,\n ) => Promise<void>;\n listDormantMetadataSweepRequests: (\n execSql: ExecSql,\n requesterUserId: string,\n ) => Promise<readonly DormantMetadataSweepRequest[]>;\n}\n\nexport async function requestDormantMetadataRestorationSweeps(\n execSql: ExecSql,\n input: { requesterUserId: string },\n): Promise<number> {\n await ensureContainerTables(execSql);\n const requestedAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(execSql).runMutation(async (db) => {\n const organizations = await db\n .selectDistinct({\n organizationId: dormantContainerMetadata.organizationId,\n })\n .from(dormantContainerMetadata)\n .orderBy(dormantContainerMetadata.organizationId);\n if (organizations.length === 0) {\n return 0;\n }\n\n await db\n .insert(dormantMetadataSweepRequests)\n .values(\n organizations.map(({ organizationId }) => ({\n attemptCount: 0,\n generation: 1,\n lastAttemptedAt: null,\n organizationId,\n requestedAt,\n requesterUserId: input.requesterUserId,\n })),\n )\n .onConflictDoUpdate({\n target: [\n dormantMetadataSweepRequests.organizationId,\n dormantMetadataSweepRequests.requesterUserId,\n ],\n set: {\n attemptCount: 0,\n generation: sql`${dormantMetadataSweepRequests.generation} + 1`,\n lastAttemptedAt: null,\n requestedAt: sql`excluded.requested_at`,\n },\n })\n .run();\n return organizations.length;\n });\n}\n\nexport async function listDormantMetadataSweepRequests(\n execSql: ExecSql,\n requesterUserId: string,\n): Promise<readonly DormantMetadataSweepRequest[]> {\n await ensureContainerTables(execSql);\n return getClientSQLitePersistenceRuntime(execSql)\n .db.select({\n attemptCount: dormantMetadataSweepRequests.attemptCount,\n generation: dormantMetadataSweepRequests.generation,\n lastAttemptedAt: dormantMetadataSweepRequests.lastAttemptedAt,\n organizationId: dormantMetadataSweepRequests.organizationId,\n requestedAt: dormantMetadataSweepRequests.requestedAt,\n requesterUserId: dormantMetadataSweepRequests.requesterUserId,\n })\n .from(dormantMetadataSweepRequests)\n .where(eq(dormantMetadataSweepRequests.requesterUserId, requesterUserId))\n .orderBy(dormantMetadataSweepRequests.organizationId);\n}\n\nexport async function claimDormantMetadataSweepAttempt(\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n attemptedAt: string,\n stillCurrent?: (() => boolean) | undefined,\n): Promise<boolean> {\n await ensureContainerTables(execSql);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const claim = async (tx: ClientSQLiteTransactionScope) => {\n const [current] = await tx\n .select({ attemptCount: dormantMetadataSweepRequests.attemptCount })\n .from(dormantMetadataSweepRequests)\n .where(\n and(\n eq(dormantMetadataSweepRequests.organizationId, sweep.organizationId),\n eq(\n dormantMetadataSweepRequests.requesterUserId,\n sweep.requesterUserId,\n ),\n eq(dormantMetadataSweepRequests.generation, sweep.generation),\n ),\n )\n .limit(1);\n if (!current || current.attemptCount !== sweep.attemptCount) {\n return false;\n }\n await tx\n .update(dormantMetadataSweepRequests)\n .set({\n attemptCount: current.attemptCount + 1,\n lastAttemptedAt: attemptedAt,\n })\n .where(\n and(\n eq(dormantMetadataSweepRequests.organizationId, sweep.organizationId),\n eq(\n dormantMetadataSweepRequests.requesterUserId,\n sweep.requesterUserId,\n ),\n eq(dormantMetadataSweepRequests.generation, sweep.generation),\n eq(dormantMetadataSweepRequests.attemptCount, current.attemptCount),\n ),\n )\n .run();\n return true;\n };\n if (!stillCurrent) {\n return runtime.transaction(claim);\n }\n const outcome = await runtime.guardedTransaction(claim, stillCurrent);\n return outcome.committed && outcome.result === true;\n}\n\nexport async function completeDormantMetadataSweepRequest(\n execSql: ExecSql,\n sweep: DormantMetadataSweepRequest,\n stillCurrent?: (() => boolean) | undefined,\n): Promise<void> {\n await ensureContainerTables(execSql);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const complete = async (tx: ClientSQLiteTransactionScope) => {\n await tx\n .delete(dormantMetadataSweepRequests)\n .where(\n and(\n eq(dormantMetadataSweepRequests.organizationId, sweep.organizationId),\n eq(\n dormantMetadataSweepRequests.requesterUserId,\n sweep.requesterUserId,\n ),\n eq(dormantMetadataSweepRequests.generation, sweep.generation),\n ),\n )\n .run();\n };\n if (stillCurrent) {\n await runtime.guardedTransaction(complete, stillCurrent);\n return;\n }\n await runtime.transaction(complete);\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { and, asc, eq, inArray, sql } from "drizzle-orm";
|
|
2
2
|
import { containerDocumentTombstoneHolds, documentContainerProjection, documentProjection, } from "../../../sqlite/schema/index.js";
|
|
3
|
-
import { filterWritableDocumentPlacements } from "../../
|
|
3
|
+
import { filterWritableDocumentPlacements } from "../../container-contents/documentPlacement.js";
|
|
4
4
|
/** Keep `IN (...)` lists well under SQLite's bound-parameter limit. */
|
|
5
5
|
const HOLD_SQL_ID_BATCH_SIZE = 400;
|
|
6
6
|
function batches(values) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerDocumentTombstoneHolds.js","sourceRoot":"","sources":["containerDocumentTombstoneHolds.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n containerDocumentTombstoneHolds,\n documentContainerProjection,\n documentProjection,\n} from \"../../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { filterWritableDocumentPlacements } from \"../../containers/documentPlacement\";\nimport type { ContainerDocumentTombstoneInput } from \"../types\";\n\nexport interface ContainerDocumentPlacementKey {\n readonly containerId: string;\n readonly documentId: string;\n}\n\nexport type HeldContainerDocumentTombstone = Omit<\n ContainerDocumentTombstoneInput,\n \"accessEpoch\" | \"linkedContainerIds\"\n> & {\n /** Held without a verification attempt; the backoff does not advance. */\n readonly deferred?: boolean | undefined;\n /** A verified head still links it; retry the tombstone while keeping it visible. */\n readonly refuted?: boolean | undefined;\n};\n\n/** Keep `IN (...)` lists well under SQLite's bound-parameter limit. */\nconst HOLD_SQL_ID_BATCH_SIZE = 400;\n\nfunction batches<T>(values: ReadonlyArray<T>): T[][] {\n const unique = Array.from(new Set(values));\n const result: T[][] = [];\n for (let index = 0; index < unique.length; index += HOLD_SQL_ID_BATCH_SIZE) {\n result.push(unique.slice(index, index + HOLD_SQL_ID_BATCH_SIZE));\n }\n return result;\n}\n\nexport function containerDocumentPlacementKey(\n placement: ContainerDocumentPlacementKey,\n): string {\n return `${placement.documentId}\\u0000${placement.containerId}`;\n}\nconst placementKey = containerDocumentPlacementKey;\n\nexport async function deleteContainerDocumentTombstoneHoldRows(\n tx: ClientSQLiteTransactionScope,\n placements: ReadonlyArray<ContainerDocumentPlacementKey>,\n): Promise<void> {\n for (const placement of placements) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(\n and(\n eq(containerDocumentTombstoneHolds.documentId, placement.documentId),\n eq(\n containerDocumentTombstoneHolds.containerId,\n placement.containerId,\n ),\n ),\n )\n .run();\n }\n}\n\n/**\n * A local move takes ownership of a document's placement: the intent, not a\n * server listing, now says where it lives, so every hold that was hiding one\n * of its placements is released with the link rewrite.\n */\nexport async function deleteContainerDocumentTombstoneHoldsForDocuments(\n tx: ClientSQLiteTransactionScope,\n documentIds: ReadonlyArray<string>,\n): Promise<void> {\n for (const batch of batches(documentIds)) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(inArray(containerDocumentTombstoneHolds.documentId, batch))\n .run();\n }\n}\n\n/** Holds on containers whose link rows are being removed locally. */\nexport async function deleteContainerDocumentTombstoneHoldsForContainers(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n for (const batch of batches(containerIds)) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(inArray(containerDocumentTombstoneHolds.containerId, batch))\n .run();\n }\n}\n\n/**\n * The placements among `placements` that exist locally: a link row, or a\n * document projection row whose primary container is the named container.\n * A tombstone for any other placement has nothing to remove or hide, so it\n * is not worth fetching and verifying the document head for.\n */\nexport async function listKnownContainerDocumentPlacementsInTransaction(\n tx: ClientSQLiteTransactionScope,\n placements: ReadonlyArray<ContainerDocumentPlacementKey>,\n): Promise<ContainerDocumentPlacementKey[]> {\n const known = new Set<string>();\n for (const batch of batches(placements.map((entry) => entry.documentId))) {\n const [linkRows, projectionRows] = await Promise.all([\n tx\n .select({\n containerId: documentContainerProjection.containerId,\n documentId: documentContainerProjection.documentId,\n })\n .from(documentContainerProjection)\n .where(inArray(documentContainerProjection.documentId, batch)),\n tx\n .select({\n containerId: documentProjection.containerId,\n documentId: documentProjection.documentId,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.documentId, batch)),\n ]);\n for (const row of [...linkRows, ...projectionRows]) {\n if (row.documentId !== null && row.containerId !== null) {\n known.add(\n placementKey({\n containerId: row.containerId,\n documentId: row.documentId,\n }),\n );\n }\n }\n }\n return placements.filter((placement) => known.has(placementKey(placement)));\n}\n\n/**\n * Hold listing tombstones whose signed evidence is unavailable. A placement a\n * pending move intent owns is never held: the intent, not the listing, decides\n * where the document lives until it settles (`ProtectPendingTombstones`).\n */\nexport async function holdContainerDocumentTombstonesInTransaction(\n tx: ClientSQLiteTransactionScope,\n tombstones: ReadonlyArray<HeldContainerDocumentTombstone>,\n now: string,\n): Promise<void> {\n const writable = new Set(\n (\n await filterWritableDocumentPlacements(\n tx,\n tombstones.map((tombstone) => ({\n documentId: tombstone.documentId,\n containerIds: [],\n })),\n )\n ).map((input) => input.documentId),\n );\n for (const tombstone of tombstones) {\n if (!writable.has(tombstone.documentId)) continue;\n const row = {\n containerId: tombstone.containerId,\n documentId: tombstone.documentId,\n tombstonedAt: tombstone.updatedAt,\n hidden: !tombstone.refuted,\n updatedAt: now,\n };\n // A deferred hold was not attempted: it keeps its attempt count and its\n // last-attempt time, so it stays due and is not starved by the cap.\n await tx\n .insert(containerDocumentTombstoneHolds)\n .values({ ...row, attempts: tombstone.deferred ? 0 : 1 })\n .onConflictDoUpdate({\n target: [\n containerDocumentTombstoneHolds.documentId,\n containerDocumentTombstoneHolds.containerId,\n ],\n set: tombstone.deferred\n ? { tombstonedAt: row.tombstonedAt }\n : {\n ...row,\n hidden: tombstone.refuted\n ? false\n : containerDocumentTombstoneHolds.hidden,\n attempts: sql`${containerDocumentTombstoneHolds.attempts} + 1`,\n },\n })\n .run();\n }\n}\n\n/** Release the holds on placements a listing has re-asserted as linked. */\nexport async function deleteContainerDocumentTombstoneHoldRowsForLinks(\n tx: ClientSQLiteTransactionScope,\n links: ReadonlyArray<{\n readonly containerIds: ReadonlyArray<string>;\n readonly documentId: string;\n }>,\n): Promise<void> {\n for (const link of links) {\n for (const batch of batches(link.containerIds)) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(\n and(\n eq(containerDocumentTombstoneHolds.documentId, link.documentId),\n inArray(containerDocumentTombstoneHolds.containerId, batch),\n ),\n )\n .run();\n }\n }\n}\n\nexport interface ContainerDocumentTombstoneHoldRow\n extends ContainerDocumentPlacementKey {\n readonly attempts: number;\n readonly hidden: boolean;\n readonly tombstonedAt: string;\n readonly updatedAt: string;\n}\n\nconst holdRowSelection = {\n attempts: containerDocumentTombstoneHolds.attempts,\n hidden: containerDocumentTombstoneHolds.hidden,\n containerId: containerDocumentTombstoneHolds.containerId,\n documentId: containerDocumentTombstoneHolds.documentId,\n tombstonedAt: containerDocumentTombstoneHolds.tombstonedAt,\n updatedAt: containerDocumentTombstoneHolds.updatedAt,\n};\n\n/** Every hold on the given containers, including visible refuted retries. */\nexport async function listContainerDocumentTombstoneHoldsInTransaction(\n handle: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<ContainerDocumentTombstoneHoldRow[]> {\n const holds: ContainerDocumentTombstoneHoldRow[] = [];\n for (const batch of batches(containerIds)) {\n holds.push(\n ...(await handle\n .select(holdRowSelection)\n .from(containerDocumentTombstoneHolds)\n .where(inArray(containerDocumentTombstoneHolds.containerId, batch))\n .orderBy(\n asc(containerDocumentTombstoneHolds.containerId),\n asc(containerDocumentTombstoneHolds.documentId),\n )),\n );\n }\n return holds;\n}\n\n/** Every hidden hold on the given documents, in any container. */\nexport async function listContainerDocumentTombstoneHoldsForDocumentsInTransaction(\n handle: ClientSQLiteTransactionScope,\n documentIds: ReadonlyArray<string>,\n): Promise<ContainerDocumentTombstoneHoldRow[]> {\n const holds: ContainerDocumentTombstoneHoldRow[] = [];\n for (const batch of batches(documentIds)) {\n holds.push(\n ...(await handle\n .select(holdRowSelection)\n .from(containerDocumentTombstoneHolds)\n .where(\n and(\n inArray(containerDocumentTombstoneHolds.documentId, batch),\n eq(containerDocumentTombstoneHolds.hidden, true),\n ),\n )\n .orderBy(\n asc(containerDocumentTombstoneHolds.documentId),\n asc(containerDocumentTombstoneHolds.containerId),\n )),\n );\n }\n return holds;\n}\n\n/**\n * Split the holds on the given containers into those whose placement is gone\n * (the document was purged, reset, or relinked locally: nothing left to hide,\n * so the hold is dropped) and those still hiding a placement.\n */\nexport async function partitionContainerDocumentTombstoneHolds(\n handle: ClientSQLiteTransactionScope,\n holds: ReadonlyArray<ContainerDocumentTombstoneHoldRow>,\n): Promise<{\n live: ContainerDocumentTombstoneHoldRow[];\n orphaned: ContainerDocumentTombstoneHoldRow[];\n}> {\n const known = new Set(\n (\n await listKnownContainerDocumentPlacementsInTransaction(handle, holds)\n ).map(placementKey),\n );\n return {\n live: holds.filter((hold) => known.has(placementKey(hold))),\n orphaned: holds.filter((hold) => !known.has(placementKey(hold))),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerDocumentTombstoneHolds.js","sourceRoot":"","sources":["containerDocumentTombstoneHolds.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n containerDocumentTombstoneHolds,\n documentContainerProjection,\n documentProjection,\n} from \"../../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { filterWritableDocumentPlacements } from \"../../container-contents/documentPlacement\";\nimport type { ContainerDocumentTombstoneInput } from \"../types\";\n\nexport interface ContainerDocumentPlacementKey {\n readonly containerId: string;\n readonly documentId: string;\n}\n\nexport type HeldContainerDocumentTombstone = Omit<\n ContainerDocumentTombstoneInput,\n \"accessEpoch\" | \"linkedContainerIds\"\n> & {\n /** Held without a verification attempt; the backoff does not advance. */\n readonly deferred?: boolean | undefined;\n /** A verified head still links it; retry the tombstone while keeping it visible. */\n readonly refuted?: boolean | undefined;\n};\n\n/** Keep `IN (...)` lists well under SQLite's bound-parameter limit. */\nconst HOLD_SQL_ID_BATCH_SIZE = 400;\n\nfunction batches<T>(values: ReadonlyArray<T>): T[][] {\n const unique = Array.from(new Set(values));\n const result: T[][] = [];\n for (let index = 0; index < unique.length; index += HOLD_SQL_ID_BATCH_SIZE) {\n result.push(unique.slice(index, index + HOLD_SQL_ID_BATCH_SIZE));\n }\n return result;\n}\n\nexport function containerDocumentPlacementKey(\n placement: ContainerDocumentPlacementKey,\n): string {\n return `${placement.documentId}\\u0000${placement.containerId}`;\n}\nconst placementKey = containerDocumentPlacementKey;\n\nexport async function deleteContainerDocumentTombstoneHoldRows(\n tx: ClientSQLiteTransactionScope,\n placements: ReadonlyArray<ContainerDocumentPlacementKey>,\n): Promise<void> {\n for (const placement of placements) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(\n and(\n eq(containerDocumentTombstoneHolds.documentId, placement.documentId),\n eq(\n containerDocumentTombstoneHolds.containerId,\n placement.containerId,\n ),\n ),\n )\n .run();\n }\n}\n\n/**\n * A local move takes ownership of a document's placement: the intent, not a\n * server listing, now says where it lives, so every hold that was hiding one\n * of its placements is released with the link rewrite.\n */\nexport async function deleteContainerDocumentTombstoneHoldsForDocuments(\n tx: ClientSQLiteTransactionScope,\n documentIds: ReadonlyArray<string>,\n): Promise<void> {\n for (const batch of batches(documentIds)) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(inArray(containerDocumentTombstoneHolds.documentId, batch))\n .run();\n }\n}\n\n/** Holds on containers whose link rows are being removed locally. */\nexport async function deleteContainerDocumentTombstoneHoldsForContainers(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n for (const batch of batches(containerIds)) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(inArray(containerDocumentTombstoneHolds.containerId, batch))\n .run();\n }\n}\n\n/**\n * The placements among `placements` that exist locally: a link row, or a\n * document projection row whose primary container is the named container.\n * A tombstone for any other placement has nothing to remove or hide, so it\n * is not worth fetching and verifying the document head for.\n */\nexport async function listKnownContainerDocumentPlacementsInTransaction(\n tx: ClientSQLiteTransactionScope,\n placements: ReadonlyArray<ContainerDocumentPlacementKey>,\n): Promise<ContainerDocumentPlacementKey[]> {\n const known = new Set<string>();\n for (const batch of batches(placements.map((entry) => entry.documentId))) {\n const [linkRows, projectionRows] = await Promise.all([\n tx\n .select({\n containerId: documentContainerProjection.containerId,\n documentId: documentContainerProjection.documentId,\n })\n .from(documentContainerProjection)\n .where(inArray(documentContainerProjection.documentId, batch)),\n tx\n .select({\n containerId: documentProjection.containerId,\n documentId: documentProjection.documentId,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.documentId, batch)),\n ]);\n for (const row of [...linkRows, ...projectionRows]) {\n if (row.documentId !== null && row.containerId !== null) {\n known.add(\n placementKey({\n containerId: row.containerId,\n documentId: row.documentId,\n }),\n );\n }\n }\n }\n return placements.filter((placement) => known.has(placementKey(placement)));\n}\n\n/**\n * Hold listing tombstones whose signed evidence is unavailable. A placement a\n * pending move intent owns is never held: the intent, not the listing, decides\n * where the document lives until it settles (`ProtectPendingTombstones`).\n */\nexport async function holdContainerDocumentTombstonesInTransaction(\n tx: ClientSQLiteTransactionScope,\n tombstones: ReadonlyArray<HeldContainerDocumentTombstone>,\n now: string,\n): Promise<void> {\n const writable = new Set(\n (\n await filterWritableDocumentPlacements(\n tx,\n tombstones.map((tombstone) => ({\n documentId: tombstone.documentId,\n containerIds: [],\n })),\n )\n ).map((input) => input.documentId),\n );\n for (const tombstone of tombstones) {\n if (!writable.has(tombstone.documentId)) continue;\n const row = {\n containerId: tombstone.containerId,\n documentId: tombstone.documentId,\n tombstonedAt: tombstone.updatedAt,\n hidden: !tombstone.refuted,\n updatedAt: now,\n };\n // A deferred hold was not attempted: it keeps its attempt count and its\n // last-attempt time, so it stays due and is not starved by the cap.\n await tx\n .insert(containerDocumentTombstoneHolds)\n .values({ ...row, attempts: tombstone.deferred ? 0 : 1 })\n .onConflictDoUpdate({\n target: [\n containerDocumentTombstoneHolds.documentId,\n containerDocumentTombstoneHolds.containerId,\n ],\n set: tombstone.deferred\n ? { tombstonedAt: row.tombstonedAt }\n : {\n ...row,\n hidden: tombstone.refuted\n ? false\n : containerDocumentTombstoneHolds.hidden,\n attempts: sql`${containerDocumentTombstoneHolds.attempts} + 1`,\n },\n })\n .run();\n }\n}\n\n/** Release the holds on placements a listing has re-asserted as linked. */\nexport async function deleteContainerDocumentTombstoneHoldRowsForLinks(\n tx: ClientSQLiteTransactionScope,\n links: ReadonlyArray<{\n readonly containerIds: ReadonlyArray<string>;\n readonly documentId: string;\n }>,\n): Promise<void> {\n for (const link of links) {\n for (const batch of batches(link.containerIds)) {\n await tx\n .delete(containerDocumentTombstoneHolds)\n .where(\n and(\n eq(containerDocumentTombstoneHolds.documentId, link.documentId),\n inArray(containerDocumentTombstoneHolds.containerId, batch),\n ),\n )\n .run();\n }\n }\n}\n\nexport interface ContainerDocumentTombstoneHoldRow\n extends ContainerDocumentPlacementKey {\n readonly attempts: number;\n readonly hidden: boolean;\n readonly tombstonedAt: string;\n readonly updatedAt: string;\n}\n\nconst holdRowSelection = {\n attempts: containerDocumentTombstoneHolds.attempts,\n hidden: containerDocumentTombstoneHolds.hidden,\n containerId: containerDocumentTombstoneHolds.containerId,\n documentId: containerDocumentTombstoneHolds.documentId,\n tombstonedAt: containerDocumentTombstoneHolds.tombstonedAt,\n updatedAt: containerDocumentTombstoneHolds.updatedAt,\n};\n\n/** Every hold on the given containers, including visible refuted retries. */\nexport async function listContainerDocumentTombstoneHoldsInTransaction(\n handle: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n): Promise<ContainerDocumentTombstoneHoldRow[]> {\n const holds: ContainerDocumentTombstoneHoldRow[] = [];\n for (const batch of batches(containerIds)) {\n holds.push(\n ...(await handle\n .select(holdRowSelection)\n .from(containerDocumentTombstoneHolds)\n .where(inArray(containerDocumentTombstoneHolds.containerId, batch))\n .orderBy(\n asc(containerDocumentTombstoneHolds.containerId),\n asc(containerDocumentTombstoneHolds.documentId),\n )),\n );\n }\n return holds;\n}\n\n/** Every hidden hold on the given documents, in any container. */\nexport async function listContainerDocumentTombstoneHoldsForDocumentsInTransaction(\n handle: ClientSQLiteTransactionScope,\n documentIds: ReadonlyArray<string>,\n): Promise<ContainerDocumentTombstoneHoldRow[]> {\n const holds: ContainerDocumentTombstoneHoldRow[] = [];\n for (const batch of batches(documentIds)) {\n holds.push(\n ...(await handle\n .select(holdRowSelection)\n .from(containerDocumentTombstoneHolds)\n .where(\n and(\n inArray(containerDocumentTombstoneHolds.documentId, batch),\n eq(containerDocumentTombstoneHolds.hidden, true),\n ),\n )\n .orderBy(\n asc(containerDocumentTombstoneHolds.documentId),\n asc(containerDocumentTombstoneHolds.containerId),\n )),\n );\n }\n return holds;\n}\n\n/**\n * Split the holds on the given containers into those whose placement is gone\n * (the document was purged, reset, or relinked locally: nothing left to hide,\n * so the hold is dropped) and those still hiding a placement.\n */\nexport async function partitionContainerDocumentTombstoneHolds(\n handle: ClientSQLiteTransactionScope,\n holds: ReadonlyArray<ContainerDocumentTombstoneHoldRow>,\n): Promise<{\n live: ContainerDocumentTombstoneHoldRow[];\n orphaned: ContainerDocumentTombstoneHoldRow[];\n}> {\n const known = new Set(\n (\n await listKnownContainerDocumentPlacementsInTransaction(handle, holds)\n ).map(placementKey),\n );\n return {\n live: holds.filter((hold) => known.has(placementKey(hold))),\n orphaned: holds.filter((hold) => !known.has(placementKey(hold))),\n };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { and, asc, desc, eq, inArray, notInArray } from "drizzle-orm";
|
|
2
2
|
import { documentContainerProjection, documentProjection, documents, } from "../../../sqlite/schema/index.js";
|
|
3
3
|
import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
|
|
4
|
-
import { filterWritableDocumentPlacements } from "../../
|
|
4
|
+
import { filterWritableDocumentPlacements } from "../../container-contents/documentPlacement.js";
|
|
5
5
|
import { getLatestTimestamp } from "../../latestTimestamp.js";
|
|
6
6
|
import { DOCUMENTS_APP_KIND } from "./constants.js";
|
|
7
7
|
import { deleteContainerDocumentTombstoneHoldRows } from "./containerDocumentTombstoneHolds.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerDocumentTombstones.js","sourceRoot":"","sources":["containerDocumentTombstones.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, desc, eq, inArray, notInArray } from \"drizzle-orm\";\nimport {\n documentContainerProjection,\n documentProjection,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport { filterWritableDocumentPlacements } from \"../../containers/documentPlacement\";\nimport { getLatestTimestamp } from \"../../latestTimestamp\";\nimport type { ContainerDocumentTombstoneInput } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport { deleteContainerDocumentTombstoneHoldRows } from \"./containerDocumentTombstoneHolds\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n mapDocumentSummary,\n} from \"./documentProjectionRows\";\n\nfunction dedupeContainerDocumentTombstones(\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): ContainerDocumentTombstoneInput[] {\n return Array.from(\n new Map(\n tombstones.map((tombstone) => [\n `${tombstone.documentId}\\u0000${tombstone.containerId}`,\n tombstone,\n ]),\n ).values(),\n );\n}\n\nfunction buildContainerDocumentTombstoneState(\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): {\n removedContainerIdsByDocumentId: Map<string, Set<string>>;\n tombstoneUpdatedAtByDocumentId: Map<string, string>;\n verifiedLinkedContainerIdsByDocumentId: Map<string, ReadonlySet<string>>;\n} {\n const removedContainerIdsByDocumentId = new Map<string, Set<string>>();\n const tombstoneUpdatedAtByDocumentId = new Map<string, string>();\n const verifiedLinkedContainerIdsByDocumentId = new Map<\n string,\n ReadonlySet<string>\n >();\n\n for (const tombstone of uniqueTombstones) {\n verifiedLinkedContainerIdsByDocumentId.set(\n tombstone.documentId,\n new Set(tombstone.linkedContainerIds),\n );\n const removedContainerIds =\n removedContainerIdsByDocumentId.get(tombstone.documentId) ?? new Set();\n removedContainerIds.add(tombstone.containerId);\n removedContainerIdsByDocumentId.set(\n tombstone.documentId,\n removedContainerIds,\n );\n tombstoneUpdatedAtByDocumentId.set(\n tombstone.documentId,\n getLatestTimestamp(\n tombstoneUpdatedAtByDocumentId.get(tombstone.documentId),\n tombstone.updatedAt,\n ),\n );\n }\n\n return {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n };\n}\n\n/**\n * Remove the tombstoned placement and, with the head now verified, every\n * remaining local link row the head does not link: those are listing-seeded\n * rows, and leaving one would keep showing the document in a container the\n * signed link set never named. Rows the head links are kept as they are.\n */\nasync function deleteContainerDocumentTombstoneRows(\n tx: ClientSQLiteTransactionScope,\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n verifiedLinkedContainerIdsByDocumentId: ReadonlyMap<\n string,\n ReadonlySet<string>\n >,\n): Promise<void> {\n for (const tombstone of uniqueTombstones) {\n await tx\n .delete(documentContainerProjection)\n .where(\n and(\n eq(documentContainerProjection.documentId, tombstone.documentId),\n eq(documentContainerProjection.containerId, tombstone.containerId),\n ),\n )\n .run();\n }\n for (const [documentId, linked] of verifiedLinkedContainerIdsByDocumentId) {\n await tx\n .delete(documentContainerProjection)\n .where(\n linked.size === 0\n ? eq(documentContainerProjection.documentId, documentId)\n : and(\n eq(documentContainerProjection.documentId, documentId),\n notInArray(documentContainerProjection.containerId, [...linked]),\n ),\n )\n .run();\n }\n}\n\n/**\n * The primary container after a removal: the first remaining local row the\n * verified head links. A remaining row the head does not link is a\n * listing-seeded row and never becomes the primary, so a listing cannot\n * re-home the document. With no such row the document is unplaced (`null`)\n * and reachable through orphan recovery, rather than pointed at a head\n * container this device may not be able to read.\n */\nfunction selectNextContainerId(\n remainingContainerIds: ReadonlyArray<string>,\n verifiedLinkedContainerIds: ReadonlySet<string>,\n): string | null {\n return (\n remainingContainerIds.find((containerId) =>\n verifiedLinkedContainerIds.has(containerId),\n ) ?? null\n );\n}\n\nasync function updateSelectedContainersForDocumentTombstones(input: {\n documentId: string;\n removedContainerIds: ReadonlySet<string>;\n tombstoneUpdatedAt: string | undefined;\n tx: ClientSQLiteTransactionScope;\n verifiedLinkedContainerIds: ReadonlySet<string>;\n}): Promise<string[]> {\n const { documentId, removedContainerIds, tombstoneUpdatedAt, tx } = input;\n // A server document can own more than one local projection row: identity\n // recovery legitimately rematerializes a second projection for the same\n // documentId before semantic convergence completes. The link delete above is\n // keyed by (documentId, containerId) and the container item view surfaces a\n // document by its primary container_id, so EVERY projection row still pointing\n // at a removed container must be repaired here — resolving a single localId\n // left a duplicate row stranded at the source, keeping a moved document\n // visible in the container it was unlinked from.\n const localIds = (\n await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.documentId, documentId),\n ),\n )\n ).map((row) => row.localId);\n if (localIds.length === 0) {\n return [];\n }\n\n const projectionRows = await tx\n .select({\n localId: documentProjection.localId,\n containerId: documentProjection.containerId,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.localId, localIds));\n // Every projection row whose primary container is tombstoned OR outside the\n // verified link set is repointed: a primary at a listing-seeded row would\n // otherwise keep showing the document in a container the head never named.\n const rowsAtRemovedContainer = projectionRows.flatMap((row) =>\n row.localId !== null &&\n row.containerId !== null &&\n (removedContainerIds.has(row.containerId) ||\n !input.verifiedLinkedContainerIds.has(row.containerId))\n ? [{ localId: row.localId, updatedAt: row.updatedAt ?? undefined }]\n : [],\n );\n if (rowsAtRemovedContainer.length === 0) {\n return [];\n }\n\n const remainingLinkRows = await tx\n .select({ containerId: documentContainerProjection.containerId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, documentId))\n .orderBy(asc(documentContainerProjection.containerId));\n const nextContainerId = selectNextContainerId(\n remainingLinkRows.map((row) => row.containerId),\n input.verifiedLinkedContainerIds,\n );\n\n const changedLocalIds: string[] = [];\n for (const row of rowsAtRemovedContainer) {\n await tx\n .update(documentProjection)\n .set({\n containerId: nextContainerId,\n updatedAt: getLatestTimestamp(row.updatedAt, tombstoneUpdatedAt),\n })\n .where(eq(documentProjection.localId, row.localId))\n .run();\n changedLocalIds.push(row.localId);\n }\n\n return changedLocalIds;\n}\n\nexport async function applyContainerDocumentTombstonesWithExec(\n execSql: ExecSql,\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n) {\n const uniqueTombstones = dedupeContainerDocumentTombstones(tombstones);\n if (uniqueTombstones.length === 0) {\n return [];\n }\n\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return db.transaction(async (tx) => {\n // Besides the pending-intent guard, the verified head must not be older\n // than local document state: a lagging or replayed head must never\n // delete rows a newer listing or settled move wrote (`CheckEpoch`).\n const writable = await filterWritableDocumentPlacements(\n tx,\n uniqueTombstones.map((tombstone) => ({\n accessEpoch: tombstone.accessEpoch,\n documentId: tombstone.documentId,\n containerIds: [],\n })),\n );\n const writableIds = new Set(writable.map((input) => input.documentId));\n const applicable = uniqueTombstones.filter((tombstone) =>\n writableIds.has(tombstone.documentId),\n );\n const {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n } = buildContainerDocumentTombstoneState(applicable);\n await deleteContainerDocumentTombstoneRows(\n tx,\n applicable,\n verifiedLinkedContainerIdsByDocumentId,\n );\n await deleteContainerDocumentTombstoneHoldRows(tx, applicable);\n\n const changedLocalIds: string[] = [];\n for (const [\n documentId,\n removedContainerIds,\n ] of removedContainerIdsByDocumentId) {\n changedLocalIds.push(\n ...(await updateSelectedContainersForDocumentTombstones({\n documentId,\n removedContainerIds,\n tombstoneUpdatedAt: tombstoneUpdatedAtByDocumentId.get(documentId),\n tx,\n verifiedLinkedContainerIds:\n verifiedLinkedContainerIdsByDocumentId.get(documentId) ?? new Set(),\n })),\n );\n }\n\n if (changedLocalIds.length === 0) {\n return [];\n }\n\n const rows = await tx\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(inArray(documentProjection.localId, changedLocalIds))\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerDocumentTombstones.js","sourceRoot":"","sources":["containerDocumentTombstones.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, asc, desc, eq, inArray, notInArray } from \"drizzle-orm\";\nimport {\n documentContainerProjection,\n documentProjection,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport { filterWritableDocumentPlacements } from \"../../container-contents/documentPlacement\";\nimport { getLatestTimestamp } from \"../../latestTimestamp\";\nimport type { ContainerDocumentTombstoneInput } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport { deleteContainerDocumentTombstoneHoldRows } from \"./containerDocumentTombstoneHolds\";\nimport {\n documentSummaryJoin,\n documentSummarySelection,\n mapDocumentSummary,\n} from \"./documentProjectionRows\";\n\nfunction dedupeContainerDocumentTombstones(\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): ContainerDocumentTombstoneInput[] {\n return Array.from(\n new Map(\n tombstones.map((tombstone) => [\n `${tombstone.documentId}\\u0000${tombstone.containerId}`,\n tombstone,\n ]),\n ).values(),\n );\n}\n\nfunction buildContainerDocumentTombstoneState(\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n): {\n removedContainerIdsByDocumentId: Map<string, Set<string>>;\n tombstoneUpdatedAtByDocumentId: Map<string, string>;\n verifiedLinkedContainerIdsByDocumentId: Map<string, ReadonlySet<string>>;\n} {\n const removedContainerIdsByDocumentId = new Map<string, Set<string>>();\n const tombstoneUpdatedAtByDocumentId = new Map<string, string>();\n const verifiedLinkedContainerIdsByDocumentId = new Map<\n string,\n ReadonlySet<string>\n >();\n\n for (const tombstone of uniqueTombstones) {\n verifiedLinkedContainerIdsByDocumentId.set(\n tombstone.documentId,\n new Set(tombstone.linkedContainerIds),\n );\n const removedContainerIds =\n removedContainerIdsByDocumentId.get(tombstone.documentId) ?? new Set();\n removedContainerIds.add(tombstone.containerId);\n removedContainerIdsByDocumentId.set(\n tombstone.documentId,\n removedContainerIds,\n );\n tombstoneUpdatedAtByDocumentId.set(\n tombstone.documentId,\n getLatestTimestamp(\n tombstoneUpdatedAtByDocumentId.get(tombstone.documentId),\n tombstone.updatedAt,\n ),\n );\n }\n\n return {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n };\n}\n\n/**\n * Remove the tombstoned placement and, with the head now verified, every\n * remaining local link row the head does not link: those are listing-seeded\n * rows, and leaving one would keep showing the document in a container the\n * signed link set never named. Rows the head links are kept as they are.\n */\nasync function deleteContainerDocumentTombstoneRows(\n tx: ClientSQLiteTransactionScope,\n uniqueTombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n verifiedLinkedContainerIdsByDocumentId: ReadonlyMap<\n string,\n ReadonlySet<string>\n >,\n): Promise<void> {\n for (const tombstone of uniqueTombstones) {\n await tx\n .delete(documentContainerProjection)\n .where(\n and(\n eq(documentContainerProjection.documentId, tombstone.documentId),\n eq(documentContainerProjection.containerId, tombstone.containerId),\n ),\n )\n .run();\n }\n for (const [documentId, linked] of verifiedLinkedContainerIdsByDocumentId) {\n await tx\n .delete(documentContainerProjection)\n .where(\n linked.size === 0\n ? eq(documentContainerProjection.documentId, documentId)\n : and(\n eq(documentContainerProjection.documentId, documentId),\n notInArray(documentContainerProjection.containerId, [...linked]),\n ),\n )\n .run();\n }\n}\n\n/**\n * The primary container after a removal: the first remaining local row the\n * verified head links. A remaining row the head does not link is a\n * listing-seeded row and never becomes the primary, so a listing cannot\n * re-home the document. With no such row the document is unplaced (`null`)\n * and reachable through orphan recovery, rather than pointed at a head\n * container this device may not be able to read.\n */\nfunction selectNextContainerId(\n remainingContainerIds: ReadonlyArray<string>,\n verifiedLinkedContainerIds: ReadonlySet<string>,\n): string | null {\n return (\n remainingContainerIds.find((containerId) =>\n verifiedLinkedContainerIds.has(containerId),\n ) ?? null\n );\n}\n\nasync function updateSelectedContainersForDocumentTombstones(input: {\n documentId: string;\n removedContainerIds: ReadonlySet<string>;\n tombstoneUpdatedAt: string | undefined;\n tx: ClientSQLiteTransactionScope;\n verifiedLinkedContainerIds: ReadonlySet<string>;\n}): Promise<string[]> {\n const { documentId, removedContainerIds, tombstoneUpdatedAt, tx } = input;\n // A server document can own more than one local projection row: identity\n // recovery legitimately rematerializes a second projection for the same\n // documentId before semantic convergence completes. The link delete above is\n // keyed by (documentId, containerId) and the container item view surfaces a\n // document by its primary container_id, so EVERY projection row still pointing\n // at a removed container must be repaired here — resolving a single localId\n // left a duplicate row stranded at the source, keeping a moved document\n // visible in the container it was unlinked from.\n const localIds = (\n await tx\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.documentId, documentId),\n ),\n )\n ).map((row) => row.localId);\n if (localIds.length === 0) {\n return [];\n }\n\n const projectionRows = await tx\n .select({\n localId: documentProjection.localId,\n containerId: documentProjection.containerId,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .where(inArray(documentProjection.localId, localIds));\n // Every projection row whose primary container is tombstoned OR outside the\n // verified link set is repointed: a primary at a listing-seeded row would\n // otherwise keep showing the document in a container the head never named.\n const rowsAtRemovedContainer = projectionRows.flatMap((row) =>\n row.localId !== null &&\n row.containerId !== null &&\n (removedContainerIds.has(row.containerId) ||\n !input.verifiedLinkedContainerIds.has(row.containerId))\n ? [{ localId: row.localId, updatedAt: row.updatedAt ?? undefined }]\n : [],\n );\n if (rowsAtRemovedContainer.length === 0) {\n return [];\n }\n\n const remainingLinkRows = await tx\n .select({ containerId: documentContainerProjection.containerId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, documentId))\n .orderBy(asc(documentContainerProjection.containerId));\n const nextContainerId = selectNextContainerId(\n remainingLinkRows.map((row) => row.containerId),\n input.verifiedLinkedContainerIds,\n );\n\n const changedLocalIds: string[] = [];\n for (const row of rowsAtRemovedContainer) {\n await tx\n .update(documentProjection)\n .set({\n containerId: nextContainerId,\n updatedAt: getLatestTimestamp(row.updatedAt, tombstoneUpdatedAt),\n })\n .where(eq(documentProjection.localId, row.localId))\n .run();\n changedLocalIds.push(row.localId);\n }\n\n return changedLocalIds;\n}\n\nexport async function applyContainerDocumentTombstonesWithExec(\n execSql: ExecSql,\n tombstones: ReadonlyArray<ContainerDocumentTombstoneInput>,\n) {\n const uniqueTombstones = dedupeContainerDocumentTombstones(tombstones);\n if (uniqueTombstones.length === 0) {\n return [];\n }\n\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n\n return db.transaction(async (tx) => {\n // Besides the pending-intent guard, the verified head must not be older\n // than local document state: a lagging or replayed head must never\n // delete rows a newer listing or settled move wrote (`CheckEpoch`).\n const writable = await filterWritableDocumentPlacements(\n tx,\n uniqueTombstones.map((tombstone) => ({\n accessEpoch: tombstone.accessEpoch,\n documentId: tombstone.documentId,\n containerIds: [],\n })),\n );\n const writableIds = new Set(writable.map((input) => input.documentId));\n const applicable = uniqueTombstones.filter((tombstone) =>\n writableIds.has(tombstone.documentId),\n );\n const {\n removedContainerIdsByDocumentId,\n tombstoneUpdatedAtByDocumentId,\n verifiedLinkedContainerIdsByDocumentId,\n } = buildContainerDocumentTombstoneState(applicable);\n await deleteContainerDocumentTombstoneRows(\n tx,\n applicable,\n verifiedLinkedContainerIdsByDocumentId,\n );\n await deleteContainerDocumentTombstoneHoldRows(tx, applicable);\n\n const changedLocalIds: string[] = [];\n for (const [\n documentId,\n removedContainerIds,\n ] of removedContainerIdsByDocumentId) {\n changedLocalIds.push(\n ...(await updateSelectedContainersForDocumentTombstones({\n documentId,\n removedContainerIds,\n tombstoneUpdatedAt: tombstoneUpdatedAtByDocumentId.get(documentId),\n tx,\n verifiedLinkedContainerIds:\n verifiedLinkedContainerIdsByDocumentId.get(documentId) ?? new Set(),\n })),\n );\n }\n\n if (changedLocalIds.length === 0) {\n return [];\n }\n\n const rows = await tx\n .select(documentSummarySelection)\n .from(documentProjection)\n .leftJoin(documents, documentSummaryJoin)\n .where(inArray(documentProjection.localId, changedLocalIds))\n .orderBy(\n desc(documentProjection.updatedAt),\n desc(documentProjection.localId),\n );\n\n return rows.map(mapDocumentSummary);\n });\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_DOCUMENT_ACCESS_EPOCH } from "../../../documents/documentConstants.js";
|
|
2
|
-
import { loadDocumentMovePlacement } from "../../
|
|
2
|
+
import { loadDocumentMovePlacement } from "../../container-contents/documentPlacement.js";
|
|
3
3
|
import { resolvePersistedAccessStateHash } from "./documentRuntimeState.js";
|
|
4
4
|
export async function resolveDiscoveredDocumentPlacement(tx, existing, input) {
|
|
5
5
|
const intent = await loadDocumentMovePlacement(tx, input.documentId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discoveredDocumentPlacement.js","sourceRoot":"","sources":["discoveredDocumentPlacement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AAGrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"discoveredDocumentPlacement.js","sourceRoot":"","sources":["discoveredDocumentPlacement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AAGrF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AAEvF,OAAO,EAAE,+BAA+B,EAAE,MAAM,wBAAwB,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,kCAAkC,CACtD,EAAgC,EAChC,QAAqC,EACrC,KAA8B;IAE9B,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC5E,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAC1B,QAAQ,EAAE,WAAW,IAAI,6BAA6B,EACtD,KAAK,CAAC,WAAW,CAClB,CAAC;IACF,MAAM,kBAAkB,GACtB,MAAM,EAAE,UAAU,KAAK,eAAe;QACpC,CAAC,CAAC,CAAC,QAAQ,EAAE,WAAW,IAAI,MAAM,CAAC,iBAAiB,CAAC;QACrD,CAAC,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAChC,MAAM,WAAW,GACf,kBAAkB;QAClB,CAAC,KAAK;YACJ,CAAC,CAAC,QAAQ,CAAC,WAAW;YACtB,CAAC,CAAC,QAAQ,EAAE,WAAW;gBACnB,KAAK,CAAC,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;gBACzD,CAAC,CAAC,QAAQ,CAAC,WAAW;gBACtB,CAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,KAAK,CAAC,WAAW,CAAC;oBAChE,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC;oBAC3B,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC5B,OAAO;QACL,WAAW;QACX,WAAW;QACX,eAAe,EAAE,+BAA+B,CAAC,QAAQ,EAAE;YACzD,WAAW;YACX,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe;YACzE,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC;KACH,CAAC;AACJ,CAAC","sourcesContent":["import { DEFAULT_DOCUMENT_ACCESS_EPOCH } from \"../../../documents/documentConstants\";\nimport type { DiscoveredDocumentInput } from \"../../../documents/documentSummary\";\nimport type { ClientSQLiteTransactionScope } from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport { loadDocumentMovePlacement } from \"../../container-contents/documentPlacement\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { resolvePersistedAccessStateHash } from \"./documentRuntimeState\";\n\nexport async function resolveDiscoveredDocumentPlacement(\n tx: ClientSQLiteTransactionScope,\n existing: StoredDocumentRecord | null,\n input: DiscoveredDocumentInput,\n) {\n const intent = await loadDocumentMovePlacement(tx, input.documentId);\n const stale = existing !== null && existing.accessEpoch > input.accessEpoch;\n const accessEpoch = Math.max(\n existing?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH,\n input.accessEpoch,\n );\n const pendingContainerId =\n intent?.intentType === \"document.link\"\n ? (existing?.containerId ?? intent.targetContainerId)\n : intent?.targetContainerId;\n const containerId =\n pendingContainerId ??\n (stale\n ? existing.containerId\n : existing?.containerId &&\n input.linkedContainerIds.includes(existing.containerId)\n ? existing.containerId\n : (input.linkedContainerIds.find((id) => id === input.containerId) ??\n input.linkedContainerIds[0] ??\n input.containerId));\n return {\n accessEpoch,\n containerId,\n accessStateHash: resolvePersistedAccessStateHash(existing, {\n accessEpoch,\n accessStateHash: stale ? existing.accessStateHash : input.accessStateHash,\n documentId: input.documentId,\n }),\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { encodeVersionVector, exportUpdatesSince } from "../../../internal/loro/index.js";
|
|
2
|
-
import { getDefaultContainerName, readContainerMetadataValue, writeContainerMetadataValue, } from "../../../
|
|
2
|
+
import { getDefaultContainerName, readContainerMetadataValue, writeContainerMetadataValue, } from "../../../workflows/container-contents/metadata/containerMetadataDocument.js";
|
|
3
3
|
import { createDetachedContainerMetadataState, installDetachedContainerMetadataState, } from "../../../workflows/container-contents/metadata/metadataStateIsolation.js";
|
|
4
4
|
import { removeMissingContainerState } from "../containerState/missingContainerState.js";
|
|
5
5
|
import { updateContainerContentsSnapshot } from "../state.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"systemContainerIcon.js","sourceRoot":"","sources":["systemContainerIcon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,
|
|
1
|
+
{"version":3,"file":"systemContainerIcon.js","sourceRoot":"","sources":["systemContainerIcon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,0EAA0E,CAAC;AAClF,OAAO,EACL,oCAAoC,EACpC,qCAAqC,GACtC,MAAM,uEAAuE,CAAC;AAE/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AAEtF,OAAO,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAC;AAa3D,SAAS,4BAA4B,CACnC,IAA+B;IAE/B,OAAO,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAO9C;IACC,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC;IAChE,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,SAAS,EAAE;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,oBAAoB,GAAG,MAAM,oCAAoC,CACrE,KAAK,CAAC,cAAc,CACrB,CAAC;IACF,IAAI,CAAC,SAAS,EAAE;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,QAAQ,GAAG,0BAA0B,CACzC,oBAAoB,CAAC,GAAG,EACxB,uBAAuB,CAAC,oBAAoB,CAAC,SAAS,CAAC,QAAQ,CAAC,CACjE,CAAC;IACF,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1E,2BAA2B,CAAC,oBAAoB,CAAC,GAAG,EAAE;QACpD,GAAG,QAAQ;QACX,IAAI;KACL,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,kBAAkB,CAC/B,oBAAoB,CAAC,GAAG,EACxB,mBAAmB,CACpB,CAAC;IACF,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,WAAW,CAC/C,oBAAoB,EACpB,IAAI,EACJ,MAAM,CACP,CAAC;IACF,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,2BAA2B,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,iBAAiB,KAAK,WAAW,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QACtD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,qCAAqC,CACnC,KAAK,CAAC,cAAc,EACpB,oBAAoB,EACpB,EAAE,8BAA8B,EAAE,IAAI,EAAE,CACzC,CAAC;IACF,+BAA+B,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC3C,KAAK,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { encodeVersionVector, exportUpdatesSince } from \"@tearleads/loro\";\nimport {\n getDefaultContainerName,\n readContainerMetadataValue,\n writeContainerMetadataValue,\n} from \"../../../workflows/container-contents/metadata/containerMetadataDocument\";\nimport {\n createDetachedContainerMetadataState,\n installDetachedContainerMetadataState,\n} from \"../../../workflows/container-contents/metadata/metadataStateIsolation\";\nimport type { PersistContainerStateResult } from \"../../../workflows/container-contents/remoteHydration\";\nimport { removeMissingContainerState } from \"../containerState/missingContainerState\";\nimport type { ContainerWriteGuard } from \"../remoteWrites/writeGeneration\";\nimport { updateContainerContentsSnapshot } from \"../state\";\nimport type {\n ContainerContentsStoreSyncAgent,\n ContainerState,\n} from \"../syncAgent\";\nimport type { ContainerContentsStoreState } from \"../types\";\n\ntype PersistSystemContainerIcon = (\n containerState: ContainerState,\n icon: string | null,\n update: Uint8Array,\n) => Promise<PersistContainerStateResult[\"status\"]>;\n\nfunction normalizeSystemContainerIcon(\n icon: string | null | undefined,\n): string | null {\n return icon?.trim() || null;\n}\n\nexport async function applySystemContainerIcon(input: {\n readonly containerState: ContainerState;\n readonly icon: string | null | undefined;\n readonly persistIcon: PersistSystemContainerIcon;\n readonly state: ContainerContentsStoreState;\n readonly syncAgent: ContainerContentsStoreSyncAgent;\n readonly isCurrent?: ContainerWriteGuard | undefined;\n}): Promise<boolean> {\n const isCurrent = input.isCurrent ?? (() => true);\n const icon = normalizeSystemContainerIcon(input.icon);\n const currentIcon = input.containerState.container.icon ?? null;\n if (currentIcon === icon) {\n return true;\n }\n\n if (!isCurrent()) return false;\n const persistenceCandidate = await createDetachedContainerMetadataState(\n input.containerState,\n );\n if (!isCurrent()) return false;\n const metadata = readContainerMetadataValue(\n persistenceCandidate.doc,\n getDefaultContainerName(persistenceCandidate.container.parentId),\n );\n const sourceVersionVector = encodeVersionVector(persistenceCandidate.doc);\n writeContainerMetadataValue(persistenceCandidate.doc, {\n ...metadata,\n icon,\n });\n const update = exportUpdatesSince(\n persistenceCandidate.doc,\n sourceVersionVector,\n );\n const persistenceStatus = await input.persistIcon(\n persistenceCandidate,\n icon,\n update,\n );\n if (persistenceStatus === \"missing\") {\n removeMissingContainerState(input.state, input.containerState);\n }\n if (persistenceStatus !== \"persisted\" || !isCurrent()) {\n return false;\n }\n installDetachedContainerMetadataState(\n input.containerState,\n persistenceCandidate,\n { preserveConcurrentMetadataEdit: true },\n );\n updateContainerContentsSnapshot(input.state);\n if (input.containerState.record.documentId) {\n input.syncAgent.scheduleSync();\n }\n return true;\n}\n"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { inspectBlobSource, } from "../../../../data/documents/blob/shared/blobSourceSnapshot.js";
|
|
2
|
-
import { DEFAULT_BLOB_CHUNK_SIZE_BYTES } from "../../../../data/documents/blob/shared/crypto.js";
|
|
3
1
|
import { getDocumentAttachments } from "../../../../data/documents/documentContent.js";
|
|
2
|
+
import { DEFAULT_BLOB_CHUNK_SIZE_BYTES, inspectBlobSource, } from "../../../../workflows/blobs/index.js";
|
|
4
3
|
import { deletePendingAttachment } from "../attachments/attachmentPersistence.js";
|
|
5
4
|
import { resolveAttachmentUploadResume, } from "./attachmentUploadResume.js";
|
|
6
5
|
export function pendingAttachmentMatchesIntent(input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachmentSourceUpload.js","sourceRoot":"","sources":["attachmentSourceUpload.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"attachmentSourceUpload.js","sourceRoot":"","sources":["attachmentSourceUpload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,EAGL,6BAA6B,EAC7B,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAG/E,OAAO,EAEL,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAQlC,MAAM,UAAU,8BAA8B,CAC5C,KAAyB;IAEzB,OAAO,CACL,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI;QACxB,sBAAsB,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAC1C,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,iBAAiB,CAAC,MAAM;YAC9C,IAAI,CAAC,aAAa,KAAK,KAAK,CAAC,iBAAiB,CAAC,aAAa,CAC/D,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,KAAyB;IAEzB,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,KAAK,CAAC;IACjE,0EAA0E;IAC1E,kEAAkE;IAClE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CACpB,0CAA0C,iBAAiB,CAAC,MAAM,+EAA+E,CAClJ,CAAC;IACF,MAAM,uBAAuB,CAC3B,KAAK,EACL,iBAAiB,CAAC,MAAM,EACxB,iBAAiB,CAAC,UAAU,EAC5B,oBAAoB,CACrB,CAAC;IACF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,KAEC;IAKD,IAAI,SAAS,GACX,KAAK,CAAC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,IAAI,6BAA6B,CAAC;IAE5E,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAClE,IAAI,CAAC,8BAA8B,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxD,IAAI,KAAK,CAAC,iBAAiB,CAAC,aAAa,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,6BAA6B,CAChD,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,iBAAiB,EACvB,QAAQ,CAAC,MAAM,EACf,KAAK,CAAC,oBAAoB,CAC3B,CAAC;QACF,MAAM,iBAAiB,GACrB,MAAM,CAAC,SAAS,EAAE,QAAQ,IAAI,6BAA6B,CAAC;QAC9D,IAAI,CAAC,8BAA8B,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACxD,IAAI,iBAAiB,KAAK,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAC9B,CAAC;QACD,SAAS,GAAG,iBAAiB,CAAC;IAChC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["import { getDocumentAttachments } from \"../../../../data/documents/documentContent\";\nimport {\n type BlobByteSource,\n type BlobSourceSnapshot,\n DEFAULT_BLOB_CHUNK_SIZE_BYTES,\n inspectBlobSource,\n} from \"../../../../workflows/blobs\";\nimport type { PendingAttachmentRecord } from \"../../../../workflows/documents\";\nimport { deletePendingAttachment } from \"../attachments/attachmentPersistence\";\nimport type { DocumentStoreState } from \"../state\";\nimport type { DocumentStoreSyncGeneration } from \"../sync/syncGeneration\";\nimport {\n type AttachmentUploadResume,\n resolveAttachmentUploadResume,\n} from \"./attachmentUploadResume\";\n\ninterface PendingSourceInput {\n attachmentGeneration: DocumentStoreSyncGeneration;\n pendingAttachment: PendingAttachmentRecord;\n state: DocumentStoreState;\n}\n\nexport function pendingAttachmentMatchesIntent(\n input: PendingSourceInput,\n): boolean {\n return (\n input.state.doc !== null &&\n getDocumentAttachments(input.state.doc).some(\n (item) =>\n item.slotId === input.pendingAttachment.slotId &&\n item.contentSha256 === input.pendingAttachment.contentSha256,\n )\n );\n}\n\nexport async function dropUnavailablePendingAttachment(\n input: PendingSourceInput,\n): Promise<\"dropped\"> {\n const { state, pendingAttachment, attachmentGeneration } = input;\n // Unusable bytes or superseded intent cannot be retried. Delete only this\n // storage identity so a concurrently queued replacement survives.\n state.runtime.util.log(\n `Documents: dropping pending attachment ${pendingAttachment.slotId}; its bytes are unavailable or changed, or its content intent was superseded.`,\n );\n await deletePendingAttachment(\n state,\n pendingAttachment.slotId,\n pendingAttachment.storageKey,\n attachmentGeneration,\n );\n return \"dropped\";\n}\n\nexport async function resolveAttachmentSourceUpload(\n input: PendingSourceInput & {\n source: BlobByteSource;\n },\n): Promise<{\n readonly resume: AttachmentUploadResume;\n readonly snapshot: BlobSourceSnapshot;\n} | null> {\n let chunkSize =\n input.pendingAttachment.upload?.partSize ?? DEFAULT_BLOB_CHUNK_SIZE_BYTES;\n\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const snapshot = await inspectBlobSource(input.source, chunkSize);\n if (!pendingAttachmentMatchesIntent(input)) return null;\n if (input.pendingAttachment.contentSha256 !== snapshot.sha256) {\n return null;\n }\n const resume = await resolveAttachmentUploadResume(\n input.state,\n input.pendingAttachment,\n snapshot.sha256,\n input.attachmentGeneration,\n );\n const resolvedChunkSize =\n resume.multipart?.partSize ?? DEFAULT_BLOB_CHUNK_SIZE_BYTES;\n if (!pendingAttachmentMatchesIntent(input)) return null;\n if (resolvedChunkSize === snapshot.chunkSize) {\n return { resume, snapshot };\n }\n chunkSize = resolvedChunkSize;\n }\n\n throw new Error(\"Blob source changed while preparing its upload identity\");\n}\n"]}
|