@tearleads/client-sdk 0.1.44 → 0.1.45
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/persistence/container-contents/containerContentsPersistence.js +2 -3
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerCreateIntentSettlement.js +16 -16
- package/data/persistence/container-contents/containerCreateIntentSettlement.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +5 -11
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerDocumentReassignment.js +13 -13
- package/data/persistence/container-contents/containerDocumentReassignment.js.map +1 -1
- package/data/persistence/container-contents/containerHydrationPersistence.js +7 -4
- package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerIntentPersistence.js +43 -42
- package/data/persistence/container-contents/containerIntentPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +15 -20
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMoveAbandonPersistence.js +1 -6
- package/data/persistence/container-contents/containerMoveAbandonPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMoveIntentRows.js +9 -8
- package/data/persistence/container-contents/containerMoveIntentRows.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +4 -8
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRecoveryPersistence.js +20 -19
- package/data/persistence/container-contents/containerRecoveryPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerRemovalWork.js +10 -10
- package/data/persistence/container-contents/containerRemovalWork.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +21 -44
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/documentLinkRemovalRepair.js +12 -11
- package/data/persistence/container-contents/documentLinkRemovalRepair.js.map +1 -1
- package/data/persistence/container-contents/documentMoveIntentPersistence.js +53 -28
- package/data/persistence/container-contents/documentMoveIntentPersistence.js.map +1 -1
- package/data/persistence/container-contents/documentPlacementIntentEnqueue.js +9 -8
- package/data/persistence/container-contents/documentPlacementIntentEnqueue.js.map +1 -1
- package/data/persistence/container-contents/documentPurgePlacement.js +6 -6
- package/data/persistence/container-contents/documentPurgePlacement.js.map +1 -1
- package/data/persistence/container-contents/dormantContainerMetadata.js +1 -5
- package/data/persistence/container-contents/dormantContainerMetadata.js.map +1 -1
- package/data/persistence/container-contents/pendingContainerCreate.js +5 -5
- package/data/persistence/container-contents/pendingContainerCreate.js.map +1 -1
- package/data/persistence/containers/containerPersistence.js +10 -27
- package/data/persistence/containers/containerPersistence.js.map +1 -1
- package/data/persistence/containers/documentContainerProjectionPersistence.js +2 -2
- package/data/persistence/containers/documentContainerProjectionPersistence.js.map +1 -1
- package/data/persistence/containers/documentPlacement.js +10 -10
- package/data/persistence/containers/documentPlacement.js.map +1 -1
- package/data/persistence/documents/internal/discardDocument.js +5 -5
- package/data/persistence/documents/internal/discardDocument.js.map +1 -1
- package/data/persistence/documents/internal/documentDeletionPersistence.js +7 -9
- package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentMutationPersistence.js +6 -8
- package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
- package/data/persistence/documents/internal/ensureDocumentsSchema.js +2 -2
- package/data/persistence/documents/internal/ensureDocumentsSchema.js.map +1 -1
- package/data/persistence/documents/internal/orphanSideRows.js +3 -22
- package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
- package/data/persistence/organizations/organizationDataUsagePersistence.js +31 -64
- package/data/persistence/organizations/organizationDataUsagePersistence.js.map +1 -1
- package/data/persistence/organizations/organizationReadModelPurge.js +1 -5
- package/data/persistence/organizations/organizationReadModelPurge.js.map +1 -1
- package/data/persistence/principalCurrentAcknowledgementPersistence.js +24 -17
- package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
- package/data/persistence/principalHistoryIncompleteRetention.js +3 -9
- package/data/persistence/principalHistoryIncompleteRetention.js.map +1 -1
- package/data/persistence/principalHistoryStagePersistence.d.ts +3 -9
- package/data/persistence/principalHistoryStagePersistence.js +15 -25
- package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
- package/data/persistence/principalHistoryStageRetention.js +16 -15
- package/data/persistence/principalHistoryStageRetention.js.map +1 -1
- package/data/persistence/principalHistoryUnpublishedRetention.js +6 -13
- package/data/persistence/principalHistoryUnpublishedRetention.js.map +1 -1
- package/data/sqlite/containerSchema.d.ts +84 -180
- package/data/sqlite/containerSchema.js +14 -23
- package/data/sqlite/containerSchema.js.map +1 -1
- package/data/sqlite/documentPlacementIntentSchema.js +3 -50
- package/data/sqlite/documentPlacementIntentSchema.js.map +1 -1
- package/data/sqlite/documentSyncFailurePersistence.d.ts +16 -6
- package/data/sqlite/documentSyncFailurePersistence.js +44 -54
- package/data/sqlite/documentSyncFailurePersistence.js.map +1 -1
- package/data/sqlite/{documentPlacementIntentSchema.d.ts → localIntentSchema.d.ts} +162 -88
- package/data/sqlite/localIntentSchema.js +90 -0
- package/data/sqlite/localIntentSchema.js.map +1 -0
- package/data/sqlite/organizationDataUsageSchema.js +11 -17
- package/data/sqlite/organizationDataUsageSchema.js.map +1 -1
- package/data/sqlite/principalHistoryRetentionSchema.js +0 -15
- package/data/sqlite/principalHistoryRetentionSchema.js.map +1 -1
- package/data/sqlite/principalHistoryStageSchema.d.ts +44 -2
- package/data/sqlite/principalHistoryStageSchema.js +14 -2
- package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
- package/data/sqlite/schema.d.ts +947 -2112
- package/data/sqlite/schema.js +26 -134
- package/data/sqlite/schema.js.map +1 -1
- package/package.json +1 -1
- package/workflows/container-contents/documentPriming.js +6 -10
- package/workflows/container-contents/documentPriming.js.map +1 -1
- package/workflows/container-contents/documentQueries/sql.js +11 -10
- package/workflows/container-contents/documentQueries/sql.js.map +1 -1
- package/workflows/container-contents/documentQueries.js +2 -2
- package/workflows/container-contents/documentQueries.js.map +1 -1
- package/workflows/container-contents/pendingDownloads.js +2 -5
- package/workflows/container-contents/pendingDownloads.js.map +1 -1
- package/workflows/container-contents/pendingWrites/deferredTails.js +3 -11
- package/workflows/container-contents/pendingWrites/deferredTails.js.map +1 -1
- package/workflows/container-contents/pendingWrites/sources.js +56 -80
- package/workflows/container-contents/pendingWrites/sources.js.map +1 -1
- package/workflows/container-contents/pendingWrites.js +6 -4
- package/workflows/container-contents/pendingWrites.js.map +1 -1
- package/workflows/container-contents/remoteContainerState.js +2 -1
- package/workflows/container-contents/remoteContainerState.js.map +1 -1
- package/workflows/sync/remoteReset.js +16 -23
- package/workflows/sync/remoteReset.js.map +1 -1
- package/workflows/sync/remoteResetPrincipalScope.js +1 -2
- package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
- package/workflows/sync/remoteResetScope.js +15 -8
- package/workflows/sync/remoteResetScope.js.map +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eq } from "drizzle-orm";
|
|
2
2
|
import { hasQueuedDocumentUpdates, settleQueuedDocumentUpdatesInTransaction, } from "../../sqlite/documentPendingUpdatePersistence.js";
|
|
3
3
|
import { enqueueDocumentPendingUpdate, ensureDocumentProjectionTables, ensureDocumentTables, } from "../../sqlite/documentPersistence.js";
|
|
4
|
-
import {
|
|
4
|
+
import { containerHydrationTombstones, containers, documentContainerProjectionTables, localIntentTables, } from "../../sqlite/schema.js";
|
|
5
5
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
6
6
|
import { ensureSqlTables, runOncePerConnection, runSerializedSqlMutation, } from "../../sqlite/sqlSchema.js";
|
|
7
7
|
import { ensureContainerTables, loadContainerById, loadContainers as loadContainerRecords, } from "../containers/containerPersistence.js";
|
|
@@ -89,8 +89,7 @@ export const sqlContainerContentsPersistence = {
|
|
|
89
89
|
await runOncePerConnection(execSql, "ensure:container-contents", () => runSerializedSqlMutation(execSql, async (lockedExecSql) => {
|
|
90
90
|
await ensureContainerTables(lockedExecSql);
|
|
91
91
|
await ensureDocumentTables(lockedExecSql);
|
|
92
|
-
await ensureSqlTables(lockedExecSql,
|
|
93
|
-
await ensureSqlTables(lockedExecSql, containerMoveIntentTables);
|
|
92
|
+
await ensureSqlTables(lockedExecSql, localIntentTables);
|
|
94
93
|
await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);
|
|
95
94
|
await ensureDocumentProjectionTables(lockedExecSql);
|
|
96
95
|
await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerContentsPersistence.js","sourceRoot":"","sources":["containerContentsPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../sqlite/documentPendingUpdatePersistence\";\nimport {\n enqueueDocumentPendingUpdate,\n ensureDocumentProjectionTables,\n ensureDocumentTables,\n} from \"../../sqlite/documentPersistence\";\nimport {\n containerCreateIntentTables,\n containerHydrationTombstones,\n containerMoveIntentTables,\n containers,\n documentContainerProjectionTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runOncePerConnection,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport {\n ensureContainerTables,\n loadContainerById,\n loadContainers as loadContainerRecords,\n} from \"../containers/containerPersistence\";\nimport { sqlContainerSyncWatermarkPersistence } from \"../containers/containerSyncWatermarkPersistence\";\nimport { getLatestTimestamp } from \"../latestTimestamp\";\nimport {\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n listDormantMetadataSweepRequests,\n} from \"./dormantMetadataSweep\";\n\nexport type {\n ContainerContentsPersistence,\n ContainerCreateIntentRecord,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n ContainerMoveIntentRecord,\n LocalRootDescendantReparentInput,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nexport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n SaveContainerOptions,\n SaveContainerWithPendingUpdateOptions,\n} from \"./containerContentsPersistenceTypes\";\nimport { deleteStoredContainers } from \"./containerDeletionPersistence\";\nimport {\n commitStoredHydratedContainer,\n loadStoredHeldContainerBinding,\n} from \"./containerHydrationPersistence\";\nimport { containerIntentPersistence } from \"./containerIntentPersistence\";\nimport {\n commitStoredMetadataMutation,\n settleStoredMetadataPendingUpdates,\n} from \"./containerMetadataMutationPersistence\";\nimport { containerMetadataPullContinuationPersistence } from \"./containerMetadataPullContinuationPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { abandonStoredMoveIntentRevision } from \"./containerMoveAbandonPersistence\";\nimport { containerPendingUpdatePersistence } from \"./containerPendingUpdatePersistence\";\nimport { rebindStoredHeldContainer } from \"./containerRebindPersistence\";\nimport { containerReconcilePersistence } from \"./containerReconcilePersistence\";\nimport { isSupersededContainerBinding } from \"./supersededContainerBindings\";\n\nasync function saveStoredContainer(\n execSql: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[0],\n container: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[1],\n record: ContainerMetadataRecord | null,\n options?:\n | SaveContainerOptions\n | SaveContainerWithPendingUpdateOptions\n | undefined,\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt =\n options?.localUpdatedAt ?? options?.updatedAt ?? new Date().toISOString();\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const save = async (tx: ClientSQLiteTransactionScope) => {\n const saved = await saveContainerContentsContainerRows({\n container,\n createIntent: options?.createIntent,\n moveIntent: options?.moveIntent,\n record,\n serverTimestamps: options?.serverTimestamps,\n tx,\n localUpdatedAt,\n });\n if (options && \"pendingUpdate\" in options) {\n await enqueueDocumentPendingUpdate(\n lockedExecSql,\n getContainerMetadataScope(container.id),\n options.pendingUpdate,\n );\n }\n return saved;\n };\n if (!options?.stillCurrent) {\n return runtime.transaction(save);\n }\n const outcome = await runtime.guardedTransaction(\n save,\n options.stillCurrent,\n { behavior: \"immediate\" },\n );\n // Guarded callers recheck the same monotonic generation immediately after\n // this await. Returning the untouched candidate keeps the long-standing\n // non-null save contract while the transaction itself remains rolled back.\n return outcome.result ?? container;\n });\n}\n\nexport const sqlContainerContentsPersistence: ContainerContentsPersistence = {\n ...containerIntentPersistence,\n ...containerMetadataPullContinuationPersistence,\n commitHydratedContainer: commitStoredHydratedContainer,\n commitMetadataMutation: commitStoredMetadataMutation,\n settleAcceptedMetadataPendingUpdates: settleStoredMetadataPendingUpdates,\n listDormantMetadataSweepRequests,\n ...containerPendingUpdatePersistence,\n ...containerReconcilePersistence,\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n async containerExists(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ id: containers.id })\n .from(containers)\n .where(eq(containers.id, containerId))\n .limit(1);\n return rows.length > 0;\n },\n async deleteContainer(execSql, containerId, options) {\n await sqlContainerContentsPersistence.deleteContainers(execSql, [\n {\n containerId,\n reason: options?.reason ?? \"deleted\",\n updatedAt: options?.updatedAt ?? new Date().toISOString(),\n },\n ]);\n },\n async deleteContainers(execSql, removals, options) {\n return deleteStoredContainers(execSql, removals, options);\n },\n async ensureSchema(execSql) {\n // Once ensured on this connection, skip the outer mutation lock entirely:\n // ensureSchema runs on every query path, and re-acquiring the lock just to\n // no-op would queue reads behind unrelated writes.\n await runOncePerConnection(execSql, \"ensure:container-contents\", () =>\n runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await ensureSqlTables(lockedExecSql, containerCreateIntentTables);\n await ensureSqlTables(lockedExecSql, containerMoveIntentTables);\n await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);\n await ensureDocumentProjectionTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n }),\n );\n },\n async loadHeldContainerBinding(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return loadStoredHeldContainerBinding(execSql, containerId);\n },\n async isSupersededContainerBinding(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return isSupersededContainerBinding(execSql, input);\n },\n async abandonMoveIntentRevision(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return abandonStoredMoveIntentRevision(execSql, input);\n },\n async rebindHeldContainer(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return rebindStoredHeldContainer(execSql, input);\n },\n async loadContainerMetadataRecord(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return selectContainerMetadataRecord(execSql, containerId);\n },\n async loadContainerHydrationTombstones(execSql) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n containerId: containerHydrationTombstones.containerId,\n generation: containerHydrationTombstones.generation,\n reason: containerHydrationTombstones.reason,\n updatedAt: containerHydrationTombstones.updatedAt,\n })\n .from(containerHydrationTombstones)\n .where(eq(containerHydrationTombstones.cleared, false));\n return rows.flatMap((row) =>\n row.reason === \"access_revoked\" || row.reason === \"deleted\"\n ? [{ ...row, reason: row.reason }]\n : [],\n );\n },\n async loadContainers(execSql) {\n const containers = await loadContainerRecords(execSql);\n const storedContainers = await Promise.all(\n containers.map(async (container) => ({\n container,\n record: await selectContainerMetadataRecord(execSql, container.id),\n })),\n );\n\n return storedContainers;\n },\n async loadContainerMetadataState(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const container = await loadContainerById(execSql, containerId);\n if (!container) {\n return null;\n }\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n },\n async saveContainer(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerWithPendingUpdate(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerAndDeletePendingUpdates(\n execSql,\n container,\n record,\n pendingUpdateIds,\n ) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const scope = getContainerMetadataScope(container.id);\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n scope,\n pendingUpdateIds,\n );\n const hasRemainingPendingUpdates = await hasQueuedDocumentUpdates(\n tx,\n scope,\n );\n const containerToSave = hasRemainingPendingUpdates\n ? container\n : {\n ...container,\n serverUpdatedAt: getLatestTimestamp(\n container.serverUpdatedAt,\n localUpdatedAt,\n ),\n };\n\n return saveContainerContentsContainerRows({\n container: containerToSave,\n record,\n tx,\n localUpdatedAt,\n });\n },\n );\n });\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"containerContentsPersistence.js","sourceRoot":"","sources":["containerContentsPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { eq } from \"drizzle-orm\";\nimport {\n hasQueuedDocumentUpdates,\n settleQueuedDocumentUpdatesInTransaction,\n} from \"../../sqlite/documentPendingUpdatePersistence\";\nimport {\n enqueueDocumentPendingUpdate,\n ensureDocumentProjectionTables,\n ensureDocumentTables,\n} from \"../../sqlite/documentPersistence\";\nimport {\n containerHydrationTombstones,\n containers,\n documentContainerProjectionTables,\n localIntentTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runOncePerConnection,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport {\n ensureContainerTables,\n loadContainerById,\n loadContainers as loadContainerRecords,\n} from \"../containers/containerPersistence\";\nimport { sqlContainerSyncWatermarkPersistence } from \"../containers/containerSyncWatermarkPersistence\";\nimport { getLatestTimestamp } from \"../latestTimestamp\";\nimport {\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n listDormantMetadataSweepRequests,\n} from \"./dormantMetadataSweep\";\n\nexport type {\n ContainerContentsPersistence,\n ContainerCreateIntentRecord,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n ContainerMoveIntentRecord,\n LocalRootDescendantReparentInput,\n StoredContainerState,\n} from \"./containerContentsPersistenceTypes\";\nexport { CONTAINER_METADATA_APP_KIND } from \"./dormantContainerMetadata\";\n\nimport type {\n ContainerContentsPersistence,\n ContainerMetadataRecord,\n SaveContainerOptions,\n SaveContainerWithPendingUpdateOptions,\n} from \"./containerContentsPersistenceTypes\";\nimport { deleteStoredContainers } from \"./containerDeletionPersistence\";\nimport {\n commitStoredHydratedContainer,\n loadStoredHeldContainerBinding,\n} from \"./containerHydrationPersistence\";\nimport { containerIntentPersistence } from \"./containerIntentPersistence\";\nimport {\n commitStoredMetadataMutation,\n settleStoredMetadataPendingUpdates,\n} from \"./containerMetadataMutationPersistence\";\nimport { containerMetadataPullContinuationPersistence } from \"./containerMetadataPullContinuationPersistence\";\nimport {\n getContainerMetadataScope,\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { abandonStoredMoveIntentRevision } from \"./containerMoveAbandonPersistence\";\nimport { containerPendingUpdatePersistence } from \"./containerPendingUpdatePersistence\";\nimport { rebindStoredHeldContainer } from \"./containerRebindPersistence\";\nimport { containerReconcilePersistence } from \"./containerReconcilePersistence\";\nimport { isSupersededContainerBinding } from \"./supersededContainerBindings\";\n\nasync function saveStoredContainer(\n execSql: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[0],\n container: Parameters<ContainerContentsPersistence[\"saveContainer\"]>[1],\n record: ContainerMetadataRecord | null,\n options?:\n | SaveContainerOptions\n | SaveContainerWithPendingUpdateOptions\n | undefined,\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt =\n options?.localUpdatedAt ?? options?.updatedAt ?? new Date().toISOString();\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const save = async (tx: ClientSQLiteTransactionScope) => {\n const saved = await saveContainerContentsContainerRows({\n container,\n createIntent: options?.createIntent,\n moveIntent: options?.moveIntent,\n record,\n serverTimestamps: options?.serverTimestamps,\n tx,\n localUpdatedAt,\n });\n if (options && \"pendingUpdate\" in options) {\n await enqueueDocumentPendingUpdate(\n lockedExecSql,\n getContainerMetadataScope(container.id),\n options.pendingUpdate,\n );\n }\n return saved;\n };\n if (!options?.stillCurrent) {\n return runtime.transaction(save);\n }\n const outcome = await runtime.guardedTransaction(\n save,\n options.stillCurrent,\n { behavior: \"immediate\" },\n );\n // Guarded callers recheck the same monotonic generation immediately after\n // this await. Returning the untouched candidate keeps the long-standing\n // non-null save contract while the transaction itself remains rolled back.\n return outcome.result ?? container;\n });\n}\n\nexport const sqlContainerContentsPersistence: ContainerContentsPersistence = {\n ...containerIntentPersistence,\n ...containerMetadataPullContinuationPersistence,\n commitHydratedContainer: commitStoredHydratedContainer,\n commitMetadataMutation: commitStoredMetadataMutation,\n settleAcceptedMetadataPendingUpdates: settleStoredMetadataPendingUpdates,\n listDormantMetadataSweepRequests,\n ...containerPendingUpdatePersistence,\n ...containerReconcilePersistence,\n claimDormantMetadataSweepAttempt,\n completeDormantMetadataSweepRequest,\n async containerExists(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ id: containers.id })\n .from(containers)\n .where(eq(containers.id, containerId))\n .limit(1);\n return rows.length > 0;\n },\n async deleteContainer(execSql, containerId, options) {\n await sqlContainerContentsPersistence.deleteContainers(execSql, [\n {\n containerId,\n reason: options?.reason ?? \"deleted\",\n updatedAt: options?.updatedAt ?? new Date().toISOString(),\n },\n ]);\n },\n async deleteContainers(execSql, removals, options) {\n return deleteStoredContainers(execSql, removals, options);\n },\n async ensureSchema(execSql) {\n // Once ensured on this connection, skip the outer mutation lock entirely:\n // ensureSchema runs on every query path, and re-acquiring the lock just to\n // no-op would queue reads behind unrelated writes.\n await runOncePerConnection(execSql, \"ensure:container-contents\", () =>\n runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentTables(lockedExecSql);\n await ensureSqlTables(lockedExecSql, localIntentTables);\n await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);\n await ensureDocumentProjectionTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n }),\n );\n },\n async loadHeldContainerBinding(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return loadStoredHeldContainerBinding(execSql, containerId);\n },\n async isSupersededContainerBinding(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return isSupersededContainerBinding(execSql, input);\n },\n async abandonMoveIntentRevision(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return abandonStoredMoveIntentRevision(execSql, input);\n },\n async rebindHeldContainer(execSql, input) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return rebindStoredHeldContainer(execSql, input);\n },\n async loadContainerMetadataRecord(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n return selectContainerMetadataRecord(execSql, containerId);\n },\n async loadContainerHydrationTombstones(execSql) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({\n containerId: containerHydrationTombstones.containerId,\n generation: containerHydrationTombstones.generation,\n reason: containerHydrationTombstones.reason,\n updatedAt: containerHydrationTombstones.updatedAt,\n })\n .from(containerHydrationTombstones)\n .where(eq(containerHydrationTombstones.cleared, false));\n return rows.flatMap((row) =>\n row.reason === \"access_revoked\" || row.reason === \"deleted\"\n ? [{ ...row, reason: row.reason }]\n : [],\n );\n },\n async loadContainers(execSql) {\n const containers = await loadContainerRecords(execSql);\n const storedContainers = await Promise.all(\n containers.map(async (container) => ({\n container,\n record: await selectContainerMetadataRecord(execSql, container.id),\n })),\n );\n\n return storedContainers;\n },\n async loadContainerMetadataState(execSql, containerId) {\n await sqlContainerContentsPersistence.ensureSchema(execSql);\n const container = await loadContainerById(execSql, containerId);\n if (!container) {\n return null;\n }\n return {\n container,\n record: await selectContainerMetadataRecord(execSql, containerId),\n };\n },\n async saveContainer(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerWithPendingUpdate(execSql, container, record, options) {\n return saveStoredContainer(execSql, container, record, options);\n },\n async saveContainerAndDeletePendingUpdates(\n execSql,\n container,\n record,\n pendingUpdateIds,\n ) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const localUpdatedAt = new Date().toISOString();\n return getClientSQLitePersistenceRuntime(lockedExecSql).transaction(\n async (tx) => {\n const scope = getContainerMetadataScope(container.id);\n await settleQueuedDocumentUpdatesInTransaction(\n tx,\n scope,\n pendingUpdateIds,\n );\n const hasRemainingPendingUpdates = await hasQueuedDocumentUpdates(\n tx,\n scope,\n );\n const containerToSave = hasRemainingPendingUpdates\n ? container\n : {\n ...container,\n serverUpdatedAt: getLatestTimestamp(\n container.serverUpdatedAt,\n localUpdatedAt,\n ),\n };\n\n return saveContainerContentsContainerRows({\n container: containerToSave,\n record,\n tx,\n localUpdatedAt,\n });\n },\n );\n });\n },\n};\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { and, eq } from "drizzle-orm";
|
|
2
|
-
import {
|
|
2
|
+
import { inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema.js";
|
|
3
3
|
import { CONTAINER_CREATE_INTENT_TYPE, CONTAINER_MOVE_INTENT_TYPE, } from "./containerContentsPersistenceTypes.js";
|
|
4
4
|
import { saveContainerMoveIntent } from "./containerMoveIntentRows.js";
|
|
5
5
|
async function markContainerCreateIntentRevisionSynced(input) {
|
|
6
6
|
const updated = await input.tx
|
|
7
|
-
.update(
|
|
7
|
+
.update(localIntents)
|
|
8
8
|
.set({
|
|
9
9
|
syncStatus: "synced",
|
|
10
10
|
remoteContainerId: input.remoteContainerId,
|
|
@@ -13,8 +13,8 @@ async function markContainerCreateIntentRevisionSynced(input) {
|
|
|
13
13
|
lastError: null,
|
|
14
14
|
updatedAt: new Date().toISOString(),
|
|
15
15
|
})
|
|
16
|
-
.where(and(eq(
|
|
17
|
-
.returning({ containerId:
|
|
16
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate), eq(localIntents.subjectId, input.containerId), eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE), eq(localIntents.syncStatus, "pending"), eq(localIntents.id, input.expectedIntentId), eq(localIntents.updatedAt, input.expectedUpdatedAt)))
|
|
17
|
+
.returning({ containerId: localIntents.subjectId });
|
|
18
18
|
return updated.length > 0;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -41,18 +41,18 @@ function owedCreateMove(input) {
|
|
|
41
41
|
* parent is done and is dropped.
|
|
42
42
|
*/
|
|
43
43
|
async function rebaseQueuedMove(input) {
|
|
44
|
-
const queued = and(eq(
|
|
44
|
+
const queued = and(inLocalIntentLane(LOCAL_INTENT_LANES.containerMove), eq(localIntents.subjectId, input.containerId), eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE));
|
|
45
45
|
const arrived = await input.tx
|
|
46
|
-
.delete(
|
|
47
|
-
.where(and(queued, eq(
|
|
48
|
-
.returning({ containerId:
|
|
46
|
+
.delete(localIntents)
|
|
47
|
+
.where(and(queued, eq(localIntents.targetContainerId, input.supersededMovePreviousParentId)))
|
|
48
|
+
.returning({ containerId: localIntents.subjectId });
|
|
49
49
|
if (arrived.length > 0)
|
|
50
50
|
return "synced";
|
|
51
51
|
const rebased = await input.tx
|
|
52
|
-
.update(
|
|
53
|
-
.set({
|
|
52
|
+
.update(localIntents)
|
|
53
|
+
.set({ sourceContainerId: input.supersededMovePreviousParentId })
|
|
54
54
|
.where(queued)
|
|
55
|
-
.returning({ containerId:
|
|
55
|
+
.returning({ containerId: localIntents.subjectId });
|
|
56
56
|
return rebased.length > 0 ? "converted-to-move" : "none";
|
|
57
57
|
}
|
|
58
58
|
async function queueOwedCreateMove(input) {
|
|
@@ -90,12 +90,12 @@ export async function settleContainerCreateIntentRevision(input) {
|
|
|
90
90
|
}
|
|
91
91
|
const [currentIntent] = await input.tx
|
|
92
92
|
.select({
|
|
93
|
-
id:
|
|
94
|
-
parentContainerId:
|
|
95
|
-
updatedAt:
|
|
93
|
+
id: localIntents.id,
|
|
94
|
+
parentContainerId: localIntents.targetContainerId,
|
|
95
|
+
updatedAt: localIntents.updatedAt,
|
|
96
96
|
})
|
|
97
|
-
.from(
|
|
98
|
-
.where(and(eq(
|
|
97
|
+
.from(localIntents)
|
|
98
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate), eq(localIntents.subjectId, input.containerId), eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE), eq(localIntents.syncStatus, "pending")))
|
|
99
99
|
.limit(1);
|
|
100
100
|
if (!currentIntent?.id)
|
|
101
101
|
return "superseded";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerCreateIntentSettlement.js","sourceRoot":"","sources":["containerCreateIntentSettlement.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport {\n containerCreateIntents,\n containerMoveIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n CONTAINER_CREATE_INTENT_TYPE,\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerMoveIntentInput,\n} from \"./containerContentsPersistenceTypes\";\nimport { saveContainerMoveIntent } from \"./containerMoveIntentRows\";\n\nasync function markContainerCreateIntentRevisionSynced(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n remoteContainerId: string;\n remoteMetadataAccessStateHash: string;\n remoteMetadataDocumentId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const updated = await input.tx\n .update(containerCreateIntents)\n .set({\n syncStatus: \"synced\",\n remoteContainerId: input.remoteContainerId,\n remoteMetadataDocumentId: input.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash: input.remoteMetadataAccessStateHash,\n lastError: null,\n updatedAt: new Date().toISOString(),\n })\n .where(\n and(\n eq(containerCreateIntents.containerId, input.containerId),\n eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(containerCreateIntents.syncStatus, \"pending\"),\n eq(containerCreateIntents.id, input.expectedIntentId),\n eq(containerCreateIntents.updatedAt, input.expectedUpdatedAt),\n ),\n )\n .returning({ containerId: containerCreateIntents.containerId });\n return updated.length > 0;\n}\n\n/**\n * The move an adopted create still owes: to the desired parent, citing where\n * the folder is now. A desired parent equal to the created one means the user\n * never moved it away, so a later remote move by another writer stands.\n */\nfunction owedCreateMove(input: {\n readonly createdParentContainerId?: string | undefined;\n readonly desiredParentContainerId: string;\n readonly supersededMovePreviousParentId: string;\n}): ContainerMoveIntentInput | null {\n const desired = input.desiredParentContainerId;\n if (\n desired === input.supersededMovePreviousParentId ||\n desired === input.createdParentContainerId\n ) {\n return null;\n }\n return {\n parentContainerId: desired,\n previousParentContainerId: input.supersededMovePreviousParentId,\n };\n}\n\n/**\n * A local move of a folder the listing already carried queues its own move\n * intent, which is newer than the create's parent: it keeps its destination,\n * and now cites where the folder sits remotely rather than the parent it was\n * queued from, which never committed. One whose destination is already that\n * parent is done and is dropped.\n */\nasync function rebaseQueuedMove(input: {\n readonly containerId: string;\n readonly supersededMovePreviousParentId: string;\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<\"converted-to-move\" | \"none\" | \"synced\"> {\n const queued = and(\n eq(containerMoveIntents.containerId, input.containerId),\n eq(containerMoveIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n );\n const arrived = await input.tx\n .delete(containerMoveIntents)\n .where(\n and(\n queued,\n eq(\n containerMoveIntents.parentContainerId,\n input.supersededMovePreviousParentId,\n ),\n ),\n )\n .returning({ containerId: containerMoveIntents.containerId });\n if (arrived.length > 0) return \"synced\";\n const rebased = await input.tx\n .update(containerMoveIntents)\n .set({ previousParentContainerId: input.supersededMovePreviousParentId })\n .where(queued)\n .returning({ containerId: containerMoveIntents.containerId });\n return rebased.length > 0 ? \"converted-to-move\" : \"none\";\n}\n\nasync function queueOwedCreateMove(input: {\n readonly containerId: string;\n readonly createdParentContainerId?: string | undefined;\n readonly desiredParentContainerId: string;\n readonly supersededMovePreviousParentId: string;\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<\"converted-to-move\" | \"synced\"> {\n const queued = await rebaseQueuedMove(input);\n if (queued !== \"none\") return queued;\n const moveIntent = owedCreateMove(input);\n if (!moveIntent) return \"synced\";\n await saveContainerMoveIntent({\n containerId: input.containerId,\n moveIntent,\n tx: input.tx,\n updatedAt: new Date().toISOString(),\n });\n return \"converted-to-move\";\n}\n\nexport async function settleContainerCreateIntentRevision(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n remoteContainerId: string;\n remoteMetadataAccessStateHash: string;\n remoteMetadataDocumentId: string;\n supersededMovePreviousParentId?: string | undefined;\n createdParentContainerId?: string | undefined;\n desiredParentContainerId?: string | undefined;\n tx: ClientSQLiteTransactionScope;\n}): Promise<\"converted-to-move\" | \"superseded\" | \"synced\"> {\n const previousParentId = input.supersededMovePreviousParentId;\n if (await markContainerCreateIntentRevisionSynced(input)) {\n // An adopted create may still owe a move: the user can move the folder\n // after its create committed.\n if (\n previousParentId === undefined ||\n input.desiredParentContainerId === undefined\n ) {\n return \"synced\";\n }\n return queueOwedCreateMove({\n ...input,\n desiredParentContainerId: input.desiredParentContainerId,\n supersededMovePreviousParentId: previousParentId,\n });\n }\n if (previousParentId === undefined) {\n return \"superseded\";\n }\n\n const [currentIntent] = await input.tx\n .select({\n id: containerCreateIntents.id,\n parentContainerId: containerCreateIntents.parentContainerId,\n updatedAt: containerCreateIntents.updatedAt,\n })\n .from(containerCreateIntents)\n .where(\n and(\n eq(containerCreateIntents.containerId, input.containerId),\n eq(containerCreateIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(containerCreateIntents.syncStatus, \"pending\"),\n ),\n )\n .limit(1);\n if (!currentIntent?.id) return \"superseded\";\n\n const adopted = await markContainerCreateIntentRevisionSynced({\n ...input,\n expectedIntentId: currentIntent.id,\n expectedUpdatedAt: currentIntent.updatedAt,\n });\n if (!adopted) return \"superseded\";\n return queueOwedCreateMove({\n ...input,\n desiredParentContainerId: currentIntent.parentContainerId,\n supersededMovePreviousParentId: previousParentId,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerCreateIntentSettlement.js","sourceRoot":"","sources":["containerCreateIntentSettlement.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport {\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n CONTAINER_CREATE_INTENT_TYPE,\n CONTAINER_MOVE_INTENT_TYPE,\n type ContainerMoveIntentInput,\n} from \"./containerContentsPersistenceTypes\";\nimport { saveContainerMoveIntent } from \"./containerMoveIntentRows\";\n\nasync function markContainerCreateIntentRevisionSynced(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n remoteContainerId: string;\n remoteMetadataAccessStateHash: string;\n remoteMetadataDocumentId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const updated = await input.tx\n .update(localIntents)\n .set({\n syncStatus: \"synced\",\n remoteContainerId: input.remoteContainerId,\n remoteMetadataDocumentId: input.remoteMetadataDocumentId,\n remoteMetadataAccessStateHash: input.remoteMetadataAccessStateHash,\n lastError: null,\n updatedAt: new Date().toISOString(),\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.subjectId, input.containerId),\n eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(localIntents.syncStatus, \"pending\"),\n eq(localIntents.id, input.expectedIntentId),\n eq(localIntents.updatedAt, input.expectedUpdatedAt),\n ),\n )\n .returning({ containerId: localIntents.subjectId });\n return updated.length > 0;\n}\n\n/**\n * The move an adopted create still owes: to the desired parent, citing where\n * the folder is now. A desired parent equal to the created one means the user\n * never moved it away, so a later remote move by another writer stands.\n */\nfunction owedCreateMove(input: {\n readonly createdParentContainerId?: string | undefined;\n readonly desiredParentContainerId: string;\n readonly supersededMovePreviousParentId: string;\n}): ContainerMoveIntentInput | null {\n const desired = input.desiredParentContainerId;\n if (\n desired === input.supersededMovePreviousParentId ||\n desired === input.createdParentContainerId\n ) {\n return null;\n }\n return {\n parentContainerId: desired,\n previousParentContainerId: input.supersededMovePreviousParentId,\n };\n}\n\n/**\n * A local move of a folder the listing already carried queues its own move\n * intent, which is newer than the create's parent: it keeps its destination,\n * and now cites where the folder sits remotely rather than the parent it was\n * queued from, which never committed. One whose destination is already that\n * parent is done and is dropped.\n */\nasync function rebaseQueuedMove(input: {\n readonly containerId: string;\n readonly supersededMovePreviousParentId: string;\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<\"converted-to-move\" | \"none\" | \"synced\"> {\n const queued = and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, input.containerId),\n eq(localIntents.intentType, CONTAINER_MOVE_INTENT_TYPE),\n );\n const arrived = await input.tx\n .delete(localIntents)\n .where(\n and(\n queued,\n eq(\n localIntents.targetContainerId,\n input.supersededMovePreviousParentId,\n ),\n ),\n )\n .returning({ containerId: localIntents.subjectId });\n if (arrived.length > 0) return \"synced\";\n const rebased = await input.tx\n .update(localIntents)\n .set({ sourceContainerId: input.supersededMovePreviousParentId })\n .where(queued)\n .returning({ containerId: localIntents.subjectId });\n return rebased.length > 0 ? \"converted-to-move\" : \"none\";\n}\n\nasync function queueOwedCreateMove(input: {\n readonly containerId: string;\n readonly createdParentContainerId?: string | undefined;\n readonly desiredParentContainerId: string;\n readonly supersededMovePreviousParentId: string;\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<\"converted-to-move\" | \"synced\"> {\n const queued = await rebaseQueuedMove(input);\n if (queued !== \"none\") return queued;\n const moveIntent = owedCreateMove(input);\n if (!moveIntent) return \"synced\";\n await saveContainerMoveIntent({\n containerId: input.containerId,\n moveIntent,\n tx: input.tx,\n updatedAt: new Date().toISOString(),\n });\n return \"converted-to-move\";\n}\n\nexport async function settleContainerCreateIntentRevision(input: {\n containerId: string;\n expectedIntentId: string;\n expectedUpdatedAt: string;\n remoteContainerId: string;\n remoteMetadataAccessStateHash: string;\n remoteMetadataDocumentId: string;\n supersededMovePreviousParentId?: string | undefined;\n createdParentContainerId?: string | undefined;\n desiredParentContainerId?: string | undefined;\n tx: ClientSQLiteTransactionScope;\n}): Promise<\"converted-to-move\" | \"superseded\" | \"synced\"> {\n const previousParentId = input.supersededMovePreviousParentId;\n if (await markContainerCreateIntentRevisionSynced(input)) {\n // An adopted create may still owe a move: the user can move the folder\n // after its create committed.\n if (\n previousParentId === undefined ||\n input.desiredParentContainerId === undefined\n ) {\n return \"synced\";\n }\n return queueOwedCreateMove({\n ...input,\n desiredParentContainerId: input.desiredParentContainerId,\n supersededMovePreviousParentId: previousParentId,\n });\n }\n if (previousParentId === undefined) {\n return \"superseded\";\n }\n\n const [currentIntent] = await input.tx\n .select({\n id: localIntents.id,\n parentContainerId: localIntents.targetContainerId,\n updatedAt: localIntents.updatedAt,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerCreate),\n eq(localIntents.subjectId, input.containerId),\n eq(localIntents.intentType, CONTAINER_CREATE_INTENT_TYPE),\n eq(localIntents.syncStatus, \"pending\"),\n ),\n )\n .limit(1);\n if (!currentIntent?.id) return \"superseded\";\n\n const adopted = await markContainerCreateIntentRevisionSynced({\n ...input,\n expectedIntentId: currentIntent.id,\n expectedUpdatedAt: currentIntent.updatedAt,\n });\n if (!adopted) return \"superseded\";\n return queueOwedCreateMove({\n ...input,\n desiredParentContainerId: currentIntent.parentContainerId,\n supersededMovePreviousParentId: previousParentId,\n });\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { inArray } from "drizzle-orm";
|
|
1
|
+
import { and, inArray } from "drizzle-orm";
|
|
2
2
|
import { ensureDocumentProjectionTables } from "../../sqlite/documentPersistence.js";
|
|
3
|
-
import {
|
|
3
|
+
import { containers, documentContainerProjectionTables, documentPlacementIntentTables, inContainerIntentLanes, localIntents, } from "../../sqlite/schema.js";
|
|
4
4
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
5
5
|
import { ensureSqlTables, runSerializedSqlMutation, } from "../../sqlite/sqlSchema.js";
|
|
6
6
|
import { deleteContainerRowsInTransaction, ensureContainerTables, } from "../containers/containerPersistence.js";
|
|
@@ -111,12 +111,8 @@ async function applyContainerRemovals(input) {
|
|
|
111
111
|
else {
|
|
112
112
|
await repairLinkIntentsForRemovedContainers({ containerIds, tx: input.tx });
|
|
113
113
|
await input.tx
|
|
114
|
-
.delete(
|
|
115
|
-
.where(inArray(
|
|
116
|
-
.run();
|
|
117
|
-
await input.tx
|
|
118
|
-
.delete(containerMoveIntents)
|
|
119
|
-
.where(inArray(containerMoveIntents.containerId, containerIds))
|
|
114
|
+
.delete(localIntents)
|
|
115
|
+
.where(and(inContainerIntentLanes(), inArray(localIntents.subjectId, containerIds)))
|
|
120
116
|
.run();
|
|
121
117
|
}
|
|
122
118
|
await deleteContainerRowsInTransaction(input.tx, containerIds);
|
|
@@ -130,10 +126,8 @@ export async function deleteStoredContainers(execSql, removals, options) {
|
|
|
130
126
|
return [];
|
|
131
127
|
return runSerializedSqlMutation(execSql, async (lockedExecSql) => {
|
|
132
128
|
await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);
|
|
133
|
-
await ensureSqlTables(lockedExecSql,
|
|
129
|
+
await ensureSqlTables(lockedExecSql, documentPlacementIntentTables);
|
|
134
130
|
await ensureContainerTables(lockedExecSql);
|
|
135
|
-
await ensureSqlTables(lockedExecSql, containerCreateIntentTables);
|
|
136
|
-
await ensureSqlTables(lockedExecSql, containerMoveIntentTables);
|
|
137
131
|
await ensureDocumentProjectionTables(lockedExecSql);
|
|
138
132
|
await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);
|
|
139
133
|
const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerDeletionPersistence.js","sourceRoot":"","sources":["containerDeletionPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { inArray } from \"drizzle-orm\";\nimport { ensureDocumentProjectionTables } from \"../../sqlite/documentPersistence\";\nimport {\n containerCreateIntents,\n containerCreateIntentTables,\n containerMoveIntents,\n containerMoveIntentTables,\n containers,\n documentContainerProjectionTables,\n documentMoveIntentTables,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport {\n deleteContainerRowsInTransaction,\n ensureContainerTables,\n} from \"../containers/containerPersistence\";\nimport {\n deleteContainerWatermarksInTransaction,\n sqlContainerSyncWatermarkPersistence,\n} from \"../containers/containerSyncWatermarkPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerDeletionGuard,\n ContainerRemoval,\n} from \"./containerContentsPersistenceTypes\";\nimport { recordContainerHydrationTombstones } from \"./containerHydrationPersistence\";\nimport { containerIdsWithRemovalWork } from \"./containerRemovalWork\";\nimport { repairDocumentsForRemovedContainersInTransaction } from \"./containerStructuralRepair\";\nimport {\n refreshPlacementIntentsAfterRemoval,\n repairLinkIntentsForRemovedContainers,\n} from \"./documentLinkRemovalRepair\";\nimport {\n deleteContainerMetadataDocumentRowsInTransaction,\n retainDormantContainerMetadataInTransaction,\n} from \"./dormantContainerMetadata\";\n\ntype DeleteContainerOptions = NonNullable<\n Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[2]\n>;\n\nfunction normalizeContainerRemovals(\n removals: ReadonlyArray<ContainerRemoval>,\n): ContainerRemoval[] {\n const removalByContainerId = new Map<string, ContainerRemoval>();\n for (const removal of removals) {\n const current = removalByContainerId.get(removal.containerId);\n if (\n !current ||\n (current.reason === \"access_revoked\" && removal.reason === \"deleted\") ||\n (current.reason === removal.reason &&\n current.updatedAt < removal.updatedAt)\n ) {\n removalByContainerId.set(removal.containerId, removal);\n }\n }\n return Array.from(removalByContainerId.values());\n}\n\nfunction loadGuardedContainerRows(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n) {\n return tx\n .select({\n effectiveAccessLevel: containers.effectiveAccessLevel,\n id: containers.id,\n metadataDocumentId: containers.metadataDocumentId,\n organizationId: containers.organizationId,\n parentId: containers.parentId,\n serverCreatedAt: containers.serverCreatedAt,\n serverUpdatedAt: containers.serverUpdatedAt,\n systemSlot: containers.systemSlot,\n })\n .from(containers)\n .where(inArray(containers.id, [...containerIds]));\n}\n\ntype GuardedContainerRow = Awaited<\n ReturnType<typeof loadGuardedContainerRows>\n>[number];\n\nfunction sameGuardedContainerRow(\n row: GuardedContainerRow | undefined,\n guard: ContainerDeletionGuard,\n): boolean {\n const expected = guard.expectedContainer;\n if (!row || !expected) return row === undefined && expected === null;\n return (\n row.id === expected.id &&\n row.organizationId === expected.organizationId &&\n row.parentId === expected.parentId &&\n row.metadataDocumentId === expected.metadataDocumentId &&\n row.systemSlot === (expected.systemSlot ?? null) &&\n row.effectiveAccessLevel === (expected.effectiveAccessLevel ?? \"read\") &&\n row.serverCreatedAt === (expected.serverCreatedAt ?? null) &&\n row.serverUpdatedAt === (expected.serverUpdatedAt ?? null)\n );\n}\n\nasync function canApplyContainerRemovals(input: {\n expectedContainers: DeleteContainerOptions[\"expectedContainers\"];\n removals: ReadonlyArray<ContainerRemoval>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const currentRows = await loadGuardedContainerRows(\n input.tx,\n input.removals.map((removal) => removal.containerId),\n );\n const currentRowById = new Map(\n currentRows.flatMap((row) => (row.id ? ([[row.id, row]] as const) : [])),\n );\n const guardById = new Map(\n input.expectedContainers?.map((guard) => [guard.containerId, guard]) ?? [],\n );\n return input.removals.every((removal) => {\n const currentRow = currentRowById.get(removal.containerId);\n const guard = guardById.get(removal.containerId);\n return (\n (!guard || sameGuardedContainerRow(currentRow, guard)) &&\n (currentRow?.serverUpdatedAt == null ||\n currentRow.serverUpdatedAt <= removal.updatedAt)\n );\n });\n}\n\nasync function retainRemovedContainerMetadata(input: {\n containerIds: ReadonlyArray<string>;\n retainedAt: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n if (input.containerIds.length === 0) return;\n const retainedContainers = await input.tx\n .select({\n containerId: containers.id,\n organizationId: containers.organizationId,\n })\n .from(containers)\n .where(inArray(containers.id, [...input.containerIds]));\n await retainDormantContainerMetadataInTransaction(\n input.tx,\n retainedContainers.flatMap((container) =>\n container.containerId\n ? [\n {\n containerId: container.containerId,\n organizationId: container.organizationId,\n retainedAt: input.retainedAt,\n },\n ]\n : [],\n ),\n );\n}\n\nasync function applyContainerRemovals(input: {\n discoveryOnly: DeleteContainerOptions[\"discoveryOnly\"];\n metadataDeleteIds: ReadonlyArray<string>;\n removals: ReadonlyArray<ContainerRemoval>;\n retainedMetadataIds: ReadonlyArray<string>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<ReadonlyArray<string>> {\n const containerIds = input.removals.map((removal) => removal.containerId);\n await recordContainerHydrationTombstones({\n removals: input.removals,\n tx: input.tx,\n });\n await retainRemovedContainerMetadata({\n containerIds: input.retainedMetadataIds,\n retainedAt: new Date().toISOString(),\n tx: input.tx,\n });\n // Listing clocks are untrusted; they cannot advance local projection clocks.\n const localObservedAt = new Date().toISOString();\n await repairDocumentsForRemovedContainersInTransaction({\n removals: input.discoveryOnly\n ? input.removals.map((removal) => ({\n ...removal,\n updatedAt: localObservedAt,\n }))\n : input.removals,\n tx: input.tx,\n });\n if (input.discoveryOnly) {\n await refreshPlacementIntentsAfterRemoval({ containerIds, tx: input.tx });\n } else {\n await repairLinkIntentsForRemovedContainers({ containerIds, tx: input.tx });\n await input.tx\n .delete(containerCreateIntents)\n .where(inArray(containerCreateIntents.containerId, containerIds))\n .run();\n await input.tx\n .delete(containerMoveIntents)\n .where(inArray(containerMoveIntents.containerId, containerIds))\n .run();\n }\n await deleteContainerRowsInTransaction(input.tx, containerIds);\n await deleteContainerMetadataDocumentRowsInTransaction(\n input.tx,\n input.metadataDeleteIds,\n );\n await deleteContainerWatermarksInTransaction(input.tx, containerIds);\n return containerIds;\n}\n\nexport async function deleteStoredContainers(\n execSql: Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[0],\n removals: Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[1],\n options?: Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[2],\n): Promise<ReadonlyArray<string>> {\n const uniqueRemovals = normalizeContainerRemovals(removals);\n if (uniqueRemovals.length === 0) return [];\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);\n await ensureSqlTables(lockedExecSql, documentMoveIntentTables);\n await ensureContainerTables(lockedExecSql);\n await ensureSqlTables(lockedExecSql, containerCreateIntentTables);\n await ensureSqlTables(lockedExecSql, containerMoveIntentTables);\n await ensureDocumentProjectionTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const remove = async (tx: ClientSQLiteTransactionScope) => {\n if (\n options?.beforeDeleteInTransaction &&\n !(await options.beforeDeleteInTransaction(lockedExecSql))\n )\n return [];\n if (\n !(await canApplyContainerRemovals({\n expectedContainers: options?.expectedContainers,\n removals: uniqueRemovals,\n tx,\n }))\n ) {\n return [];\n }\n const retainedMetadataIds = options?.discoveryOnly\n ? await containerIdsWithRemovalWork(\n tx,\n uniqueRemovals.map((removal) => removal.containerId),\n )\n : [];\n return applyContainerRemovals({\n discoveryOnly: options?.discoveryOnly,\n metadataDeleteIds: uniqueRemovals.flatMap((removal) =>\n retainedMetadataIds.includes(removal.containerId)\n ? []\n : [removal.containerId],\n ),\n removals: uniqueRemovals,\n retainedMetadataIds,\n tx,\n });\n };\n if (!options?.stillCurrent) {\n return runtime.transaction(remove, { behavior: \"immediate\" });\n }\n const outcome = await runtime.guardedTransaction(\n remove,\n options.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.result ?? [];\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerDeletionPersistence.js","sourceRoot":"","sources":["containerDeletionPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, inArray } from \"drizzle-orm\";\nimport { ensureDocumentProjectionTables } from \"../../sqlite/documentPersistence\";\nimport {\n containers,\n documentContainerProjectionTables,\n documentPlacementIntentTables,\n inContainerIntentLanes,\n localIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n ensureSqlTables,\n runSerializedSqlMutation,\n} from \"../../sqlite/sqlSchema\";\nimport {\n deleteContainerRowsInTransaction,\n ensureContainerTables,\n} from \"../containers/containerPersistence\";\nimport {\n deleteContainerWatermarksInTransaction,\n sqlContainerSyncWatermarkPersistence,\n} from \"../containers/containerSyncWatermarkPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerDeletionGuard,\n ContainerRemoval,\n} from \"./containerContentsPersistenceTypes\";\nimport { recordContainerHydrationTombstones } from \"./containerHydrationPersistence\";\nimport { containerIdsWithRemovalWork } from \"./containerRemovalWork\";\nimport { repairDocumentsForRemovedContainersInTransaction } from \"./containerStructuralRepair\";\nimport {\n refreshPlacementIntentsAfterRemoval,\n repairLinkIntentsForRemovedContainers,\n} from \"./documentLinkRemovalRepair\";\nimport {\n deleteContainerMetadataDocumentRowsInTransaction,\n retainDormantContainerMetadataInTransaction,\n} from \"./dormantContainerMetadata\";\n\ntype DeleteContainerOptions = NonNullable<\n Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[2]\n>;\n\nfunction normalizeContainerRemovals(\n removals: ReadonlyArray<ContainerRemoval>,\n): ContainerRemoval[] {\n const removalByContainerId = new Map<string, ContainerRemoval>();\n for (const removal of removals) {\n const current = removalByContainerId.get(removal.containerId);\n if (\n !current ||\n (current.reason === \"access_revoked\" && removal.reason === \"deleted\") ||\n (current.reason === removal.reason &&\n current.updatedAt < removal.updatedAt)\n ) {\n removalByContainerId.set(removal.containerId, removal);\n }\n }\n return Array.from(removalByContainerId.values());\n}\n\nfunction loadGuardedContainerRows(\n tx: ClientSQLiteTransactionScope,\n containerIds: ReadonlyArray<string>,\n) {\n return tx\n .select({\n effectiveAccessLevel: containers.effectiveAccessLevel,\n id: containers.id,\n metadataDocumentId: containers.metadataDocumentId,\n organizationId: containers.organizationId,\n parentId: containers.parentId,\n serverCreatedAt: containers.serverCreatedAt,\n serverUpdatedAt: containers.serverUpdatedAt,\n systemSlot: containers.systemSlot,\n })\n .from(containers)\n .where(inArray(containers.id, [...containerIds]));\n}\n\ntype GuardedContainerRow = Awaited<\n ReturnType<typeof loadGuardedContainerRows>\n>[number];\n\nfunction sameGuardedContainerRow(\n row: GuardedContainerRow | undefined,\n guard: ContainerDeletionGuard,\n): boolean {\n const expected = guard.expectedContainer;\n if (!row || !expected) return row === undefined && expected === null;\n return (\n row.id === expected.id &&\n row.organizationId === expected.organizationId &&\n row.parentId === expected.parentId &&\n row.metadataDocumentId === expected.metadataDocumentId &&\n row.systemSlot === (expected.systemSlot ?? null) &&\n row.effectiveAccessLevel === (expected.effectiveAccessLevel ?? \"read\") &&\n row.serverCreatedAt === (expected.serverCreatedAt ?? null) &&\n row.serverUpdatedAt === (expected.serverUpdatedAt ?? null)\n );\n}\n\nasync function canApplyContainerRemovals(input: {\n expectedContainers: DeleteContainerOptions[\"expectedContainers\"];\n removals: ReadonlyArray<ContainerRemoval>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<boolean> {\n const currentRows = await loadGuardedContainerRows(\n input.tx,\n input.removals.map((removal) => removal.containerId),\n );\n const currentRowById = new Map(\n currentRows.flatMap((row) => (row.id ? ([[row.id, row]] as const) : [])),\n );\n const guardById = new Map(\n input.expectedContainers?.map((guard) => [guard.containerId, guard]) ?? [],\n );\n return input.removals.every((removal) => {\n const currentRow = currentRowById.get(removal.containerId);\n const guard = guardById.get(removal.containerId);\n return (\n (!guard || sameGuardedContainerRow(currentRow, guard)) &&\n (currentRow?.serverUpdatedAt == null ||\n currentRow.serverUpdatedAt <= removal.updatedAt)\n );\n });\n}\n\nasync function retainRemovedContainerMetadata(input: {\n containerIds: ReadonlyArray<string>;\n retainedAt: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n if (input.containerIds.length === 0) return;\n const retainedContainers = await input.tx\n .select({\n containerId: containers.id,\n organizationId: containers.organizationId,\n })\n .from(containers)\n .where(inArray(containers.id, [...input.containerIds]));\n await retainDormantContainerMetadataInTransaction(\n input.tx,\n retainedContainers.flatMap((container) =>\n container.containerId\n ? [\n {\n containerId: container.containerId,\n organizationId: container.organizationId,\n retainedAt: input.retainedAt,\n },\n ]\n : [],\n ),\n );\n}\n\nasync function applyContainerRemovals(input: {\n discoveryOnly: DeleteContainerOptions[\"discoveryOnly\"];\n metadataDeleteIds: ReadonlyArray<string>;\n removals: ReadonlyArray<ContainerRemoval>;\n retainedMetadataIds: ReadonlyArray<string>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<ReadonlyArray<string>> {\n const containerIds = input.removals.map((removal) => removal.containerId);\n await recordContainerHydrationTombstones({\n removals: input.removals,\n tx: input.tx,\n });\n await retainRemovedContainerMetadata({\n containerIds: input.retainedMetadataIds,\n retainedAt: new Date().toISOString(),\n tx: input.tx,\n });\n // Listing clocks are untrusted; they cannot advance local projection clocks.\n const localObservedAt = new Date().toISOString();\n await repairDocumentsForRemovedContainersInTransaction({\n removals: input.discoveryOnly\n ? input.removals.map((removal) => ({\n ...removal,\n updatedAt: localObservedAt,\n }))\n : input.removals,\n tx: input.tx,\n });\n if (input.discoveryOnly) {\n await refreshPlacementIntentsAfterRemoval({ containerIds, tx: input.tx });\n } else {\n await repairLinkIntentsForRemovedContainers({ containerIds, tx: input.tx });\n await input.tx\n .delete(localIntents)\n .where(\n and(\n inContainerIntentLanes(),\n inArray(localIntents.subjectId, containerIds),\n ),\n )\n .run();\n }\n await deleteContainerRowsInTransaction(input.tx, containerIds);\n await deleteContainerMetadataDocumentRowsInTransaction(\n input.tx,\n input.metadataDeleteIds,\n );\n await deleteContainerWatermarksInTransaction(input.tx, containerIds);\n return containerIds;\n}\n\nexport async function deleteStoredContainers(\n execSql: Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[0],\n removals: Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[1],\n options?: Parameters<ContainerContentsPersistence[\"deleteContainers\"]>[2],\n): Promise<ReadonlyArray<string>> {\n const uniqueRemovals = normalizeContainerRemovals(removals);\n if (uniqueRemovals.length === 0) return [];\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n await ensureSqlTables(lockedExecSql, documentContainerProjectionTables);\n await ensureSqlTables(lockedExecSql, documentPlacementIntentTables);\n await ensureContainerTables(lockedExecSql);\n await ensureDocumentProjectionTables(lockedExecSql);\n await sqlContainerSyncWatermarkPersistence.ensureSchema(lockedExecSql);\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const remove = async (tx: ClientSQLiteTransactionScope) => {\n if (\n options?.beforeDeleteInTransaction &&\n !(await options.beforeDeleteInTransaction(lockedExecSql))\n )\n return [];\n if (\n !(await canApplyContainerRemovals({\n expectedContainers: options?.expectedContainers,\n removals: uniqueRemovals,\n tx,\n }))\n ) {\n return [];\n }\n const retainedMetadataIds = options?.discoveryOnly\n ? await containerIdsWithRemovalWork(\n tx,\n uniqueRemovals.map((removal) => removal.containerId),\n )\n : [];\n return applyContainerRemovals({\n discoveryOnly: options?.discoveryOnly,\n metadataDeleteIds: uniqueRemovals.flatMap((removal) =>\n retainedMetadataIds.includes(removal.containerId)\n ? []\n : [removal.containerId],\n ),\n removals: uniqueRemovals,\n retainedMetadataIds,\n tx,\n });\n };\n if (!options?.stillCurrent) {\n return runtime.transaction(remove, { behavior: \"immediate\" });\n }\n const outcome = await runtime.guardedTransaction(\n remove,\n options.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.result ?? [];\n });\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { and, eq, inArray, or, sql } from "drizzle-orm";
|
|
2
2
|
import { uniqueSortedStrings } from "../../documents/shared/readers.js";
|
|
3
3
|
import { documentIntentLinkTargets } from "../../sqlite/documentPlacementIntentSchema.js";
|
|
4
|
-
import { documentContainerProjection,
|
|
4
|
+
import { documentContainerProjection, documentProjection, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema.js";
|
|
5
5
|
import { deleteContainerDocumentTombstoneHoldRowsForLinks, deleteContainerDocumentTombstoneHoldsForContainers, } from "../documents/containerDocumentTombstoneHoldsPersistence.js";
|
|
6
6
|
import { DOCUMENT_LINK_INTENT_TYPE, DOCUMENT_MOVE_INTENT_TYPE, } from "./documentMoveIntentPersistence.js";
|
|
7
7
|
async function reassignDocumentLinksForContainer(input) {
|
|
@@ -61,14 +61,14 @@ async function reassignDocumentMoveIntentsForContainer(input) {
|
|
|
61
61
|
const { fromContainerId, toContainerId, tx, updatedAt } = input;
|
|
62
62
|
const affectedIntents = await tx
|
|
63
63
|
.select({
|
|
64
|
-
documentId:
|
|
65
|
-
id:
|
|
64
|
+
documentId: localIntents.subjectId,
|
|
65
|
+
id: localIntents.id,
|
|
66
66
|
})
|
|
67
|
-
.from(
|
|
68
|
-
.where(and(inArray(
|
|
67
|
+
.from(localIntents)
|
|
68
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement), inArray(localIntents.intentType, [
|
|
69
69
|
DOCUMENT_MOVE_INTENT_TYPE,
|
|
70
70
|
DOCUMENT_LINK_INTENT_TYPE,
|
|
71
|
-
]), or(eq(
|
|
71
|
+
]), or(eq(localIntents.sourceContainerId, fromContainerId), eq(localIntents.targetContainerId, fromContainerId), inArray(localIntents.id, tx
|
|
72
72
|
.select({ id: documentIntentLinkTargets.intentId })
|
|
73
73
|
.from(documentIntentLinkTargets)
|
|
74
74
|
.where(and(eq(documentIntentLinkTargets.containerId, fromContainerId), eq(documentIntentLinkTargets.operation, "link")))))));
|
|
@@ -97,25 +97,25 @@ async function reassignDocumentMoveIntentsForContainer(input) {
|
|
|
97
97
|
})))
|
|
98
98
|
.run();
|
|
99
99
|
await tx
|
|
100
|
-
.update(
|
|
100
|
+
.update(localIntents)
|
|
101
101
|
.set({
|
|
102
102
|
id,
|
|
103
103
|
lastAttemptedAt: null,
|
|
104
104
|
lastError: null,
|
|
105
105
|
sourceContainerId: sql `CASE
|
|
106
|
-
WHEN ${
|
|
106
|
+
WHEN ${localIntents.sourceContainerId} = ${fromContainerId}
|
|
107
107
|
THEN ${toContainerId}
|
|
108
|
-
ELSE ${
|
|
108
|
+
ELSE ${localIntents.sourceContainerId}
|
|
109
109
|
END`,
|
|
110
110
|
syncStatus: "pending",
|
|
111
111
|
targetContainerId: sql `CASE
|
|
112
|
-
WHEN ${
|
|
112
|
+
WHEN ${localIntents.targetContainerId} = ${fromContainerId}
|
|
113
113
|
THEN ${toContainerId}
|
|
114
|
-
ELSE ${
|
|
114
|
+
ELSE ${localIntents.targetContainerId}
|
|
115
115
|
END`,
|
|
116
|
-
updatedAt: sql `max(${
|
|
116
|
+
updatedAt: sql `max(${localIntents.updatedAt}, ${updatedAt})`,
|
|
117
117
|
})
|
|
118
|
-
.where(eq(
|
|
118
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement), eq(localIntents.subjectId, intent.documentId)))
|
|
119
119
|
.run();
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerDocumentReassignment.js","sourceRoot":"","sources":["containerDocumentReassignment.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, or, sql } from \"drizzle-orm\";\nimport { uniqueSortedStrings } from \"../../documents/shared/readers\";\nimport { documentIntentLinkTargets } from \"../../sqlite/documentPlacementIntentSchema\";\nimport {\n documentContainerProjection,\n documentMoveIntents,\n documentProjection,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n deleteContainerDocumentTombstoneHoldRowsForLinks,\n deleteContainerDocumentTombstoneHoldsForContainers,\n} from \"../documents/containerDocumentTombstoneHoldsPersistence\";\nimport {\n DOCUMENT_LINK_INTENT_TYPE,\n DOCUMENT_MOVE_INTENT_TYPE,\n} from \"./documentMoveIntentPersistence\";\n\ninterface ContainerDocumentReassignmentInput {\n readonly fromContainerId: string;\n readonly toContainerId: string;\n readonly tx: ClientSQLiteTransactionScope;\n readonly updatedAt: string;\n}\n\nasync function reassignDocumentLinksForContainer(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n const { fromContainerId, toContainerId, tx, updatedAt } = input;\n await tx.run(sql`\n INSERT INTO ${documentContainerProjection} (\n ${sql.raw(\"document_id\")},\n ${sql.raw(\"container_id\")},\n ${sql.raw(\"updated_at\")}\n )\n SELECT\n ${documentContainerProjection.documentId},\n ${toContainerId},\n max(${documentContainerProjection.updatedAt}, ${updatedAt})\n FROM ${documentContainerProjection}\n WHERE ${documentContainerProjection.containerId} = ${fromContainerId}\n ON CONFLICT (\n ${sql.raw(\"document_id\")},\n ${sql.raw(\"container_id\")}\n ) DO UPDATE SET\n ${sql.raw(\"updated_at\")} = max(\n ${sql.raw(\"updated_at\")},\n excluded.${sql.raw(\"updated_at\")}\n )\n `);\n\n // The reassigned placements are asserted locally: a stale hold on the\n // destination would hide them, and holds on the vacated container have\n // nothing left to hide.\n const movedDocumentIds = (\n await tx\n .select({ documentId: documentContainerProjection.documentId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.containerId, fromContainerId))\n ).map((row) => row.documentId);\n await deleteContainerDocumentTombstoneHoldRowsForLinks(\n tx,\n movedDocumentIds.map((documentId) => ({\n containerIds: [toContainerId],\n documentId,\n })),\n );\n await deleteContainerDocumentTombstoneHoldsForContainers(tx, [\n fromContainerId,\n ]);\n await tx\n .delete(documentContainerProjection)\n .where(eq(documentContainerProjection.containerId, fromContainerId))\n .run();\n}\n\nasync function reassignPrimaryDocumentsForContainer(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n const { fromContainerId, toContainerId, tx, updatedAt } = input;\n await tx\n .update(documentProjection)\n .set({\n containerId: toContainerId,\n updatedAt: sql`max(${documentProjection.updatedAt}, ${updatedAt})`,\n })\n .where(eq(documentProjection.containerId, fromContainerId))\n .run();\n}\n\nasync function reassignDocumentMoveIntentsForContainer(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n const { fromContainerId, toContainerId, tx, updatedAt } = input;\n const affectedIntents = await tx\n .select({\n documentId: documentMoveIntents.documentId,\n id: documentMoveIntents.id,\n })\n .from(documentMoveIntents)\n .where(\n and(\n inArray(documentMoveIntents.intentType, [\n DOCUMENT_MOVE_INTENT_TYPE,\n DOCUMENT_LINK_INTENT_TYPE,\n ]),\n or(\n eq(documentMoveIntents.sourceContainerId, fromContainerId),\n eq(documentMoveIntents.targetContainerId, fromContainerId),\n inArray(\n documentMoveIntents.id,\n tx\n .select({ id: documentIntentLinkTargets.intentId })\n .from(documentIntentLinkTargets)\n .where(\n and(\n eq(documentIntentLinkTargets.containerId, fromContainerId),\n eq(documentIntentLinkTargets.operation, \"link\"),\n ),\n ),\n ),\n ),\n ),\n );\n for (const intent of affectedIntents) {\n const id = crypto.randomUUID();\n const targets = await tx\n .select()\n .from(documentIntentLinkTargets)\n .where(eq(documentIntentLinkTargets.intentId, intent.id ?? \"\"));\n await tx\n .delete(documentIntentLinkTargets)\n .where(eq(documentIntentLinkTargets.intentId, intent.id ?? \"\"))\n .run();\n const retained = new Map(\n targets.map((target) => [target.containerId, target.operation]),\n );\n if (retained.get(fromContainerId) === \"link\") {\n retained.delete(fromContainerId);\n retained.set(toContainerId, \"link\");\n }\n if (retained.size)\n await tx\n .insert(documentIntentLinkTargets)\n .values(\n uniqueSortedStrings([...retained.keys()]).map((containerId) => ({\n intentId: id,\n containerId,\n operation: retained.get(containerId) ?? \"link\",\n })),\n )\n .run();\n await tx\n .update(documentMoveIntents)\n .set({\n id,\n lastAttemptedAt: null,\n lastError: null,\n sourceContainerId: sql`CASE\n WHEN ${documentMoveIntents.sourceContainerId} = ${fromContainerId}\n THEN ${toContainerId}\n ELSE ${documentMoveIntents.sourceContainerId}\n END`,\n syncStatus: \"pending\",\n targetContainerId: sql`CASE\n WHEN ${documentMoveIntents.targetContainerId} = ${fromContainerId}\n THEN ${toContainerId}\n ELSE ${documentMoveIntents.targetContainerId}\n END`,\n updatedAt: sql`max(${documentMoveIntents.updatedAt}, ${updatedAt})`,\n })\n .where(eq(documentMoveIntents.documentId, intent.documentId))\n .run();\n }\n}\n\nexport async function reassignContainerDocumentsInTransaction(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n await reassignDocumentLinksForContainer(input);\n await reassignPrimaryDocumentsForContainer(input);\n await reassignDocumentMoveIntentsForContainer(input);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerDocumentReassignment.js","sourceRoot":"","sources":["containerDocumentReassignment.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, inArray, or, sql } from \"drizzle-orm\";\nimport { uniqueSortedStrings } from \"../../documents/shared/readers\";\nimport { documentIntentLinkTargets } from \"../../sqlite/documentPlacementIntentSchema\";\nimport {\n documentContainerProjection,\n documentProjection,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport {\n deleteContainerDocumentTombstoneHoldRowsForLinks,\n deleteContainerDocumentTombstoneHoldsForContainers,\n} from \"../documents/containerDocumentTombstoneHoldsPersistence\";\nimport {\n DOCUMENT_LINK_INTENT_TYPE,\n DOCUMENT_MOVE_INTENT_TYPE,\n} from \"./documentMoveIntentPersistence\";\n\ninterface ContainerDocumentReassignmentInput {\n readonly fromContainerId: string;\n readonly toContainerId: string;\n readonly tx: ClientSQLiteTransactionScope;\n readonly updatedAt: string;\n}\n\nasync function reassignDocumentLinksForContainer(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n const { fromContainerId, toContainerId, tx, updatedAt } = input;\n await tx.run(sql`\n INSERT INTO ${documentContainerProjection} (\n ${sql.raw(\"document_id\")},\n ${sql.raw(\"container_id\")},\n ${sql.raw(\"updated_at\")}\n )\n SELECT\n ${documentContainerProjection.documentId},\n ${toContainerId},\n max(${documentContainerProjection.updatedAt}, ${updatedAt})\n FROM ${documentContainerProjection}\n WHERE ${documentContainerProjection.containerId} = ${fromContainerId}\n ON CONFLICT (\n ${sql.raw(\"document_id\")},\n ${sql.raw(\"container_id\")}\n ) DO UPDATE SET\n ${sql.raw(\"updated_at\")} = max(\n ${sql.raw(\"updated_at\")},\n excluded.${sql.raw(\"updated_at\")}\n )\n `);\n\n // The reassigned placements are asserted locally: a stale hold on the\n // destination would hide them, and holds on the vacated container have\n // nothing left to hide.\n const movedDocumentIds = (\n await tx\n .select({ documentId: documentContainerProjection.documentId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.containerId, fromContainerId))\n ).map((row) => row.documentId);\n await deleteContainerDocumentTombstoneHoldRowsForLinks(\n tx,\n movedDocumentIds.map((documentId) => ({\n containerIds: [toContainerId],\n documentId,\n })),\n );\n await deleteContainerDocumentTombstoneHoldsForContainers(tx, [\n fromContainerId,\n ]);\n await tx\n .delete(documentContainerProjection)\n .where(eq(documentContainerProjection.containerId, fromContainerId))\n .run();\n}\n\nasync function reassignPrimaryDocumentsForContainer(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n const { fromContainerId, toContainerId, tx, updatedAt } = input;\n await tx\n .update(documentProjection)\n .set({\n containerId: toContainerId,\n updatedAt: sql`max(${documentProjection.updatedAt}, ${updatedAt})`,\n })\n .where(eq(documentProjection.containerId, fromContainerId))\n .run();\n}\n\nasync function reassignDocumentMoveIntentsForContainer(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n const { fromContainerId, toContainerId, tx, updatedAt } = input;\n const affectedIntents = await tx\n .select({\n documentId: localIntents.subjectId,\n id: localIntents.id,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n inArray(localIntents.intentType, [\n DOCUMENT_MOVE_INTENT_TYPE,\n DOCUMENT_LINK_INTENT_TYPE,\n ]),\n or(\n eq(localIntents.sourceContainerId, fromContainerId),\n eq(localIntents.targetContainerId, fromContainerId),\n inArray(\n localIntents.id,\n tx\n .select({ id: documentIntentLinkTargets.intentId })\n .from(documentIntentLinkTargets)\n .where(\n and(\n eq(documentIntentLinkTargets.containerId, fromContainerId),\n eq(documentIntentLinkTargets.operation, \"link\"),\n ),\n ),\n ),\n ),\n ),\n );\n for (const intent of affectedIntents) {\n const id = crypto.randomUUID();\n const targets = await tx\n .select()\n .from(documentIntentLinkTargets)\n .where(eq(documentIntentLinkTargets.intentId, intent.id ?? \"\"));\n await tx\n .delete(documentIntentLinkTargets)\n .where(eq(documentIntentLinkTargets.intentId, intent.id ?? \"\"))\n .run();\n const retained = new Map(\n targets.map((target) => [target.containerId, target.operation]),\n );\n if (retained.get(fromContainerId) === \"link\") {\n retained.delete(fromContainerId);\n retained.set(toContainerId, \"link\");\n }\n if (retained.size)\n await tx\n .insert(documentIntentLinkTargets)\n .values(\n uniqueSortedStrings([...retained.keys()]).map((containerId) => ({\n intentId: id,\n containerId,\n operation: retained.get(containerId) ?? \"link\",\n })),\n )\n .run();\n await tx\n .update(localIntents)\n .set({\n id,\n lastAttemptedAt: null,\n lastError: null,\n sourceContainerId: sql`CASE\n WHEN ${localIntents.sourceContainerId} = ${fromContainerId}\n THEN ${toContainerId}\n ELSE ${localIntents.sourceContainerId}\n END`,\n syncStatus: \"pending\",\n targetContainerId: sql`CASE\n WHEN ${localIntents.targetContainerId} = ${fromContainerId}\n THEN ${toContainerId}\n ELSE ${localIntents.targetContainerId}\n END`,\n updatedAt: sql`max(${localIntents.updatedAt}, ${updatedAt})`,\n })\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.documentPlacement),\n eq(localIntents.subjectId, intent.documentId),\n ),\n )\n .run();\n }\n}\n\nexport async function reassignContainerDocumentsInTransaction(\n input: ContainerDocumentReassignmentInput,\n): Promise<void> {\n await reassignDocumentLinksForContainer(input);\n await reassignPrimaryDocumentsForContainer(input);\n await reassignDocumentMoveIntentsForContainer(input);\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import { KeyingVerificationError } from "../../../internal/crypto/index.js";
|
|
|
2
2
|
import { and, eq, inArray, sql } from "drizzle-orm";
|
|
3
3
|
import { assertHeldContainerBinding, heldContainerBinding, } from "../../containers/containerBinding.js";
|
|
4
4
|
import { documentSyncPullContinuationsEqual } from "../../documents/shared/pullContinuation.js";
|
|
5
|
-
import { containerHydrationTombstones,
|
|
5
|
+
import { containerHydrationTombstones, containers, dormantContainerMetadata, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema.js";
|
|
6
6
|
import { getClientSQLitePersistenceRuntime, } from "../../sqlite/sqlitePersistenceRuntime.js";
|
|
7
7
|
import { runSerializedSqlMutation } from "../../sqlite/sqlSchema.js";
|
|
8
8
|
import { loadContainerById } from "../containers/containerPersistence.js";
|
|
@@ -70,9 +70,12 @@ async function placementCheckpointMatches(tx, input) {
|
|
|
70
70
|
/** A retained local move continues to own placement after verified reattachment. */
|
|
71
71
|
async function saveRecoveredContainer(tx, input) {
|
|
72
72
|
const [move] = await tx
|
|
73
|
-
.select(
|
|
74
|
-
.
|
|
75
|
-
|
|
73
|
+
.select({
|
|
74
|
+
parentContainerId: localIntents.targetContainerId,
|
|
75
|
+
updatedAt: localIntents.updatedAt,
|
|
76
|
+
})
|
|
77
|
+
.from(localIntents)
|
|
78
|
+
.where(and(inLocalIntentLane(LOCAL_INTENT_LANES.containerMove), eq(localIntents.subjectId, input.container.id), inArray(localIntents.syncStatus, ["pending", "blocked"])))
|
|
76
79
|
.limit(1);
|
|
77
80
|
return saveContainerContentsContainerRows({
|
|
78
81
|
container: move
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerHydrationPersistence.js","sourceRoot":"","sources":["containerHydrationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { and, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n assertHeldContainerBinding,\n type HeldContainerBinding,\n heldContainerBinding,\n} from \"../../containers/containerBinding\";\nimport { documentSyncPullContinuationsEqual } from \"../../documents/shared/pullContinuation\";\nimport {\n containerHydrationTombstones,\n containerMoveIntents,\n containers,\n dormantContainerMetadata,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport { loadContainerById } from \"../containers/containerPersistence\";\nimport { loadStoredAccessManifestCheckpoint } from \"../keyingCheckpointPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n} from \"./containerContentsPersistenceTypes\";\nimport {\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { isSupersededContainerBinding } from \"./supersededContainerBindings\";\n\nfunction sameNullableValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nfunction sameMetadataRecord(\n current: ContainerMetadataRecord | null,\n expected: ContainerMetadataRecord | null,\n): boolean {\n if (!current || !expected) return current === expected;\n return (\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableValue(current.accessStateHash, expected.accessStateHash) &&\n sameNullableValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n sameNullableValue(current.contentKeyBundle, expected.contentKeyBundle) &&\n sameNullableValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n ) &&\n current.metadataUpdates === expected.metadataUpdates &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired)\n );\n}\n\nfunction sameHydrationTombstone(\n current:\n | { generation: number; reason: string; updatedAt: string }\n | undefined,\n expected: ContainerHydrationTombstone | null | undefined,\n): boolean {\n return (\n current !== undefined &&\n expected != null &&\n current.generation === expected.generation &&\n current.reason === expected.reason &&\n current.updatedAt === expected.updatedAt\n );\n}\n\nexport async function recordContainerHydrationTombstones(input: {\n removals: ReadonlyArray<{\n containerId: string;\n reason: \"access_revoked\" | \"deleted\";\n updatedAt: string;\n }>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n if (input.removals.length === 0) return;\n await input.tx\n .insert(containerHydrationTombstones)\n .values([...input.removals])\n .onConflictDoUpdate({\n target: containerHydrationTombstones.containerId,\n set: {\n generation: sql`${containerHydrationTombstones.generation} + 1`,\n cleared: false,\n reason: sql`CASE\n WHEN ${containerHydrationTombstones.reason} = 'deleted' THEN 'deleted'\n ELSE excluded.reason\n END`,\n updatedAt: sql`MAX(${containerHydrationTombstones.updatedAt}, excluded.updated_at)`,\n },\n })\n .run();\n}\n\nasync function placementCheckpointMatches(\n tx: ClientSQLiteTransactionScope,\n input: Parameters<ContainerContentsPersistence[\"commitHydratedContainer\"]>[1],\n): Promise<boolean> {\n const expected = input.expectedPlacementCheckpoint;\n if (!expected) return true;\n const current = await loadStoredAccessManifestCheckpoint(tx, expected);\n return (\n expected.objectKind === \"container\" &&\n expected.objectId === input.container.id &&\n expected.organizationId === input.container.organizationId &&\n current?.epoch === expected.epoch &&\n current.manifestHash === expected.manifestHash\n );\n}\n\n/** A retained local move continues to own placement after verified reattachment. */\nasync function saveRecoveredContainer(\n tx: ClientSQLiteTransactionScope,\n input: Parameters<ContainerContentsPersistence[\"commitHydratedContainer\"]>[1],\n) {\n const [move] = await tx\n .select()\n .from(containerMoveIntents)\n .where(\n and(\n eq(containerMoveIntents.containerId, input.container.id),\n inArray(containerMoveIntents.syncStatus, [\"pending\", \"blocked\"]),\n ),\n )\n .limit(1);\n return saveContainerContentsContainerRows({\n container: move\n ? { ...input.container, parentId: move.parentContainerId }\n : input.container,\n localUpdatedAt:\n move?.updatedAt ??\n input.saveOptions.localUpdatedAt ??\n input.remoteUpdatedAt,\n record: input.record,\n serverTimestamps: input.saveOptions.serverTimestamps,\n tx,\n });\n}\n\nasync function loadDormantOrganizationId(\n execSql: ExecSql,\n containerId: string,\n): Promise<string | null> {\n const [row] = await getClientSQLitePersistenceRuntime(execSql)\n .db.select({ organizationId: dormantContainerMetadata.organizationId })\n .from(dormantContainerMetadata)\n .where(eq(dormantContainerMetadata.containerId, containerId))\n .limit(1);\n return row?.organizationId ?? null;\n}\n\n/**\n * The binding this device holds for a container id: its live row, or the\n * organization and metadata target retained after access loss. Null when the\n * device has never held the container.\n */\nexport async function loadStoredHeldContainerBinding(\n execSql: ExecSql,\n containerId: string,\n): Promise<HeldContainerBinding | null> {\n const container = await loadContainerById(execSql, containerId);\n const record = await selectContainerMetadataRecord(execSql, containerId);\n if (container) return heldContainerBinding({ container, record });\n if (!record) return null;\n // Retention records the organization with each retained record; without one\n // the retained metadata target still pins the binding.\n const dormantOrganizationId = await loadDormantOrganizationId(\n execSql,\n containerId,\n );\n return {\n organizationId: dormantOrganizationId ?? \"\",\n metadataDocumentId: record.documentId,\n };\n}\n\nexport async function commitStoredHydratedContainer(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitHydratedContainer\"]\n >[0],\n input: Parameters<ContainerContentsPersistence[\"commitHydratedContainer\"]>[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const commit = async (tx: ClientSQLiteTransactionScope) => {\n const existingContainers = await tx\n .select({ id: containers.id })\n .from(containers)\n .where(eq(containers.id, input.container.id))\n .limit(1);\n if (existingContainers.length > 0) return { committed: false as const };\n if (!(await placementCheckpointMatches(tx, input)))\n return { committed: false as const };\n\n const fences = await tx\n .select({\n generation: containerHydrationTombstones.generation,\n reason: containerHydrationTombstones.reason,\n updatedAt: containerHydrationTombstones.updatedAt,\n })\n .from(containerHydrationTombstones)\n .where(\n and(\n eq(containerHydrationTombstones.containerId, input.container.id),\n eq(containerHydrationTombstones.cleared, false),\n ),\n )\n .limit(1);\n const fence = fences[0];\n const currentDormantRecord = await selectContainerMetadataRecord(\n lockedExecSql,\n input.container.id,\n );\n if (\n fence &&\n !sameHydrationTombstone(fence, input.expectedHydrationTombstone)\n ) {\n return { committed: false as const };\n }\n if (\n !sameMetadataRecord(currentDormantRecord, input.expectedDormantRecord)\n ) {\n return { committed: false as const };\n }\n if (\n await isSupersededContainerBinding(lockedExecSql, {\n containerId: input.container.id,\n organizationId: input.container.organizationId,\n })\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container was re-homed away from this organization\",\n );\n }\n // Retained metadata keeps its organization and target; a relisting that\n // names others rolls back rather than replacing retained private edits.\n const dormantOrganizationId = await loadDormantOrganizationId(\n lockedExecSql,\n input.container.id,\n );\n assertHeldContainerBinding(\n {\n organizationId: dormantOrganizationId ?? \"\",\n metadataDocumentId: currentDormantRecord?.documentId ?? null,\n },\n {\n organizationId: input.container.organizationId,\n metadataDocumentIds: [\n input.container.metadataDocumentId,\n input.record.documentId,\n ],\n },\n );\n\n const container = await saveRecoveredContainer(tx, input);\n await tx\n .update(containerHydrationTombstones)\n .set({ cleared: true })\n .where(eq(containerHydrationTombstones.containerId, input.container.id))\n .run();\n return { committed: true as const, container };\n };\n if (!input.stillCurrent) {\n return runtime.transaction(commit, { behavior: \"immediate\" });\n }\n const outcome = await runtime.guardedTransaction(\n commit,\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.result ?? { committed: false as const };\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"containerHydrationPersistence.js","sourceRoot":"","sources":["containerHydrationPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { and, eq, inArray, sql } from \"drizzle-orm\";\nimport {\n assertHeldContainerBinding,\n type HeldContainerBinding,\n heldContainerBinding,\n} from \"../../containers/containerBinding\";\nimport { documentSyncPullContinuationsEqual } from \"../../documents/shared/pullContinuation\";\nimport {\n containerHydrationTombstones,\n containers,\n dormantContainerMetadata,\n inLocalIntentLane,\n LOCAL_INTENT_LANES,\n localIntents,\n} from \"../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, runSerializedSqlMutation } from \"../../sqlite/sqlSchema\";\nimport { loadContainerById } from \"../containers/containerPersistence\";\nimport { loadStoredAccessManifestCheckpoint } from \"../keyingCheckpointPersistence\";\nimport type {\n ContainerContentsPersistence,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n} from \"./containerContentsPersistenceTypes\";\nimport {\n saveContainerContentsContainerRows,\n selectContainerMetadataRecord,\n} from \"./containerMetadataRows\";\nimport { isSupersededContainerBinding } from \"./supersededContainerBindings\";\n\nfunction sameNullableValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nfunction sameMetadataRecord(\n current: ContainerMetadataRecord | null,\n expected: ContainerMetadataRecord | null,\n): boolean {\n if (!current || !expected) return current === expected;\n return (\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableValue(current.accessStateHash, expected.accessStateHash) &&\n sameNullableValue(current.lastCommitLsn, expected.lastCommitLsn) &&\n sameNullableValue(current.contentKeyBundle, expected.contentKeyBundle) &&\n sameNullableValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n ) &&\n current.metadataUpdates === expected.metadataUpdates &&\n current.snapshotEndVersion === expected.snapshotEndVersion &&\n documentSyncPullContinuationsEqual(\n current.pullContinuation,\n expected.pullContinuation,\n ) &&\n Boolean(current.pullContinuationRecoveryRequired) ===\n Boolean(expected.pullContinuationRecoveryRequired)\n );\n}\n\nfunction sameHydrationTombstone(\n current:\n | { generation: number; reason: string; updatedAt: string }\n | undefined,\n expected: ContainerHydrationTombstone | null | undefined,\n): boolean {\n return (\n current !== undefined &&\n expected != null &&\n current.generation === expected.generation &&\n current.reason === expected.reason &&\n current.updatedAt === expected.updatedAt\n );\n}\n\nexport async function recordContainerHydrationTombstones(input: {\n removals: ReadonlyArray<{\n containerId: string;\n reason: \"access_revoked\" | \"deleted\";\n updatedAt: string;\n }>;\n tx: ClientSQLiteTransactionScope;\n}): Promise<void> {\n if (input.removals.length === 0) return;\n await input.tx\n .insert(containerHydrationTombstones)\n .values([...input.removals])\n .onConflictDoUpdate({\n target: containerHydrationTombstones.containerId,\n set: {\n generation: sql`${containerHydrationTombstones.generation} + 1`,\n cleared: false,\n reason: sql`CASE\n WHEN ${containerHydrationTombstones.reason} = 'deleted' THEN 'deleted'\n ELSE excluded.reason\n END`,\n updatedAt: sql`MAX(${containerHydrationTombstones.updatedAt}, excluded.updated_at)`,\n },\n })\n .run();\n}\n\nasync function placementCheckpointMatches(\n tx: ClientSQLiteTransactionScope,\n input: Parameters<ContainerContentsPersistence[\"commitHydratedContainer\"]>[1],\n): Promise<boolean> {\n const expected = input.expectedPlacementCheckpoint;\n if (!expected) return true;\n const current = await loadStoredAccessManifestCheckpoint(tx, expected);\n return (\n expected.objectKind === \"container\" &&\n expected.objectId === input.container.id &&\n expected.organizationId === input.container.organizationId &&\n current?.epoch === expected.epoch &&\n current.manifestHash === expected.manifestHash\n );\n}\n\n/** A retained local move continues to own placement after verified reattachment. */\nasync function saveRecoveredContainer(\n tx: ClientSQLiteTransactionScope,\n input: Parameters<ContainerContentsPersistence[\"commitHydratedContainer\"]>[1],\n) {\n const [move] = await tx\n .select({\n parentContainerId: localIntents.targetContainerId,\n updatedAt: localIntents.updatedAt,\n })\n .from(localIntents)\n .where(\n and(\n inLocalIntentLane(LOCAL_INTENT_LANES.containerMove),\n eq(localIntents.subjectId, input.container.id),\n inArray(localIntents.syncStatus, [\"pending\", \"blocked\"]),\n ),\n )\n .limit(1);\n return saveContainerContentsContainerRows({\n container: move\n ? { ...input.container, parentId: move.parentContainerId }\n : input.container,\n localUpdatedAt:\n move?.updatedAt ??\n input.saveOptions.localUpdatedAt ??\n input.remoteUpdatedAt,\n record: input.record,\n serverTimestamps: input.saveOptions.serverTimestamps,\n tx,\n });\n}\n\nasync function loadDormantOrganizationId(\n execSql: ExecSql,\n containerId: string,\n): Promise<string | null> {\n const [row] = await getClientSQLitePersistenceRuntime(execSql)\n .db.select({ organizationId: dormantContainerMetadata.organizationId })\n .from(dormantContainerMetadata)\n .where(eq(dormantContainerMetadata.containerId, containerId))\n .limit(1);\n return row?.organizationId ?? null;\n}\n\n/**\n * The binding this device holds for a container id: its live row, or the\n * organization and metadata target retained after access loss. Null when the\n * device has never held the container.\n */\nexport async function loadStoredHeldContainerBinding(\n execSql: ExecSql,\n containerId: string,\n): Promise<HeldContainerBinding | null> {\n const container = await loadContainerById(execSql, containerId);\n const record = await selectContainerMetadataRecord(execSql, containerId);\n if (container) return heldContainerBinding({ container, record });\n if (!record) return null;\n // Retention records the organization with each retained record; without one\n // the retained metadata target still pins the binding.\n const dormantOrganizationId = await loadDormantOrganizationId(\n execSql,\n containerId,\n );\n return {\n organizationId: dormantOrganizationId ?? \"\",\n metadataDocumentId: record.documentId,\n };\n}\n\nexport async function commitStoredHydratedContainer(\n execSql: Parameters<\n ContainerContentsPersistence[\"commitHydratedContainer\"]\n >[0],\n input: Parameters<ContainerContentsPersistence[\"commitHydratedContainer\"]>[1],\n) {\n return runSerializedSqlMutation(execSql, async (lockedExecSql) => {\n const runtime = getClientSQLitePersistenceRuntime(lockedExecSql);\n const commit = async (tx: ClientSQLiteTransactionScope) => {\n const existingContainers = await tx\n .select({ id: containers.id })\n .from(containers)\n .where(eq(containers.id, input.container.id))\n .limit(1);\n if (existingContainers.length > 0) return { committed: false as const };\n if (!(await placementCheckpointMatches(tx, input)))\n return { committed: false as const };\n\n const fences = await tx\n .select({\n generation: containerHydrationTombstones.generation,\n reason: containerHydrationTombstones.reason,\n updatedAt: containerHydrationTombstones.updatedAt,\n })\n .from(containerHydrationTombstones)\n .where(\n and(\n eq(containerHydrationTombstones.containerId, input.container.id),\n eq(containerHydrationTombstones.cleared, false),\n ),\n )\n .limit(1);\n const fence = fences[0];\n const currentDormantRecord = await selectContainerMetadataRecord(\n lockedExecSql,\n input.container.id,\n );\n if (\n fence &&\n !sameHydrationTombstone(fence, input.expectedHydrationTombstone)\n ) {\n return { committed: false as const };\n }\n if (\n !sameMetadataRecord(currentDormantRecord, input.expectedDormantRecord)\n ) {\n return { committed: false as const };\n }\n if (\n await isSupersededContainerBinding(lockedExecSql, {\n containerId: input.container.id,\n organizationId: input.container.organizationId,\n })\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container was re-homed away from this organization\",\n );\n }\n // Retained metadata keeps its organization and target; a relisting that\n // names others rolls back rather than replacing retained private edits.\n const dormantOrganizationId = await loadDormantOrganizationId(\n lockedExecSql,\n input.container.id,\n );\n assertHeldContainerBinding(\n {\n organizationId: dormantOrganizationId ?? \"\",\n metadataDocumentId: currentDormantRecord?.documentId ?? null,\n },\n {\n organizationId: input.container.organizationId,\n metadataDocumentIds: [\n input.container.metadataDocumentId,\n input.record.documentId,\n ],\n },\n );\n\n const container = await saveRecoveredContainer(tx, input);\n await tx\n .update(containerHydrationTombstones)\n .set({ cleared: true })\n .where(eq(containerHydrationTombstones.containerId, input.container.id))\n .run();\n return { committed: true as const, container };\n };\n if (!input.stillCurrent) {\n return runtime.transaction(commit, { behavior: \"immediate\" });\n }\n const outcome = await runtime.guardedTransaction(\n commit,\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n return outcome.result ?? { committed: false as const };\n });\n}\n"]}
|