@tearleads/client-sdk 0.1.76 → 0.1.77
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/{containers → persistence/container-contents}/containerBinding.js +1 -1
- package/data/persistence/container-contents/containerContentsPersistence.js +2 -2
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.d.ts +2 -2
- package/data/persistence/container-contents/containerContentsPersistenceTypes.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +2 -2
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerHydrationPersistence.js +2 -2
- package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +2 -2
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
- package/data/persistence/container-contents/containerRebindPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +2 -2
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/dormantMetadataSweep.js +1 -1
- package/data/persistence/container-contents/dormantMetadataSweep.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
- package/data/persistence/documents/internal/discoveredDocumentPlacement.js +1 -1
- package/data/persistence/documents/internal/discoveredDocumentPlacement.js.map +1 -1
- package/package.json +1 -1
- package/stores/container-contents/systemContainers/systemContainerIcon.js +1 -1
- package/stores/container-contents/systemContainers/systemContainerIcon.js.map +1 -1
- package/workflows/container-contents/container-state/create/createChild.js +1 -1
- package/workflows/container-contents/container-state/create/createChild.js.map +1 -1
- package/workflows/container-contents/container-state/purge/purgeTree.js +1 -1
- package/workflows/container-contents/container-state/purge/purgeTree.js.map +1 -1
- package/workflows/container-contents/container-state/types.js.map +1 -1
- package/workflows/container-contents/containerPersistence.d.ts +3 -3
- package/workflows/container-contents/containerPersistence.js +1 -1
- package/workflows/container-contents/containerPersistence.js.map +1 -1
- package/workflows/container-contents/documentLinks/documentLinkIntent.js +1 -1
- package/workflows/container-contents/documentLinks/documentLinkIntent.js.map +1 -1
- package/workflows/container-contents/documentLinks/index.js +1 -1
- package/workflows/container-contents/documentLinks/index.js.map +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntent.js +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntent.js.map +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntentSettlement.js +2 -2
- package/workflows/container-contents/documentMove/documentMoveIntentSettlement.js.map +1 -1
- package/workflows/container-contents/documentQueries/documentSubtreeQueries.js +1 -1
- package/workflows/container-contents/documentQueries/documentSubtreeQueries.js.map +1 -1
- package/workflows/container-contents/documentQueries/index.js +3 -3
- package/workflows/container-contents/documentQueries/index.js.map +1 -1
- package/workflows/container-contents/documentQueries/pendingDownloads.js +1 -1
- package/workflows/container-contents/documentQueries/pendingDownloads.js.map +1 -1
- package/workflows/container-contents/index.d.ts +1 -1
- package/workflows/container-contents/index.js +1 -1
- package/workflows/container-contents/index.js.map +1 -1
- package/workflows/container-contents/info/blobInfo.js +1 -1
- package/workflows/container-contents/info/blobInfo.js.map +1 -1
- package/workflows/container-contents/info/containerInfo.js +2 -2
- package/workflows/container-contents/info/containerInfo.js.map +1 -1
- package/{data/containers → workflows/container-contents/metadata}/containerMetadataDocument.d.ts +1 -1
- package/{data/containers → workflows/container-contents/metadata}/containerMetadataDocument.js +2 -2
- package/workflows/container-contents/metadata/containerMetadataDocument.js.map +1 -0
- package/workflows/container-contents/metadata/metadataMutationPreparation.js +1 -1
- package/workflows/container-contents/metadata/metadataMutationPreparation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataPersistence.js +1 -1
- package/workflows/container-contents/metadata/metadataPersistence.js.map +1 -1
- package/workflows/container-contents/metadata/metadataRecord.js.map +1 -1
- package/workflows/container-contents/metadata/metadataStateIsolation.js +1 -1
- package/workflows/container-contents/metadata/metadataStateIsolation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js.map +1 -1
- package/workflows/container-contents/metadata/metadataTypes.d.ts +2 -2
- package/workflows/container-contents/metadata/metadataTypes.js.map +1 -1
- package/workflows/container-contents/recovery/folderRecovery.js +1 -1
- package/workflows/container-contents/recovery/folderRecovery.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/replacementBinding.js +1 -1
- package/workflows/container-contents/remoteHydration/destination/replacementBinding.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js.map +1 -1
- package/workflows/container-contents/remoteHydration/heldContainerRebind.js +1 -1
- package/workflows/container-contents/remoteHydration/heldContainerRebind.js.map +1 -1
- package/workflows/container-contents/remoteHydration/reattachMetadata.js +1 -1
- package/workflows/container-contents/remoteHydration/reattachMetadata.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js +2 -2
- package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js.map +1 -1
- package/workflows/container-contents/remoteHydration/types.d.ts +1 -1
- package/workflows/container-contents/remoteHydration/types.js.map +1 -1
- package/workflows/container-contents/storedContainerState.js +1 -1
- package/workflows/container-contents/storedContainerState.js.map +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js.map +1 -1
- package/workflows/organizations/readModel/localReadModelDetails.js +1 -1
- package/workflows/organizations/readModel/localReadModelDetails.js.map +1 -1
- package/workflows/registration/bootstrapRootContainer.js +1 -1
- package/workflows/registration/bootstrapRootContainer.js.map +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.js +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.js.map +1 -1
- package/workflows/registration/rootMetadataBootstrap.js +1 -1
- package/workflows/registration/rootMetadataBootstrap.js.map +1 -1
- package/workflows/sync/remoteReset.js +1 -1
- package/workflows/sync/remoteReset.js.map +1 -1
- package/data/containers/containerMetadataDocument.js.map +0 -1
- /package/data/{containers → persistence/container-contents}/containerBinding.d.ts +0 -0
- /package/data/{containers → persistence/container-contents}/containerBinding.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.d.ts +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.d.ts +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/documentContainerProjectionPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/documentContainerProjectionPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/documentPlacement.js +0 -0
- /package/data/persistence/{containers → container-contents}/documentPlacement.js.map +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { bytesToBase64 } from "../../../../internal/encoding/index.js";
|
|
2
|
-
import { createInitializedContainerMetadataDocument } from "../../../../data/containers/containerMetadataDocument.js";
|
|
3
2
|
import { createPendingUpdateFields } from "../../../../data/documents/documentSync.js";
|
|
4
3
|
import { deriveStableUuidV4Shaped } from "../../../../data/keying/stableUuid.js";
|
|
5
4
|
import { defaultContainerContentsPersistence } from "../../containerPersistence.js";
|
|
5
|
+
import { createInitializedContainerMetadataDocument } from "../../metadata/containerMetadataDocument.js";
|
|
6
6
|
import { loadContainerWriterProjectionForState } from "../projectionCache.js";
|
|
7
7
|
import { createRemoteContainer } from "../remote.js";
|
|
8
8
|
import { CONTAINER_ALREADY_COMMITTED } from "./createWithMetadata.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createChild.js","sourceRoot":"","sources":["createChild.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport { createInitializedContainerMetadataDocument } from \"../../../../data/containers/containerMetadataDocument\";\nimport { createPendingUpdateFields } from \"../../../../data/documents/documentSync\";\nimport { deriveStableUuidV4Shaped } from \"../../../../data/keying/stableUuid\";\nimport type { ProjectionUserKeyResolver } from \"../../../../data/keyingProjectionVerification\";\nimport type {\n ContainerContentsPersistence,\n ContainerDocumentRecord as DocumentRecord,\n} from \"../../containerPersistence\";\nimport { defaultContainerContentsPersistence } from \"../../containerPersistence\";\nimport type { ContainerState } from \"../../remoteHydration\";\nimport { loadContainerWriterProjectionForState } from \"../projectionCache\";\nimport { createRemoteContainer } from \"../remote\";\nimport type {\n ContainerMetadataDocumentState,\n ContainerWorkflowRuntime,\n CreatedChildContainerState,\n} from \"../types\";\nimport { CONTAINER_ALREADY_COMMITTED } from \"./createWithMetadata\";\n\nconst SYSTEM_CONTAINER_ID_NAMESPACE_BYTES = new Uint8Array([\n 0xc5, 0x5e, 0x8f, 0x2e, 0x3d, 0x82, 0x4b, 0x4d, 0x8d, 0xbd, 0x0d, 0xd2, 0xd3,\n 0x60, 0xb3, 0x6d,\n]);\n\n/**\n * Derives a stable, UUID-shaped container id for a built-in system slot.\n *\n * The namespace digest makes each slot idempotent across stale store snapshots.\n * The UUID version and variant bits are normalized to a v4 shape because remote\n * container APIs currently validate container ids with the same v4 UUID contract\n * they use for random user-created containers.\n */\nfunction deriveSystemContainerId(input: {\n parentContainerId: string;\n systemSlot: ContainerSystemSlot;\n}): Promise<string> {\n return deriveStableUuidV4Shaped(\n SYSTEM_CONTAINER_ID_NAMESPACE_BYTES,\n `${input.parentContainerId}\\u0000${input.systemSlot}`,\n );\n}\n\nasync function createChildContainerId(\n parentContainerId: string,\n systemSlot: ContainerSystemSlot | null | undefined,\n): Promise<string> {\n return systemSlot\n ? deriveSystemContainerId({ parentContainerId, systemSlot })\n : crypto.randomUUID();\n}\n\nasync function buildRemoteContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n trimmedName: string;\n}): Promise<ContainerState | null> {\n const {\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n trimmedName,\n } = input;\n const parentProjection = await loadContainerWriterProjectionForState({\n containerState: parentState,\n runtime,\n });\n if (!parentProjection) {\n return null;\n }\n\n const created = await createRemoteContainer({\n systemSlot,\n containerId: childId,\n parentContainerId: parentState.container.id,\n parentProjection,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n });\n\n if (!created || created === CONTAINER_ALREADY_COMMITTED) {\n // A benign manifest-exists conflict means the container is already committed\n // remotely (a lost create response). This eager path cannot rebuild its\n // committed metadata state, so leave the create intent to reconcile it via\n // hydration rather than fabricating a local record from a missing response.\n return null;\n }\n\n return {\n container: {\n id: created.containerId,\n // The creator owns a newly-created container until the server reconciles.\n effectiveAccessLevel: \"admin\",\n organizationId: created.organizationId,\n parentId: created.parentId,\n metadataDocumentId: created.metadataDocumentId,\n systemSlot: created.systemSlot,\n name: trimmedName,\n icon,\n createdAt: created.createdAt,\n serverCreatedAt: created.createdAt,\n serverUpdatedAt: created.updatedAt,\n updatedAt: created.updatedAt,\n },\n doc,\n record: {\n ...initialRecord,\n accessEpoch: 1,\n accessStateHash: created.accessManifestHash,\n ...created.persistedMetadataState,\n },\n };\n}\n\nfunction buildLocalContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n trimmedName: string;\n}): ContainerState {\n const {\n systemSlot,\n childId,\n doc,\n icon,\n initialRecord,\n parentState,\n trimmedName,\n } = input;\n\n return {\n container: {\n id: childId,\n effectiveAccessLevel: \"admin\",\n organizationId: parentState.container.organizationId,\n parentId: parentState.container.id,\n metadataDocumentId: null,\n systemSlot: systemSlot ?? null,\n name: trimmedName,\n icon,\n },\n doc,\n record: initialRecord,\n };\n}\n\nfunction createInitialChildContainerDocumentRecord(input: {\n childId: string;\n initialUpdate: Uint8Array;\n}): DocumentRecord {\n return {\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n id: input.childId,\n lastCommitLsn: null,\n metadataUpdates: bytesToBase64(input.initialUpdate),\n snapshotEndVersion: \"\",\n };\n}\n\nfunction resolveAtomicChildContainerSave(\n persistence: ContainerContentsPersistence,\n): NonNullable<\n ContainerContentsPersistence[\"saveContainerWithPendingUpdate\"]\n> | null {\n const saveContainerWithPendingUpdate =\n persistence.saveContainerWithPendingUpdate;\n if (!saveContainerWithPendingUpdate) return null;\n const inheritedSqlAtomicSave =\n saveContainerWithPendingUpdate ===\n defaultContainerContentsPersistence.saveContainerWithPendingUpdate &&\n (persistence.saveContainer !==\n defaultContainerContentsPersistence.saveContainer ||\n persistence.enqueuePendingUpdate !==\n defaultContainerContentsPersistence.enqueuePendingUpdate);\n return inheritedSqlAtomicSave ? null : saveContainerWithPendingUpdate;\n}\n\nasync function persistCreatedChildContainer(input: {\n containerState: ContainerState;\n initialUpdate: Uint8Array;\n persistence: ContainerContentsPersistence;\n queueRemoteSync: boolean;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean | null> {\n const { containerState, persistence, queueRemoteSync, runtime } = input;\n const createIntent =\n queueRemoteSync &&\n !containerState.record.documentId &&\n containerState.container.parentId\n ? { parentContainerId: containerState.container.parentId }\n : undefined;\n const shouldRequestSync =\n queueRemoteSync &&\n (!containerState.record.documentId ||\n Boolean(containerState.record.contentKeyBundle));\n const saveOptions =\n createIntent || input.stillCurrent\n ? {\n ...(createIntent ? { createIntent } : {}),\n stillCurrent: input.stillCurrent,\n }\n : undefined;\n const pendingUpdate = shouldRequestSync\n ? createPendingUpdateFields(input.initialUpdate)\n : null;\n if (pendingUpdate) {\n const saveContainerWithPendingUpdate =\n resolveAtomicChildContainerSave(persistence);\n if (!saveContainerWithPendingUpdate) return null;\n containerState.container = await saveContainerWithPendingUpdate(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n { ...saveOptions, pendingUpdate },\n );\n } else {\n containerState.container = await persistence.saveContainer(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n saveOptions,\n );\n }\n return input.stillCurrent?.() === false ? null : shouldRequestSync;\n}\n\nexport async function createChildContainerState(input: {\n systemSlot?: ContainerSystemSlot | null | undefined;\n createRemote: boolean;\n icon?: string | null | undefined;\n name: string;\n parentState: ContainerState;\n persistence: ContainerContentsPersistence;\n queueRemoteSync?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<CreatedChildContainerState | null> {\n const {\n createRemote,\n systemSlot,\n name,\n parentState,\n persistence,\n queueRemoteSync = true,\n resolveProjectionUserKey,\n runtime,\n } = input;\n const trimmedName = name.trim();\n if (!trimmedName) {\n return null;\n }\n\n const icon = input.icon?.trim() || null;\n const childId = await createChildContainerId(\n parentState.container.id,\n systemSlot,\n );\n const { doc, initialUpdate } =\n await createInitializedContainerMetadataDocument(childId, {\n icon,\n name: trimmedName,\n });\n const initialRecord = createInitialChildContainerDocumentRecord({\n childId,\n initialUpdate,\n });\n if (input.stillCurrent?.() === false) return null;\n // An initial metadata update and its container identity are one durable unit.\n // Refuse before any remote create when an adapter cannot provide\n // that atomic operation; a SQLite transaction cannot roll back adapter-owned\n // side effects.\n if (queueRemoteSync && !resolveAtomicChildContainerSave(persistence)) {\n return null;\n }\n\n const remoteChildState = createRemote\n ? await buildRemoteContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent: input.stillCurrent,\n trimmedName,\n })\n : null;\n const containerState =\n remoteChildState ??\n buildLocalContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n trimmedName,\n });\n const shouldRequestSync = await persistCreatedChildContainer({\n containerState,\n initialUpdate,\n persistence,\n queueRemoteSync,\n runtime,\n stillCurrent: input.stillCurrent,\n });\n if (shouldRequestSync === null) return null;\n\n return {\n containerState,\n initialUpdate,\n shouldRequestSync,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"createChild.js","sourceRoot":"","sources":["createChild.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAM9E,OAAO,EAAE,mCAAmC,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,0CAA0C,EAAE,MAAM,0CAA0C,CAAC;AAEtG,OAAO,EAAE,qCAAqC,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAMlD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,mCAAmC,GAAG,IAAI,UAAU,CAAC;IACzD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC5E,IAAI,EAAE,IAAI,EAAE,IAAI;CACjB,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,SAAS,uBAAuB,CAAC,KAGhC;IACC,OAAO,wBAAwB,CAC7B,mCAAmC,EACnC,GAAG,KAAK,CAAC,iBAAiB,SAAS,KAAK,CAAC,UAAU,EAAE,CACtD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,iBAAyB,EACzB,UAAkD;IAElD,OAAO,UAAU;QACf,CAAC,CAAC,uBAAuB,CAAC,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC;QAC5D,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;AAC1B,CAAC;AAED,KAAK,UAAU,+CAA+C,CAAC,KAW9D;IACC,MAAM,EACJ,OAAO,EACP,IAAI,EACJ,UAAU,EACV,GAAG,EACH,aAAa,EACb,WAAW,EACX,wBAAwB,EACxB,OAAO,EACP,YAAY,EACZ,WAAW,GACZ,GAAG,KAAK,CAAC;IACV,MAAM,gBAAgB,GAAG,MAAM,qCAAqC,CAAC;QACnE,cAAc,EAAE,WAAW;QAC3B,OAAO;KACR,CAAC,CAAC;IACH,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC;QAC1C,UAAU;QACV,WAAW,EAAE,OAAO;QACpB,iBAAiB,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE;QAC3C,gBAAgB;QAChB,wBAAwB;QACxB,OAAO;QACP,YAAY;KACb,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,2BAA2B,EAAE,CAAC;QACxD,6EAA6E;QAC7E,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,SAAS,EAAE;YACT,EAAE,EAAE,OAAO,CAAC,WAAW;YACvB,0EAA0E;YAC1E,oBAAoB,EAAE,OAAO;YAC7B,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;YAC9C,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,IAAI,EAAE,WAAW;YACjB,IAAI;YACJ,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,eAAe,EAAE,OAAO,CAAC,SAAS;YAClC,eAAe,EAAE,OAAO,CAAC,SAAS;YAClC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B;QACD,GAAG;QACH,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,OAAO,CAAC,kBAAkB;YAC3C,GAAG,OAAO,CAAC,sBAAsB;SAClC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,8CAA8C,CAAC,KAQvD;IACC,MAAM,EACJ,UAAU,EACV,OAAO,EACP,GAAG,EACH,IAAI,EACJ,aAAa,EACb,WAAW,EACX,WAAW,GACZ,GAAG,KAAK,CAAC;IAEV,OAAO;QACL,SAAS,EAAE;YACT,EAAE,EAAE,OAAO;YACX,oBAAoB,EAAE,OAAO;YAC7B,cAAc,EAAE,WAAW,CAAC,SAAS,CAAC,cAAc;YACpD,QAAQ,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE;YAClC,kBAAkB,EAAE,IAAI;YACxB,UAAU,EAAE,UAAU,IAAI,IAAI;YAC9B,IAAI,EAAE,WAAW;YACjB,IAAI;SACL;QACD,GAAG;QACH,MAAM,EAAE,aAAa;KACtB,CAAC;AACJ,CAAC;AAED,SAAS,yCAAyC,CAAC,KAGlD;IACC,OAAO;QACL,WAAW,EAAE,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,gBAAgB,EAAE,IAAI;QACtB,UAAU,EAAE,IAAI;QAChB,kBAAkB,EAAE,IAAI;QACxB,sBAAsB,EAAE,IAAI;QAC5B,EAAE,EAAE,KAAK,CAAC,OAAO;QACjB,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC;QACnD,kBAAkB,EAAE,EAAE;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,WAAyC;IAIzC,MAAM,8BAA8B,GAClC,WAAW,CAAC,8BAA8B,CAAC;IAC7C,IAAI,CAAC,8BAA8B;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,sBAAsB,GAC1B,8BAA8B;QAC5B,mCAAmC,CAAC,8BAA8B;QACpE,CAAC,WAAW,CAAC,aAAa;YACxB,mCAAmC,CAAC,aAAa;YACjD,WAAW,CAAC,oBAAoB;gBAC9B,mCAAmC,CAAC,oBAAoB,CAAC,CAAC;IAChE,OAAO,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,8BAA8B,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,4BAA4B,CAAC,KAO3C;IACC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IACxE,MAAM,YAAY,GAChB,eAAe;QACf,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU;QACjC,cAAc,CAAC,SAAS,CAAC,QAAQ;QAC/B,CAAC,CAAC,EAAE,iBAAiB,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,EAAE;QAC1D,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,iBAAiB,GACrB,eAAe;QACf,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU;YAChC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACrD,MAAM,WAAW,GACf,YAAY,IAAI,KAAK,CAAC,YAAY;QAChC,CAAC,CAAC;YACE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC;QACH,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,aAAa,GAAG,iBAAiB;QACrC,CAAC,CAAC,yBAAyB,CAAC,KAAK,CAAC,aAAa,CAAC;QAChD,CAAC,CAAC,IAAI,CAAC;IACT,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,8BAA8B,GAClC,+BAA+B,CAAC,WAAW,CAAC,CAAC;QAC/C,IAAI,CAAC,8BAA8B;YAAE,OAAO,IAAI,CAAC;QACjD,cAAc,CAAC,SAAS,GAAG,MAAM,8BAA8B,CAC7D,OAAO,CAAC,KAAK,CAAC,OAAO,EACrB,cAAc,CAAC,SAAS,EACxB,cAAc,CAAC,MAAM,EACrB,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,CAClC,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,SAAS,GAAG,MAAM,WAAW,CAAC,aAAa,CACxD,OAAO,CAAC,KAAK,CAAC,OAAO,EACrB,cAAc,CAAC,SAAS,EACxB,cAAc,CAAC,MAAM,EACrB,WAAW,CACZ,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAW/C;IACC,MAAM,EACJ,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,eAAe,GAAG,IAAI,EACtB,wBAAwB,EACxB,OAAO,GACR,GAAG,KAAK,CAAC;IACV,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAC1C,WAAW,CAAC,SAAS,CAAC,EAAE,EACxB,UAAU,CACX,CAAC;IACF,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,GAC1B,MAAM,0CAA0C,CAAC,OAAO,EAAE;QACxD,IAAI;QACJ,IAAI,EAAE,WAAW;KAClB,CAAC,CAAC;IACL,MAAM,aAAa,GAAG,yCAAyC,CAAC;QAC9D,OAAO;QACP,aAAa;KACd,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAClD,8EAA8E;IAC9E,iEAAiE;IACjE,6EAA6E;IAC7E,gBAAgB;IAChB,IAAI,eAAe,IAAI,CAAC,+BAA+B,CAAC,WAAW,CAAC,EAAE,CAAC;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,YAAY;QACnC,CAAC,CAAC,MAAM,+CAA+C,CAAC;YACpD,OAAO;YACP,IAAI;YACJ,UAAU;YACV,GAAG;YACH,aAAa;YACb,WAAW;YACX,wBAAwB;YACxB,OAAO;YACP,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW;SACZ,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,cAAc,GAClB,gBAAgB;QAChB,8CAA8C,CAAC;YAC7C,OAAO;YACP,IAAI;YACJ,UAAU;YACV,GAAG;YACH,aAAa;YACb,WAAW;YACX,WAAW;SACZ,CAAC,CAAC;IACL,MAAM,iBAAiB,GAAG,MAAM,4BAA4B,CAAC;QAC3D,cAAc;QACd,aAAa;QACb,WAAW;QACX,eAAe;QACf,OAAO;QACP,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAC;IACH,IAAI,iBAAiB,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE5C,OAAO;QACL,cAAc;QACd,aAAa;QACb,iBAAiB;KAClB,CAAC;AACJ,CAAC","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport { createPendingUpdateFields } from \"../../../../data/documents/documentSync\";\nimport { deriveStableUuidV4Shaped } from \"../../../../data/keying/stableUuid\";\nimport type { ProjectionUserKeyResolver } from \"../../../../data/keyingProjectionVerification\";\nimport type {\n ContainerContentsPersistence,\n ContainerDocumentRecord as DocumentRecord,\n} from \"../../containerPersistence\";\nimport { defaultContainerContentsPersistence } from \"../../containerPersistence\";\nimport { createInitializedContainerMetadataDocument } from \"../../metadata/containerMetadataDocument\";\nimport type { ContainerState } from \"../../remoteHydration\";\nimport { loadContainerWriterProjectionForState } from \"../projectionCache\";\nimport { createRemoteContainer } from \"../remote\";\nimport type {\n ContainerMetadataDocumentState,\n ContainerWorkflowRuntime,\n CreatedChildContainerState,\n} from \"../types\";\nimport { CONTAINER_ALREADY_COMMITTED } from \"./createWithMetadata\";\n\nconst SYSTEM_CONTAINER_ID_NAMESPACE_BYTES = new Uint8Array([\n 0xc5, 0x5e, 0x8f, 0x2e, 0x3d, 0x82, 0x4b, 0x4d, 0x8d, 0xbd, 0x0d, 0xd2, 0xd3,\n 0x60, 0xb3, 0x6d,\n]);\n\n/**\n * Derives a stable, UUID-shaped container id for a built-in system slot.\n *\n * The namespace digest makes each slot idempotent across stale store snapshots.\n * The UUID version and variant bits are normalized to a v4 shape because remote\n * container APIs currently validate container ids with the same v4 UUID contract\n * they use for random user-created containers.\n */\nfunction deriveSystemContainerId(input: {\n parentContainerId: string;\n systemSlot: ContainerSystemSlot;\n}): Promise<string> {\n return deriveStableUuidV4Shaped(\n SYSTEM_CONTAINER_ID_NAMESPACE_BYTES,\n `${input.parentContainerId}\\u0000${input.systemSlot}`,\n );\n}\n\nasync function createChildContainerId(\n parentContainerId: string,\n systemSlot: ContainerSystemSlot | null | undefined,\n): Promise<string> {\n return systemSlot\n ? deriveSystemContainerId({ parentContainerId, systemSlot })\n : crypto.randomUUID();\n}\n\nasync function buildRemoteContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n trimmedName: string;\n}): Promise<ContainerState | null> {\n const {\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n trimmedName,\n } = input;\n const parentProjection = await loadContainerWriterProjectionForState({\n containerState: parentState,\n runtime,\n });\n if (!parentProjection) {\n return null;\n }\n\n const created = await createRemoteContainer({\n systemSlot,\n containerId: childId,\n parentContainerId: parentState.container.id,\n parentProjection,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n });\n\n if (!created || created === CONTAINER_ALREADY_COMMITTED) {\n // A benign manifest-exists conflict means the container is already committed\n // remotely (a lost create response). This eager path cannot rebuild its\n // committed metadata state, so leave the create intent to reconcile it via\n // hydration rather than fabricating a local record from a missing response.\n return null;\n }\n\n return {\n container: {\n id: created.containerId,\n // The creator owns a newly-created container until the server reconciles.\n effectiveAccessLevel: \"admin\",\n organizationId: created.organizationId,\n parentId: created.parentId,\n metadataDocumentId: created.metadataDocumentId,\n systemSlot: created.systemSlot,\n name: trimmedName,\n icon,\n createdAt: created.createdAt,\n serverCreatedAt: created.createdAt,\n serverUpdatedAt: created.updatedAt,\n updatedAt: created.updatedAt,\n },\n doc,\n record: {\n ...initialRecord,\n accessEpoch: 1,\n accessStateHash: created.accessManifestHash,\n ...created.persistedMetadataState,\n },\n };\n}\n\nfunction buildLocalContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n trimmedName: string;\n}): ContainerState {\n const {\n systemSlot,\n childId,\n doc,\n icon,\n initialRecord,\n parentState,\n trimmedName,\n } = input;\n\n return {\n container: {\n id: childId,\n effectiveAccessLevel: \"admin\",\n organizationId: parentState.container.organizationId,\n parentId: parentState.container.id,\n metadataDocumentId: null,\n systemSlot: systemSlot ?? null,\n name: trimmedName,\n icon,\n },\n doc,\n record: initialRecord,\n };\n}\n\nfunction createInitialChildContainerDocumentRecord(input: {\n childId: string;\n initialUpdate: Uint8Array;\n}): DocumentRecord {\n return {\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n id: input.childId,\n lastCommitLsn: null,\n metadataUpdates: bytesToBase64(input.initialUpdate),\n snapshotEndVersion: \"\",\n };\n}\n\nfunction resolveAtomicChildContainerSave(\n persistence: ContainerContentsPersistence,\n): NonNullable<\n ContainerContentsPersistence[\"saveContainerWithPendingUpdate\"]\n> | null {\n const saveContainerWithPendingUpdate =\n persistence.saveContainerWithPendingUpdate;\n if (!saveContainerWithPendingUpdate) return null;\n const inheritedSqlAtomicSave =\n saveContainerWithPendingUpdate ===\n defaultContainerContentsPersistence.saveContainerWithPendingUpdate &&\n (persistence.saveContainer !==\n defaultContainerContentsPersistence.saveContainer ||\n persistence.enqueuePendingUpdate !==\n defaultContainerContentsPersistence.enqueuePendingUpdate);\n return inheritedSqlAtomicSave ? null : saveContainerWithPendingUpdate;\n}\n\nasync function persistCreatedChildContainer(input: {\n containerState: ContainerState;\n initialUpdate: Uint8Array;\n persistence: ContainerContentsPersistence;\n queueRemoteSync: boolean;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean | null> {\n const { containerState, persistence, queueRemoteSync, runtime } = input;\n const createIntent =\n queueRemoteSync &&\n !containerState.record.documentId &&\n containerState.container.parentId\n ? { parentContainerId: containerState.container.parentId }\n : undefined;\n const shouldRequestSync =\n queueRemoteSync &&\n (!containerState.record.documentId ||\n Boolean(containerState.record.contentKeyBundle));\n const saveOptions =\n createIntent || input.stillCurrent\n ? {\n ...(createIntent ? { createIntent } : {}),\n stillCurrent: input.stillCurrent,\n }\n : undefined;\n const pendingUpdate = shouldRequestSync\n ? createPendingUpdateFields(input.initialUpdate)\n : null;\n if (pendingUpdate) {\n const saveContainerWithPendingUpdate =\n resolveAtomicChildContainerSave(persistence);\n if (!saveContainerWithPendingUpdate) return null;\n containerState.container = await saveContainerWithPendingUpdate(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n { ...saveOptions, pendingUpdate },\n );\n } else {\n containerState.container = await persistence.saveContainer(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n saveOptions,\n );\n }\n return input.stillCurrent?.() === false ? null : shouldRequestSync;\n}\n\nexport async function createChildContainerState(input: {\n systemSlot?: ContainerSystemSlot | null | undefined;\n createRemote: boolean;\n icon?: string | null | undefined;\n name: string;\n parentState: ContainerState;\n persistence: ContainerContentsPersistence;\n queueRemoteSync?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<CreatedChildContainerState | null> {\n const {\n createRemote,\n systemSlot,\n name,\n parentState,\n persistence,\n queueRemoteSync = true,\n resolveProjectionUserKey,\n runtime,\n } = input;\n const trimmedName = name.trim();\n if (!trimmedName) {\n return null;\n }\n\n const icon = input.icon?.trim() || null;\n const childId = await createChildContainerId(\n parentState.container.id,\n systemSlot,\n );\n const { doc, initialUpdate } =\n await createInitializedContainerMetadataDocument(childId, {\n icon,\n name: trimmedName,\n });\n const initialRecord = createInitialChildContainerDocumentRecord({\n childId,\n initialUpdate,\n });\n if (input.stillCurrent?.() === false) return null;\n // An initial metadata update and its container identity are one durable unit.\n // Refuse before any remote create when an adapter cannot provide\n // that atomic operation; a SQLite transaction cannot roll back adapter-owned\n // side effects.\n if (queueRemoteSync && !resolveAtomicChildContainerSave(persistence)) {\n return null;\n }\n\n const remoteChildState = createRemote\n ? await buildRemoteContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent: input.stillCurrent,\n trimmedName,\n })\n : null;\n const containerState =\n remoteChildState ??\n buildLocalContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n trimmedName,\n });\n const shouldRequestSync = await persistCreatedChildContainer({\n containerState,\n initialUpdate,\n persistence,\n queueRemoteSync,\n runtime,\n stillCurrent: input.stillCurrent,\n });\n if (shouldRequestSync === null) return null;\n\n return {\n containerState,\n initialUpdate,\n shouldRequestSync,\n };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_DOCUMENT_KIND } from "../../../../data/documents/documentConstants.js";
|
|
2
|
-
import { sqlDocumentContainerProjectionPersistence } from "../../../../data/persistence/
|
|
2
|
+
import { sqlDocumentContainerProjectionPersistence } from "../../../../data/persistence/container-contents/documentContainerProjectionPersistence.js";
|
|
3
3
|
import { listDocumentsByContainerIdsOrDocumentIds } from "../../../../data/persistence/documents/documentsPersistence.js";
|
|
4
4
|
import { unlinkRemoteContainerDocument } from "../../documentLinks/index.js";
|
|
5
5
|
import { purgeLocalContainerDocument, purgeRemoteContainerDocument, } from "../../tombstones/documentPurge.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purgeTree.js","sourceRoot":"","sources":["purgeTree.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../../../../data/documents/documentConstants\";\nimport type { DocumentSummary } from \"../../../../data/documents/documentSummary\";\nimport type { ProjectionUserKeyResolver } from \"../../../../data/keyingProjectionVerification\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../../data/persistence/containers/documentContainerProjectionPersistence\";\nimport { listDocumentsByContainerIdsOrDocumentIds } from \"../../../../data/persistence/documents/documentsPersistence\";\nimport type { SubtreePurgeRoot } from \"../../../documents/purge/subtreePurgeScope\";\nimport type { ContainerContentsPersistence } from \"../../containerPersistence\";\nimport { unlinkRemoteContainerDocument } from \"../../documentLinks\";\nimport type { ContainerState } from \"../../remoteHydration\";\nimport type { ContainerContentsWorkflowRuntime } from \"../../runtime\";\nimport {\n purgeLocalContainerDocument,\n purgeRemoteContainerDocument,\n} from \"../../tombstones/documentPurge\";\nimport type { PurgeProgress } from \"./purgeProgress\";\nimport {\n collectSubtreeLeafFirst,\n snapshotContainerStates,\n} from \"./purgeTreeCollection\";\nimport { deleteSubtreeContainers } from \"./purgeTreeContainerDeletion\";\nimport { createSubtreePurgeScope } from \"./purgeTreeScope\";\n\nexport { collectSubtreeLeafFirst } from \"./purgeTreeCollection\";\n\n// The store runtime satisfies the per-document purge/unlink workflows, so the\n// cascade reuses it verbatim.\ntype PurgeContainerTreeRuntime = ContainerContentsWorkflowRuntime;\n\ninterface PurgeContainerTreeInput {\n readonly containersById: ReadonlyMap<string, ContainerState>;\n readonly documentOperations?: SubtreeDocumentOperations | undefined;\n // When true, tear down everything UNDER the root (its documents plus every\n // descendant container) but never delete the root container itself. This is\n // how \"Empty Trash\" reuses the same engine: the Trash bin is a protected system\n // container that must survive while its whole contents are destroyed.\n readonly keepRootContainer?: boolean;\n readonly onProgress?: ((progress: PurgeProgress) => void) | undefined;\n readonly persistence: ContainerContentsPersistence;\n readonly prepareDocumentRotationSnapshot: (\n document: DocumentSummary,\n ) => Promise<Uint8Array | null>;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly rootContainerId: string;\n readonly runtime: PurgeContainerTreeRuntime;\n /** Stops a stale store generation between complete destructive units. */\n readonly stillCurrent?: (() => boolean) | undefined;\n // Checked at each unit boundary (between whole documents / whole containers),\n // never mid-remote-call, so a cancelled run stops on a consistent prefix.\n readonly signal?: AbortSignal | undefined;\n}\n\ninterface PurgeContainerTreeResult {\n readonly aborted: boolean;\n readonly completedCount: number;\n readonly failedCount: number;\n readonly purgedContainerIds: readonly string[];\n readonly remoteDeletedContainerIds: readonly string[];\n readonly totalCount: number;\n}\n\ninterface SubtreeDocumentPlan {\n // Synced documents whose every link falls inside the subtree: reduce them to\n // one retained link, as required by the purge endpoint, then destroy them.\n readonly purge: readonly {\n document: DocumentSummary;\n unlinkContainerIds: readonly string[];\n }[];\n // Synced documents also linked outside the subtree: keep them, but unlink\n // from each in-subtree container so the containers can be deleted.\n readonly unlinkByDocument: ReadonlyMap<\n string,\n { document: DocumentSummary; containerIds: readonly string[] }\n >;\n // Never-synced documents (no remote id): destroy locally only.\n readonly purgeLocal: readonly DocumentSummary[];\n}\n\ntype SubtreeDocumentDisposition =\n | { kind: \"purge\"; unlinkContainerIds: readonly string[] }\n | { kind: \"purge-local\" }\n | { kind: \"unlink\"; containerIds: readonly string[] };\n\n// Destroy local-only documents locally. Destroy synced documents only when all\n// links are in the subtree; preserve documents with an external link. The purge\n// plan reduces owned documents to the server-required sole link first.\nexport function classifySubtreeDocument(input: {\n readonly documentId: string | null;\n readonly linkedContainerIds: readonly string[];\n readonly preferredContainerId?: string | null | undefined;\n readonly subtreeContainerIds: ReadonlySet<string>;\n}): SubtreeDocumentDisposition {\n if (!input.documentId) {\n return { kind: \"purge-local\" };\n }\n const hasExternalLink = input.linkedContainerIds.some(\n (containerId) => !input.subtreeContainerIds.has(containerId),\n );\n if (!hasExternalLink) {\n const linkedContainerIds = Array.from(\n new Set(\n input.linkedContainerIds.filter((containerId) =>\n input.subtreeContainerIds.has(containerId),\n ),\n ),\n );\n const retainedContainerId =\n input.preferredContainerId &&\n linkedContainerIds.includes(input.preferredContainerId)\n ? input.preferredContainerId\n : linkedContainerIds[0];\n return {\n kind: \"purge\",\n unlinkContainerIds: linkedContainerIds.filter(\n (containerId) => containerId !== retainedContainerId,\n ),\n };\n }\n return {\n kind: \"unlink\",\n containerIds: input.linkedContainerIds.filter((containerId) =>\n input.subtreeContainerIds.has(containerId),\n ),\n };\n}\n\nasync function planSubtreeDocuments(input: {\n readonly execSql: PurgeContainerTreeRuntime[\"infra\"][\"execSql\"];\n readonly subtreeContainerIds: ReadonlySet<string>;\n}): Promise<SubtreeDocumentPlan> {\n const documents = await listDocumentsByContainerIdsOrDocumentIds(\n input.execSql,\n {\n containerIds: [...input.subtreeContainerIds],\n documentIds: [],\n },\n );\n const remoteDocumentIds = documents.flatMap((document) =>\n document.documentId ? [document.documentId] : [],\n );\n const linkedContainerIdsByDocumentId =\n await sqlDocumentContainerProjectionPersistence.listLinkedContainerIdsByDocumentIds(\n input.execSql,\n remoteDocumentIds,\n );\n\n const purge: Array<{\n document: DocumentSummary;\n unlinkContainerIds: readonly string[];\n }> = [];\n const purgeLocal: DocumentSummary[] = [];\n const unlinkByDocument = new Map<\n string,\n { document: DocumentSummary; containerIds: readonly string[] }\n >();\n for (const document of documents) {\n const disposition = classifySubtreeDocument({\n documentId: document.documentId ?? null,\n linkedContainerIds: document.documentId\n ? (linkedContainerIdsByDocumentId.get(document.documentId) ?? [])\n : [],\n preferredContainerId: document.containerId,\n subtreeContainerIds: input.subtreeContainerIds,\n });\n if (disposition.kind === \"purge-local\") {\n purgeLocal.push(document);\n } else if (disposition.kind === \"purge\") {\n purge.push({\n document,\n unlinkContainerIds: disposition.unlinkContainerIds,\n });\n } else if (document.documentId) {\n unlinkByDocument.set(document.documentId, {\n document,\n containerIds: disposition.containerIds,\n });\n }\n }\n\n return { purge, purgeLocal, unlinkByDocument };\n}\n\nasync function unlinkSubtreeDocument(input: {\n /** Rechecks the document and this exact unlink target before dispatch. */\n readonly beforeSubmit: (targetContainerId: string) => Promise<boolean>;\n readonly expectedSubtreeRoot: SubtreePurgeRoot;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly containerIds: readonly string[];\n readonly document: DocumentSummary;\n readonly prepareDocumentRotationSnapshot: PurgeContainerTreeInput[\"prepareDocumentRotationSnapshot\"];\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly runtime: PurgeContainerTreeRuntime;\n}): Promise<boolean> {\n const documentId = input.document.documentId;\n if (!documentId) {\n return true;\n }\n let rotationSnapshot: Uint8Array | null;\n try {\n rotationSnapshot = await input.prepareDocumentRotationSnapshot(\n input.document,\n );\n } catch {\n return false;\n }\n if (!rotationSnapshot) {\n return false;\n }\n for (const containerId of input.containerIds) {\n const result = await unlinkRemoteContainerDocument({\n beforeSubmit: () => input.beforeSubmit(containerId),\n documentId,\n expectedSubtreeRoot: input.expectedSubtreeRoot,\n isCurrent: input.stillCurrent,\n noteId: input.document.id,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n rotationSnapshot,\n runtime: input.runtime,\n targetContainerId: containerId,\n });\n if (result === null) {\n return false;\n }\n }\n return true;\n}\n\ninterface SubtreeDocumentOperations {\n readonly purgeLocal: (document: DocumentSummary) => Promise<boolean>;\n readonly purgeRemote: (document: DocumentSummary) => Promise<boolean>;\n readonly unlink: (\n document: DocumentSummary,\n containerIds: readonly string[],\n ) => Promise<boolean>;\n}\n\nfunction resolveSubtreeDocumentOperations(\n input: PurgeContainerTreeInput,\n scope: ReturnType<typeof createSubtreePurgeScope>,\n): SubtreeDocumentOperations {\n const expectedSubtreeRoot = selectedSubtreeRoot(input);\n const operations: SubtreeDocumentOperations = input.documentOperations ?? {\n purgeLocal: async (document) =>\n (await purgeLocalContainerDocument({\n beforeDeleteInTransaction: (execSql) =>\n scope.assertLocalScopeInTransaction(\n execSql,\n document.containerId,\n document.id,\n ),\n noteId: document.id,\n expectedContainerId: document.containerId,\n runtime: input.runtime,\n })) !== null,\n purgeRemote: async (document) =>\n Boolean(\n document.documentId &&\n (await purgeRemoteContainerDocument({\n beforeSubmit: () => scope.allowsDocument(document),\n documentId: document.documentId,\n expectedSubtreeRoot,\n stillCurrent: input.stillCurrent,\n documentKind: document.documentKind ?? DEFAULT_DOCUMENT_KIND,\n noteId: document.id,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n runtime: input.runtime,\n })),\n ),\n unlink: (document, containerIds) =>\n unlinkSubtreeDocument({\n // Target preparation and signing can outlast the upfront checks.\n beforeSubmit: async (containerId) =>\n (await scope.allowsDocument(document)) &&\n (await scope.allowsContainer(containerId)),\n containerIds,\n document,\n expectedSubtreeRoot,\n stillCurrent: input.stillCurrent,\n prepareDocumentRotationSnapshot: input.prepareDocumentRotationSnapshot,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n runtime: input.runtime,\n }),\n };\n return {\n purgeLocal: async (document) =>\n (await scope.allowsDocument(document)) &&\n (await operations.purgeLocal(document)),\n purgeRemote: async (document) =>\n (await scope.allowsDocument(document)) &&\n (await operations.purgeRemote(document)),\n unlink: async (document, containerIds) => {\n if (!(await scope.allowsDocument(document))) return false;\n for (const containerId of containerIds) {\n if (!(await scope.allowsContainer(containerId))) return false;\n }\n return operations.unlink(document, containerIds);\n },\n };\n}\n\ninterface SubtreeTeardownResult {\n readonly aborted: boolean;\n}\n\n// Signed request paths must keep the root under the parent it was selected\n// from; a settled restore elsewhere preserves the root's own documents too.\nfunction selectedSubtreeRoot(\n input: Pick<PurgeContainerTreeInput, \"containersById\" | \"rootContainerId\">,\n): SubtreePurgeRoot {\n return {\n id: input.rootContainerId,\n parentId:\n input.containersById.get(input.rootContainerId)?.container.parentId ??\n null,\n };\n}\n\nfunction purgeWasCancelled(input: {\n readonly signal?: AbortSignal | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): boolean {\n return input.signal?.aborted === true || input.stillCurrent?.() === false;\n}\n\n// Tear down one whole document per progress step. A failed document is skipped,\n// leaving its container undeletable while the remaining subtree work continues.\n// Cancellation is honored only between complete document operations.\nasync function teardownSubtreeDocuments(input: {\n readonly documentOperations: SubtreeDocumentOperations;\n readonly plan: SubtreeDocumentPlan;\n readonly reportStep: (ok: boolean) => void;\n readonly signal?: AbortSignal | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<SubtreeTeardownResult> {\n for (const {\n document,\n containerIds,\n } of input.plan.unlinkByDocument.values()) {\n if (purgeWasCancelled(input)) {\n return { aborted: true };\n }\n const unlinked = await input.documentOperations.unlink(\n document,\n containerIds,\n );\n input.reportStep(unlinked);\n }\n for (const { document, unlinkContainerIds } of input.plan.purge) {\n if (purgeWasCancelled(input)) {\n return { aborted: true };\n }\n if (\n unlinkContainerIds.length > 0 &&\n !(await input.documentOperations.unlink(document, unlinkContainerIds))\n ) {\n input.reportStep(false);\n continue;\n }\n input.reportStep(await input.documentOperations.purgeRemote(document));\n }\n for (const document of input.plan.purgeLocal) {\n if (purgeWasCancelled(input)) {\n return { aborted: true };\n }\n input.reportStep(await input.documentOperations.purgeLocal(document));\n }\n return { aborted: false };\n}\n\n// Permanently destroy a folder that lives inside Trash, including everything\n// under it (or, with keepRootContainer, everything under the Trash bin while\n// leaving the bin in place — this is \"Empty Trash\"). Documents are destroyed only\n// when the subtree holds their last link; multi-folder documents are unlinked\n// from the subtree and preserved. Containers are deleted leaf-first so each\n// delete obeys the leaf-only constraint the store and server enforce. Every step\n// is remote-first then local (the per-document and per-container workflows handle\n// that internally), so a cancel between steps leaves local state reflecting\n// exactly the completed remote work.\n//\n// Progress is determinate: the plan (a pure read) completes before any\n// destructive step, so onProgress reports completed/failed against a total known\n// up front. A failed item is skipped rather than aborting the run, so the result\n// reports whatever prefix was actually destroyed alongside completed/failed\n// counts and whether a cancellation cut it short. Returns null only when the\n// target container is absent from the snapshot.\nexport async function purgeContainerTree(\n request: PurgeContainerTreeInput,\n): Promise<PurgeContainerTreeResult | null> {\n if (purgeWasCancelled(request)) {\n return null;\n }\n const input = {\n ...request,\n containersById: snapshotContainerStates(request.containersById),\n };\n const subtreeStates = collectSubtreeLeafFirst(\n input.containersById,\n input.rootContainerId,\n );\n if (subtreeStates.length === 0) {\n return null;\n }\n const subtreeContainerIds = new Set(\n subtreeStates.map((containerState) => containerState.container.id),\n );\n\n const plan = await planSubtreeDocuments({\n execSql: input.runtime.infra.execSql,\n subtreeContainerIds,\n });\n if (purgeWasCancelled(input)) {\n return null;\n }\n\n // Empty Trash keeps the Trash bin itself: tear down everything it holds, but\n // exclude the root from the container deletions (deleting a system container\n // would be rejected anyway).\n const containerStatesToDelete = input.keepRootContainer\n ? subtreeStates.filter(\n (containerState) =>\n containerState.container.id !== input.rootContainerId,\n )\n : subtreeStates;\n\n // The total is fully known here — planning is a pure read that completes before\n // any destructive step. Unlink work is counted per document (not per container\n // link) so completed can never exceed total even when a document has several\n // in-subtree links.\n const totalCount =\n plan.unlinkByDocument.size +\n plan.purge.length +\n plan.purgeLocal.length +\n containerStatesToDelete.length;\n\n let completedCount = 0;\n let failedCount = 0;\n const emitProgress = () => {\n input.onProgress?.({ completedCount, failedCount, totalCount });\n };\n const reportStep = (ok: boolean) => {\n if (ok) {\n completedCount += 1;\n } else {\n failedCount += 1;\n }\n emitProgress();\n };\n // Emit the initial 0/total so a determinate bar renders immediately, before the\n // first (potentially slow) remote call.\n emitProgress();\n\n const scope = createSubtreePurgeScope(input);\n const teardown = await teardownSubtreeDocuments({\n documentOperations: resolveSubtreeDocumentOperations(input, scope),\n plan,\n reportStep,\n signal: input.signal,\n stillCurrent: input.stillCurrent,\n });\n\n let purgedContainerIds: readonly string[] = [];\n let remoteDeletedContainerIds: readonly string[] = [];\n let aborted = teardown.aborted;\n if (!teardown.aborted) {\n const deletion = await deleteSubtreeContainers({\n allowsContainer: scope.allowsContainer,\n allowsLocalScopeInTransaction: scope.allowsLocalScopeInTransaction,\n root: selectedSubtreeRoot(input),\n persistence: input.persistence,\n reportStep,\n runtime: input.runtime,\n signal: input.signal,\n stillCurrent: input.stillCurrent,\n subtreeStates: containerStatesToDelete,\n });\n purgedContainerIds = deletion.purgedContainerIds;\n remoteDeletedContainerIds = deletion.remoteDeletedContainerIds;\n aborted = deletion.aborted;\n }\n\n return {\n aborted,\n completedCount,\n failedCount,\n purgedContainerIds,\n remoteDeletedContainerIds,\n totalCount,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"purgeTree.js","sourceRoot":"","sources":["purgeTree.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_KIND } from \"../../../../data/documents/documentConstants\";\nimport type { DocumentSummary } from \"../../../../data/documents/documentSummary\";\nimport type { ProjectionUserKeyResolver } from \"../../../../data/keyingProjectionVerification\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { listDocumentsByContainerIdsOrDocumentIds } from \"../../../../data/persistence/documents/documentsPersistence\";\nimport type { SubtreePurgeRoot } from \"../../../documents/purge/subtreePurgeScope\";\nimport type { ContainerContentsPersistence } from \"../../containerPersistence\";\nimport { unlinkRemoteContainerDocument } from \"../../documentLinks\";\nimport type { ContainerState } from \"../../remoteHydration\";\nimport type { ContainerContentsWorkflowRuntime } from \"../../runtime\";\nimport {\n purgeLocalContainerDocument,\n purgeRemoteContainerDocument,\n} from \"../../tombstones/documentPurge\";\nimport type { PurgeProgress } from \"./purgeProgress\";\nimport {\n collectSubtreeLeafFirst,\n snapshotContainerStates,\n} from \"./purgeTreeCollection\";\nimport { deleteSubtreeContainers } from \"./purgeTreeContainerDeletion\";\nimport { createSubtreePurgeScope } from \"./purgeTreeScope\";\n\nexport { collectSubtreeLeafFirst } from \"./purgeTreeCollection\";\n\n// The store runtime satisfies the per-document purge/unlink workflows, so the\n// cascade reuses it verbatim.\ntype PurgeContainerTreeRuntime = ContainerContentsWorkflowRuntime;\n\ninterface PurgeContainerTreeInput {\n readonly containersById: ReadonlyMap<string, ContainerState>;\n readonly documentOperations?: SubtreeDocumentOperations | undefined;\n // When true, tear down everything UNDER the root (its documents plus every\n // descendant container) but never delete the root container itself. This is\n // how \"Empty Trash\" reuses the same engine: the Trash bin is a protected system\n // container that must survive while its whole contents are destroyed.\n readonly keepRootContainer?: boolean;\n readonly onProgress?: ((progress: PurgeProgress) => void) | undefined;\n readonly persistence: ContainerContentsPersistence;\n readonly prepareDocumentRotationSnapshot: (\n document: DocumentSummary,\n ) => Promise<Uint8Array | null>;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly rootContainerId: string;\n readonly runtime: PurgeContainerTreeRuntime;\n /** Stops a stale store generation between complete destructive units. */\n readonly stillCurrent?: (() => boolean) | undefined;\n // Checked at each unit boundary (between whole documents / whole containers),\n // never mid-remote-call, so a cancelled run stops on a consistent prefix.\n readonly signal?: AbortSignal | undefined;\n}\n\ninterface PurgeContainerTreeResult {\n readonly aborted: boolean;\n readonly completedCount: number;\n readonly failedCount: number;\n readonly purgedContainerIds: readonly string[];\n readonly remoteDeletedContainerIds: readonly string[];\n readonly totalCount: number;\n}\n\ninterface SubtreeDocumentPlan {\n // Synced documents whose every link falls inside the subtree: reduce them to\n // one retained link, as required by the purge endpoint, then destroy them.\n readonly purge: readonly {\n document: DocumentSummary;\n unlinkContainerIds: readonly string[];\n }[];\n // Synced documents also linked outside the subtree: keep them, but unlink\n // from each in-subtree container so the containers can be deleted.\n readonly unlinkByDocument: ReadonlyMap<\n string,\n { document: DocumentSummary; containerIds: readonly string[] }\n >;\n // Never-synced documents (no remote id): destroy locally only.\n readonly purgeLocal: readonly DocumentSummary[];\n}\n\ntype SubtreeDocumentDisposition =\n | { kind: \"purge\"; unlinkContainerIds: readonly string[] }\n | { kind: \"purge-local\" }\n | { kind: \"unlink\"; containerIds: readonly string[] };\n\n// Destroy local-only documents locally. Destroy synced documents only when all\n// links are in the subtree; preserve documents with an external link. The purge\n// plan reduces owned documents to the server-required sole link first.\nexport function classifySubtreeDocument(input: {\n readonly documentId: string | null;\n readonly linkedContainerIds: readonly string[];\n readonly preferredContainerId?: string | null | undefined;\n readonly subtreeContainerIds: ReadonlySet<string>;\n}): SubtreeDocumentDisposition {\n if (!input.documentId) {\n return { kind: \"purge-local\" };\n }\n const hasExternalLink = input.linkedContainerIds.some(\n (containerId) => !input.subtreeContainerIds.has(containerId),\n );\n if (!hasExternalLink) {\n const linkedContainerIds = Array.from(\n new Set(\n input.linkedContainerIds.filter((containerId) =>\n input.subtreeContainerIds.has(containerId),\n ),\n ),\n );\n const retainedContainerId =\n input.preferredContainerId &&\n linkedContainerIds.includes(input.preferredContainerId)\n ? input.preferredContainerId\n : linkedContainerIds[0];\n return {\n kind: \"purge\",\n unlinkContainerIds: linkedContainerIds.filter(\n (containerId) => containerId !== retainedContainerId,\n ),\n };\n }\n return {\n kind: \"unlink\",\n containerIds: input.linkedContainerIds.filter((containerId) =>\n input.subtreeContainerIds.has(containerId),\n ),\n };\n}\n\nasync function planSubtreeDocuments(input: {\n readonly execSql: PurgeContainerTreeRuntime[\"infra\"][\"execSql\"];\n readonly subtreeContainerIds: ReadonlySet<string>;\n}): Promise<SubtreeDocumentPlan> {\n const documents = await listDocumentsByContainerIdsOrDocumentIds(\n input.execSql,\n {\n containerIds: [...input.subtreeContainerIds],\n documentIds: [],\n },\n );\n const remoteDocumentIds = documents.flatMap((document) =>\n document.documentId ? [document.documentId] : [],\n );\n const linkedContainerIdsByDocumentId =\n await sqlDocumentContainerProjectionPersistence.listLinkedContainerIdsByDocumentIds(\n input.execSql,\n remoteDocumentIds,\n );\n\n const purge: Array<{\n document: DocumentSummary;\n unlinkContainerIds: readonly string[];\n }> = [];\n const purgeLocal: DocumentSummary[] = [];\n const unlinkByDocument = new Map<\n string,\n { document: DocumentSummary; containerIds: readonly string[] }\n >();\n for (const document of documents) {\n const disposition = classifySubtreeDocument({\n documentId: document.documentId ?? null,\n linkedContainerIds: document.documentId\n ? (linkedContainerIdsByDocumentId.get(document.documentId) ?? [])\n : [],\n preferredContainerId: document.containerId,\n subtreeContainerIds: input.subtreeContainerIds,\n });\n if (disposition.kind === \"purge-local\") {\n purgeLocal.push(document);\n } else if (disposition.kind === \"purge\") {\n purge.push({\n document,\n unlinkContainerIds: disposition.unlinkContainerIds,\n });\n } else if (document.documentId) {\n unlinkByDocument.set(document.documentId, {\n document,\n containerIds: disposition.containerIds,\n });\n }\n }\n\n return { purge, purgeLocal, unlinkByDocument };\n}\n\nasync function unlinkSubtreeDocument(input: {\n /** Rechecks the document and this exact unlink target before dispatch. */\n readonly beforeSubmit: (targetContainerId: string) => Promise<boolean>;\n readonly expectedSubtreeRoot: SubtreePurgeRoot;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly containerIds: readonly string[];\n readonly document: DocumentSummary;\n readonly prepareDocumentRotationSnapshot: PurgeContainerTreeInput[\"prepareDocumentRotationSnapshot\"];\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly runtime: PurgeContainerTreeRuntime;\n}): Promise<boolean> {\n const documentId = input.document.documentId;\n if (!documentId) {\n return true;\n }\n let rotationSnapshot: Uint8Array | null;\n try {\n rotationSnapshot = await input.prepareDocumentRotationSnapshot(\n input.document,\n );\n } catch {\n return false;\n }\n if (!rotationSnapshot) {\n return false;\n }\n for (const containerId of input.containerIds) {\n const result = await unlinkRemoteContainerDocument({\n beforeSubmit: () => input.beforeSubmit(containerId),\n documentId,\n expectedSubtreeRoot: input.expectedSubtreeRoot,\n isCurrent: input.stillCurrent,\n noteId: input.document.id,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n rotationSnapshot,\n runtime: input.runtime,\n targetContainerId: containerId,\n });\n if (result === null) {\n return false;\n }\n }\n return true;\n}\n\ninterface SubtreeDocumentOperations {\n readonly purgeLocal: (document: DocumentSummary) => Promise<boolean>;\n readonly purgeRemote: (document: DocumentSummary) => Promise<boolean>;\n readonly unlink: (\n document: DocumentSummary,\n containerIds: readonly string[],\n ) => Promise<boolean>;\n}\n\nfunction resolveSubtreeDocumentOperations(\n input: PurgeContainerTreeInput,\n scope: ReturnType<typeof createSubtreePurgeScope>,\n): SubtreeDocumentOperations {\n const expectedSubtreeRoot = selectedSubtreeRoot(input);\n const operations: SubtreeDocumentOperations = input.documentOperations ?? {\n purgeLocal: async (document) =>\n (await purgeLocalContainerDocument({\n beforeDeleteInTransaction: (execSql) =>\n scope.assertLocalScopeInTransaction(\n execSql,\n document.containerId,\n document.id,\n ),\n noteId: document.id,\n expectedContainerId: document.containerId,\n runtime: input.runtime,\n })) !== null,\n purgeRemote: async (document) =>\n Boolean(\n document.documentId &&\n (await purgeRemoteContainerDocument({\n beforeSubmit: () => scope.allowsDocument(document),\n documentId: document.documentId,\n expectedSubtreeRoot,\n stillCurrent: input.stillCurrent,\n documentKind: document.documentKind ?? DEFAULT_DOCUMENT_KIND,\n noteId: document.id,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n runtime: input.runtime,\n })),\n ),\n unlink: (document, containerIds) =>\n unlinkSubtreeDocument({\n // Target preparation and signing can outlast the upfront checks.\n beforeSubmit: async (containerId) =>\n (await scope.allowsDocument(document)) &&\n (await scope.allowsContainer(containerId)),\n containerIds,\n document,\n expectedSubtreeRoot,\n stillCurrent: input.stillCurrent,\n prepareDocumentRotationSnapshot: input.prepareDocumentRotationSnapshot,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n runtime: input.runtime,\n }),\n };\n return {\n purgeLocal: async (document) =>\n (await scope.allowsDocument(document)) &&\n (await operations.purgeLocal(document)),\n purgeRemote: async (document) =>\n (await scope.allowsDocument(document)) &&\n (await operations.purgeRemote(document)),\n unlink: async (document, containerIds) => {\n if (!(await scope.allowsDocument(document))) return false;\n for (const containerId of containerIds) {\n if (!(await scope.allowsContainer(containerId))) return false;\n }\n return operations.unlink(document, containerIds);\n },\n };\n}\n\ninterface SubtreeTeardownResult {\n readonly aborted: boolean;\n}\n\n// Signed request paths must keep the root under the parent it was selected\n// from; a settled restore elsewhere preserves the root's own documents too.\nfunction selectedSubtreeRoot(\n input: Pick<PurgeContainerTreeInput, \"containersById\" | \"rootContainerId\">,\n): SubtreePurgeRoot {\n return {\n id: input.rootContainerId,\n parentId:\n input.containersById.get(input.rootContainerId)?.container.parentId ??\n null,\n };\n}\n\nfunction purgeWasCancelled(input: {\n readonly signal?: AbortSignal | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): boolean {\n return input.signal?.aborted === true || input.stillCurrent?.() === false;\n}\n\n// Tear down one whole document per progress step. A failed document is skipped,\n// leaving its container undeletable while the remaining subtree work continues.\n// Cancellation is honored only between complete document operations.\nasync function teardownSubtreeDocuments(input: {\n readonly documentOperations: SubtreeDocumentOperations;\n readonly plan: SubtreeDocumentPlan;\n readonly reportStep: (ok: boolean) => void;\n readonly signal?: AbortSignal | undefined;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<SubtreeTeardownResult> {\n for (const {\n document,\n containerIds,\n } of input.plan.unlinkByDocument.values()) {\n if (purgeWasCancelled(input)) {\n return { aborted: true };\n }\n const unlinked = await input.documentOperations.unlink(\n document,\n containerIds,\n );\n input.reportStep(unlinked);\n }\n for (const { document, unlinkContainerIds } of input.plan.purge) {\n if (purgeWasCancelled(input)) {\n return { aborted: true };\n }\n if (\n unlinkContainerIds.length > 0 &&\n !(await input.documentOperations.unlink(document, unlinkContainerIds))\n ) {\n input.reportStep(false);\n continue;\n }\n input.reportStep(await input.documentOperations.purgeRemote(document));\n }\n for (const document of input.plan.purgeLocal) {\n if (purgeWasCancelled(input)) {\n return { aborted: true };\n }\n input.reportStep(await input.documentOperations.purgeLocal(document));\n }\n return { aborted: false };\n}\n\n// Permanently destroy a folder that lives inside Trash, including everything\n// under it (or, with keepRootContainer, everything under the Trash bin while\n// leaving the bin in place — this is \"Empty Trash\"). Documents are destroyed only\n// when the subtree holds their last link; multi-folder documents are unlinked\n// from the subtree and preserved. Containers are deleted leaf-first so each\n// delete obeys the leaf-only constraint the store and server enforce. Every step\n// is remote-first then local (the per-document and per-container workflows handle\n// that internally), so a cancel between steps leaves local state reflecting\n// exactly the completed remote work.\n//\n// Progress is determinate: the plan (a pure read) completes before any\n// destructive step, so onProgress reports completed/failed against a total known\n// up front. A failed item is skipped rather than aborting the run, so the result\n// reports whatever prefix was actually destroyed alongside completed/failed\n// counts and whether a cancellation cut it short. Returns null only when the\n// target container is absent from the snapshot.\nexport async function purgeContainerTree(\n request: PurgeContainerTreeInput,\n): Promise<PurgeContainerTreeResult | null> {\n if (purgeWasCancelled(request)) {\n return null;\n }\n const input = {\n ...request,\n containersById: snapshotContainerStates(request.containersById),\n };\n const subtreeStates = collectSubtreeLeafFirst(\n input.containersById,\n input.rootContainerId,\n );\n if (subtreeStates.length === 0) {\n return null;\n }\n const subtreeContainerIds = new Set(\n subtreeStates.map((containerState) => containerState.container.id),\n );\n\n const plan = await planSubtreeDocuments({\n execSql: input.runtime.infra.execSql,\n subtreeContainerIds,\n });\n if (purgeWasCancelled(input)) {\n return null;\n }\n\n // Empty Trash keeps the Trash bin itself: tear down everything it holds, but\n // exclude the root from the container deletions (deleting a system container\n // would be rejected anyway).\n const containerStatesToDelete = input.keepRootContainer\n ? subtreeStates.filter(\n (containerState) =>\n containerState.container.id !== input.rootContainerId,\n )\n : subtreeStates;\n\n // The total is fully known here — planning is a pure read that completes before\n // any destructive step. Unlink work is counted per document (not per container\n // link) so completed can never exceed total even when a document has several\n // in-subtree links.\n const totalCount =\n plan.unlinkByDocument.size +\n plan.purge.length +\n plan.purgeLocal.length +\n containerStatesToDelete.length;\n\n let completedCount = 0;\n let failedCount = 0;\n const emitProgress = () => {\n input.onProgress?.({ completedCount, failedCount, totalCount });\n };\n const reportStep = (ok: boolean) => {\n if (ok) {\n completedCount += 1;\n } else {\n failedCount += 1;\n }\n emitProgress();\n };\n // Emit the initial 0/total so a determinate bar renders immediately, before the\n // first (potentially slow) remote call.\n emitProgress();\n\n const scope = createSubtreePurgeScope(input);\n const teardown = await teardownSubtreeDocuments({\n documentOperations: resolveSubtreeDocumentOperations(input, scope),\n plan,\n reportStep,\n signal: input.signal,\n stillCurrent: input.stillCurrent,\n });\n\n let purgedContainerIds: readonly string[] = [];\n let remoteDeletedContainerIds: readonly string[] = [];\n let aborted = teardown.aborted;\n if (!teardown.aborted) {\n const deletion = await deleteSubtreeContainers({\n allowsContainer: scope.allowsContainer,\n allowsLocalScopeInTransaction: scope.allowsLocalScopeInTransaction,\n root: selectedSubtreeRoot(input),\n persistence: input.persistence,\n reportStep,\n runtime: input.runtime,\n signal: input.signal,\n stillCurrent: input.stillCurrent,\n subtreeStates: containerStatesToDelete,\n });\n purgedContainerIds = deletion.purgedContainerIds;\n remoteDeletedContainerIds = deletion.remoteDeletedContainerIds;\n aborted = deletion.aborted;\n }\n\n return {\n aborted,\n completedCount,\n failedCount,\n purgedContainerIds,\n remoteDeletedContainerIds,\n totalCount,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type {\n ContainerDeleteResponse,\n ContainerWriterProjectionResponse,\n ReferencedPrincipalStateResponse,\n} from \"@tearleads/validators/response\";\nimport type {
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type {\n ContainerDeleteResponse,\n ContainerWriterProjectionResponse,\n ReferencedPrincipalStateResponse,\n} from \"@tearleads/validators/response\";\nimport type { ProjectionUserKeyResolver } from \"../../../data/keyingProjectionVerification\";\nimport type { DocumentRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type {\n createRemoteContainer,\n moveRemoteContainer,\n shareRemoteContainer,\n} from \"../../containers\";\nimport type { createRemoteDocument } from \"../../documents\";\nimport type { shareRemoteContainerWithGroup } from \"../../organizations/groupShare\";\nimport type { CurrentPrincipalPolicyReader } from \"../../principals/currentPrincipalPolicyReader\";\nimport type { PrincipalPolicyHistoryReader } from \"../../principals/principalPolicyHistoryReader\";\nimport type {\n ContainerContentsPersistence,\n ContainerCreateIntentRecord,\n ContainerMoveIntentRecord,\n} from \"../containerPersistence\";\nimport type { createInitializedContainerMetadataDocument } from \"../metadata/containerMetadataDocument\";\nimport type {\n ContainerState,\n RemoteContainer as HydratedRemoteContainer,\n RemoteContainerHydrationHost,\n} from \"../remoteHydration\";\nimport type { ContainerContentsWorkflowRuntime } from \"../runtime\";\n\nexport type ContainerWorkflowApi = Parameters<\n typeof createRemoteContainer\n>[0][\"apiClient\"] &\n Parameters<typeof shareRemoteContainer>[0][\"apiClient\"] &\n Parameters<typeof shareRemoteContainerWithGroup>[0][\"apiClient\"] &\n Parameters<typeof moveRemoteContainer>[0][\"apiClient\"] &\n Parameters<typeof createRemoteDocument>[0][\"apiClient\"] &\n Partial<PrincipalPolicyHistoryReader> &\n CurrentPrincipalPolicyReader & {\n deleteContainerResult(\n containerId: string,\n options?: {\n expectedPaymentRequiredOrganizationId?: string;\n reportErrors?: boolean;\n requiredAncestorId?: string | undefined;\n },\n ): Promise<\n | { data: ContainerDeleteResponse; ok: true }\n | {\n ok: false;\n report: () => void;\n status: number | null;\n }\n >;\n primeContainerWriterProjection(\n containerId: string,\n projection: ContainerWriterProjectionResponse,\n ): void;\n };\n\nexport interface ContainerWorkflowRuntime\n extends Pick<\n ContainerContentsWorkflowRuntime,\n | \"auth\"\n | \"crypto\"\n | \"infra\"\n | \"resolveTrustedUserIdentity\"\n | \"state\"\n | \"util\"\n > {\n readonly apiClient: ContainerWorkflowApi;\n}\n\nexport interface CreatedRemoteContainerState {\n accessManifestHash: string;\n /**\n * The metadata seed the create committed, settled by the caller instead of\n * a first metadata sync. Absent when the create carried no seed or fell back\n * to a plain create.\n */\n metadataSeed?:\n | { readonly commitLsn: string | null; readonly updateId: string }\n | undefined;\n /** The slot this client signed into the create; never the server's echo. */\n systemSlot: ContainerSystemSlot | null;\n containerId: string;\n createdAt: string;\n metadataDocumentId: string;\n organizationId: string;\n /** A created container is a child; the acknowledgement echoed this parent. */\n parentId: string;\n persistedMetadataState: Pick<\n DocumentRecord,\n | \"documentId\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\"\n >;\n updatedAt: string;\n}\n\nexport interface SharedRemoteContainerState {\n accessEpoch: number;\n accessManifestHash: string;\n createdAt: string;\n metadataDocumentId: string;\n referencedPrincipalHeads: ReferencedPrincipalStateResponse[];\n updatedAt: string;\n writerProjection: ContainerWriterProjectionResponse | null;\n}\n\nexport interface SharedContainerState {\n container: ContainerState[\"container\"];\n record: ContainerState[\"record\"];\n}\n\nexport type SharedContainerStateResult =\n | { status: \"missing\" }\n | { status: \"confirmed\" }\n | (SharedContainerState & {\n status: \"identity-superseded\" | \"persisted\";\n });\n\nexport type RemoteContainer = HydratedRemoteContainer;\n\nexport type ContainerMetadataDocumentState = Awaited<\n ReturnType<typeof createInitializedContainerMetadataDocument>\n>[\"doc\"];\n\nexport interface CreatedChildContainerState {\n containerState: ContainerState;\n initialUpdate: Uint8Array;\n shouldRequestSync: boolean;\n}\n\nexport interface ContainerIntentSyncState {\n containersById: ReadonlyMap<string, ContainerState>;\n /**\n * Metadata update ids this device sent, so their own update echoes are\n * classified as self-authored (shared with the metadata sync).\n */\n locallyAcceptedMetadataUpdateIds?: Set<string> | undefined;\n /** Metadata document ids of folder creates in flight (shared with hints). */\n plannedMetadataDocumentIds?: Set<string> | undefined;\n persistence: ContainerContentsPersistence;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n /**\n * Verifies that a listed container is this device's pending create before it\n * is adopted and returns where it sits; `assertContainerCreateAdoptable`\n * unless a test replaces it.\n */\n verifyCreateAdoption?: (input: {\n readonly containerId: string;\n readonly expectedOrganizationId: string;\n }) => Promise<AdoptedContainerPlacement>;\n}\n\n/** Where a verified listed create committed, and where its container is now. */\nexport interface AdoptedContainerPlacement {\n /** The parent its signed epoch-1 `container.create` named. */\n readonly createdParentId: string;\n /** The verified head's parent; another writer may have moved it since. */\n readonly currentParentId: string;\n}\n\nexport type ContainerCreateIntentSyncState = ContainerIntentSyncState;\n\nexport type ContainerCreateIntentSyncHost = Pick<\n RemoteContainerHydrationHost,\n \"persistContainerState\"\n>;\n\nexport interface ContainerCreateIntentSyncInput {\n host: ContainerCreateIntentSyncHost;\n /** A parent whose own create has not settled takes no child create. */\n isCreatePending: (containerId: string) => boolean;\n isCurrent: () => boolean;\n isRemoteSyncBlocked: (organizationId: string) => boolean;\n intent: ContainerCreateIntentRecord;\n requestRemoteReconciliation: (parentContainerId: string | null) => void;\n state: ContainerCreateIntentSyncState;\n}\n\nexport type ContainerMoveIntentSyncState = ContainerIntentSyncState;\n\nexport type ContainerMoveIntentSyncHost = Pick<\n RemoteContainerHydrationHost,\n \"persistContainerState\" | \"updateSnapshot\"\n>;\n\n/** Later passes for moves the server accepted but no pass settled. */\nexport interface AcceptedMoveRetry {\n /** The server holds the move: schedule a replay to settle it. */\n arm: (intentId: string) => void;\n /** A replay failed; continue an accepted move's retries, if it has some. */\n resume: (intentId: string) => void;\n}\n\nexport interface ContainerMoveIntentSyncInput {\n host: ContainerMoveIntentSyncHost;\n isCurrent: () => boolean;\n /** A folder whose create has not settled takes no structural writes. */\n isCreatePending: (containerId: string) => boolean;\n isRemoteSyncBlocked: (organizationId: string) => boolean;\n intent: ContainerMoveIntentRecord;\n requestRemoteReconciliation: (parentContainerId: string | null) => void;\n acceptedMoveRetry: AcceptedMoveRetry;\n state: ContainerMoveIntentSyncState;\n}\n"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { SyncWatermark } from "../../internal/validators/response/index.js";
|
|
2
2
|
import type { ContainerContentsPersistence } from "../../data/persistence/container-contents/containerContentsPersistence.js";
|
|
3
|
-
import { type ContainerSyncLaneCheckRecord, type ContainerSyncWatermarkLane } from "../../data/persistence/
|
|
3
|
+
import { type ContainerSyncLaneCheckRecord, type ContainerSyncWatermarkLane } from "../../data/persistence/container-contents/containerSyncWatermarkPersistence.js";
|
|
4
4
|
import type { ExecSql } from "../../data/sqlite/sqlSchema.js";
|
|
5
5
|
export type { ContainerContentsPersistence, ContainerCreateIntentRecord, ContainerHydrationTombstone, ContainerMetadataRecord, ContainerMetadataRecord as ContainerDocumentRecord, ContainerMoveIntentRecord, LocalRootDescendantReparentInput, StoredContainerState, } from "../../data/persistence/container-contents/containerContentsPersistence.js";
|
|
6
6
|
export { sqlContainerContentsPersistence as defaultContainerContentsPersistence } from "../../data/persistence/container-contents/containerContentsPersistence.js";
|
|
7
|
-
export type { ContainerRecord } from "../../data/persistence/
|
|
8
|
-
export type { ContainerSyncWatermarkLane } from "../../data/persistence/
|
|
7
|
+
export type { ContainerRecord } from "../../data/persistence/container-contents/containerPersistence.js";
|
|
8
|
+
export type { ContainerSyncWatermarkLane } from "../../data/persistence/container-contents/containerSyncWatermarkPersistence.js";
|
|
9
9
|
export declare function enqueuePendingContainerUpdate(execSql: ExecSql, persistence: ContainerContentsPersistence, params: {
|
|
10
10
|
containerId: string;
|
|
11
11
|
sourceVersionVector?: string | null | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createPendingUpdateFields } from "../../data/documents/documentSync.js";
|
|
2
|
-
import { containerContentsSyncLane, containerParentSyncLane, sqlContainerSyncWatermarkPersistence, } from "../../data/persistence/
|
|
2
|
+
import { containerContentsSyncLane, containerParentSyncLane, sqlContainerSyncWatermarkPersistence, } from "../../data/persistence/container-contents/containerSyncWatermarkPersistence.js";
|
|
3
3
|
export { sqlContainerContentsPersistence as defaultContainerContentsPersistence } from "../../data/persistence/container-contents/containerContentsPersistence.js";
|
|
4
4
|
export async function enqueuePendingContainerUpdate(execSql, persistence, params) {
|
|
5
5
|
const pendingUpdateFields = createPendingUpdateFields(params.update, params.sourceVersionVector);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerPersistence.js","sourceRoot":"","sources":["containerPersistence.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,OAAO,EAGL,yBAAyB,EACzB,uBAAuB,EACvB,oCAAoC,GACrC,MAAM,
|
|
1
|
+
{"version":3,"file":"containerPersistence.js","sourceRoot":"","sources":["containerPersistence.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,OAAO,EAGL,yBAAyB,EACzB,uBAAuB,EACvB,oCAAoC,GACrC,MAAM,6EAA6E,CAAC;AAarF,OAAO,EAAE,+BAA+B,IAAI,mCAAmC,EAAE,MAAM,wEAAwE,CAAC;AAIhK,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,OAAgB,EAChB,WAAyC,EACzC,MAIC;IAED,MAAM,mBAAmB,GAAG,yBAAyB,CACnD,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,mBAAmB,CAC3B,CAAC;IACF,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,WAAW,CAAC,oBAAoB,CAAC,OAAO,EAAE;QAC/C,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,GAAG,mBAAmB;KACvB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,QAAuB;IAEvB,OAAO,uBAAuB,CAAC,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,WAAmB;IAEnB,OAAO,yBAAyB,CAAC,WAAW,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAgB,EAChB,QAAoC;IAEpC,OAAO,oCAAoC,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAgB,EAChB,QAAoC,EACpC,SAAwB;IAExB,MAAM,oCAAoC,CAAC,aAAa,CACtD,OAAO,EACP,QAAQ,EACR,SAAS,CACV,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,OAAgB,EAChB,SAAoD;IAEpD,OAAO,oCAAoC,CAAC,gBAAgB,CAC1D,OAAO,EACP,SAAS,CACV,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAgB,EAChB,QAAoC;IAEpC,MAAM,oCAAoC,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qCAAqC,CACzD,OAAgB,EAChB,QAAoC,EACpC,KAGC,EACD,YAA0C;IAE1C,OAAO,oCAAoC,CAAC,eAAe,CACzD,OAAO,EACP,QAAQ,EACR,KAAK,EACL,EAAE,YAAY,EAAE,CACjB,CAAC;AACJ,CAAC","sourcesContent":["import type { SyncWatermark } from \"@tearleads/validators/response\";\nimport { createPendingUpdateFields } from \"../../data/documents/documentSync\";\nimport type { ContainerContentsPersistence } from \"../../data/persistence/container-contents/containerContentsPersistence\";\nimport {\n type ContainerSyncLaneCheckRecord,\n type ContainerSyncWatermarkLane,\n containerContentsSyncLane,\n containerParentSyncLane,\n sqlContainerSyncWatermarkPersistence,\n} from \"../../data/persistence/container-contents/containerSyncWatermarkPersistence\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\n\nexport type {\n ContainerContentsPersistence,\n ContainerCreateIntentRecord,\n ContainerHydrationTombstone,\n ContainerMetadataRecord,\n ContainerMetadataRecord as ContainerDocumentRecord,\n ContainerMoveIntentRecord,\n LocalRootDescendantReparentInput,\n StoredContainerState,\n} from \"../../data/persistence/container-contents/containerContentsPersistence\";\nexport { sqlContainerContentsPersistence as defaultContainerContentsPersistence } from \"../../data/persistence/container-contents/containerContentsPersistence\";\nexport type { ContainerRecord } from \"../../data/persistence/container-contents/containerPersistence\";\nexport type { ContainerSyncWatermarkLane } from \"../../data/persistence/container-contents/containerSyncWatermarkPersistence\";\n\nexport async function enqueuePendingContainerUpdate(\n execSql: ExecSql,\n persistence: ContainerContentsPersistence,\n params: {\n containerId: string;\n sourceVersionVector?: string | null | undefined;\n update: Uint8Array;\n },\n): Promise<string | null> {\n const pendingUpdateFields = createPendingUpdateFields(\n params.update,\n params.sourceVersionVector,\n );\n if (!pendingUpdateFields) {\n return null;\n }\n\n return persistence.enqueuePendingUpdate(execSql, {\n containerId: params.containerId,\n ...pendingUpdateFields,\n });\n}\n\nexport function createContainerParentSyncLane(\n parentId: string | null,\n): ContainerSyncWatermarkLane {\n return containerParentSyncLane(parentId);\n}\n\nexport function createContainerContentsSyncLane(\n containerId: string,\n): ContainerSyncWatermarkLane {\n return containerContentsSyncLane(containerId);\n}\n\nexport async function loadContainerSyncWatermark(\n execSql: ExecSql,\n syncLane: ContainerSyncWatermarkLane,\n): Promise<SyncWatermark | null> {\n return sqlContainerSyncWatermarkPersistence.loadWatermark(execSql, syncLane);\n}\n\nexport async function saveContainerSyncWatermark(\n execSql: ExecSql,\n syncLane: ContainerSyncWatermarkLane,\n watermark: SyncWatermark,\n): Promise<void> {\n await sqlContainerSyncWatermarkPersistence.saveWatermark(\n execSql,\n syncLane,\n watermark,\n );\n}\n\nexport async function loadContainerSyncLaneCheckRecords(\n execSql: ExecSql,\n syncLanes: ReadonlyArray<ContainerSyncWatermarkLane>,\n): Promise<Array<ContainerSyncLaneCheckRecord | null>> {\n return sqlContainerSyncWatermarkPersistence.loadCheckRecords(\n execSql,\n syncLanes,\n );\n}\n\nexport async function markContainerSyncLaneChecked(\n execSql: ExecSql,\n syncLane: ContainerSyncWatermarkLane,\n): Promise<void> {\n await sqlContainerSyncWatermarkPersistence.markChecked(execSql, syncLane);\n}\n\n/**\n * Records one lane fetch in a single guarded upsert: the cursor when the page\n * carried one and the freshness marker when the lane is fully drained.\n */\nexport async function recordContainerSyncLaneFetchIfCurrent(\n execSql: ExecSql,\n syncLane: ContainerSyncWatermarkLane,\n fetch: {\n readonly checked: boolean;\n readonly watermark: SyncWatermark | null;\n },\n stillCurrent?: (() => boolean) | undefined,\n): Promise<boolean> {\n return sqlContainerSyncWatermarkPersistence.recordLaneFetch(\n execSql,\n syncLane,\n fetch,\n { stillCurrent },\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { uniqueSortedStrings } from "../../../data/documents/shared/readers.js";
|
|
2
|
+
import { sqlDocumentContainerProjectionPersistence as links } from "../../../data/persistence/container-contents/documentContainerProjectionPersistence.js";
|
|
2
3
|
import { sqlDocumentMoveIntentPersistence } from "../../../data/persistence/container-contents/documentMoveIntentPersistence.js";
|
|
3
|
-
import { sqlDocumentContainerProjectionPersistence as links } from "../../../data/persistence/containers/documentContainerProjectionPersistence.js";
|
|
4
4
|
import { defaultDocumentsPersistence } from "../../documents/index.js";
|
|
5
5
|
import { relinkContainerDocumentLocally } from "./documentLocalRelink.js";
|
|
6
6
|
export async function addDocumentLinkLocally(input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentLinkIntent.js","sourceRoot":"","sources":["documentLinkIntent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"documentLinkIntent.js","sourceRoot":"","sources":["documentLinkIntent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentSummary } from \"../../../data/documents/documentSummary\";\nimport { uniqueSortedStrings } from \"../../../data/documents/shared/readers\";\nimport { sqlDocumentContainerProjectionPersistence as links } from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { sqlDocumentMoveIntentPersistence } from \"../../../data/persistence/container-contents/documentMoveIntentPersistence\";\nimport { defaultDocumentsPersistence } from \"../../documents\";\nimport type {\n DocumentStructuralMutationHost,\n DocumentStructuralMutationLocalStore,\n DocumentStructuralMutationRuntime,\n SetLinkedContainerIdsForDocument,\n} from \"../documentQueries/documentStructureTypes\";\nimport { relinkContainerDocumentLocally } from \"./documentLocalRelink\";\n\nexport async function addDocumentLinkLocally<TRuntime>(input: {\n currentDocumentStore: DocumentStructuralMutationLocalStore<TRuntime>;\n host: DocumentStructuralMutationHost<TRuntime>;\n note: DocumentSummary & { documentId: string; containerId: string };\n runtime: DocumentStructuralMutationRuntime;\n scheduleSync?: (() => void) | undefined;\n setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n targetContainerId: string;\n}): Promise<DocumentSummary | null> {\n const { note, runtime, targetContainerId } = input;\n const persisted = await defaultDocumentsPersistence.loadDocument(\n runtime.infra.execSql,\n note.id,\n );\n if (!persisted) return null;\n const intentId = crypto.randomUUID();\n let linkedContainerIds: readonly string[] = [];\n const linkedNote = await relinkContainerDocumentLocally({\n ...input,\n accessEpoch: persisted.accessEpoch,\n requestSync: false,\n targetContainerId: note.containerId,\n commitSideEffect: async (execSql) => {\n const currentLinks = await links.listLinkedContainerIds(\n execSql,\n note.documentId,\n );\n linkedContainerIds = uniqueSortedStrings([\n ...currentLinks,\n note.containerId,\n targetContainerId,\n ]);\n await sqlDocumentMoveIntentPersistence.enqueueLinkIntent(execSql, {\n id: intentId,\n documentId: note.documentId,\n localId: note.id,\n sourceContainerId: note.containerId,\n targetContainerId,\n });\n await links.replaceDocumentLinks(\n execSql,\n note.documentId,\n linkedContainerIds,\n { moveIntentId: intentId },\n );\n },\n });\n if (!linkedNote) return null;\n input.setLinkedContainerIdsForDocument(note.documentId, linkedContainerIds);\n input.scheduleSync?.();\n runtime.util.log(\n `Container contents: queued note ${note.id} link to ${targetContainerId}`,\n );\n return linkedNote;\n}\n\nexport async function removeDocumentLinkLocally<TRuntime>(\n input: Omit<\n Parameters<typeof addDocumentLinkLocally<TRuntime>>[0],\n \"targetContainerId\"\n > & { removedContainerId: string },\n): Promise<DocumentSummary | null> {\n const { note, runtime, removedContainerId } = input;\n const execSql = runtime.infra.execSql;\n const persisted = await defaultDocumentsPersistence.loadDocument(\n execSql,\n note.id,\n );\n if (!persisted) return null;\n const currentLinks = await links.listLinkedContainerIds(\n execSql,\n note.documentId,\n );\n const remaining = currentLinks.filter((id) => id !== removedContainerId);\n const nextContainerId = remaining.includes(note.containerId)\n ? note.containerId\n : remaining[0];\n if (!nextContainerId || !currentLinks.includes(removedContainerId))\n return null;\n const intentId = crypto.randomUUID();\n let linkedContainerIds: readonly string[] = [];\n const unlinkedNote = await relinkContainerDocumentLocally({\n ...input,\n accessEpoch: persisted.accessEpoch,\n requestSync: false,\n targetContainerId: nextContainerId,\n commitSideEffect: async (transactionExecSql) => {\n linkedContainerIds = (\n await links.listLinkedContainerIds(transactionExecSql, note.documentId)\n ).filter((id) => id !== removedContainerId);\n if (!linkedContainerIds.includes(nextContainerId))\n throw new Error(\"Document placement changed before unlink\");\n await sqlDocumentMoveIntentPersistence.enqueueUnlinkIntent(\n transactionExecSql,\n {\n id: intentId,\n documentId: note.documentId,\n localId: note.id,\n removedContainerId,\n targetContainerId: nextContainerId,\n },\n );\n await links.replaceDocumentLinks(\n transactionExecSql,\n note.documentId,\n linkedContainerIds,\n { moveIntentId: intentId },\n );\n },\n });\n if (!unlinkedNote) return null;\n input.setLinkedContainerIdsForDocument(note.documentId, linkedContainerIds);\n input.scheduleSync?.();\n return unlinkedNote;\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assertDocumentWriterProjectionConsistent, readLinkedContainerIdsFromDocumentManifest, } from "../../../data/documents/shared/projection/index.js";
|
|
2
2
|
import { persistedDocumentCreateStateFromWriterProjection } from "../../../data/documents/shared/responses.js";
|
|
3
3
|
import { reportAndRethrowKeyingVerificationError } from "../../../data/keyingProjectionVerification/error.js";
|
|
4
|
-
import { sqlDocumentContainerProjectionPersistence } from "../../../data/persistence/
|
|
4
|
+
import { sqlDocumentContainerProjectionPersistence } from "../../../data/persistence/container-contents/documentContainerProjectionPersistence.js";
|
|
5
5
|
import { errorMessage } from "../../../data/shared/errorMessage.js";
|
|
6
6
|
import { isDatabaseUnavailableError } from "../../../data/sync/databaseUnavailable.js";
|
|
7
7
|
import { relinkRemoteDocument, resolveDocumentCreateAuthor, } from "../../documents/index.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { VerifiedDocumentLinkSetManifest } from \"@tearleads/crypto\";\nimport type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n assertDocumentWriterProjectionConsistent,\n readLinkedContainerIdsFromDocumentManifest,\n} from \"../../../data/documents/shared/projection\";\nimport { persistedDocumentCreateStateFromWriterProjection } from \"../../../data/documents/shared/responses\";\nimport type { ProjectionUserKeyResolver } from \"../../../data/keyingProjectionVerification\";\nimport { reportAndRethrowKeyingVerificationError } from \"../../../data/keyingProjectionVerification/error\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../data/persistence/containers/documentContainerProjectionPersistence\";\nimport { errorMessage } from \"../../../data/shared/errorMessage\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { isDatabaseUnavailableError } from \"../../../data/sync/databaseUnavailable\";\nimport {\n type DocumentLinkSetFailureHandler,\n type RelinkRemoteDocumentResult,\n relinkRemoteDocument,\n resolveDocumentCreateAuthor,\n} from \"../../documents\";\nimport type { SubtreePurgeRoot } from \"../../documents/purge/subtreePurgeScope\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../principals/runtimePolicyWarmer\";\nimport { resolveContainerDocumentMoveUnlinkIds } from \"../documentMove/documentMoveUnlinkIds\";\nimport type { ContainerContentsWorkflowRuntime } from \"../runtime\";\n\ntype ContainerDocumentLinkApi = Parameters<\n typeof relinkRemoteDocument\n>[0][\"apiClient\"];\ntype ContainerDocumentLinkOperation = Parameters<\n typeof relinkRemoteDocument\n>[0][\"operation\"];\ntype RemoteDocumentPersistedState =\n RelinkRemoteDocumentResult[\"persistedState\"];\n\n// A cold-cache denial must keep its HTTP status: collapsing a 403 to null\n// would leave an access-denied move routinely retriable instead of parking\n// it for the access-restored signal (row 7).\nasync function fetchMoveWriterProjection(input: {\n documentId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n runtime: ContainerDocumentLinkRuntime;\n}): Promise<Awaited<\n ReturnType<ContainerDocumentLinkApi[\"getDocumentWriterProjection\"]>\n> | null> {\n const { apiClient } = input.runtime;\n const result = await apiClient.getDocumentWriterProjectionResult(\n input.documentId,\n { reportErrors: false },\n );\n if (result.ok) {\n return result.data;\n }\n result.report();\n input.onFailure?.({ message: result.message, status: result.status });\n return null;\n}\n\ninterface ContainerDocumentLinkRuntime\n extends Pick<\n ContainerContentsWorkflowRuntime,\n | \"auth\"\n | \"crypto\"\n | \"infra\"\n | \"resolveTrustedUserIdentity\"\n | \"state\"\n | \"util\"\n > {\n apiClient: ContainerDocumentLinkApi &\n Pick<\n ContainerContentsWorkflowRuntime[\"apiClient\"],\n \"getPrincipalPolicyPages\" | \"getProjectionPolicyHistoryPages\"\n >;\n}\n\ntype MoveRemoteContainerDocumentStatus = \"complete\" | \"partial\";\n\ninterface MoveRemoteContainerDocumentResult {\n accessEpoch: number | null;\n accessStateHash: string | null;\n linkedContainerIds: readonly string[];\n nextContainerId: string;\n remoteState: RemoteDocumentPersistedState | null;\n status: MoveRemoteContainerDocumentStatus;\n}\n\nexport type { RemoteDocumentPersistedState };\n\nexport async function initializeDocumentLinksSchema(\n execSql: ExecSql,\n): Promise<void> {\n await sqlDocumentContainerProjectionPersistence.ensureSchema(execSql);\n}\n\nexport async function listDocumentLinkedContainerIds(\n execSql: ExecSql,\n documentId: string,\n): Promise<ReadonlyArray<string>> {\n return sqlDocumentContainerProjectionPersistence.listLinkedContainerIds(\n execSql,\n documentId,\n );\n}\n\nexport async function replaceDocumentLinks(\n execSql: ExecSql,\n documentId: string,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n await sqlDocumentContainerProjectionPersistence.replaceDocumentLinks(\n execSql,\n documentId,\n containerIds,\n );\n}\n\nfunction resolveActiveDocumentContainerId(\n linkedContainerIds: ReadonlyArray<string>,\n preferredContainerId: string,\n): string | null {\n if (linkedContainerIds.includes(preferredContainerId)) {\n return preferredContainerId;\n }\n\n return linkedContainerIds[0] ?? null;\n}\n\nfunction containerDocumentMoveResult(input: {\n document: RelinkRemoteDocumentResult;\n nextContainerId: string;\n status: MoveRemoteContainerDocumentStatus;\n}): MoveRemoteContainerDocumentResult {\n return {\n accessEpoch: input.document.plan.state.epoch,\n accessStateHash: input.document.response.accessManifest.manifestHash,\n linkedContainerIds: input.document.linkedContainerIds,\n nextContainerId: input.nextContainerId,\n remoteState: input.document.persistedState,\n status: input.status,\n };\n}\n\nasync function containerDocumentAlreadyMovedResult(input: {\n writerProjection: DocumentWriterProjectionResponse;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerDocumentLinkRuntime;\n isCurrent?: (() => boolean) | undefined;\n linkedContainerIds: readonly string[];\n nextContainerId: string;\n status: MoveRemoteContainerDocumentStatus;\n}): Promise<MoveRemoteContainerDocumentResult> {\n const verified: { head?: VerifiedDocumentLinkSetManifest | undefined } = {};\n await assertDocumentWriterProjectionConsistent(input.writerProjection, {\n execSql: input.runtime.infra.execSql,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.isCurrent,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.runtime,\n ),\n onVerifiedAuthorization: (authorization) => {\n verified.head = authorization.documentManifestByHash.get(\n input.writerProjection.documentManifest.manifestHash,\n );\n },\n });\n if (!verified.head)\n throw new Error(\"Move replay lacks a verified document head\");\n return {\n accessEpoch: verified.head.state.epoch,\n accessStateHash: verified.head.manifestHash,\n linkedContainerIds: input.linkedContainerIds,\n nextContainerId: input.nextContainerId,\n remoteState: persistedDocumentCreateStateFromWriterProjection(\n input.writerProjection,\n ),\n status: input.status,\n };\n}\n\n/**\n * Hand a link/unlink/move/purge failure to host diagnostics as a real `Error`.\n * The caller's string-only log line stays the fallback for a host without\n * `logError`, so this never logs a second copy of the same failure.\n */\nfunction reportDocumentLinkMutationFailure(\n util: ContainerDocumentLinkRuntime[\"util\"],\n error: unknown,\n): void {\n // `ApiClient` returns `RequestFailure` objects instead of throwing, so\n // offline and 403/404/409 already left through the `!result` branch: a status\n // filter here would be dead code. Only a database lost mid-flight stays quiet.\n if (!util.logError || isDatabaseUnavailableError(error)) return;\n try {\n // A host logger that throws or rejects must not replace the null result or\n // skip the failure handler below.\n void Promise.resolve(\n util.logError(\"Container contents: document link mutation failed\", error),\n ).catch(() => undefined);\n } catch {\n // Hosts may throw synchronously or return a rejected promise.\n }\n}\n\nexport async function relinkRemoteContainerDocument(input: {\n beforeSubmit?: (() => Promise<boolean>) | undefined;\n documentId: string;\n expectedSubtreeRoot?: SubtreePurgeRoot | undefined;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n operation: ContainerDocumentLinkOperation;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot?: Uint8Array | undefined;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<RelinkRemoteDocumentResult | null> {\n const {\n documentId,\n noteId,\n operation,\n resolveProjectionUserKey,\n runtime,\n targetContainerId,\n } = input;\n const author = resolveDocumentCreateAuthor(runtime);\n const targetSecretKey = runtime.crypto.encapsulationKeyPair?.secretKey;\n const execSql = runtime.infra.execSql;\n if (input.isCurrent?.() === false) return null;\n if (!author || !targetSecretKey) {\n runtime.util.log(\n \"Container contents: document mutation skipped because the local key context is unavailable\",\n );\n input.onFailure?.({\n message: \"the local key context is unavailable\",\n status: null,\n });\n return null;\n }\n\n try {\n const result = await relinkRemoteDocument({\n beforeSubmit: input.beforeSubmit,\n apiClient: runtime.apiClient,\n author,\n documentId,\n expectedSubtreeRoot: input.expectedSubtreeRoot,\n execSql,\n onFailure: input.onFailure,\n operation,\n resolveProjectionUserKey,\n rotationSnapshot: input.rotationSnapshot,\n stillCurrent: input.isCurrent,\n targetContainerId,\n targetSecretKey,\n warmReferencedPrincipalPolicies:\n createRuntimePrincipalPolicyWarmer(runtime),\n });\n if (!result) {\n runtime.util.log(\n `Container contents: failed to ${operation} note ${noteId} ${operation === \"link\" ? \"to\" : \"from\"} container ${targetContainerId}`,\n );\n return null;\n }\n if (input.isCurrent?.() === false) return null;\n\n await sqlDocumentContainerProjectionPersistence.replaceDocumentLinks(\n execSql,\n documentId,\n result.linkedContainerIds,\n { stillCurrent: input.isCurrent },\n );\n\n return result;\n } catch (error) {\n await reportAndRethrowKeyingVerificationError(\n error,\n runtime.util.reportSecurityIncident,\n {\n objectId: documentId,\n objectKind: \"document\",\n operation: `document.${operation}`,\n },\n );\n const message = errorMessage(error);\n runtime.util.log(\n `Container contents: failed to ${operation} note ${noteId} ${operation === \"link\" ? \"to\" : \"from\"} container ${targetContainerId}: ${message}`,\n );\n // After the keying rethrow above, so a verification failure keeps its\n // security incident instead of being reported twice, and before the failure\n // handler, so a throwing caller callback cannot swallow the report.\n reportDocumentLinkMutationFailure(runtime.util, error);\n input.onFailure?.({ message, status: null });\n return null;\n }\n}\n\nasync function linkRemoteContainerDocument(input: {\n documentId: string;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<RelinkRemoteDocumentResult | null> {\n return relinkRemoteContainerDocument({\n ...input,\n operation: \"link\",\n });\n}\n\nexport async function unlinkRemoteContainerDocument(input: {\n beforeSubmit?: (() => Promise<boolean>) | undefined;\n documentId: string;\n expectedSubtreeRoot?: SubtreePurgeRoot | undefined;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot: Uint8Array;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<RelinkRemoteDocumentResult | null> {\n return relinkRemoteContainerDocument({\n ...input,\n operation: \"unlink\",\n });\n}\n\nexport async function moveRemoteContainerDocument(input: {\n linkOnly?: boolean | undefined;\n additionalLinkContainerIds?: readonly string[] | undefined;\n removedLinkContainerIds?: readonly string[] | undefined;\n currentContainerId: string;\n documentId: string;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n replaceLinkedContainers?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot: Uint8Array;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<MoveRemoteContainerDocumentResult | null> {\n const {\n documentId,\n noteId,\n resolveProjectionUserKey,\n runtime,\n targetContainerId,\n } = input;\n if (input.isCurrent?.() === false) return null;\n const writerProjection = await fetchMoveWriterProjection({\n documentId,\n onFailure: input.onFailure,\n runtime,\n });\n if (!writerProjection || input.isCurrent?.() === false) {\n return null;\n }\n if (writerProjection.documentId !== documentId)\n throw new Error(\"Move replay document id mismatch\");\n const initialLinkedContainerIds =\n readLinkedContainerIdsFromDocumentManifest(writerProjection);\n\n let latestLinkedContainerIds: readonly string[] = initialLinkedContainerIds;\n let latestDocument: RelinkRemoteDocumentResult | null = null;\n for (const linkTarget of new Set([\n ...(input.linkOnly ? [] : [targetContainerId]),\n ...(input.additionalLinkContainerIds ?? []),\n ])) {\n if (latestLinkedContainerIds.includes(linkTarget)) continue;\n const linkedDocument = await linkRemoteContainerDocument({\n documentId,\n isCurrent: input.isCurrent,\n noteId,\n onFailure: input.onFailure,\n resolveProjectionUserKey,\n runtime,\n targetContainerId: linkTarget,\n });\n if (!linkedDocument || input.isCurrent?.() === false) {\n return null;\n }\n\n latestDocument = linkedDocument;\n latestLinkedContainerIds = linkedDocument.linkedContainerIds;\n }\n\n const unlinkContainerIds = resolveContainerDocumentMoveUnlinkIds({\n ...input,\n linkedContainerIds: latestLinkedContainerIds,\n });\n\n const unlinked = await unlinkMovedDocumentSources({\n ...input,\n latestDocument,\n latestLinkedContainerIds,\n unlinkContainerIds,\n });\n if (!unlinked) return null;\n latestDocument = unlinked.latestDocument;\n latestLinkedContainerIds = unlinked.latestLinkedContainerIds;\n\n const nextContainerId = resolveActiveDocumentContainerId(\n latestLinkedContainerIds,\n targetContainerId,\n );\n if (!nextContainerId) {\n return null;\n }\n\n const status =\n unlinked.failedUnlinkContainerIds.length > 0 ? \"partial\" : \"complete\";\n return latestDocument\n ? containerDocumentMoveResult({\n document: latestDocument,\n nextContainerId,\n status,\n })\n : containerDocumentAlreadyMovedResult({\n writerProjection,\n resolveProjectionUserKey,\n runtime,\n isCurrent: input.isCurrent,\n linkedContainerIds: latestLinkedContainerIds,\n nextContainerId,\n status,\n });\n}\n\n// The unlink half of a move: every source is attempted even when an earlier\n// one fails, so one dead source cannot strand the others; a failed unlink\n// leaves the move \"partial\" for the queue to retry.\nasync function unlinkMovedDocumentSources(input: {\n documentId: string;\n isCurrent?: (() => boolean) | undefined;\n latestDocument: RelinkRemoteDocumentResult | null;\n latestLinkedContainerIds: readonly string[];\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot: Uint8Array;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n unlinkContainerIds: readonly string[];\n}): Promise<{\n failedUnlinkContainerIds: readonly string[];\n latestDocument: RelinkRemoteDocumentResult | null;\n latestLinkedContainerIds: readonly string[];\n} | null> {\n const { noteId, runtime, targetContainerId } = input;\n let { latestDocument, latestLinkedContainerIds } = input;\n const failedUnlinkContainerIds: string[] = [];\n for (const unlinkContainerId of input.unlinkContainerIds) {\n if (input.isCurrent?.() === false) return null;\n const unlinkedDocument = await unlinkRemoteContainerDocument({\n documentId: input.documentId,\n isCurrent: input.isCurrent,\n noteId,\n onFailure: input.onFailure,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n rotationSnapshot: input.rotationSnapshot,\n runtime,\n targetContainerId: unlinkContainerId,\n });\n if (input.isCurrent?.() === false) return null;\n if (!unlinkedDocument) {\n failedUnlinkContainerIds.push(unlinkContainerId);\n runtime.util.log(\n `Container contents: note ${noteId} was linked to ${targetContainerId} but failed to unlink from ${unlinkContainerId}`,\n );\n continue;\n }\n\n latestDocument = unlinkedDocument;\n latestLinkedContainerIds = unlinkedDocument.linkedContainerIds;\n }\n return { failedUnlinkContainerIds, latestDocument, latestLinkedContainerIds };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { VerifiedDocumentLinkSetManifest } from \"@tearleads/crypto\";\nimport type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n assertDocumentWriterProjectionConsistent,\n readLinkedContainerIdsFromDocumentManifest,\n} from \"../../../data/documents/shared/projection\";\nimport { persistedDocumentCreateStateFromWriterProjection } from \"../../../data/documents/shared/responses\";\nimport type { ProjectionUserKeyResolver } from \"../../../data/keyingProjectionVerification\";\nimport { reportAndRethrowKeyingVerificationError } from \"../../../data/keyingProjectionVerification/error\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { errorMessage } from \"../../../data/shared/errorMessage\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { isDatabaseUnavailableError } from \"../../../data/sync/databaseUnavailable\";\nimport {\n type DocumentLinkSetFailureHandler,\n type RelinkRemoteDocumentResult,\n relinkRemoteDocument,\n resolveDocumentCreateAuthor,\n} from \"../../documents\";\nimport type { SubtreePurgeRoot } from \"../../documents/purge/subtreePurgeScope\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../principals/runtimePolicyWarmer\";\nimport { resolveContainerDocumentMoveUnlinkIds } from \"../documentMove/documentMoveUnlinkIds\";\nimport type { ContainerContentsWorkflowRuntime } from \"../runtime\";\n\ntype ContainerDocumentLinkApi = Parameters<\n typeof relinkRemoteDocument\n>[0][\"apiClient\"];\ntype ContainerDocumentLinkOperation = Parameters<\n typeof relinkRemoteDocument\n>[0][\"operation\"];\ntype RemoteDocumentPersistedState =\n RelinkRemoteDocumentResult[\"persistedState\"];\n\n// A cold-cache denial must keep its HTTP status: collapsing a 403 to null\n// would leave an access-denied move routinely retriable instead of parking\n// it for the access-restored signal (row 7).\nasync function fetchMoveWriterProjection(input: {\n documentId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n runtime: ContainerDocumentLinkRuntime;\n}): Promise<Awaited<\n ReturnType<ContainerDocumentLinkApi[\"getDocumentWriterProjection\"]>\n> | null> {\n const { apiClient } = input.runtime;\n const result = await apiClient.getDocumentWriterProjectionResult(\n input.documentId,\n { reportErrors: false },\n );\n if (result.ok) {\n return result.data;\n }\n result.report();\n input.onFailure?.({ message: result.message, status: result.status });\n return null;\n}\n\ninterface ContainerDocumentLinkRuntime\n extends Pick<\n ContainerContentsWorkflowRuntime,\n | \"auth\"\n | \"crypto\"\n | \"infra\"\n | \"resolveTrustedUserIdentity\"\n | \"state\"\n | \"util\"\n > {\n apiClient: ContainerDocumentLinkApi &\n Pick<\n ContainerContentsWorkflowRuntime[\"apiClient\"],\n \"getPrincipalPolicyPages\" | \"getProjectionPolicyHistoryPages\"\n >;\n}\n\ntype MoveRemoteContainerDocumentStatus = \"complete\" | \"partial\";\n\ninterface MoveRemoteContainerDocumentResult {\n accessEpoch: number | null;\n accessStateHash: string | null;\n linkedContainerIds: readonly string[];\n nextContainerId: string;\n remoteState: RemoteDocumentPersistedState | null;\n status: MoveRemoteContainerDocumentStatus;\n}\n\nexport type { RemoteDocumentPersistedState };\n\nexport async function initializeDocumentLinksSchema(\n execSql: ExecSql,\n): Promise<void> {\n await sqlDocumentContainerProjectionPersistence.ensureSchema(execSql);\n}\n\nexport async function listDocumentLinkedContainerIds(\n execSql: ExecSql,\n documentId: string,\n): Promise<ReadonlyArray<string>> {\n return sqlDocumentContainerProjectionPersistence.listLinkedContainerIds(\n execSql,\n documentId,\n );\n}\n\nexport async function replaceDocumentLinks(\n execSql: ExecSql,\n documentId: string,\n containerIds: ReadonlyArray<string>,\n): Promise<void> {\n await sqlDocumentContainerProjectionPersistence.replaceDocumentLinks(\n execSql,\n documentId,\n containerIds,\n );\n}\n\nfunction resolveActiveDocumentContainerId(\n linkedContainerIds: ReadonlyArray<string>,\n preferredContainerId: string,\n): string | null {\n if (linkedContainerIds.includes(preferredContainerId)) {\n return preferredContainerId;\n }\n\n return linkedContainerIds[0] ?? null;\n}\n\nfunction containerDocumentMoveResult(input: {\n document: RelinkRemoteDocumentResult;\n nextContainerId: string;\n status: MoveRemoteContainerDocumentStatus;\n}): MoveRemoteContainerDocumentResult {\n return {\n accessEpoch: input.document.plan.state.epoch,\n accessStateHash: input.document.response.accessManifest.manifestHash,\n linkedContainerIds: input.document.linkedContainerIds,\n nextContainerId: input.nextContainerId,\n remoteState: input.document.persistedState,\n status: input.status,\n };\n}\n\nasync function containerDocumentAlreadyMovedResult(input: {\n writerProjection: DocumentWriterProjectionResponse;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerDocumentLinkRuntime;\n isCurrent?: (() => boolean) | undefined;\n linkedContainerIds: readonly string[];\n nextContainerId: string;\n status: MoveRemoteContainerDocumentStatus;\n}): Promise<MoveRemoteContainerDocumentResult> {\n const verified: { head?: VerifiedDocumentLinkSetManifest | undefined } = {};\n await assertDocumentWriterProjectionConsistent(input.writerProjection, {\n execSql: input.runtime.infra.execSql,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.isCurrent,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.runtime,\n ),\n onVerifiedAuthorization: (authorization) => {\n verified.head = authorization.documentManifestByHash.get(\n input.writerProjection.documentManifest.manifestHash,\n );\n },\n });\n if (!verified.head)\n throw new Error(\"Move replay lacks a verified document head\");\n return {\n accessEpoch: verified.head.state.epoch,\n accessStateHash: verified.head.manifestHash,\n linkedContainerIds: input.linkedContainerIds,\n nextContainerId: input.nextContainerId,\n remoteState: persistedDocumentCreateStateFromWriterProjection(\n input.writerProjection,\n ),\n status: input.status,\n };\n}\n\n/**\n * Hand a link/unlink/move/purge failure to host diagnostics as a real `Error`.\n * The caller's string-only log line stays the fallback for a host without\n * `logError`, so this never logs a second copy of the same failure.\n */\nfunction reportDocumentLinkMutationFailure(\n util: ContainerDocumentLinkRuntime[\"util\"],\n error: unknown,\n): void {\n // `ApiClient` returns `RequestFailure` objects instead of throwing, so\n // offline and 403/404/409 already left through the `!result` branch: a status\n // filter here would be dead code. Only a database lost mid-flight stays quiet.\n if (!util.logError || isDatabaseUnavailableError(error)) return;\n try {\n // A host logger that throws or rejects must not replace the null result or\n // skip the failure handler below.\n void Promise.resolve(\n util.logError(\"Container contents: document link mutation failed\", error),\n ).catch(() => undefined);\n } catch {\n // Hosts may throw synchronously or return a rejected promise.\n }\n}\n\nexport async function relinkRemoteContainerDocument(input: {\n beforeSubmit?: (() => Promise<boolean>) | undefined;\n documentId: string;\n expectedSubtreeRoot?: SubtreePurgeRoot | undefined;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n operation: ContainerDocumentLinkOperation;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot?: Uint8Array | undefined;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<RelinkRemoteDocumentResult | null> {\n const {\n documentId,\n noteId,\n operation,\n resolveProjectionUserKey,\n runtime,\n targetContainerId,\n } = input;\n const author = resolveDocumentCreateAuthor(runtime);\n const targetSecretKey = runtime.crypto.encapsulationKeyPair?.secretKey;\n const execSql = runtime.infra.execSql;\n if (input.isCurrent?.() === false) return null;\n if (!author || !targetSecretKey) {\n runtime.util.log(\n \"Container contents: document mutation skipped because the local key context is unavailable\",\n );\n input.onFailure?.({\n message: \"the local key context is unavailable\",\n status: null,\n });\n return null;\n }\n\n try {\n const result = await relinkRemoteDocument({\n beforeSubmit: input.beforeSubmit,\n apiClient: runtime.apiClient,\n author,\n documentId,\n expectedSubtreeRoot: input.expectedSubtreeRoot,\n execSql,\n onFailure: input.onFailure,\n operation,\n resolveProjectionUserKey,\n rotationSnapshot: input.rotationSnapshot,\n stillCurrent: input.isCurrent,\n targetContainerId,\n targetSecretKey,\n warmReferencedPrincipalPolicies:\n createRuntimePrincipalPolicyWarmer(runtime),\n });\n if (!result) {\n runtime.util.log(\n `Container contents: failed to ${operation} note ${noteId} ${operation === \"link\" ? \"to\" : \"from\"} container ${targetContainerId}`,\n );\n return null;\n }\n if (input.isCurrent?.() === false) return null;\n\n await sqlDocumentContainerProjectionPersistence.replaceDocumentLinks(\n execSql,\n documentId,\n result.linkedContainerIds,\n { stillCurrent: input.isCurrent },\n );\n\n return result;\n } catch (error) {\n await reportAndRethrowKeyingVerificationError(\n error,\n runtime.util.reportSecurityIncident,\n {\n objectId: documentId,\n objectKind: \"document\",\n operation: `document.${operation}`,\n },\n );\n const message = errorMessage(error);\n runtime.util.log(\n `Container contents: failed to ${operation} note ${noteId} ${operation === \"link\" ? \"to\" : \"from\"} container ${targetContainerId}: ${message}`,\n );\n // After the keying rethrow above, so a verification failure keeps its\n // security incident instead of being reported twice, and before the failure\n // handler, so a throwing caller callback cannot swallow the report.\n reportDocumentLinkMutationFailure(runtime.util, error);\n input.onFailure?.({ message, status: null });\n return null;\n }\n}\n\nasync function linkRemoteContainerDocument(input: {\n documentId: string;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<RelinkRemoteDocumentResult | null> {\n return relinkRemoteContainerDocument({\n ...input,\n operation: \"link\",\n });\n}\n\nexport async function unlinkRemoteContainerDocument(input: {\n beforeSubmit?: (() => Promise<boolean>) | undefined;\n documentId: string;\n expectedSubtreeRoot?: SubtreePurgeRoot | undefined;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot: Uint8Array;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<RelinkRemoteDocumentResult | null> {\n return relinkRemoteContainerDocument({\n ...input,\n operation: \"unlink\",\n });\n}\n\nexport async function moveRemoteContainerDocument(input: {\n linkOnly?: boolean | undefined;\n additionalLinkContainerIds?: readonly string[] | undefined;\n removedLinkContainerIds?: readonly string[] | undefined;\n currentContainerId: string;\n documentId: string;\n isCurrent?: (() => boolean) | undefined;\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n replaceLinkedContainers?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot: Uint8Array;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n}): Promise<MoveRemoteContainerDocumentResult | null> {\n const {\n documentId,\n noteId,\n resolveProjectionUserKey,\n runtime,\n targetContainerId,\n } = input;\n if (input.isCurrent?.() === false) return null;\n const writerProjection = await fetchMoveWriterProjection({\n documentId,\n onFailure: input.onFailure,\n runtime,\n });\n if (!writerProjection || input.isCurrent?.() === false) {\n return null;\n }\n if (writerProjection.documentId !== documentId)\n throw new Error(\"Move replay document id mismatch\");\n const initialLinkedContainerIds =\n readLinkedContainerIdsFromDocumentManifest(writerProjection);\n\n let latestLinkedContainerIds: readonly string[] = initialLinkedContainerIds;\n let latestDocument: RelinkRemoteDocumentResult | null = null;\n for (const linkTarget of new Set([\n ...(input.linkOnly ? [] : [targetContainerId]),\n ...(input.additionalLinkContainerIds ?? []),\n ])) {\n if (latestLinkedContainerIds.includes(linkTarget)) continue;\n const linkedDocument = await linkRemoteContainerDocument({\n documentId,\n isCurrent: input.isCurrent,\n noteId,\n onFailure: input.onFailure,\n resolveProjectionUserKey,\n runtime,\n targetContainerId: linkTarget,\n });\n if (!linkedDocument || input.isCurrent?.() === false) {\n return null;\n }\n\n latestDocument = linkedDocument;\n latestLinkedContainerIds = linkedDocument.linkedContainerIds;\n }\n\n const unlinkContainerIds = resolveContainerDocumentMoveUnlinkIds({\n ...input,\n linkedContainerIds: latestLinkedContainerIds,\n });\n\n const unlinked = await unlinkMovedDocumentSources({\n ...input,\n latestDocument,\n latestLinkedContainerIds,\n unlinkContainerIds,\n });\n if (!unlinked) return null;\n latestDocument = unlinked.latestDocument;\n latestLinkedContainerIds = unlinked.latestLinkedContainerIds;\n\n const nextContainerId = resolveActiveDocumentContainerId(\n latestLinkedContainerIds,\n targetContainerId,\n );\n if (!nextContainerId) {\n return null;\n }\n\n const status =\n unlinked.failedUnlinkContainerIds.length > 0 ? \"partial\" : \"complete\";\n return latestDocument\n ? containerDocumentMoveResult({\n document: latestDocument,\n nextContainerId,\n status,\n })\n : containerDocumentAlreadyMovedResult({\n writerProjection,\n resolveProjectionUserKey,\n runtime,\n isCurrent: input.isCurrent,\n linkedContainerIds: latestLinkedContainerIds,\n nextContainerId,\n status,\n });\n}\n\n// The unlink half of a move: every source is attempted even when an earlier\n// one fails, so one dead source cannot strand the others; a failed unlink\n// leaves the move \"partial\" for the queue to retry.\nasync function unlinkMovedDocumentSources(input: {\n documentId: string;\n isCurrent?: (() => boolean) | undefined;\n latestDocument: RelinkRemoteDocumentResult | null;\n latestLinkedContainerIds: readonly string[];\n noteId: string;\n onFailure?: DocumentLinkSetFailureHandler | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n rotationSnapshot: Uint8Array;\n runtime: ContainerDocumentLinkRuntime;\n targetContainerId: string;\n unlinkContainerIds: readonly string[];\n}): Promise<{\n failedUnlinkContainerIds: readonly string[];\n latestDocument: RelinkRemoteDocumentResult | null;\n latestLinkedContainerIds: readonly string[];\n} | null> {\n const { noteId, runtime, targetContainerId } = input;\n let { latestDocument, latestLinkedContainerIds } = input;\n const failedUnlinkContainerIds: string[] = [];\n for (const unlinkContainerId of input.unlinkContainerIds) {\n if (input.isCurrent?.() === false) return null;\n const unlinkedDocument = await unlinkRemoteContainerDocument({\n documentId: input.documentId,\n isCurrent: input.isCurrent,\n noteId,\n onFailure: input.onFailure,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n rotationSnapshot: input.rotationSnapshot,\n runtime,\n targetContainerId: unlinkContainerId,\n });\n if (input.isCurrent?.() === false) return null;\n if (!unlinkedDocument) {\n failedUnlinkContainerIds.push(unlinkContainerId);\n runtime.util.log(\n `Container contents: note ${noteId} was linked to ${targetContainerId} but failed to unlink from ${unlinkContainerId}`,\n );\n continue;\n }\n\n latestDocument = unlinkedDocument;\n latestLinkedContainerIds = unlinkedDocument.linkedContainerIds;\n }\n return { failedUnlinkContainerIds, latestDocument, latestLinkedContainerIds };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_DOCUMENT_ACCESS_EPOCH } from "../../../data/documents/documentConstants.js";
|
|
2
2
|
import { uniqueSortedStrings } from "../../../data/documents/shared/readers.js";
|
|
3
|
+
import { sqlDocumentContainerProjectionPersistence } from "../../../data/persistence/container-contents/documentContainerProjectionPersistence.js";
|
|
3
4
|
import { sqlDocumentMoveIntentPersistence } from "../../../data/persistence/container-contents/documentMoveIntentPersistence.js";
|
|
4
|
-
import { sqlDocumentContainerProjectionPersistence } from "../../../data/persistence/containers/documentContainerProjectionPersistence.js";
|
|
5
5
|
import { defaultDocumentsPersistence } from "../../documents/index.js";
|
|
6
6
|
import { listDocumentLinkedContainerIds } from "../documentLinks/index.js";
|
|
7
7
|
import { relinkContainerDocumentLocally } from "../documentLinks/documentLocalRelink.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentMoveIntent.js","sourceRoot":"","sources":["documentMoveIntent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,2CAA2C,CAAC;AAE1F,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"documentMoveIntent.js","sourceRoot":"","sources":["documentMoveIntent.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEFAULT_DOCUMENT_ACCESS_EPOCH } from \"../../../data/documents/documentConstants\";\nimport type { DocumentSummary } from \"../../../data/documents/documentSummary\";\nimport { uniqueSortedStrings } from \"../../../data/documents/shared/readers\";\nimport { sqlDocumentContainerProjectionPersistence } from \"../../../data/persistence/container-contents/documentContainerProjectionPersistence\";\nimport { sqlDocumentMoveIntentPersistence } from \"../../../data/persistence/container-contents/documentMoveIntentPersistence\";\nimport { defaultDocumentsPersistence } from \"../../documents\";\nimport { listDocumentLinkedContainerIds } from \"../documentLinks\";\nimport { relinkContainerDocumentLocally } from \"../documentLinks/documentLocalRelink\";\nimport type {\n DocumentStructuralMutationHost,\n DocumentStructuralMutationLocalStore,\n DocumentStructuralMutationRuntime,\n SetLinkedContainerIdsForDocument,\n} from \"../documentQueries/documentStructureTypes\";\n\nasync function resolveOptimisticDocumentMoveLinks(input: {\n currentContainerId: string | null;\n documentId: string;\n replaceLinkedContainers?: boolean | undefined;\n runtime: DocumentStructuralMutationRuntime;\n targetContainerId: string;\n}): Promise<string[]> {\n if (input.replaceLinkedContainers) {\n return [input.targetContainerId];\n }\n\n const currentLinkedContainerIds = await listDocumentLinkedContainerIds(\n input.runtime.infra.execSql,\n input.documentId,\n );\n const linkedContainerIds =\n currentLinkedContainerIds.length > 0\n ? currentLinkedContainerIds\n : input.currentContainerId\n ? [input.currentContainerId]\n : [];\n\n return uniqueSortedStrings([\n ...linkedContainerIds.filter(\n (containerId) => containerId !== input.currentContainerId,\n ),\n input.targetContainerId,\n ]);\n}\n\nasync function resolveLocalMoveAccessEpoch(input: {\n localId: string;\n runtime: DocumentStructuralMutationRuntime;\n}): Promise<number> {\n const existingDocument = await defaultDocumentsPersistence.loadDocument(\n input.runtime.infra.execSql,\n input.localId,\n );\n // The local relink must keep the document's current key epoch. Falling back\n // is only for partially seeded local state; downgrading synced documents\n // would make offline edits use stale access material.\n return existingDocument?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n}\n\nexport async function moveRemoteDocumentLinkLocally<TRuntime>(params: {\n currentDocumentStore: DocumentStructuralMutationLocalStore<TRuntime>;\n expandNode: (nodeId: string) => void;\n host: DocumentStructuralMutationHost<TRuntime>;\n note: DocumentSummary & { documentId: string };\n replaceLinkedContainers?: boolean | undefined;\n runtime: DocumentStructuralMutationRuntime;\n scheduleSync?: (() => void) | undefined;\n setLinkedContainerIdsForDocument: SetLinkedContainerIdsForDocument;\n targetContainerId: string;\n}): Promise<{ linksChanged: boolean; note: DocumentSummary | null }> {\n const {\n currentDocumentStore,\n expandNode,\n host,\n note,\n replaceLinkedContainers,\n runtime,\n scheduleSync,\n setLinkedContainerIdsForDocument,\n targetContainerId,\n } = params;\n const linkedContainerIds = await resolveOptimisticDocumentMoveLinks({\n currentContainerId: note.containerId,\n documentId: note.documentId,\n replaceLinkedContainers,\n runtime,\n targetContainerId,\n });\n\n // Apply the user's chosen placement locally now, then replay the signed\n // link-set mutation from this durable intent when auth/network/key context is\n // back. This mirrors container move intents: UI state should not wait on the\n // server, but the remote contract still converges through the normal writer\n // projection path.\n const intentId = crypto.randomUUID();\n\n const movedNote = await relinkContainerDocumentLocally({\n accessEpoch: await resolveLocalMoveAccessEpoch({\n localId: note.id,\n runtime,\n }),\n currentDocumentStore,\n host,\n note,\n commitSideEffect: async (execSql) => {\n await sqlDocumentMoveIntentPersistence.enqueueMoveIntent(execSql, {\n id: intentId,\n documentId: note.documentId,\n localId: note.id,\n replaceLinkedContainers,\n sourceContainerId: note.containerId,\n targetContainerId,\n });\n await sqlDocumentContainerProjectionPersistence.replaceDocumentLinks(\n execSql,\n note.documentId,\n linkedContainerIds,\n { moveIntentId: intentId },\n );\n },\n requestSync: false,\n runtime,\n targetContainerId,\n });\n if (!movedNote) {\n return { linksChanged: false, note: null };\n }\n\n setLinkedContainerIdsForDocument(note.documentId, linkedContainerIds);\n expandNode(targetContainerId);\n scheduleSync?.();\n runtime.util.log(\n `Container contents: queued note ${movedNote.id} move to ${targetContainerId}`,\n );\n return { linksChanged: true, note: movedNote };\n}\n"]}
|