@tearleads/client-sdk 0.1.76 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/{documents/blob/shared → blobs/attachments}/blobEnvelopeStream.js +1 -1
- package/data/{documents/blob/shared → blobs/attachments}/blobEnvelopeStream.js.map +1 -1
- package/data/blobs/attachments/blobRecordCrypto.d.ts +26 -0
- package/data/{documents/blob/shared → blobs/attachments}/blobRecordCrypto.js +2 -2
- package/data/{documents/blob/shared → blobs/attachments}/blobSourceSnapshot.d.ts +1 -1
- package/data/{documents/blob/shared → blobs/attachments}/blobSourceSnapshot.js +2 -2
- package/data/blobs/attachments/blobSourceSnapshot.js.map +1 -0
- package/data/blobs/attachments/chunkedBlobCrypto.d.ts +17 -0
- package/data/{documents/blob/shared → blobs/attachments}/chunkedBlobCrypto.js +3 -3
- package/data/blobs/attachments/chunkedBlobCrypto.js.map +1 -0
- package/data/blobs/attachments/crypto.d.ts +3 -0
- package/data/blobs/attachments/encryptedUploadParts.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/events.js +3 -3
- package/data/blobs/attachments/events.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/projection.js +8 -8
- package/data/blobs/attachments/projection.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/readers.js +3 -3
- package/data/blobs/attachments/readers.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/responses.js +2 -2
- package/data/blobs/attachments/responses.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/types.d.ts +8 -8
- package/data/blobs/attachments/types.js.map +1 -0
- package/data/{containers → persistence/container-contents}/containerBinding.js +1 -1
- package/data/persistence/container-contents/containerContentsPersistence.js +2 -2
- package/data/persistence/container-contents/containerContentsPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerContentsPersistenceTypes.d.ts +2 -2
- package/data/persistence/container-contents/containerContentsPersistenceTypes.js.map +1 -1
- package/data/persistence/container-contents/containerDeletionPersistence.js +2 -2
- package/data/persistence/container-contents/containerDeletionPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerHydrationPersistence.js +2 -2
- package/data/persistence/container-contents/containerHydrationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js +2 -2
- package/data/persistence/container-contents/containerMetadataMutationPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js +1 -1
- package/data/persistence/container-contents/containerMetadataRows.js.map +1 -1
- package/data/persistence/container-contents/containerRebindPersistence.js.map +1 -1
- package/data/persistence/container-contents/containerReconcilePersistence.js +2 -2
- package/data/persistence/container-contents/containerReconcilePersistence.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/dormantMetadataSweep.js +1 -1
- package/data/persistence/container-contents/dormantMetadataSweep.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstoneHolds.js.map +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js +1 -1
- package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
- package/data/persistence/documents/internal/discoveredDocumentPlacement.js +1 -1
- package/data/persistence/documents/internal/discoveredDocumentPlacement.js.map +1 -1
- package/package.json +1 -1
- package/stores/container-contents/systemContainers/systemContainerIcon.js +1 -1
- package/stores/container-contents/systemContainers/systemContainerIcon.js.map +1 -1
- package/stores/documents/documentStore/attachmentUpload/attachmentSourceUpload.js +1 -2
- package/stores/documents/documentStore/attachmentUpload/attachmentSourceUpload.js.map +1 -1
- package/stores/documents/documentStore/sync/syncAttachments.js.map +1 -1
- package/workflows/blobs/detach.js +2 -2
- package/workflows/blobs/detach.js.map +1 -1
- package/workflows/blobs/hydration/blobChunkDecryption.js +1 -1
- package/workflows/blobs/hydration/blobChunkDecryption.js.map +1 -1
- package/workflows/blobs/hydration/decrypt.d.ts +1 -1
- package/workflows/blobs/hydration/decrypt.js +4 -4
- package/workflows/blobs/hydration/decrypt.js.map +1 -1
- package/workflows/blobs/index.d.ts +3 -1
- package/workflows/blobs/index.js +3 -0
- package/workflows/blobs/index.js.map +1 -1
- package/workflows/blobs/upload/automaticMultipartUpload.js +1 -1
- package/workflows/blobs/upload/automaticMultipartUpload.js.map +1 -1
- package/workflows/blobs/upload/index.d.ts +2 -2
- package/workflows/blobs/upload/index.js +4 -4
- package/workflows/blobs/upload/index.js.map +1 -1
- package/workflows/blobs/upload/multipartFirstParts.js.map +1 -1
- package/workflows/blobs/upload/multipartStageFailures.js.map +1 -1
- package/workflows/blobs/upload/multipartStageResolution.js.map +1 -1
- package/workflows/blobs/upload/multipartUpload.js.map +1 -1
- package/workflows/blobs/verification/attachmentBindingVerification.js.map +1 -1
- package/workflows/blobs/verification/attachmentKeyAuthenticator.js +1 -1
- package/workflows/blobs/verification/attachmentKeyAuthenticator.js.map +1 -1
- package/workflows/blobs/verification/retainedAttachmentVerification.js +1 -1
- package/workflows/blobs/verification/retainedAttachmentVerification.js.map +1 -1
- package/workflows/blobs/verification/writerProjection.js +1 -1
- package/workflows/blobs/verification/writerProjection.js.map +1 -1
- package/workflows/container-contents/container-state/create/createChild.js +1 -1
- package/workflows/container-contents/container-state/create/createChild.js.map +1 -1
- package/workflows/container-contents/container-state/purge/purgeTree.js +1 -1
- package/workflows/container-contents/container-state/purge/purgeTree.js.map +1 -1
- package/workflows/container-contents/container-state/types.js.map +1 -1
- package/workflows/container-contents/containerPersistence.d.ts +3 -3
- package/workflows/container-contents/containerPersistence.js +1 -1
- package/workflows/container-contents/containerPersistence.js.map +1 -1
- package/workflows/container-contents/documentLinks/documentLinkIntent.js +1 -1
- package/workflows/container-contents/documentLinks/documentLinkIntent.js.map +1 -1
- package/workflows/container-contents/documentLinks/index.js +1 -1
- package/workflows/container-contents/documentLinks/index.js.map +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntent.js +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntent.js.map +1 -1
- package/workflows/container-contents/documentMove/documentMoveIntentSettlement.js +2 -2
- package/workflows/container-contents/documentMove/documentMoveIntentSettlement.js.map +1 -1
- package/workflows/container-contents/documentQueries/documentSubtreeQueries.js +1 -1
- package/workflows/container-contents/documentQueries/documentSubtreeQueries.js.map +1 -1
- package/workflows/container-contents/documentQueries/index.js +3 -3
- package/workflows/container-contents/documentQueries/index.js.map +1 -1
- package/workflows/container-contents/documentQueries/pendingDownloads.js +1 -1
- package/workflows/container-contents/documentQueries/pendingDownloads.js.map +1 -1
- package/workflows/container-contents/index.d.ts +1 -1
- package/workflows/container-contents/index.js +1 -1
- package/workflows/container-contents/index.js.map +1 -1
- package/workflows/container-contents/info/blobInfo.js +1 -1
- package/workflows/container-contents/info/blobInfo.js.map +1 -1
- package/workflows/container-contents/info/containerInfo.js +2 -2
- package/workflows/container-contents/info/containerInfo.js.map +1 -1
- package/{data/containers → workflows/container-contents/metadata}/containerMetadataDocument.d.ts +1 -1
- package/{data/containers → workflows/container-contents/metadata}/containerMetadataDocument.js +2 -2
- package/workflows/container-contents/metadata/containerMetadataDocument.js.map +1 -0
- package/workflows/container-contents/metadata/metadataMutationPreparation.js +1 -1
- package/workflows/container-contents/metadata/metadataMutationPreparation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataPersistence.js +1 -1
- package/workflows/container-contents/metadata/metadataPersistence.js.map +1 -1
- package/workflows/container-contents/metadata/metadataRecord.js.map +1 -1
- package/workflows/container-contents/metadata/metadataStateIsolation.js +1 -1
- package/workflows/container-contents/metadata/metadataStateIsolation.js.map +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js +1 -1
- package/workflows/container-contents/metadata/metadataSyncSettlement.js.map +1 -1
- package/workflows/container-contents/metadata/metadataTypes.d.ts +2 -2
- package/workflows/container-contents/metadata/metadataTypes.js.map +1 -1
- package/workflows/container-contents/recovery/folderRecovery.js +1 -1
- package/workflows/container-contents/recovery/folderRecovery.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/replacementBinding.js +1 -1
- package/workflows/container-contents/remoteHydration/destination/replacementBinding.js.map +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js +1 -1
- package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js.map +1 -1
- package/workflows/container-contents/remoteHydration/heldContainerRebind.js +1 -1
- package/workflows/container-contents/remoteHydration/heldContainerRebind.js.map +1 -1
- package/workflows/container-contents/remoteHydration/reattachMetadata.js +1 -1
- package/workflows/container-contents/remoteHydration/reattachMetadata.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js +2 -2
- package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js.map +1 -1
- package/workflows/container-contents/remoteHydration/types.d.ts +1 -1
- package/workflows/container-contents/remoteHydration/types.js.map +1 -1
- package/workflows/container-contents/storedContainerState.js +1 -1
- package/workflows/container-contents/storedContainerState.js.map +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js +1 -1
- package/workflows/organizations/groupMetadata/groupMetadataAccess.js.map +1 -1
- package/workflows/organizations/readModel/localReadModelDetails.js +1 -1
- package/workflows/organizations/readModel/localReadModelDetails.js.map +1 -1
- package/workflows/registration/bootstrapRootContainer.js +1 -1
- package/workflows/registration/bootstrapRootContainer.js.map +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.js +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.js.map +1 -1
- package/workflows/registration/rootMetadataBootstrap.js +1 -1
- package/workflows/registration/rootMetadataBootstrap.js.map +1 -1
- package/workflows/sync/remoteReset.js +1 -1
- package/workflows/sync/remoteReset.js.map +1 -1
- package/data/containers/containerMetadataDocument.js.map +0 -1
- package/data/documents/blob/shared/blobSourceSnapshot.js.map +0 -1
- package/data/documents/blob/shared/chunkedBlobCrypto.js.map +0 -1
- package/data/documents/blob/shared/encryptedUploadParts.js.map +0 -1
- package/data/documents/blob/shared/events.js.map +0 -1
- package/data/documents/blob/shared/projection.js.map +0 -1
- package/data/documents/blob/shared/readers.js.map +0 -1
- package/data/documents/blob/shared/responses.js.map +0 -1
- package/data/documents/blob/shared/types.js.map +0 -1
- /package/data/{documents/blob/shared → blobs/attachments}/blobRecordCrypto.js.map +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/crypto.js +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/crypto.js.map +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/encryptedUploadParts.js +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/types.js +0 -0
- /package/data/{containers → persistence/container-contents}/containerBinding.d.ts +0 -0
- /package/data/{containers → persistence/container-contents}/containerBinding.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.d.ts +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/containerPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.d.ts +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/containerSyncWatermarkPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/documentContainerProjectionPersistence.js +0 -0
- /package/data/persistence/{containers → container-contents}/documentContainerProjectionPersistence.js.map +0 -0
- /package/data/persistence/{containers → container-contents}/documentPlacement.js +0 -0
- /package/data/persistence/{containers → container-contents}/documentPlacement.js.map +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadataRecord.js","sourceRoot":"","sources":["metadataRecord.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport { exportAllUpdates } from \"@tearleads/loro\";\nimport type { ContainerRecord } from \"../../../data/persistence/
|
|
1
|
+
{"version":3,"file":"metadataRecord.js","sourceRoot":"","sources":["metadataRecord.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport { exportAllUpdates } from \"@tearleads/loro\";\nimport type { ContainerRecord } from \"../../../data/persistence/container-contents/containerPersistence\";\nimport type { ContainerDocumentRecord as DocumentRecord } from \"../containerPersistence\";\nimport {\n currentMetadataPullContinuation,\n type resolveMetadataSecurityContext,\n} from \"./metadataMutationPreparation\";\nimport type {\n ContainerMetadataPatch,\n ContainerMetadataState,\n} from \"./metadataTypes\";\n\ntype NullableContainerMetadataDocumentField =\n | \"accessStateHash\"\n | \"lastCommitLsn\"\n | \"contentKeyBundle\"\n | \"documentKekTargets\"\n | \"documentManifestBundle\";\n\nexport function resolveContainerSystemSlot(\n patch: Partial<ContainerMetadataPatch>,\n container: ContainerRecord,\n): NonNullable<ContainerRecord[\"systemSlot\"]> | null {\n return patch.systemSlot ?? container.systemSlot ?? null;\n}\n\nexport function resolveMetadataDocumentId(\n patch: Partial<ContainerMetadataPatch>,\n container: ContainerRecord,\n): ContainerRecord[\"metadataDocumentId\"] {\n return (\n patch.metadataDocumentId ?? patch.documentId ?? container.metadataDocumentId\n );\n}\n\nfunction resolveNullableContainerMetadataDocumentField(\n patch: Partial<ContainerMetadataPatch>,\n key: NullableContainerMetadataDocumentField,\n currentValue: string | null | undefined,\n resetWhenUnpatched = false,\n): string | null {\n if (Object.hasOwn(patch, key)) return patch[key] ?? null;\n return resetWhenUnpatched ? null : (currentValue ?? null);\n}\n\nfunction resolveMetadataPullState(\n metadataState: ContainerMetadataState,\n patch: Partial<ContainerMetadataPatch>,\n securityContextChanged: boolean,\n): Pick<\n DocumentRecord,\n \"pullContinuation\" | \"pullContinuationRecoveryRequired\"\n> {\n if (Object.hasOwn(patch, \"pullContinuation\")) {\n return { pullContinuation: patch.pullContinuation ?? null };\n }\n if (securityContextChanged) return { pullContinuation: null };\n if (metadataState.record.pullContinuationRecoveryRequired) {\n return { pullContinuationRecoveryRequired: true };\n }\n return { pullContinuation: currentMetadataPullContinuation(metadataState) };\n}\n\nexport function buildContainerMetadataRecord(input: {\n metadataState: ContainerMetadataState;\n patch: Partial<ContainerMetadataPatch>;\n securityContext: ReturnType<typeof resolveMetadataSecurityContext>;\n}): DocumentRecord {\n const { metadataState, patch, securityContext } = input;\n return {\n id: metadataState.container.id,\n documentId: securityContext.documentId,\n metadataUpdates:\n patch.metadataUpdates ??\n bytesToBase64(exportAllUpdates(metadataState.doc)),\n snapshotEndVersion: \"\",\n accessEpoch: securityContext.accessEpoch,\n accessStateHash: resolveNullableContainerMetadataDocumentField(\n patch,\n \"accessStateHash\",\n metadataState.record.accessStateHash,\n securityContext.changed,\n ),\n lastCommitLsn: resolveNullableContainerMetadataDocumentField(\n patch,\n \"lastCommitLsn\",\n metadataState.record.lastCommitLsn,\n securityContext.documentIdChanged,\n ),\n contentKeyBundle: resolveNullableContainerMetadataDocumentField(\n patch,\n \"contentKeyBundle\",\n metadataState.record.contentKeyBundle,\n securityContext.changed,\n ),\n documentKekTargets: resolveNullableContainerMetadataDocumentField(\n patch,\n \"documentKekTargets\",\n metadataState.record.documentKekTargets,\n securityContext.changed,\n ),\n documentManifestBundle: resolveNullableContainerMetadataDocumentField(\n patch,\n \"documentManifestBundle\",\n metadataState.record.documentManifestBundle,\n securityContext.changed,\n ),\n ...resolveMetadataPullState(metadataState, patch, securityContext.changed),\n };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { encodeVersionVector, exportAllUpdates, exportFullHistorySnapshot, importSnapshot, importUpdates, satisfiesVersionVector, } from "../../../internal/loro/index.js";
|
|
2
|
-
import { createContainerMetadataDocument, getDefaultContainerName, readContainerMetadataValue, } from "../../../data/containers/containerMetadataDocument.js";
|
|
3
2
|
import { projectionGeneration } from "../projectionGeneration.js";
|
|
3
|
+
import { createContainerMetadataDocument, getDefaultContainerName, readContainerMetadataValue, } from "./containerMetadataDocument.js";
|
|
4
4
|
import { metadataSyncSecurityContextMatches } from "./metadataSyncSettlement.js";
|
|
5
5
|
function mergeConcurrentMetadataRecord(liveRecord, candidateRecord) {
|
|
6
6
|
if (metadataSyncSecurityContextMatches(liveRecord, candidateRecord)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadataStateIsolation.js","sourceRoot":"","sources":["metadataStateIsolation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,aAAa,EACb,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,
|
|
1
|
+
{"version":3,"file":"metadataStateIsolation.js","sourceRoot":"","sources":["metadataStateIsolation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n encodeVersionVector,\n exportAllUpdates,\n exportFullHistorySnapshot,\n importSnapshot,\n importUpdates,\n satisfiesVersionVector,\n} from \"@tearleads/loro\";\nimport { projectionGeneration } from \"../projectionGeneration\";\nimport {\n createContainerMetadataDocument,\n getDefaultContainerName,\n readContainerMetadataValue,\n} from \"./containerMetadataDocument\";\nimport { metadataSyncSecurityContextMatches } from \"./metadataSyncSettlement\";\nimport type { ContainerMetadataState } from \"./metadataTypes\";\n\nexport interface DetachedContainerMetadataState extends ContainerMetadataState {\n readonly detachedSource: {\n readonly metadataVersion: string;\n /** The live state's `writerProjectionGeneration` when it was detached. */\n readonly writerProjectionGeneration: number;\n };\n}\n\ninterface DetachedContainerMetadataInstallOptions {\n readonly candidateRecord?: ContainerMetadataState[\"record\"];\n readonly preserveConcurrentMetadataEdit?: boolean;\n}\n\nfunction mergeConcurrentMetadataRecord(\n liveRecord: ContainerMetadataState[\"record\"],\n candidateRecord: ContainerMetadataState[\"record\"],\n): ContainerMetadataState[\"record\"] {\n if (metadataSyncSecurityContextMatches(liveRecord, candidateRecord)) {\n return liveRecord;\n }\n\n // The live document owns the concurrent CRDT frontier, but the candidate\n // owns the newly committed remote identity. Carry only the fields that\n // describe the live CRDT history across that identity boundary.\n return {\n ...candidateRecord,\n metadataUpdates: liveRecord.metadataUpdates,\n snapshotEndVersion: liveRecord.snapshotEndVersion,\n ...(liveRecord.pendingBaseVersion === undefined\n ? {}\n : { pendingBaseVersion: liveRecord.pendingBaseVersion }),\n };\n}\n\n/**\n * Gives an asynchronous sync pass its own mutable metadata projection. Durable\n * settlement can then repair or replace the candidate without changing the\n * live store until the caller has rechecked its lifecycle generation.\n */\nexport async function createDetachedContainerMetadataState(\n metadataState: ContainerMetadataState,\n options: {\n /**\n * The live generation captured when the surrounding operation began, for\n * callers that awaited (a request, a policy warm-up) before detaching.\n */\n readonly writerProjectionGeneration?: number | undefined;\n } = {},\n): Promise<DetachedContainerMetadataState> {\n const doc = await createContainerMetadataDocument(metadataState.container.id);\n importSnapshot(doc, exportFullHistorySnapshot(metadataState.doc));\n return {\n ...metadataState,\n container: { ...metadataState.container },\n detachedSource: {\n metadataVersion: encodeVersionVector(metadataState.doc),\n writerProjectionGeneration:\n options.writerProjectionGeneration ??\n projectionGeneration(metadataState),\n },\n doc,\n record: { ...metadataState.record },\n };\n}\n\nexport function installDetachedContainerMetadataState(\n target: ContainerMetadataState,\n candidate: DetachedContainerMetadataState,\n options: DetachedContainerMetadataInstallOptions = {},\n): void {\n const candidateRecord = options.candidateRecord ?? candidate.record;\n const liveMetadataVersion = encodeVersionVector(target.doc);\n const candidateMetadataVersion = encodeVersionVector(candidate.doc);\n const liveRecord = target.record;\n const livePullContinuation = target.pullContinuation;\n const preserveConcurrentLiveMetadata =\n options.preserveConcurrentMetadataEdit === true &&\n liveMetadataVersion !== candidate.detachedSource.metadataVersion &&\n !satisfiesVersionVector(candidateMetadataVersion, liveMetadataVersion);\n const installedRecord = preserveConcurrentLiveMetadata\n ? mergeConcurrentMetadataRecord(liveRecord, candidateRecord)\n : candidateRecord;\n\n if (preserveConcurrentLiveMetadata) {\n importUpdates(target.doc, [exportAllUpdates(candidate.doc)]);\n const metadata = readContainerMetadataValue(\n target.doc,\n getDefaultContainerName(candidate.container.parentId),\n );\n target.container = {\n ...candidate.container,\n icon: metadata.icon,\n name: metadata.name,\n };\n } else {\n target.container = candidate.container;\n target.doc = candidate.doc;\n }\n // A hint invalidated the live projections while this candidate was out;\n // its copy may cite a pre-hint manifest, so the live slot stays as the hint\n // left it and the next metadata write fetches a fresh projection.\n if (\n projectionGeneration(target) ===\n candidate.detachedSource.writerProjectionGeneration\n )\n target.metadataWriterProjection = candidate.metadataWriterProjection;\n target.pullContinuation = preserveConcurrentLiveMetadata\n ? metadataSyncSecurityContextMatches(liveRecord, candidateRecord)\n ? livePullContinuation\n : (candidateRecord.pullContinuation ?? null)\n : (candidateRecord.pullContinuation ?? null);\n target.record = installedRecord;\n target.rekeyOnlyPassCount = candidate.rekeyOnlyPassCount;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { base64ToBytes } from "../../../internal/encoding/index.js";
|
|
2
2
|
import { importUpdates } from "../../../internal/loro/index.js";
|
|
3
|
-
import { createContainerMetadataDocument } from "
|
|
3
|
+
import { createContainerMetadataDocument } from "./containerMetadataDocument.js";
|
|
4
4
|
export function sameNullableMetadataValue(left, right) {
|
|
5
5
|
return (left ?? null) === (right ?? null);
|
|
6
6
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadataSyncSettlement.js","sourceRoot":"","sources":["metadataSyncSettlement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"metadataSyncSettlement.js","sourceRoot":"","sources":["metadataSyncSettlement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAQ9E,MAAM,UAAU,yBAAyB,CACvC,IAA+B,EAC/B,KAAgC;IAEhC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,kCAAkC,CAChD,OAA8B,EAC9B,QAAwB;IAExB,OAAO,CACL,OAAO,KAAK,IAAI;QAChB,OAAO,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE;QAC1B,OAAO,CAAC,UAAU,KAAK,QAAQ,CAAC,UAAU;QAC1C,OAAO,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW;QAC5C,yBAAyB,CACvB,OAAO,CAAC,eAAe,EACvB,QAAQ,CAAC,eAAe,CACzB;QACD,yBAAyB,CACvB,OAAO,CAAC,gBAAgB,EACxB,QAAQ,CAAC,gBAAgB,CAC1B;QACD,yBAAyB,CACvB,OAAO,CAAC,kBAAkB,EAC1B,QAAQ,CAAC,kBAAkB,CAC5B;QACD,yBAAyB,CACvB,OAAO,CAAC,sBAAsB,EAC9B,QAAQ,CAAC,sBAAsB,CAChC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CAAC,KAGvD;IACC,MAAM,cAAc,GAAG,MAAM,+BAA+B,CAC1D,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CACjC,CAAC;IACF,IAAI,KAAK,CAAC,aAAa,EAAE,eAAe,EAAE,CAAC;QACzC,aAAa,CAAC,cAAc,EAAE;YAC5B,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,eAAe,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,aAAa,CAAC,GAAG,GAAG,cAAc,CAAC;IACzC,KAAK,CAAC,aAAa,CAAC,wBAAwB,GAAG,IAAI,CAAC;AACtD,CAAC","sourcesContent":["import { base64ToBytes } from \"@tearleads/encoding\";\nimport { importUpdates } from \"@tearleads/loro\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { ContainerDocumentRecord as DocumentRecord } from \"../containerPersistence\";\nimport { createContainerMetadataDocument } from \"./containerMetadataDocument\";\nimport type { ContainerMetadataState } from \"./metadataTypes\";\n\nexport interface ExpectedContainerMetadataSyncState {\n pullContinuation: DocumentSyncPullContinuation | null;\n record: DocumentRecord;\n}\n\nexport function sameNullableMetadataValue(\n left: string | null | undefined,\n right: string | null | undefined,\n): boolean {\n return (left ?? null) === (right ?? null);\n}\n\nexport function metadataSyncSecurityContextMatches(\n current: DocumentRecord | null,\n expected: DocumentRecord,\n): boolean {\n return (\n current !== null &&\n current.id === expected.id &&\n current.documentId === expected.documentId &&\n current.accessEpoch === expected.accessEpoch &&\n sameNullableMetadataValue(\n current.accessStateHash,\n expected.accessStateHash,\n ) &&\n sameNullableMetadataValue(\n current.contentKeyBundle,\n expected.contentKeyBundle,\n ) &&\n sameNullableMetadataValue(\n current.documentKekTargets,\n expected.documentKekTargets,\n ) &&\n sameNullableMetadataValue(\n current.documentManifestBundle,\n expected.documentManifestBundle,\n )\n );\n}\n\nexport async function replaceSupersededMetadataIdentity(input: {\n durableRecord: DocumentRecord | null;\n metadataState: ContainerMetadataState;\n}): Promise<void> {\n const replacementDoc = await createContainerMetadataDocument(\n input.metadataState.container.id,\n );\n if (input.durableRecord?.metadataUpdates) {\n importUpdates(replacementDoc, [\n base64ToBytes(input.durableRecord.metadataUpdates),\n ]);\n }\n input.metadataState.doc = replacementDoc;\n input.metadataState.metadataWriterProjection = null;\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DocumentWriterProjectionResponse } from "../../../internal/validators/response/index.js";
|
|
2
|
-
import type { ContainerMetadataDocument } from "../../../data/containers/containerMetadataDocument.js";
|
|
3
2
|
import type { DocumentSyncPullContinuation } from "../../../data/documents/shared/sync/syncPagination.js";
|
|
4
3
|
import type { ContainerMetadataRecord } from "../../../data/persistence/container-contents/containerContentsPersistence.js";
|
|
5
|
-
import type { ContainerRecord } from "../../../data/persistence/
|
|
4
|
+
import type { ContainerRecord } from "../../../data/persistence/container-contents/containerPersistence.js";
|
|
5
|
+
import type { ContainerMetadataDocument } from "./containerMetadataDocument.js";
|
|
6
6
|
export interface ContainerMetadataState {
|
|
7
7
|
container: ContainerRecord;
|
|
8
8
|
doc: ContainerMetadataDocument;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadataTypes.js","sourceRoot":"","sources":["metadataTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type {
|
|
1
|
+
{"version":3,"file":"metadataTypes.js","sourceRoot":"","sources":["metadataTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { ContainerMetadataRecord } from \"../../../data/persistence/container-contents/containerContentsPersistence\";\nimport type { ContainerRecord } from \"../../../data/persistence/container-contents/containerPersistence\";\nimport type { ContainerMetadataDocument } from \"./containerMetadataDocument\";\n\nexport interface ContainerMetadataState {\n container: ContainerRecord;\n doc: ContainerMetadataDocument;\n metadataWriterProjection?:\n | DocumentWriterProjectionResponse\n | null\n | undefined;\n /** See `ContainerState.writerProjectionGeneration`; shared by both caches. */\n writerProjectionGeneration?: number | undefined;\n /** Durable continuation mirrored from the metadata document record. */\n pullContinuation?: DocumentSyncPullContinuation | null | undefined;\n record: ContainerMetadataRecord;\n /**\n * Consecutive completed sync passes that re-keyed conflicted pending updates\n * without settling anything; bounds the rekey-driven follow-up sync. See\n * shouldReArmAfterOutgoingSettlement.\n */\n rekeyOnlyPassCount?: number | undefined;\n}\n\nexport interface ContainerMetadataPatch {\n accessEpoch: number;\n accessStateHash: string | null;\n effectiveAccessLevel: ContainerRecord[\"effectiveAccessLevel\"];\n documentId: string | null;\n icon: string | null;\n lastCommitLsn: string | null;\n metadataDocumentId: string | null;\n systemSlot: ContainerRecord[\"systemSlot\"];\n metadataUpdates: string;\n name: string;\n organizationId: string;\n parentId: string | null;\n pullContinuation: DocumentSyncPullContinuation | null;\n contentKeyBundle: string | null;\n documentKekTargets: string | null;\n documentManifestBundle: string | null;\n}\n\nexport interface PersistedContainerMetadataState {\n container: ContainerRecord;\n createIntentSettled?: true;\n moveIntentSettled?: true;\n mutationSuperseded?: true;\n pullContinuationSuperseded?: true;\n record: ContainerMetadataRecord;\n syncIdentitySuperseded?: true;\n}\n\nexport interface SyncedContainerMetadataState\n extends PersistedContainerMetadataState {\n shouldRequestFollowupSync: boolean;\n}\n\nexport interface MissingContainerMetadataState {\n missing: true;\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { base64ToBytes } from "../../../internal/encoding/index.js";
|
|
2
2
|
import { importUpdates } from "../../../internal/loro/index.js";
|
|
3
|
-
import { createContainerMetadataDocument, readContainerMetadataValue, } from "../../../data/containers/containerMetadataDocument.js";
|
|
4
3
|
import { discardRetainedContainerMetadata, listRecoveryFolderMoveIds, listRetainedContainerMetadata, } from "../../../data/persistence/container-contents/containerRecoveryPersistence.js";
|
|
4
|
+
import { createContainerMetadataDocument, readContainerMetadataValue, } from "../metadata/containerMetadataDocument.js";
|
|
5
5
|
export function createFolderRecoveryQueries(execSql) {
|
|
6
6
|
return {
|
|
7
7
|
listRecoveryFolderMoveIds(input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folderRecovery.js","sourceRoot":"","sources":["folderRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL
|
|
1
|
+
{"version":3,"file":"folderRecovery.js","sourceRoot":"","sources":["folderRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,2EAA2E,CAAC;AAEnF,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,uCAAuC,CAAC;AAY/C,MAAM,UAAU,2BAA2B,CAAC,OAAgB;IAC1D,OAAO;QACL,yBAAyB,CAAC,KAEzB;YACC,OAAO,yBAAyB,CAAC,OAAO,EAAE,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACzE,CAAC;QACD,KAAK,CAAC,mBAAmB,CAAC,KAEzB;YACC,MAAM,OAAO,GAAG,MAAM,6BAA6B,CACjD,OAAO,EACP,KAAK,CAAC,qBAAqB,CAC5B,CAAC;YACF,OAAO,OAAO,CAAC,GAAG,CAChB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE;gBACnD,MAAM,GAAG,GAAG,MAAM,+BAA+B,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBACtE,IAAI,CAAC;oBACH,IAAI,eAAe;wBACjB,aAAa,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;oBACvD,OAAO;wBACL,GAAG,MAAM;wBACT,GAAG,0BAA0B,CAAC,GAAG,EAAE,iBAAiB,CAAC;qBACtD,CAAC;gBACJ,CAAC;wBAAS,CAAC;oBACT,GAAG,CAAC,IAAI,EAAE,CAAC;gBACb,CAAC;YACH,CAAC,CAAC,CACH,CAAC;QACJ,CAAC;QACD,qBAAqB,CACnB,KAGC;YAED,OAAO,gCAAgC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { base64ToBytes } from \"@tearleads/encoding\";\nimport { importUpdates } from \"@tearleads/loro\";\nimport {\n discardRetainedContainerMetadata,\n listRecoveryFolderMoveIds,\n listRetainedContainerMetadata,\n} from \"../../../data/persistence/container-contents/containerRecoveryPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport {\n createContainerMetadataDocument,\n readContainerMetadataValue,\n} from \"../metadata/containerMetadataDocument\";\n\nexport interface RecoveryFolder {\n containerId: string;\n organizationId: string;\n name: string;\n icon: string | null;\n pendingUpdateCount: number;\n hasStructuralIntent: boolean;\n revision: string;\n}\n\nexport function createFolderRecoveryQueries(execSql: ExecSql) {\n return {\n listRecoveryFolderMoveIds(input: {\n currentOrganizationId: string | null;\n }): Promise<string[]> {\n return listRecoveryFolderMoveIds(execSql, input.currentOrganizationId);\n },\n async listRecoveryFolders(input: {\n currentOrganizationId: string | null;\n }): Promise<RecoveryFolder[]> {\n const records = await listRetainedContainerMetadata(\n execSql,\n input.currentOrganizationId,\n );\n return Promise.all(\n records.map(async ({ metadataUpdates, ...record }) => {\n const doc = await createContainerMetadataDocument(record.containerId);\n try {\n if (metadataUpdates)\n importUpdates(doc, [base64ToBytes(metadataUpdates)]);\n return {\n ...record,\n ...readContainerMetadataValue(doc, \"Untitled folder\"),\n };\n } finally {\n doc.free();\n }\n }),\n );\n },\n discardRecoveryFolder(\n input: Pick<\n RecoveryFolder,\n \"containerId\" | \"organizationId\" | \"revision\"\n >,\n ): Promise<boolean> {\n return discardRetainedContainerMetadata(execSql, input);\n },\n };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { KeyingVerificationError, verifyOrganizationReplacementAuthorization, } from "../../../../internal/crypto/index.js";
|
|
2
|
-
import { assertHeldContainerBinding, } from "../../../../data/containers/containerBinding.js";
|
|
3
2
|
import { ProjectionDependencyUnavailableError } from "../../../../data/keyingProjectionVerification/dependencyUnavailable.js";
|
|
3
|
+
import { assertHeldContainerBinding, } from "../../../../data/persistence/container-contents/containerBinding.js";
|
|
4
4
|
import { persistOrganizationReplacementCheckpoints } from "../../../../data/persistence/keyingCheckpoints/organizationReplacementCheckpointPersistence.js";
|
|
5
5
|
import { loadOrganizationFounder } from "../../../../data/persistence/organizationFounderPersistence.js";
|
|
6
6
|
async function acceptsSharedReplacement(input, oldOrganizationId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replacementBinding.js","sourceRoot":"","sources":["replacementBinding.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,0CAA0C,GAC3C,MAAM,mBAAmB,CAAC;AAC3B,OAAO,
|
|
1
|
+
{"version":3,"file":"replacementBinding.js","sourceRoot":"","sources":["replacementBinding.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n verifyOrganizationReplacementAuthorization,\n} from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport {\n assertHeldContainerBinding,\n type HeldContainerBinding,\n} from \"../../../../data/persistence/container-contents/containerBinding\";\nimport { persistOrganizationReplacementCheckpoints } from \"../../../../data/persistence/keyingCheckpoints/organizationReplacementCheckpointPersistence\";\nimport { loadOrganizationFounder } from \"../../../../data/persistence/organizationFounderPersistence\";\nimport type { RemoteContainer, RemoteContainerHydrationState } from \"../types\";\nimport type { DestinationRole } from \"./destinationRoleCache\";\n\nexport interface BindingInput {\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly heldBinding: HeldContainerBinding | null;\n readonly listed: Pick<RemoteContainer, \"id\" | \"organizationId\">;\n readonly role: DestinationRole;\n readonly runtime: RemoteContainerHydrationState[\"runtime\"];\n}\n\nasync function acceptsSharedReplacement(\n input: BindingInput,\n oldOrganizationId: string,\n): Promise<boolean> {\n const { listed, role, runtime } = input;\n const founder = await loadOrganizationFounder(\n runtime.infra.execSql,\n oldOrganizationId,\n );\n if (!founder || role.createSignerUserId !== founder.userId) return false;\n const identity = await runtime.resolveTrustedUserIdentity(founder.userId);\n if (!identity)\n throw new ProjectionDependencyUnavailableError(\n \"Replacement founder identity is unavailable\",\n );\n if (identity.signingKeyFingerprint !== founder.signingKeyFingerprint)\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"Replacement founder differs from the held organization's pinned identity\",\n );\n const response =\n await runtime.apiClient.getContainerReplacementAuthorizationsResult(\n listed.id,\n oldOrganizationId,\n );\n if (!response.ok) {\n if (response.status === 404) return false;\n throw new ProjectionDependencyUnavailableError(response.message);\n }\n const last = verifyReplacementLineage(\n response.data.authorizations,\n oldOrganizationId,\n founder.userId,\n identity.signingPublicKey,\n );\n const replacementFounder = await loadOrganizationFounder(\n runtime.infra.execSql,\n listed.organizationId,\n );\n if (\n last?.organizationId !== listed.organizationId ||\n replacementFounder?.userId !== founder.userId ||\n replacementFounder.signingKeyFingerprint !==\n founder.signingKeyFingerprint ||\n replacementFounder.genesisStateHash !== last.organizationStateHash ||\n role.rootContainerId !== last.rootContainerId ||\n role.rootCreateManifestHash !== last.rootManifestHash ||\n role.rootMetadataDocumentId !== last.rootMetadataDocumentId\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Replacement authorization does not bind the destination genesis\",\n );\n // The founder also commits the reserved groups' genesis. Pin those even\n // when the readable folder's projection does not cite both groups yet.\n await persistOrganizationReplacementCheckpoints({\n authorization: last,\n execSql: runtime.infra.execSql,\n stillCurrent: input.stillCurrent,\n });\n return true;\n}\n\nfunction verifyReplacementLineage(\n authorizations: readonly unknown[],\n oldOrganizationId: string,\n userId: string,\n signingPublicKey: Uint8Array,\n) {\n let expected = oldOrganizationId;\n const visited = new Set([expected]);\n let last:\n | ReturnType<typeof verifyOrganizationReplacementAuthorization>\n | undefined;\n for (const candidate of authorizations) {\n const proof = verifyOrganizationReplacementAuthorization(\n candidate,\n signingPublicKey,\n );\n if (\n proof.replacesOrganizationId !== expected ||\n proof.userId !== userId ||\n visited.has(proof.organizationId)\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Replacement authorization lineage does not extend the held organization\",\n );\n expected = proof.organizationId;\n visited.add(expected);\n last = proof;\n }\n return last;\n}\n\n/** A foreign creator needs the held organization's pinned founder to authorize rehome. */\nexport async function assertPermittedDestinationBinding(\n input: BindingInput,\n): Promise<void> {\n const { heldBinding: held, listed, role, runtime } = input;\n if (role.createSignerUserId === runtime.auth.userId) return;\n if (held?.metadataDocumentId === null)\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"a local folder can bind only to its own signed create\",\n );\n if (\n held?.organizationId &&\n held.organizationId !== listed.organizationId &&\n role.systemSlot === null &&\n (await acceptsSharedReplacement(input, held.organizationId))\n )\n return;\n assertHeldContainerBinding(held, {\n organizationId: listed.organizationId,\n metadataDocumentIds: [role.metadataDocumentId],\n });\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { KeyingVerificationError, } from "../../../../internal/crypto/index.js";
|
|
2
2
|
import { deriveOrganizationMetadataContainerSystemSlot } from "../../../../internal/validators/containerSystemSlot.js";
|
|
3
|
-
import { listingRepeatsHeldOrdinaryBinding, } from "../../../../data/containers/containerBinding.js";
|
|
4
3
|
import { verifiedContainerCreateManifest } from "../../../../data/keyingProjectionVerification/container/containerCreateManifest.js";
|
|
5
4
|
import { verifyContainerDestinationProjection } from "../../../../data/keyingProjectionVerification/container/containerDestinationVerification.js";
|
|
6
5
|
import { verifyContainerWriterProjection } from "../../../../data/keyingProjectionVerification/container/containerProjectionVerification.js";
|
|
7
6
|
import { isKeyingVerificationError, reportKeyingVerificationErrorInCauseChain, runWithSecurityIncidentReporting, } from "../../../../data/keyingProjectionVerification/error.js";
|
|
7
|
+
import { listingRepeatsHeldOrdinaryBinding, } from "../../../../data/persistence/container-contents/containerBinding.js";
|
|
8
8
|
import { verifyRuntimeGroupMetadataAuthority } from "../../../organizations/groupMetadata/runtimeGroupMetadataAuthority.js";
|
|
9
9
|
import { createRuntimePrincipalPolicyWarmer } from "../../../principals/runtimePolicyWarmer.js";
|
|
10
10
|
import { cachedDestinationRole, rememberDestinationRole, } from "./destinationRoleCache.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifiedDestination.js","sourceRoot":"","sources":["verifiedDestination.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AccessManifestCheckpoint,\n KeyingVerificationError,\n type VerifiedContainerAccessManifest,\n} from \"@tearleads/crypto\";\nimport { deriveOrganizationMetadataContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport {\n type HeldContainerBinding,\n listingRepeatsHeldOrdinaryBinding,\n} from \"../../../../data/containers/containerBinding\";\nimport { verifiedContainerCreateManifest } from \"../../../../data/keyingProjectionVerification/container/containerCreateManifest\";\nimport { verifyContainerDestinationProjection } from \"../../../../data/keyingProjectionVerification/container/containerDestinationVerification\";\nimport { verifyContainerWriterProjection } from \"../../../../data/keyingProjectionVerification/container/containerProjectionVerification\";\nimport {\n isKeyingVerificationError,\n reportKeyingVerificationErrorInCauseChain,\n runWithSecurityIncidentReporting,\n} from \"../../../../data/keyingProjectionVerification/error\";\nimport { verifyRuntimeGroupMetadataAuthority } from \"../../../organizations/groupMetadata/runtimeGroupMetadataAuthority\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../../principals/runtimePolicyWarmer\";\nimport type {\n ContainerState,\n RemoteContainer,\n RemoteContainerHydrationState,\n} from \"../types\";\nimport type { PrefetchedDestinationProjection } from \"./destinationPrefetch\";\nimport {\n cachedDestinationRole,\n type DestinationRole,\n rememberDestinationRole,\n} from \"./destinationRoleCache\";\nimport { resolveWithMetadataRootReload } from \"./destinationRootReload\";\nimport { assertPermittedDestinationBinding } from \"./replacementBinding\";\n\n/** The identity a role is verified and cached under. */\ntype DestinationIdentity = Pick<RemoteContainer, \"id\" | \"organizationId\">;\n\nasync function destinationRoleFromPath(input: {\n listed: DestinationIdentity;\n path: readonly VerifiedContainerAccessManifest[];\n verifiedByHash: ReadonlyMap<string, VerifiedContainerAccessManifest>;\n}): Promise<{ role: DestinationRole; parentId: string | null }> {\n const { listed, path } = input;\n const head = path.at(-1);\n if (\n !head ||\n head.state.containerId !== listed.id ||\n head.state.organizationId !== listed.organizationId\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container destination manifest has the wrong identity\",\n );\n }\n const metadataSlot = await deriveOrganizationMetadataContainerSystemSlot({\n organizationId: listed.organizationId,\n });\n if (\n head.state.systemSlot !== null &&\n path.length !== (head.state.systemSlot === metadataSlot ? 1 : 2)\n ) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"system destination has the wrong signed topology\",\n );\n }\n // The head may be a later grant signed by any admin; only the epoch-1\n // create names the creator, and roots are always created by the org owner.\n const created = verifiedContainerCreateManifest({\n head,\n label: \"Container destination\",\n verifiedByHash: input.verifiedByHash,\n });\n const root = path[0];\n if (!root) throw new Error(\"Destination root is unavailable\");\n const rootCreated = verifiedContainerCreateManifest({\n head: root,\n label: \"Destination root\",\n verifiedByHash: input.verifiedByHash,\n });\n return {\n parentId: head.state.parentContainerId,\n role: {\n createSignerUserId: created.event.event.signerUserId,\n rootContainerId: rootCreated.state.containerId,\n rootCreateManifestHash: rootCreated.manifestHash,\n rootMetadataDocumentId: rootCreated.state.metadataDocumentId,\n metadataDocumentId: head.state.metadataDocumentId,\n ...(head.state.parentContainerId === null ||\n head.state.systemSlot !== null\n ? { parentId: head.state.parentContainerId }\n : {}),\n systemSlot: head.state.systemSlot,\n },\n };\n}\n\n/**\n * The session's root id arrives in an unsigned login response, so the root it\n * names must prove it belongs to this user: every acknowledged organization was\n * created by the session user, whose device signed the root's `container.create`.\n * A verified root created by anyone else is a substitution, never the merge\n * target for pre-login local content, whatever grants it carries. The check\n * runs on cache reuse too, since the cache is not scoped to the session user.\n */\nfunction assertRootCreatedBySessionUser(\n role: DestinationRole,\n runtime: RemoteContainerHydrationState[\"runtime\"],\n): void {\n if (role.systemSlot !== null) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"acknowledged session root cannot be a system container\",\n );\n }\n if (role.createSignerUserId !== runtime.auth.userId) {\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"acknowledged session root was not created by the session user\",\n );\n }\n}\n\nfunction assertAcknowledgedRootSigner(input: {\n listed: DestinationIdentity;\n role: DestinationRole;\n runtime: RemoteContainerHydrationState[\"runtime\"];\n}): void {\n const { listed, role, runtime } = input;\n if (role.parentId !== null || listed.id !== runtime.auth.rootContainerId) {\n return;\n }\n assertRootCreatedBySessionUser(role, runtime);\n}\n\n/**\n * Authenticate destination roles before admitting a binding or advancing any\n * placement pin. Shared rehomes additionally require signed replacement evidence.\n */\nasync function verifyDestinationRole(input: {\n heldBinding: HeldContainerBinding | null;\n prefetched: PrefetchedDestinationProjection | undefined;\n verifyCurrentPlacement: boolean;\n onVerifiedCheckpoint:\n | ((checkpoint: AccessManifestCheckpoint) => void)\n | undefined;\n isCurrent?: (() => boolean) | undefined;\n listed: DestinationIdentity;\n runtime: RemoteContainerHydrationState[\"runtime\"];\n}): Promise<{ role: DestinationRole; parentId: string | null } | null> {\n const { isCurrent, listed, runtime } = input;\n const projection = input.prefetched\n ? input.prefetched.projection\n : await runtime.apiClient.getContainerWriterProjection(listed.id);\n if (!projection || isCurrent?.() === false) return null;\n if (\n projection.containerId !== listed.id ||\n projection.organizationId !== listed.organizationId\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container destination projection has the wrong identity\",\n );\n }\n const verificationInput = {\n execSql: runtime.infra.execSql,\n projection,\n resolveUserKey: runtime.resolveTrustedUserIdentity,\n stillCurrent: isCurrent,\n warmReferencedPrincipalPolicies:\n createRuntimePrincipalPolicyWarmer(runtime),\n };\n const { path, verifiedByHash } =\n await verifyContainerDestinationProjection(verificationInput);\n if (isCurrent?.() === false) return null;\n const destination = await destinationRoleFromPath({\n listed,\n path,\n verifiedByHash,\n });\n const { role } = destination;\n // Refuse a rebinding before group checks or placement pins run for it.\n await assertPermittedDestinationBinding({\n stillCurrent: isCurrent,\n heldBinding: input.heldBinding,\n listed,\n role,\n runtime,\n });\n if (isCurrent?.() === false) return null;\n if (role.parentId === null && role.systemSlot !== null) {\n const head = path.at(-1);\n if (!head) throw new Error(\"Metadata root manifest is unavailable\");\n await verifyRuntimeGroupMetadataAuthority({\n runtime,\n organizationId: listed.organizationId,\n organizationReference: projection.policyEvidence.organization?.head,\n state: head.state,\n stillCurrent: isCurrent ?? (() => true),\n });\n }\n if (isCurrent?.() === false) return null;\n if (input.verifyCurrentPlacement) {\n // Check the immutable role before allowing current placement to advance pins.\n assertAcknowledgedRootSigner({ listed, role, runtime });\n const currentPath = await verifyContainerWriterProjection({\n ...verificationInput,\n stillCurrent: isCurrent,\n });\n const currentHead = currentPath.at(-1);\n if (!currentHead)\n throw new Error(\"Recovery placement manifest is unavailable\");\n input.onVerifiedCheckpoint?.(currentHead.checkpoint);\n }\n if (isCurrent?.() === false) return null;\n return destination;\n}\n\ntype VerifyRemoteContainerDestinationInput = {\n heldBinding: HeldContainerBinding | null;\n /** The held folder was re-homed away from the listed organization. */\n supersededListing?: boolean | undefined;\n /** Fetched ahead by page hydration; ignored when placement is refreshed. */\n prefetchedProjection?: PrefetchedDestinationProjection | undefined;\n refresh?: boolean;\n onVerifiedCheckpoint?:\n | ((checkpoint: AccessManifestCheckpoint) => void)\n | undefined;\n remoteContainer: RemoteContainer;\n state: RemoteContainerHydrationState;\n isCurrent?: (() => boolean) | undefined;\n};\n\n/** A cached immutable role, or a freshly verified one with its signed parent. */\nasync function resolveDestinationRole(\n input: VerifyRemoteContainerDestinationInput,\n): Promise<{\n freshlyVerified: boolean;\n parentId: string | null | undefined;\n role: DestinationRole;\n} | null> {\n const { remoteContainer: listed, isCurrent } = input;\n const runtime = input.state.runtime;\n const cached = input.refresh\n ? undefined\n : cachedDestinationRole(runtime.infra.execSql, listed);\n // Ordinary parent edges are not immutable. A refresh authenticates current\n // placement; a forged root hint must also be corrected from a signed path.\n if (cached && !(cached.parentId === undefined && listed.parentId === null)) {\n return { freshlyVerified: false, parentId: cached.parentId, role: cached };\n }\n const verified = await verifyDestinationRole({\n heldBinding: input.heldBinding,\n prefetched: input.refresh ? undefined : input.prefetchedProjection,\n isCurrent,\n listed,\n runtime,\n verifyCurrentPlacement: input.refresh === true,\n onVerifiedCheckpoint: input.onVerifiedCheckpoint,\n });\n if (!verified) return null;\n return {\n freshlyVerified: true,\n parentId:\n input.refresh || listed.parentId === null\n ? verified.parentId\n : verified.role.parentId,\n role: verified.role,\n };\n}\n\n/**\n * Listing hints never establish a metadata target or a system/root role, and a\n * held folder keeps its organization and metadata target unless its own user\n * re-created it or its pinned founder authorized a verified replacement.\n * A conflicting proof is refused before placement pins\n * advance or its role is cached.\n */\nexport async function verifyRemoteContainerDestination(\n input: VerifyRemoteContainerDestinationInput,\n): Promise<RemoteContainer | null> {\n const { remoteContainer: listed, state, isCurrent } = input;\n const runtime = state.runtime;\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: listed.id,\n objectKind: \"container\",\n operation: \"container.destination.verify\",\n organizationId: listed.organizationId,\n },\n async () => {\n if (input.supersededListing) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container was re-homed away from the listed organization\",\n );\n }\n // A held ordinary binding was verified (or signed by this device) when\n // it was stored; a listing that repeats it needs no second proof.\n if (\n !input.refresh &&\n listingRepeatsHeldOrdinaryBinding(input.heldBinding, listed)\n ) {\n return { ...listed, systemSlot: null };\n }\n if (input.refresh)\n runtime.apiClient.evictContainerWriterProjection(listed.id);\n // A metadata root read before a reserved-group commit is reloaded once.\n const resolved = await resolveWithMetadataRootReload(\n input,\n resolveDestinationRole,\n () => runtime.apiClient.evictContainerWriterProjection(listed.id),\n ).catch((error: unknown) => {\n // Never re-serve a cached projection that failed verification.\n if (isKeyingVerificationError(error))\n runtime.apiClient.evictContainerWriterProjection(listed.id);\n throw error;\n });\n if (!resolved || isCurrent?.() === false) return null;\n const { role, parentId } = resolved;\n // Fresh verification checked this binding before any placement pins.\n // A cached role still needs the held binding and replacement proof checked.\n if (!resolved.freshlyVerified)\n await assertPermittedDestinationBinding({\n stillCurrent: isCurrent,\n heldBinding: input.heldBinding,\n listed,\n role,\n runtime,\n });\n if (isCurrent?.() === false) return null;\n if (resolved.freshlyVerified)\n rememberDestinationRole(runtime.infra.execSql, listed, role);\n assertAcknowledgedRootSigner({ listed, role, runtime });\n return {\n ...listed,\n metadataDocumentId: role.metadataDocumentId,\n parentId: parentId === undefined ? listed.parentId : parentId,\n systemSlot: role.systemSlot,\n };\n },\n );\n}\n\n/** The root the unsigned login answer named, in the expected organization. */\nexport function isSessionRootState(\n remoteRootState: ContainerState,\n state: RemoteContainerHydrationState,\n): boolean {\n const { container } = remoteRootState;\n const { auth } = state.runtime;\n return (\n container.parentId === null &&\n !container.systemSlot &&\n container.id === auth.rootContainerId &&\n container.organizationId === auth.organizationId\n );\n}\n\n/**\n * Whether the session root may absorb the pre-login local roots. The unsigned\n * login answer only names the root; the merge target must also be the verified\n * root whose epoch-1 `container.create` the session user signed. A row persisted\n * earlier as an ordinary shared container (another user's root this device once\n * hydrated) never passed that check for this session, so the creator is checked\n * here, at the reconciliation boundary itself, before any local content is\n * re-parented. The role comes only from the cache remote hydration fills when\n * it verifies the destination: this gate never fetches, so a local refresh stays\n * independent of the network. Without a cached role the merge is left pending\n * (no incident) until hydration verifies the root and reconciles from the\n * cache. A different creator is a `signer_mismatch` incident and never a merge;\n * the refusal is the \"no merge\" outcome, so the refresh that carried it\n * completes with the local content left in place.\n */\nexport async function isVerifiedLocalRootReconciliationTarget(input: {\n remoteRootState: ContainerState;\n state: RemoteContainerHydrationState;\n}): Promise<boolean> {\n const { remoteRootState, state } = input;\n const { container } = remoteRootState;\n const runtime = state.runtime;\n if (!isSessionRootState(remoteRootState, state)) return false;\n const role = cachedDestinationRole(runtime.infra.execSql, container);\n if (!role) return false;\n try {\n if (role.parentId !== null) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"session root reconciliation target is not a verified root\",\n );\n }\n assertRootCreatedBySessionUser(role, runtime);\n return true;\n } catch (error) {\n const reported = await reportKeyingVerificationErrorInCauseChain(\n error,\n runtime.util.reportSecurityIncident,\n {\n objectId: container.id,\n objectKind: \"container\",\n operation: \"container.root.reconcile\",\n organizationId: container.organizationId,\n },\n );\n if (!reported) throw error;\n return false;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"verifiedDestination.js","sourceRoot":"","sources":["verifiedDestination.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,uBAAuB,GAExB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6CAA6C,EAAE,MAAM,2CAA2C,CAAC;AAC1G,OAAO,EAAE,+BAA+B,EAAE,MAAM,iFAAiF,CAAC;AAClI,OAAO,EAAE,oCAAoC,EAAE,MAAM,0FAA0F,CAAC;AAChJ,OAAO,EAAE,+BAA+B,EAAE,MAAM,yFAAyF,CAAC;AAC1I,OAAO,EACL,yBAAyB,EACzB,yCAAyC,EACzC,gCAAgC,GACjC,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAEL,iCAAiC,GAClC,MAAM,kEAAkE,CAAC;AAC1E,OAAO,EAAE,mCAAmC,EAAE,MAAM,oEAAoE,CAAC;AACzH,OAAO,EAAE,kCAAkC,EAAE,MAAM,yCAAyC,CAAC;AAO7F,OAAO,EACL,qBAAqB,EAErB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,iCAAiC,EAAE,MAAM,sBAAsB,CAAC;AAKzE,KAAK,UAAU,uBAAuB,CAAC,KAItC;IACC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzB,IACE,CAAC,IAAI;QACL,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC,EAAE;QACpC,IAAI,CAAC,KAAK,CAAC,cAAc,KAAK,MAAM,CAAC,cAAc,EACnD,CAAC;QACD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,uDAAuD,CACxD,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG,MAAM,6CAA6C,CAAC;QACvE,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC,CAAC;IACH,IACE,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI;QAC9B,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAChE,CAAC;QACD,MAAM,IAAI,uBAAuB,CAC/B,eAAe,EACf,kDAAkD,CACnD,CAAC;IACJ,CAAC;IACD,sEAAsE;IACtE,2EAA2E;IAC3E,MAAM,OAAO,GAAG,+BAA+B,CAAC;QAC9C,IAAI;QACJ,KAAK,EAAE,uBAAuB;QAC9B,cAAc,EAAE,KAAK,CAAC,cAAc;KACrC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAG,+BAA+B,CAAC;QAClD,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,kBAAkB;QACzB,cAAc,EAAE,KAAK,CAAC,cAAc;KACrC,CAAC,CAAC;IACH,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB;QACtC,IAAI,EAAE;YACJ,kBAAkB,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;YACpD,eAAe,EAAE,WAAW,CAAC,KAAK,CAAC,WAAW;YAC9C,sBAAsB,EAAE,WAAW,CAAC,YAAY;YAChD,sBAAsB,EAAE,WAAW,CAAC,KAAK,CAAC,kBAAkB;YAC5D,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,kBAAkB;YACjD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,KAAK,IAAI;gBACzC,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI;gBAC5B,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE;gBAC5C,CAAC,CAAC,EAAE,CAAC;YACP,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;SAClC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,8BAA8B,CACrC,IAAqB,EACrB,OAAiD;IAEjD,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACpD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,+DAA+D,CAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,4BAA4B,CAAC,KAIrC;IACC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IACxC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzE,OAAO;IACT,CAAC;IACD,8BAA8B,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,qBAAqB,CAAC,KAUpC;IACC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU;QACjC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU;QAC7B,CAAC,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,4BAA4B,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACxD,IACE,UAAU,CAAC,WAAW,KAAK,MAAM,CAAC,EAAE;QACpC,UAAU,CAAC,cAAc,KAAK,MAAM,CAAC,cAAc,EACnD,CAAC;QACD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IACD,MAAM,iBAAiB,GAAG;QACxB,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO;QAC9B,UAAU;QACV,cAAc,EAAE,OAAO,CAAC,0BAA0B;QAClD,YAAY,EAAE,SAAS;QACvB,+BAA+B,EAC7B,kCAAkC,CAAC,OAAO,CAAC;KAC9C,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAC5B,MAAM,oCAAoC,CAAC,iBAAiB,CAAC,CAAC;IAChE,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,WAAW,GAAG,MAAM,uBAAuB,CAAC;QAChD,MAAM;QACN,IAAI;QACJ,cAAc;KACf,CAAC,CAAC;IACH,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC;IAC7B,uEAAuE;IACvE,MAAM,iCAAiC,CAAC;QACtC,YAAY,EAAE,SAAS;QACvB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM;QACN,IAAI;QACJ,OAAO;KACR,CAAC,CAAC;IACH,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACpE,MAAM,mCAAmC,CAAC;YACxC,OAAO;YACP,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,qBAAqB,EAAE,UAAU,CAAC,cAAc,CAAC,YAAY,EAAE,IAAI;YACnE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,YAAY,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;SACxC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,KAAK,CAAC,sBAAsB,EAAE,CAAC;QACjC,8EAA8E;QAC9E,4BAA4B,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,MAAM,+BAA+B,CAAC;YACxD,GAAG,iBAAiB;YACpB,YAAY,EAAE,SAAS;SACxB,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,WAAW;YACd,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,KAAK,CAAC,oBAAoB,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,WAAW,CAAC;AACrB,CAAC;AAiBD,iFAAiF;AACjF,KAAK,UAAU,sBAAsB,CACnC,KAA4C;IAM5C,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;IACpC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO;QAC1B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACzD,2EAA2E;IAC3E,2EAA2E;IAC3E,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3E,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC7E,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC;QAC3C,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB;QAClE,SAAS;QACT,MAAM;QACN,OAAO;QACP,sBAAsB,EAAE,KAAK,CAAC,OAAO,KAAK,IAAI;QAC9C,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;KACjD,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO;QACL,eAAe,EAAE,IAAI;QACrB,QAAQ,EACN,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI;YACvC,CAAC,CAAC,QAAQ,CAAC,QAAQ;YACnB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ;QAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,KAA4C;IAE5C,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC5D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,OAAO,gCAAgC,CACrC,OAAO,CAAC,IAAI,CAAC,sBAAsB,EACnC;QACE,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,UAAU,EAAE,WAAW;QACvB,SAAS,EAAE,8BAA8B;QACzC,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,EACD,KAAK,IAAI,EAAE;QACT,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,0DAA0D,CAC3D,CAAC;QACJ,CAAC;QACD,uEAAuE;QACvE,kEAAkE;QAClE,IACE,CAAC,KAAK,CAAC,OAAO;YACd,iCAAiC,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,EAC5D,CAAC;YACD,OAAO,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;QACD,IAAI,KAAK,CAAC,OAAO;YACf,OAAO,CAAC,SAAS,CAAC,8BAA8B,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9D,wEAAwE;QACxE,MAAM,QAAQ,GAAG,MAAM,6BAA6B,CAClD,KAAK,EACL,sBAAsB,EACtB,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,8BAA8B,CAAC,MAAM,CAAC,EAAE,CAAC,CAClE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACzB,+DAA+D;YAC/D,IAAI,yBAAyB,CAAC,KAAK,CAAC;gBAClC,OAAO,CAAC,SAAS,CAAC,8BAA8B,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC;QACd,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC;QACtD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;QACpC,qEAAqE;QACrE,4EAA4E;QAC5E,IAAI,CAAC,QAAQ,CAAC,eAAe;YAC3B,MAAM,iCAAiC,CAAC;gBACtC,YAAY,EAAE,SAAS;gBACvB,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,MAAM;gBACN,IAAI;gBACJ,OAAO;aACR,CAAC,CAAC;QACL,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,QAAQ,CAAC,eAAe;YAC1B,uBAAuB,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/D,4BAA4B,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACxD,OAAO;YACL,GAAG,MAAM;YACT,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,QAAQ,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;YAC7D,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,kBAAkB,CAChC,eAA+B,EAC/B,KAAoC;IAEpC,MAAM,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC;IACtC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/B,OAAO,CACL,SAAS,CAAC,QAAQ,KAAK,IAAI;QAC3B,CAAC,SAAS,CAAC,UAAU;QACrB,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,eAAe;QACrC,SAAS,CAAC,cAAc,KAAK,IAAI,CAAC,cAAc,CACjD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAAC,KAG7D;IACC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACzC,MAAM,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,IAAI,CAAC,kBAAkB,CAAC,eAAe,EAAE,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC3B,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,2DAA2D,CAC5D,CAAC;QACJ,CAAC;QACD,8BAA8B,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,QAAQ,GAAG,MAAM,yCAAyC,CAC9D,KAAK,EACL,OAAO,CAAC,IAAI,CAAC,sBAAsB,EACnC;YACE,QAAQ,EAAE,SAAS,CAAC,EAAE;YACtB,UAAU,EAAE,WAAW;YACvB,SAAS,EAAE,0BAA0B;YACrC,cAAc,EAAE,SAAS,CAAC,cAAc;SACzC,CACF,CAAC;QACF,IAAI,CAAC,QAAQ;YAAE,MAAM,KAAK,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["import {\n type AccessManifestCheckpoint,\n KeyingVerificationError,\n type VerifiedContainerAccessManifest,\n} from \"@tearleads/crypto\";\nimport { deriveOrganizationMetadataContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport { verifiedContainerCreateManifest } from \"../../../../data/keyingProjectionVerification/container/containerCreateManifest\";\nimport { verifyContainerDestinationProjection } from \"../../../../data/keyingProjectionVerification/container/containerDestinationVerification\";\nimport { verifyContainerWriterProjection } from \"../../../../data/keyingProjectionVerification/container/containerProjectionVerification\";\nimport {\n isKeyingVerificationError,\n reportKeyingVerificationErrorInCauseChain,\n runWithSecurityIncidentReporting,\n} from \"../../../../data/keyingProjectionVerification/error\";\nimport {\n type HeldContainerBinding,\n listingRepeatsHeldOrdinaryBinding,\n} from \"../../../../data/persistence/container-contents/containerBinding\";\nimport { verifyRuntimeGroupMetadataAuthority } from \"../../../organizations/groupMetadata/runtimeGroupMetadataAuthority\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../../principals/runtimePolicyWarmer\";\nimport type {\n ContainerState,\n RemoteContainer,\n RemoteContainerHydrationState,\n} from \"../types\";\nimport type { PrefetchedDestinationProjection } from \"./destinationPrefetch\";\nimport {\n cachedDestinationRole,\n type DestinationRole,\n rememberDestinationRole,\n} from \"./destinationRoleCache\";\nimport { resolveWithMetadataRootReload } from \"./destinationRootReload\";\nimport { assertPermittedDestinationBinding } from \"./replacementBinding\";\n\n/** The identity a role is verified and cached under. */\ntype DestinationIdentity = Pick<RemoteContainer, \"id\" | \"organizationId\">;\n\nasync function destinationRoleFromPath(input: {\n listed: DestinationIdentity;\n path: readonly VerifiedContainerAccessManifest[];\n verifiedByHash: ReadonlyMap<string, VerifiedContainerAccessManifest>;\n}): Promise<{ role: DestinationRole; parentId: string | null }> {\n const { listed, path } = input;\n const head = path.at(-1);\n if (\n !head ||\n head.state.containerId !== listed.id ||\n head.state.organizationId !== listed.organizationId\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container destination manifest has the wrong identity\",\n );\n }\n const metadataSlot = await deriveOrganizationMetadataContainerSystemSlot({\n organizationId: listed.organizationId,\n });\n if (\n head.state.systemSlot !== null &&\n path.length !== (head.state.systemSlot === metadataSlot ? 1 : 2)\n ) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"system destination has the wrong signed topology\",\n );\n }\n // The head may be a later grant signed by any admin; only the epoch-1\n // create names the creator, and roots are always created by the org owner.\n const created = verifiedContainerCreateManifest({\n head,\n label: \"Container destination\",\n verifiedByHash: input.verifiedByHash,\n });\n const root = path[0];\n if (!root) throw new Error(\"Destination root is unavailable\");\n const rootCreated = verifiedContainerCreateManifest({\n head: root,\n label: \"Destination root\",\n verifiedByHash: input.verifiedByHash,\n });\n return {\n parentId: head.state.parentContainerId,\n role: {\n createSignerUserId: created.event.event.signerUserId,\n rootContainerId: rootCreated.state.containerId,\n rootCreateManifestHash: rootCreated.manifestHash,\n rootMetadataDocumentId: rootCreated.state.metadataDocumentId,\n metadataDocumentId: head.state.metadataDocumentId,\n ...(head.state.parentContainerId === null ||\n head.state.systemSlot !== null\n ? { parentId: head.state.parentContainerId }\n : {}),\n systemSlot: head.state.systemSlot,\n },\n };\n}\n\n/**\n * The session's root id arrives in an unsigned login response, so the root it\n * names must prove it belongs to this user: every acknowledged organization was\n * created by the session user, whose device signed the root's `container.create`.\n * A verified root created by anyone else is a substitution, never the merge\n * target for pre-login local content, whatever grants it carries. The check\n * runs on cache reuse too, since the cache is not scoped to the session user.\n */\nfunction assertRootCreatedBySessionUser(\n role: DestinationRole,\n runtime: RemoteContainerHydrationState[\"runtime\"],\n): void {\n if (role.systemSlot !== null) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"acknowledged session root cannot be a system container\",\n );\n }\n if (role.createSignerUserId !== runtime.auth.userId) {\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"acknowledged session root was not created by the session user\",\n );\n }\n}\n\nfunction assertAcknowledgedRootSigner(input: {\n listed: DestinationIdentity;\n role: DestinationRole;\n runtime: RemoteContainerHydrationState[\"runtime\"];\n}): void {\n const { listed, role, runtime } = input;\n if (role.parentId !== null || listed.id !== runtime.auth.rootContainerId) {\n return;\n }\n assertRootCreatedBySessionUser(role, runtime);\n}\n\n/**\n * Authenticate destination roles before admitting a binding or advancing any\n * placement pin. Shared rehomes additionally require signed replacement evidence.\n */\nasync function verifyDestinationRole(input: {\n heldBinding: HeldContainerBinding | null;\n prefetched: PrefetchedDestinationProjection | undefined;\n verifyCurrentPlacement: boolean;\n onVerifiedCheckpoint:\n | ((checkpoint: AccessManifestCheckpoint) => void)\n | undefined;\n isCurrent?: (() => boolean) | undefined;\n listed: DestinationIdentity;\n runtime: RemoteContainerHydrationState[\"runtime\"];\n}): Promise<{ role: DestinationRole; parentId: string | null } | null> {\n const { isCurrent, listed, runtime } = input;\n const projection = input.prefetched\n ? input.prefetched.projection\n : await runtime.apiClient.getContainerWriterProjection(listed.id);\n if (!projection || isCurrent?.() === false) return null;\n if (\n projection.containerId !== listed.id ||\n projection.organizationId !== listed.organizationId\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container destination projection has the wrong identity\",\n );\n }\n const verificationInput = {\n execSql: runtime.infra.execSql,\n projection,\n resolveUserKey: runtime.resolveTrustedUserIdentity,\n stillCurrent: isCurrent,\n warmReferencedPrincipalPolicies:\n createRuntimePrincipalPolicyWarmer(runtime),\n };\n const { path, verifiedByHash } =\n await verifyContainerDestinationProjection(verificationInput);\n if (isCurrent?.() === false) return null;\n const destination = await destinationRoleFromPath({\n listed,\n path,\n verifiedByHash,\n });\n const { role } = destination;\n // Refuse a rebinding before group checks or placement pins run for it.\n await assertPermittedDestinationBinding({\n stillCurrent: isCurrent,\n heldBinding: input.heldBinding,\n listed,\n role,\n runtime,\n });\n if (isCurrent?.() === false) return null;\n if (role.parentId === null && role.systemSlot !== null) {\n const head = path.at(-1);\n if (!head) throw new Error(\"Metadata root manifest is unavailable\");\n await verifyRuntimeGroupMetadataAuthority({\n runtime,\n organizationId: listed.organizationId,\n organizationReference: projection.policyEvidence.organization?.head,\n state: head.state,\n stillCurrent: isCurrent ?? (() => true),\n });\n }\n if (isCurrent?.() === false) return null;\n if (input.verifyCurrentPlacement) {\n // Check the immutable role before allowing current placement to advance pins.\n assertAcknowledgedRootSigner({ listed, role, runtime });\n const currentPath = await verifyContainerWriterProjection({\n ...verificationInput,\n stillCurrent: isCurrent,\n });\n const currentHead = currentPath.at(-1);\n if (!currentHead)\n throw new Error(\"Recovery placement manifest is unavailable\");\n input.onVerifiedCheckpoint?.(currentHead.checkpoint);\n }\n if (isCurrent?.() === false) return null;\n return destination;\n}\n\ntype VerifyRemoteContainerDestinationInput = {\n heldBinding: HeldContainerBinding | null;\n /** The held folder was re-homed away from the listed organization. */\n supersededListing?: boolean | undefined;\n /** Fetched ahead by page hydration; ignored when placement is refreshed. */\n prefetchedProjection?: PrefetchedDestinationProjection | undefined;\n refresh?: boolean;\n onVerifiedCheckpoint?:\n | ((checkpoint: AccessManifestCheckpoint) => void)\n | undefined;\n remoteContainer: RemoteContainer;\n state: RemoteContainerHydrationState;\n isCurrent?: (() => boolean) | undefined;\n};\n\n/** A cached immutable role, or a freshly verified one with its signed parent. */\nasync function resolveDestinationRole(\n input: VerifyRemoteContainerDestinationInput,\n): Promise<{\n freshlyVerified: boolean;\n parentId: string | null | undefined;\n role: DestinationRole;\n} | null> {\n const { remoteContainer: listed, isCurrent } = input;\n const runtime = input.state.runtime;\n const cached = input.refresh\n ? undefined\n : cachedDestinationRole(runtime.infra.execSql, listed);\n // Ordinary parent edges are not immutable. A refresh authenticates current\n // placement; a forged root hint must also be corrected from a signed path.\n if (cached && !(cached.parentId === undefined && listed.parentId === null)) {\n return { freshlyVerified: false, parentId: cached.parentId, role: cached };\n }\n const verified = await verifyDestinationRole({\n heldBinding: input.heldBinding,\n prefetched: input.refresh ? undefined : input.prefetchedProjection,\n isCurrent,\n listed,\n runtime,\n verifyCurrentPlacement: input.refresh === true,\n onVerifiedCheckpoint: input.onVerifiedCheckpoint,\n });\n if (!verified) return null;\n return {\n freshlyVerified: true,\n parentId:\n input.refresh || listed.parentId === null\n ? verified.parentId\n : verified.role.parentId,\n role: verified.role,\n };\n}\n\n/**\n * Listing hints never establish a metadata target or a system/root role, and a\n * held folder keeps its organization and metadata target unless its own user\n * re-created it or its pinned founder authorized a verified replacement.\n * A conflicting proof is refused before placement pins\n * advance or its role is cached.\n */\nexport async function verifyRemoteContainerDestination(\n input: VerifyRemoteContainerDestinationInput,\n): Promise<RemoteContainer | null> {\n const { remoteContainer: listed, state, isCurrent } = input;\n const runtime = state.runtime;\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: listed.id,\n objectKind: \"container\",\n operation: \"container.destination.verify\",\n organizationId: listed.organizationId,\n },\n async () => {\n if (input.supersededListing) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"container was re-homed away from the listed organization\",\n );\n }\n // A held ordinary binding was verified (or signed by this device) when\n // it was stored; a listing that repeats it needs no second proof.\n if (\n !input.refresh &&\n listingRepeatsHeldOrdinaryBinding(input.heldBinding, listed)\n ) {\n return { ...listed, systemSlot: null };\n }\n if (input.refresh)\n runtime.apiClient.evictContainerWriterProjection(listed.id);\n // A metadata root read before a reserved-group commit is reloaded once.\n const resolved = await resolveWithMetadataRootReload(\n input,\n resolveDestinationRole,\n () => runtime.apiClient.evictContainerWriterProjection(listed.id),\n ).catch((error: unknown) => {\n // Never re-serve a cached projection that failed verification.\n if (isKeyingVerificationError(error))\n runtime.apiClient.evictContainerWriterProjection(listed.id);\n throw error;\n });\n if (!resolved || isCurrent?.() === false) return null;\n const { role, parentId } = resolved;\n // Fresh verification checked this binding before any placement pins.\n // A cached role still needs the held binding and replacement proof checked.\n if (!resolved.freshlyVerified)\n await assertPermittedDestinationBinding({\n stillCurrent: isCurrent,\n heldBinding: input.heldBinding,\n listed,\n role,\n runtime,\n });\n if (isCurrent?.() === false) return null;\n if (resolved.freshlyVerified)\n rememberDestinationRole(runtime.infra.execSql, listed, role);\n assertAcknowledgedRootSigner({ listed, role, runtime });\n return {\n ...listed,\n metadataDocumentId: role.metadataDocumentId,\n parentId: parentId === undefined ? listed.parentId : parentId,\n systemSlot: role.systemSlot,\n };\n },\n );\n}\n\n/** The root the unsigned login answer named, in the expected organization. */\nexport function isSessionRootState(\n remoteRootState: ContainerState,\n state: RemoteContainerHydrationState,\n): boolean {\n const { container } = remoteRootState;\n const { auth } = state.runtime;\n return (\n container.parentId === null &&\n !container.systemSlot &&\n container.id === auth.rootContainerId &&\n container.organizationId === auth.organizationId\n );\n}\n\n/**\n * Whether the session root may absorb the pre-login local roots. The unsigned\n * login answer only names the root; the merge target must also be the verified\n * root whose epoch-1 `container.create` the session user signed. A row persisted\n * earlier as an ordinary shared container (another user's root this device once\n * hydrated) never passed that check for this session, so the creator is checked\n * here, at the reconciliation boundary itself, before any local content is\n * re-parented. The role comes only from the cache remote hydration fills when\n * it verifies the destination: this gate never fetches, so a local refresh stays\n * independent of the network. Without a cached role the merge is left pending\n * (no incident) until hydration verifies the root and reconciles from the\n * cache. A different creator is a `signer_mismatch` incident and never a merge;\n * the refusal is the \"no merge\" outcome, so the refresh that carried it\n * completes with the local content left in place.\n */\nexport async function isVerifiedLocalRootReconciliationTarget(input: {\n remoteRootState: ContainerState;\n state: RemoteContainerHydrationState;\n}): Promise<boolean> {\n const { remoteRootState, state } = input;\n const { container } = remoteRootState;\n const runtime = state.runtime;\n if (!isSessionRootState(remoteRootState, state)) return false;\n const role = cachedDestinationRole(runtime.infra.execSql, container);\n if (!role) return false;\n try {\n if (role.parentId !== null) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"session root reconciliation target is not a verified root\",\n );\n }\n assertRootCreatedBySessionUser(role, runtime);\n return true;\n } catch (error) {\n const reported = await reportKeyingVerificationErrorInCauseChain(\n error,\n runtime.util.reportSecurityIncident,\n {\n objectId: container.id,\n objectKind: \"container\",\n operation: \"container.root.reconcile\",\n organizationId: container.organizationId,\n },\n );\n if (!reported) throw error;\n return false;\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { rebindsHeldContainer, } from "../../../data/
|
|
1
|
+
import { rebindsHeldContainer, } from "../../../data/persistence/container-contents/containerBinding.js";
|
|
2
2
|
import { installContainerMetadataRecord } from "../metadata/metadataStateInstallation.js";
|
|
3
3
|
/**
|
|
4
4
|
* Apply a re-home verified from the session user's create or the pinned
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heldContainerRebind.js","sourceRoot":"","sources":["heldContainerRebind.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,oBAAoB,GACrB,MAAM,
|
|
1
|
+
{"version":3,"file":"heldContainerRebind.js","sourceRoot":"","sources":["heldContainerRebind.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,oBAAoB,GACrB,MAAM,+DAA+D,CAAC;AACvE,OAAO,EAAE,8BAA8B,EAAE,MAAM,uCAAuC,CAAC;AAOvF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAM5C;IACC,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC9D,IAAI,CAAC,WAAW,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5C,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,EAAE;QACnE,WAAW,EAAE,QAAQ,CAAC,EAAE;QACxB,QAAQ,EAAE,WAAW;QACrB,IAAI,EAAE;YACJ,kBAAkB,EAAE,QAAQ,CAAC,kBAAkB;YAC/C,cAAc,EAAE,QAAQ,CAAC,cAAc;SACxC;QACD,YAAY,EAAE,KAAK,CAAC,SAAS;KAC9B,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,0BAA0B,CAC/D,OAAO,EACP,QAAQ,CAAC,EAAE,CACZ,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IACnE,aAAa,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IAC3C,aAAa,CAAC,yBAAyB,GAAG,IAAI,CAAC;IAC/C,aAAa,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAC9C,8BAA8B,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7D,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import {\n type HeldContainerBinding,\n rebindsHeldContainer,\n} from \"../../../data/persistence/container-contents/containerBinding\";\nimport { installContainerMetadataRecord } from \"../metadata/metadataStateInstallation\";\nimport type {\n ContainerState,\n RemoteContainer,\n RemoteContainerHydrationState,\n} from \"./types\";\n\n/**\n * Apply a re-home verified from the session user's create or the pinned\n * founder's replacement authorization before hydration updates or inserts\n * the folder. Returns false when\n * the held binding changed underneath, leaving the listing unapplied.\n */\nexport async function rebindReHomedContainer(input: {\n existingState: ContainerState | undefined;\n heldBinding: HeldContainerBinding | null;\n isCurrent?: (() => boolean) | undefined;\n state: RemoteContainerHydrationState;\n verified: RemoteContainer;\n}): Promise<boolean> {\n const { existingState, heldBinding, state, verified } = input;\n if (!heldBinding || !rebindsHeldContainer(heldBinding, verified)) return true;\n const execSql = state.runtime.infra.execSql;\n const rebound = await state.persistence.rebindHeldContainer(execSql, {\n containerId: verified.id,\n expected: heldBinding,\n next: {\n metadataDocumentId: verified.metadataDocumentId,\n organizationId: verified.organizationId,\n },\n stillCurrent: input.isCurrent,\n });\n if (!rebound || input.isCurrent?.() === false) return false;\n if (!existingState) return true;\n const stored = await state.persistence.loadContainerMetadataState(\n execSql,\n verified.id,\n );\n if (!stored?.record || input.isCurrent?.() === false) return false;\n existingState.container = stored.container;\n existingState.containerWriterProjection = null;\n existingState.metadataWriterProjection = null;\n installContainerMetadataRecord(existingState, stored.record);\n return true;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { base64ToBytes, bytesToBase64 } from "../../../internal/encoding/index.js";
|
|
2
2
|
import { exportAllUpdates, importUpdates } from "../../../internal/loro/index.js";
|
|
3
|
-
import { readContainerMetadataValue } from "
|
|
3
|
+
import { readContainerMetadataValue } from "../metadata/containerMetadataDocument.js";
|
|
4
4
|
/**
|
|
5
5
|
* Resolve a freshly discovered container's metadata content against dormant
|
|
6
6
|
* retained state (docs/sync-edge-cases.md row 4, access_revoked branch). A
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reattachMetadata.js","sourceRoot":"","sources":["reattachMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"reattachMetadata.js","sourceRoot":"","sources":["reattachMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGlE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAGnF;;;;;;;GAOG;AACH,MAAM,UAAU,gCAAgC,CAAC,KAKhD;IASC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAClD,yEAAyE;IACzE,2EAA2E;IAC3E,sEAAsE;IACtE,IACE,aAAa,EAAE,UAAU,IAAI,IAAI;QACjC,aAAa,CAAC,UAAU,KAAK,KAAK,CAAC,wBAAwB,EAC3D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO;YACL,IAAI,EAAE,IAAI;YACV,eAAe,EAAE,aAAa,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACrD,aAAa,EAAE,IAAI;YACnB,IAAI,EAAE,WAAW;YACjB,gBAAgB,EAAE,IAAI;YACtB,kBAAkB,EAAE,EAAE;SACvB,CAAC;IACJ,CAAC;IAED,IAAI,aAAa,CAAC,eAAe,EAAE,CAAC;QAClC,aAAa,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,QAAQ,GAAG,0BAA0B,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC9D,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,eAAe,EACb,aAAa,CAAC,eAAe,IAAI,aAAa,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACvE,aAAa,EAAE,aAAa,CAAC,aAAa,IAAI,IAAI;QAClD,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,gBAAgB,EAAE,aAAa,CAAC,gCAAgC;YAC9D,CAAC,CAAC,aAAa,CAAC,gBAAgB;YAChC,CAAC,CAAC,CAAC,aAAa,CAAC,gBAAgB,IAAI,IAAI,CAAC;QAC5C,GAAG,CAAC,aAAa,CAAC,gCAAgC;YAChD,CAAC,CAAC,EAAE,gCAAgC,EAAE,IAAa,EAAE;YACrD,CAAC,CAAC,EAAE,CAAC;QACP,kBAAkB,EAAE,aAAa,CAAC,kBAAkB;KACrD,CAAC;AACJ,CAAC","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport { exportAllUpdates, importUpdates } from \"@tearleads/loro\";\nimport type { DocumentSyncPullContinuation } from \"../../../data/documents/shared/sync/pullContinuation\";\nimport type { ContainerMetadataRecord } from \"../containerPersistence\";\nimport { readContainerMetadataValue } from \"../metadata/containerMetadataDocument\";\nimport type { ContainerMetadataDocumentState } from \"./types\";\n\n/**\n * Resolve a freshly discovered container's metadata content against dormant\n * retained state (docs/sync-edge-cases.md row 4, access_revoked branch). A\n * dormant record makes this a re-attach: its content is imported into the\n * live document and projected, so a queued local rename or icon edit renders\n * immediately instead of a default name until sync succeeds. Without one, the\n * document seeds fresh with the default projection.\n */\nexport function reattachDormantContainerMetadata(input: {\n defaultName: string;\n doc: ContainerMetadataDocumentState;\n dormantRecord: ContainerMetadataRecord | null;\n remoteMetadataDocumentId: string;\n}): {\n icon: string | null;\n initialSnapshot: string;\n lastCommitLsn: string | null;\n name: string;\n pullContinuation: DocumentSyncPullContinuation | null | undefined;\n pullContinuationRecoveryRequired?: true | undefined;\n snapshotEndVersion: string;\n} {\n const { defaultName, doc, dormantRecord } = input;\n // The signed metadata document id never changes, and hydration refuses a\n // relisting that conflicts with the retained binding before reaching here.\n // A null id is a lost-response create retained via its own tombstone.\n if (\n dormantRecord?.documentId != null &&\n dormantRecord.documentId !== input.remoteMetadataDocumentId\n ) {\n throw new Error(\"Dormant container metadata binding was not verified\");\n }\n if (!dormantRecord) {\n return {\n icon: null,\n initialSnapshot: bytesToBase64(exportAllUpdates(doc)),\n lastCommitLsn: null,\n name: defaultName,\n pullContinuation: null,\n snapshotEndVersion: \"\",\n };\n }\n\n if (dormantRecord.metadataUpdates) {\n importUpdates(doc, [base64ToBytes(dormantRecord.metadataUpdates)]);\n }\n const metadata = readContainerMetadataValue(doc, defaultName);\n return {\n icon: metadata.icon,\n initialSnapshot:\n dormantRecord.metadataUpdates || bytesToBase64(exportAllUpdates(doc)),\n lastCommitLsn: dormantRecord.lastCommitLsn ?? null,\n name: metadata.name,\n pullContinuation: dormantRecord.pullContinuationRecoveryRequired\n ? dormantRecord.pullContinuation\n : (dormantRecord.pullContinuation ?? null),\n ...(dormantRecord.pullContinuationRecoveryRequired\n ? { pullContinuationRecoveryRequired: true as const }\n : {}),\n snapshotEndVersion: dormantRecord.snapshotEndVersion,\n };\n}\n"]}
|
package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { assertHeldContainerBinding, heldContainerBinding, } from "../../../../data/
|
|
2
|
-
import { createContainerMetadataDocument, getDefaultContainerName, } from "
|
|
1
|
+
import { assertHeldContainerBinding, heldContainerBinding, } from "../../../../data/persistence/container-contents/containerBinding.js";
|
|
2
|
+
import { createContainerMetadataDocument, getDefaultContainerName, } from "../../metadata/containerMetadataDocument.js";
|
|
3
3
|
import { materializeStoredContainerStateReadOnly } from "../../storedContainerState.js";
|
|
4
4
|
import { addIndexedContainerChild } from "../lanes/childIndex.js";
|
|
5
5
|
import { reattachDormantContainerMetadata } from "../reattachMetadata.js";
|
package/workflows/container-contents/remoteHydration/remoteContainers/insertRemoteContainer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insertRemoteContainer.js","sourceRoot":"","sources":["insertRemoteContainer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccessManifestCheckpoint } from \"@tearleads/crypto\";\nimport {\n assertHeldContainerBinding,\n heldContainerBinding,\n} from \"../../../../data/containers/containerBinding\";\nimport {\n createContainerMetadataDocument,\n getDefaultContainerName,\n} from \"../../../../data/containers/containerMetadataDocument\";\nimport type { ContainerHydrationTombstone } from \"../../containerPersistence\";\nimport { materializeStoredContainerStateReadOnly } from \"../../storedContainerState\";\nimport { addIndexedContainerChild } from \"../lanes/childIndex\";\nimport { reattachDormantContainerMetadata } from \"../reattachMetadata\";\nimport { reconcileLocalOnlyRootContainers } from \"../reconciliation\";\nimport type {\n ContainerChildIndex,\n ContainerState,\n RemoteContainer,\n RemoteContainerHydrationHost,\n RemoteContainerHydrationState,\n} from \"../types\";\nimport {\n applyRemoteContainerTimestamps,\n remoteContainerHydrationSaveOptions,\n} from \"./remoteContainerTimestamps\";\n\ninterface InsertRemoteContainerStateInput {\n childIdsByParentId?: ContainerChildIndex | undefined;\n host: RemoteContainerHydrationHost;\n expectedHydrationTombstone: ContainerHydrationTombstone | null;\n expectedPlacementCheckpoint?: AccessManifestCheckpoint | undefined;\n isCurrent?: (() => boolean) | undefined;\n remoteContainer: RemoteContainer;\n state: RemoteContainerHydrationState;\n}\n\nfunction createInsertedRemoteContainerState(input: {\n doc: ContainerState[\"doc\"];\n dormantRecord: Awaited<\n ReturnType<\n RemoteContainerHydrationState[\"persistence\"][\"loadContainerMetadataRecord\"]\n >\n >;\n remoteContainer: RemoteContainer;\n}): ContainerState {\n const { doc, dormantRecord, remoteContainer } = input;\n const reattached = reattachDormantContainerMetadata({\n defaultName: getDefaultContainerName(remoteContainer.parentId),\n doc,\n dormantRecord,\n remoteMetadataDocumentId: remoteContainer.metadataDocumentId,\n });\n return {\n container: applyRemoteContainerTimestamps(\n {\n id: remoteContainer.id,\n effectiveAccessLevel: remoteContainer.effectiveAccessLevel,\n organizationId: remoteContainer.organizationId,\n parentId: remoteContainer.parentId,\n metadataDocumentId: remoteContainer.metadataDocumentId,\n systemSlot: remoteContainer.systemSlot ?? null,\n name: reattached.name,\n icon: reattached.icon,\n },\n remoteContainer,\n ),\n metadataReferencedPrincipals: remoteContainer.metadataReferencedPrincipals,\n doc,\n record: {\n accessEpoch: remoteContainer.metadataAccessEpoch,\n accessStateHash: remoteContainer.metadataAccessStateHash,\n documentId: remoteContainer.metadataDocumentId,\n id: remoteContainer.id,\n lastCommitLsn: reattached.lastCommitLsn,\n metadataUpdates: reattached.initialSnapshot,\n ...(reattached.pullContinuation === undefined\n ? {}\n : { pullContinuation: reattached.pullContinuation }),\n ...(reattached.pullContinuationRecoveryRequired\n ? { pullContinuationRecoveryRequired: true as const }\n : {}),\n snapshotEndVersion: reattached.snapshotEndVersion,\n contentKeyBundle: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n },\n };\n}\n\n/**\n * Insert a verified container the device holds no live row for, re-attaching\n * retained dormant metadata whose binding matches.\n */\nexport async function insertRemoteContainerState(\n input: InsertRemoteContainerStateInput,\n): Promise<ContainerState | null> {\n const { childIdsByParentId, host, remoteContainer, state } = input;\n const execSql = state.runtime.infra.execSql;\n const persistence = state.persistence;\n const doc = await createContainerMetadataDocument(remoteContainer.id);\n if (input.isCurrent?.() === false) {\n return null;\n }\n // A container inserted with dormant retained metadata (row 4's\n // access_revoked branch) is a re-attach, not a fresh discovery: import the\n // retained content and markers instead of overwriting them with an empty\n // document. Access and keying fields still come from the remote container —\n // revocation may have rotated them.\n const dormantRecord = await persistence.loadContainerMetadataRecord(\n execSql,\n remoteContainer.id,\n );\n if (input.isCurrent?.() === false) {\n return null;\n }\n // Destination verification refused a relisting that conflicts with the\n // retained organization or metadata target. A record committed since then\n // by a concurrent hydration is refused here; commit rechecks both durably.\n assertHeldContainerBinding(\n {\n organizationId: \"\",\n metadataDocumentId: dormantRecord?.documentId ?? null,\n },\n {\n organizationId: remoteContainer.organizationId,\n metadataDocumentIds: [remoteContainer.metadataDocumentId],\n },\n );\n const containerState = createInsertedRemoteContainerState({\n doc,\n dormantRecord,\n remoteContainer,\n });\n\n const committed = await persistence.commitHydratedContainer(execSql, {\n container: containerState.container,\n expectedDormantRecord: dormantRecord,\n expectedHydrationTombstone: input.expectedHydrationTombstone,\n expectedPlacementCheckpoint: input.expectedPlacementCheckpoint,\n record: containerState.record,\n remoteUpdatedAt: remoteContainer.updatedAt,\n saveOptions: remoteContainerHydrationSaveOptions({ remoteContainer }),\n stillCurrent: input.isCurrent,\n });\n let installedState = containerState;\n if (committed.committed) {\n installedState.container = committed.container;\n } else {\n const winningStoredState = await persistence.loadContainerMetadataState(\n execSql,\n remoteContainer.id,\n );\n if (!winningStoredState) return null;\n // A concurrent hydration that won the insert holds the binding now.\n assertHeldContainerBinding(heldContainerBinding(winningStoredState), {\n organizationId: remoteContainer.organizationId,\n metadataDocumentIds: [remoteContainer.metadataDocumentId],\n });\n const winningState = await materializeStoredContainerStateReadOnly({\n storedContainer: winningStoredState,\n });\n if (\n !winningState ||\n !(await persistence.containerExists(execSql, remoteContainer.id))\n ) {\n return null;\n }\n installedState = winningState;\n installedState.metadataReferencedPrincipals =\n remoteContainer.metadataReferencedPrincipals;\n }\n if (input.isCurrent?.() === false) {\n return null;\n }\n state.containersById.set(remoteContainer.id, installedState);\n if (childIdsByParentId) {\n addIndexedContainerChild(\n childIdsByParentId,\n remoteContainer.id,\n installedState.container.parentId,\n );\n }\n await reconcileLocalOnlyRootContainers({\n childIdsByParentId,\n isCurrent: input.isCurrent,\n remoteRootState: installedState,\n requestDocumentPriming: host.requestDocumentPriming,\n state,\n });\n return installedState;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"insertRemoteContainer.js","sourceRoot":"","sources":["insertRemoteContainer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccessManifestCheckpoint } from \"@tearleads/crypto\";\nimport {\n assertHeldContainerBinding,\n heldContainerBinding,\n} from \"../../../../data/persistence/container-contents/containerBinding\";\nimport type { ContainerHydrationTombstone } from \"../../containerPersistence\";\nimport {\n createContainerMetadataDocument,\n getDefaultContainerName,\n} from \"../../metadata/containerMetadataDocument\";\nimport { materializeStoredContainerStateReadOnly } from \"../../storedContainerState\";\nimport { addIndexedContainerChild } from \"../lanes/childIndex\";\nimport { reattachDormantContainerMetadata } from \"../reattachMetadata\";\nimport { reconcileLocalOnlyRootContainers } from \"../reconciliation\";\nimport type {\n ContainerChildIndex,\n ContainerState,\n RemoteContainer,\n RemoteContainerHydrationHost,\n RemoteContainerHydrationState,\n} from \"../types\";\nimport {\n applyRemoteContainerTimestamps,\n remoteContainerHydrationSaveOptions,\n} from \"./remoteContainerTimestamps\";\n\ninterface InsertRemoteContainerStateInput {\n childIdsByParentId?: ContainerChildIndex | undefined;\n host: RemoteContainerHydrationHost;\n expectedHydrationTombstone: ContainerHydrationTombstone | null;\n expectedPlacementCheckpoint?: AccessManifestCheckpoint | undefined;\n isCurrent?: (() => boolean) | undefined;\n remoteContainer: RemoteContainer;\n state: RemoteContainerHydrationState;\n}\n\nfunction createInsertedRemoteContainerState(input: {\n doc: ContainerState[\"doc\"];\n dormantRecord: Awaited<\n ReturnType<\n RemoteContainerHydrationState[\"persistence\"][\"loadContainerMetadataRecord\"]\n >\n >;\n remoteContainer: RemoteContainer;\n}): ContainerState {\n const { doc, dormantRecord, remoteContainer } = input;\n const reattached = reattachDormantContainerMetadata({\n defaultName: getDefaultContainerName(remoteContainer.parentId),\n doc,\n dormantRecord,\n remoteMetadataDocumentId: remoteContainer.metadataDocumentId,\n });\n return {\n container: applyRemoteContainerTimestamps(\n {\n id: remoteContainer.id,\n effectiveAccessLevel: remoteContainer.effectiveAccessLevel,\n organizationId: remoteContainer.organizationId,\n parentId: remoteContainer.parentId,\n metadataDocumentId: remoteContainer.metadataDocumentId,\n systemSlot: remoteContainer.systemSlot ?? null,\n name: reattached.name,\n icon: reattached.icon,\n },\n remoteContainer,\n ),\n metadataReferencedPrincipals: remoteContainer.metadataReferencedPrincipals,\n doc,\n record: {\n accessEpoch: remoteContainer.metadataAccessEpoch,\n accessStateHash: remoteContainer.metadataAccessStateHash,\n documentId: remoteContainer.metadataDocumentId,\n id: remoteContainer.id,\n lastCommitLsn: reattached.lastCommitLsn,\n metadataUpdates: reattached.initialSnapshot,\n ...(reattached.pullContinuation === undefined\n ? {}\n : { pullContinuation: reattached.pullContinuation }),\n ...(reattached.pullContinuationRecoveryRequired\n ? { pullContinuationRecoveryRequired: true as const }\n : {}),\n snapshotEndVersion: reattached.snapshotEndVersion,\n contentKeyBundle: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n },\n };\n}\n\n/**\n * Insert a verified container the device holds no live row for, re-attaching\n * retained dormant metadata whose binding matches.\n */\nexport async function insertRemoteContainerState(\n input: InsertRemoteContainerStateInput,\n): Promise<ContainerState | null> {\n const { childIdsByParentId, host, remoteContainer, state } = input;\n const execSql = state.runtime.infra.execSql;\n const persistence = state.persistence;\n const doc = await createContainerMetadataDocument(remoteContainer.id);\n if (input.isCurrent?.() === false) {\n return null;\n }\n // A container inserted with dormant retained metadata (row 4's\n // access_revoked branch) is a re-attach, not a fresh discovery: import the\n // retained content and markers instead of overwriting them with an empty\n // document. Access and keying fields still come from the remote container —\n // revocation may have rotated them.\n const dormantRecord = await persistence.loadContainerMetadataRecord(\n execSql,\n remoteContainer.id,\n );\n if (input.isCurrent?.() === false) {\n return null;\n }\n // Destination verification refused a relisting that conflicts with the\n // retained organization or metadata target. A record committed since then\n // by a concurrent hydration is refused here; commit rechecks both durably.\n assertHeldContainerBinding(\n {\n organizationId: \"\",\n metadataDocumentId: dormantRecord?.documentId ?? null,\n },\n {\n organizationId: remoteContainer.organizationId,\n metadataDocumentIds: [remoteContainer.metadataDocumentId],\n },\n );\n const containerState = createInsertedRemoteContainerState({\n doc,\n dormantRecord,\n remoteContainer,\n });\n\n const committed = await persistence.commitHydratedContainer(execSql, {\n container: containerState.container,\n expectedDormantRecord: dormantRecord,\n expectedHydrationTombstone: input.expectedHydrationTombstone,\n expectedPlacementCheckpoint: input.expectedPlacementCheckpoint,\n record: containerState.record,\n remoteUpdatedAt: remoteContainer.updatedAt,\n saveOptions: remoteContainerHydrationSaveOptions({ remoteContainer }),\n stillCurrent: input.isCurrent,\n });\n let installedState = containerState;\n if (committed.committed) {\n installedState.container = committed.container;\n } else {\n const winningStoredState = await persistence.loadContainerMetadataState(\n execSql,\n remoteContainer.id,\n );\n if (!winningStoredState) return null;\n // A concurrent hydration that won the insert holds the binding now.\n assertHeldContainerBinding(heldContainerBinding(winningStoredState), {\n organizationId: remoteContainer.organizationId,\n metadataDocumentIds: [remoteContainer.metadataDocumentId],\n });\n const winningState = await materializeStoredContainerStateReadOnly({\n storedContainer: winningStoredState,\n });\n if (\n !winningState ||\n !(await persistence.containerExists(execSql, remoteContainer.id))\n ) {\n return null;\n }\n installedState = winningState;\n installedState.metadataReferencedPrincipals =\n remoteContainer.metadataReferencedPrincipals;\n }\n if (input.isCurrent?.() === false) {\n return null;\n }\n state.containersById.set(remoteContainer.id, installedState);\n if (childIdsByParentId) {\n addIndexedContainerChild(\n childIdsByParentId,\n remoteContainer.id,\n installedState.container.parentId,\n );\n }\n await reconcileLocalOnlyRootContainers({\n childIdsByParentId,\n isCurrent: input.isCurrent,\n remoteRootState: installedState,\n requestDocumentPriming: host.requestDocumentPriming,\n state,\n });\n return installedState;\n}\n"]}
|
package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerState.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { heldContainerBinding, listingRepeatsHeldOrdinaryBinding, } from "../../../../data/containers/containerBinding.js";
|
|
2
1
|
import { isKeyingVerificationError, runWithSecurityIncidentReporting, } from "../../../../data/keyingProjectionVerification/error.js";
|
|
3
2
|
import { isProjectionVerificationCancelledError } from "../../../../data/keyingProjectionVerification/types.js";
|
|
3
|
+
import { heldContainerBinding, listingRepeatsHeldOrdinaryBinding, } from "../../../../data/persistence/container-contents/containerBinding.js";
|
|
4
4
|
import { installContainerMetadataRecord } from "../../metadata/metadataPersistence.js";
|
|
5
5
|
import { projectionGeneration } from "../../projectionGeneration.js";
|
|
6
6
|
import { verifyRemoteContainerDestination } from "../destination/verifiedDestination.js";
|