@tearleads/client-sdk 0.1.58 → 0.1.60
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/Tearleads.d.ts +17 -17
- package/Tearleads.js +15 -15
- package/Tearleads.js.map +1 -1
- package/client/{blobs.d.ts → blobs/index.d.ts} +1 -1
- package/client/{blobs.js → blobs/index.js} +3 -3
- package/client/blobs/index.js.map +1 -0
- package/client/{containerDocumentDiscovery.js → containerContents/documentDiscovery.js} +11 -11
- package/client/containerContents/documentDiscovery.js.map +1 -0
- package/client/{containerContents.d.ts → containerContents/index.d.ts} +13 -13
- package/client/{containerContents.js → containerContents/index.js} +18 -18
- package/client/containerContents/index.js.map +1 -0
- package/client/{containerContentsTypes.d.ts → containerContents/types.d.ts} +14 -14
- package/client/containerContents/types.js +2 -0
- package/client/containerContents/types.js.map +1 -0
- package/client/{deviceFirst.d.ts → deviceFirst/index.d.ts} +7 -7
- package/client/{deviceFirst.js → deviceFirst/index.js} +11 -11
- package/client/deviceFirst/index.js.map +1 -0
- package/client/{reconciledDocumentContentPull.js → deviceFirst/reconciledDocumentContentPull.js} +1 -1
- package/client/deviceFirst/reconciledDocumentContentPull.js.map +1 -0
- package/client/{documents.d.ts → documents/index.d.ts} +5 -5
- package/client/{documents.js → documents/index.js} +5 -5
- package/client/documents/index.js.map +1 -0
- package/client/{identity.d.ts → identity/index.d.ts} +2 -2
- package/client/{identity.js → identity/index.js} +5 -5
- package/client/identity/index.js.map +1 -0
- package/client/{identityKeyPackage.d.ts → identity/keyPackage.d.ts} +1 -1
- package/client/{identityKeyPackage.js → identity/keyPackage.js} +4 -4
- package/client/identity/keyPackage.js.map +1 -0
- package/client/{userIdentities.d.ts → identity/userIdentities.d.ts} +2 -2
- package/client/{userIdentities.js → identity/userIdentities.js} +4 -4
- package/client/identity/userIdentities.js.map +1 -0
- package/client/index.d.ts +18 -18
- package/client/index.js +9 -9
- package/client/index.js.map +1 -1
- package/client/organizations/currentPrincipalMutations.js.map +1 -1
- package/client/organizations/index.d.ts +2 -2
- package/client/organizations/index.js.map +1 -1
- package/client/organizations/organizationAccessRestoration.js.map +1 -1
- package/client/organizations/organizationDataUsage.d.ts +1 -1
- package/client/organizations/organizationDataUsage.js.map +1 -1
- package/client/organizations/organizationGroupNameHydration.js.map +1 -1
- package/client/organizations/organizationGroupPresentation.d.ts +1 -1
- package/client/organizations/organizationGroupPresentation.js.map +1 -1
- package/client/organizations/organizationMetadataProfileSync.js +1 -1
- package/client/organizations/organizationMetadataProfileSync.js.map +1 -1
- package/client/organizations/organizationReadModels.d.ts +1 -1
- package/client/organizations/organizationReadModels.js.map +1 -1
- package/client/organizations/organizationWorkflowRuntime.js.map +1 -1
- package/client/organizations/organizationsTypes.d.ts +1 -1
- package/client/organizations/organizationsTypes.js.map +1 -1
- package/client/organizations/principalContainerMutations.js.map +1 -1
- package/client/organizations/principalMutationRecovery.d.ts +1 -1
- package/client/organizations/principalMutationRecovery.js.map +1 -1
- package/client/organizations/principalMutationScope.js.map +1 -1
- package/client/organizations/principalMutations.d.ts +2 -2
- package/client/organizations/principalMutations.js.map +1 -1
- package/client/root/index.d.ts +1 -1
- package/client/root/index.js.map +1 -1
- package/client/{database.d.ts → runtime/database.d.ts} +1 -1
- package/client/{database.js → runtime/database.js} +1 -1
- package/client/runtime/database.js.map +1 -0
- package/client/{principalHistoryProtection.d.ts → runtime/principalHistoryProtection.d.ts} +1 -1
- package/client/{principalHistoryProtection.js → runtime/principalHistoryProtection.js} +2 -2
- package/client/runtime/principalHistoryProtection.js.map +1 -0
- package/client/{principalMutationApi.d.ts → runtime/principalMutationApi.d.ts} +4 -4
- package/client/{principalMutationApi.js → runtime/principalMutationApi.js} +2 -2
- package/client/runtime/principalMutationApi.js.map +1 -0
- package/client/{principalMutationDispatch.js → runtime/principalMutationDispatch.js} +2 -2
- package/client/runtime/principalMutationDispatch.js.map +1 -0
- package/client/runtime/rootContainerAdoption.js.map +1 -0
- package/client/{workflowRuntime.d.ts → runtime/workflowRuntime.d.ts} +12 -12
- package/client/{workflowRuntime.js → runtime/workflowRuntime.js} +5 -5
- package/client/runtime/workflowRuntime.js.map +1 -0
- package/client/{securityIncidents.d.ts → securityIncidents/index.d.ts} +3 -3
- package/client/{securityIncidents.js → securityIncidents/index.js} +5 -5
- package/client/securityIncidents/index.js.map +1 -0
- package/client/session/index.js +1 -1
- package/client/session/index.js.map +1 -1
- package/client/session/sessionIdentityTrust.d.ts +1 -1
- package/client/session/sessionLoginRefusal.js.map +1 -1
- package/client/session/sessionOrganizationCreation.js.map +1 -1
- package/client/session/sessionPurgeRecovery.js.map +1 -1
- package/client/session/sessionRootAuthority.js.map +1 -1
- package/client/session/sessionTypes.d.ts +3 -3
- package/client/session/sessionTypes.js.map +1 -1
- package/data/blobs/createBlobStore.d.ts +1 -1
- package/data/blobs/createBlobStore.js.map +1 -1
- package/data/blobs/encryptedBlobByteSource.js +1 -1
- package/data/blobs/encryptedBlobByteSource.js.map +1 -1
- package/data/blobs/encryptedBlobEnvelope.d.ts +1 -1
- package/data/blobs/encryptedBlobEnvelope.js +2 -2
- package/data/blobs/encryptedBlobEnvelope.js.map +1 -1
- package/data/blobs/encryptedBlobStore.d.ts +1 -1
- package/data/blobs/encryptedBlobStore.js +1 -1
- package/data/blobs/encryptedBlobStore.js.map +1 -1
- package/data/blobs/memoryBlobStore.d.ts +1 -1
- package/data/blobs/memoryBlobStore.js +1 -1
- package/data/blobs/memoryBlobStore.js.map +1 -1
- package/data/blobs/opfsBlobStore.d.ts +1 -1
- package/data/blobs/opfsBlobStore.js +1 -1
- package/data/blobs/opfsBlobStore.js.map +1 -1
- package/data/containers/containerMetadataDocument.js +1 -1
- package/data/containers/containerMetadataDocument.js.map +1 -1
- package/data/containers/shared/events.js +1 -1
- package/data/containers/shared/events.js.map +1 -1
- package/data/containers/shared/heldContainerHeads.js +1 -1
- package/data/containers/shared/heldContainerHeads.js.map +1 -1
- package/data/containers/shared/mutationAcknowledgement.js +1 -1
- package/data/containers/shared/mutationAcknowledgement.js.map +1 -1
- package/data/containers/shared/principalPolicies.js +1 -1
- package/data/containers/shared/principalPolicies.js.map +1 -1
- package/data/containers/shared/readers.js +2 -2
- package/data/containers/shared/readers.js.map +1 -1
- package/data/documents/attachmentContentIdentity.js +1 -1
- package/data/documents/attachmentContentIdentity.js.map +1 -1
- package/data/documents/blob/shared/blobEnvelopeStream.js.map +1 -1
- package/data/documents/blob/shared/blobSourceSnapshot.d.ts +1 -1
- package/data/documents/blob/shared/blobSourceSnapshot.js.map +1 -1
- package/data/documents/blob/shared/chunkedBlobCrypto.js.map +1 -1
- package/data/documents/blob/shared/encryptedUploadParts.js.map +1 -1
- package/data/documents/blob/shared/events.js +1 -1
- package/data/documents/blob/shared/events.js.map +1 -1
- package/data/documents/blob/shared/types.d.ts +2 -2
- package/data/documents/blob/shared/types.js.map +1 -1
- package/data/documents/shared/containerKekPathHistory.js +1 -1
- package/data/documents/shared/containerKekPathHistory.js.map +1 -1
- package/data/documents/shared/containerKekPathVerification.d.ts +1 -1
- package/data/documents/shared/containerKekPathVerification.js +1 -1
- package/data/documents/shared/events.js +1 -1
- package/data/documents/shared/events.js.map +1 -1
- package/data/documents/shared/manifestBundleReaders.js +2 -2
- package/data/documents/shared/manifestBundleReaders.js.map +1 -1
- package/data/documents/shared/projection.d.ts +1 -1
- package/data/documents/shared/projection.js +2 -2
- package/data/documents/shared/projection.js.map +1 -1
- package/data/documents/shared/projectionContentKeys.d.ts +1 -1
- package/data/documents/shared/readers.js +3 -3
- package/data/documents/shared/readers.js.map +1 -1
- package/data/documents/shared/stableDocumentId.js +1 -1
- package/data/documents/shared/stableDocumentId.js.map +1 -1
- package/data/documents/shared/types.d.ts +1 -1
- package/data/documents/shared/types.js +1 -1
- package/data/{keyingCanonicalJson.js → keying/canonicalJson.js} +3 -3
- package/data/keying/canonicalJson.js.map +1 -0
- package/data/keyingProjectionVerification/bundleVerification.js +1 -1
- package/data/keyingProjectionVerification/bundleVerification.js.map +1 -1
- package/data/keyingProjectionVerification/containerAncestorCitations.js +1 -1
- package/data/keyingProjectionVerification/containerAncestorCitations.js.map +1 -1
- package/data/keyingProjectionVerification/containerManifestVerification.js +1 -1
- package/data/keyingProjectionVerification/containerManifestVerification.js.map +1 -1
- package/data/keyingProjectionVerification/documentManifestVerification.js +1 -1
- package/data/keyingProjectionVerification/documentManifestVerification.js.map +1 -1
- package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js +1 -1
- package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js.map +1 -1
- package/data/keyingProjectionVerification/error.js +1 -1
- package/data/keyingProjectionVerification/error.js.map +1 -1
- package/data/keyingProjectionVerification/index.d.ts +9 -0
- package/data/{keyingProjectionVerification.js → keyingProjectionVerification/index.js} +8 -8
- package/data/keyingProjectionVerification/index.js.map +1 -0
- package/data/keyingProjectionVerification/principalPolicyCache.js +1 -1
- package/data/keyingProjectionVerification/principalPolicyCache.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicyVerification.js +1 -1
- package/data/keyingProjectionVerification/principalPolicyVerification.js.map +1 -1
- package/data/keyingProjectionVerification/readers.d.ts +1 -1
- package/data/keyingProjectionVerification/readers.js +3 -3
- package/data/keyingProjectionVerification/readers.js.map +1 -1
- package/data/keyingProjectionVerification/userKeyResolver.d.ts +1 -1
- package/data/keyingProjectionVerification/userKeyResolver.js.map +1 -1
- package/data/persistence/containers/containerPersistence.js +1 -1
- package/data/persistence/containers/containerPersistence.js.map +1 -1
- package/data/persistence/documents/documentDiscoveryCandidate.js +1 -1
- package/data/persistence/documents/documentDiscoveryCandidate.js.map +1 -1
- package/data/persistence/documents/documentDiscoveryEvidencePersistence.js +1 -1
- package/data/persistence/documents/documentDiscoveryEvidencePersistence.js.map +1 -1
- package/data/persistence/documents/internal/documentProjectionRows.js +1 -1
- package/data/persistence/documents/internal/documentProjectionRows.js.map +1 -1
- package/data/persistence/documents/internal/documentRows.js +1 -1
- package/data/persistence/documents/internal/documentRows.js.map +1 -1
- package/data/persistence/principalPolicyBundleIntegrity.js +1 -1
- package/data/persistence/principalPolicyBundleIntegrity.js.map +1 -1
- package/data/persistence/principalPolicyReferenceCheckpoint.js +1 -1
- package/data/persistence/principalPolicyReferenceCheckpoint.js.map +1 -1
- package/data/persistence/principalPolicyReferenceIndexPersistence.js +1 -1
- package/data/persistence/principalPolicyReferenceIndexPersistence.js.map +1 -1
- package/data/persistence/principalPolicyReferencePersistence.js +1 -1
- package/data/persistence/principalPolicyReferencePersistence.js.map +1 -1
- package/data/persistence/securityIncidentPersistence.js.map +1 -1
- package/data/persistence/verifiedPrincipalPolicyBundle.js +1 -1
- package/data/persistence/verifiedPrincipalPolicyBundle.js.map +1 -1
- package/data/persistence/verifiedPrincipalPolicyCurrent.js +1 -1
- package/data/persistence/verifiedPrincipalPolicyCurrent.js.map +1 -1
- package/data/principals/principalMutationJournal.js +1 -1
- package/data/principals/principalMutationJournal.js.map +1 -1
- package/data/{securityIncidents.d.ts → shared/securityIncidents.d.ts} +1 -1
- package/data/sqlite/documentRecordPersistence.js +1 -1
- package/data/sqlite/documentRecordPersistence.js.map +1 -1
- package/data/sync/crdtPeerSeed.d.ts +18 -0
- package/data/sync/originatedDocuments.d.ts +1 -1
- package/data/sync/originatedDocuments.js.map +1 -1
- package/data/sync/syncCoordinator.d.ts +1 -1
- package/data/sync/syncCoordinator.js.map +1 -1
- package/package.json +1 -1
- package/stores/container-contents/backgroundHydration.js +1 -1
- package/stores/container-contents/backgroundHydration.js.map +1 -1
- package/stores/container-contents/containerContentsStore.d.ts +1 -1
- package/stores/container-contents/containerContentsStore.js.map +1 -1
- package/stores/container-contents/localRefresh.js +1 -1
- package/stores/container-contents/localRefresh.js.map +1 -1
- package/stores/container-contents/remoteContainerIngestion.js +1 -1
- package/stores/container-contents/remoteContainerIngestion.js.map +1 -1
- package/stores/container-contents/remoteWriteQueue.js +1 -1
- package/stores/container-contents/remoteWriteQueue.js.map +1 -1
- package/stores/container-contents/systemContainerHydration.js +1 -1
- package/stores/container-contents/systemContainerHydration.js.map +1 -1
- package/stores/container-contents/utils.js +1 -1
- package/stores/container-contents/utils.js.map +1 -1
- package/stores/documents/documentStore/attachmentIntents.js +1 -1
- package/stores/documents/documentStore/attachmentIntents.js.map +1 -1
- package/stores/documents/documentStore/attachmentSourceUpload.js.map +1 -1
- package/stores/documents/documentStore/attachmentStaging.js +1 -1
- package/stores/documents/documentStore/attachmentStaging.js.map +1 -1
- package/stores/documents/documentStore/attachmentUploadLane.js.map +1 -1
- package/stores/documents/documentStore/persistence.js +2 -2
- package/stores/documents/documentStore/persistence.js.map +1 -1
- package/stores/documents/documentStore/state.js +1 -1
- package/stores/documents/documentStore/state.js.map +1 -1
- package/stores/documents/documentStore/storedDocument.js +1 -1
- package/stores/documents/documentStore/storedDocument.js.map +1 -1
- package/stores/documents/documentStore/syncAttachments.js.map +1 -1
- package/stores/documents/documentStore.d.ts +1 -1
- package/stores/documents/documentStore.js.map +1 -1
- package/stores/documents/registry.d.ts +1 -1
- package/stores/documents/registry.js.map +1 -1
- package/stores/documents/types.d.ts +1 -1
- package/stores/documents/types.js.map +1 -1
- package/stores/local-projection/registry.d.ts +1 -1
- package/stores/local-projection/registry.js.map +1 -1
- package/sync/reconciliation/serviceTypes.d.ts +1 -1
- package/sync/reconciliation/serviceTypes.js.map +1 -1
- package/sync/reconciliation/triggers.d.ts +1 -1
- package/sync/reconciliation/triggers.js.map +1 -1
- package/workflows/blobs/attachmentBindingVerification.js +2 -2
- package/workflows/blobs/attachmentBindingVerification.js.map +1 -1
- package/workflows/blobs/blobChunkDecryption.js.map +1 -1
- package/workflows/blobs/decrypt.d.ts +1 -1
- package/workflows/blobs/decrypt.js +2 -2
- package/workflows/blobs/decrypt.js.map +1 -1
- package/workflows/blobs/detach.js +2 -2
- package/workflows/blobs/detach.js.map +1 -1
- package/workflows/blobs/hydrate.d.ts +3 -3
- package/workflows/blobs/hydrate.js +1 -1
- package/workflows/blobs/hydrate.js.map +1 -1
- package/workflows/blobs/hydrationResults.js.map +1 -1
- package/workflows/blobs/index.d.ts +2 -2
- package/workflows/blobs/index.js +1 -1
- package/workflows/blobs/index.js.map +1 -1
- package/workflows/blobs/multipartFirstParts.js.map +1 -1
- package/workflows/blobs/retainedAttachmentVerification.js +1 -1
- package/workflows/blobs/upload.js +3 -3
- package/workflows/blobs/upload.js.map +1 -1
- package/workflows/container-contents/container-state/createAdoption.js +1 -1
- package/workflows/container-contents/container-state/createAdoption.js.map +1 -1
- package/workflows/container-contents/container-state/createChild.js +1 -1
- package/workflows/container-contents/container-state/createChild.js.map +1 -1
- package/workflows/container-contents/container-state/createIntentSync.js +1 -1
- package/workflows/container-contents/container-state/createIntentSync.js.map +1 -1
- package/workflows/container-contents/container-state/groupGrantVerification.js +1 -1
- package/workflows/container-contents/container-state/moveIntentSync.js +1 -1
- package/workflows/container-contents/container-state/moveIntentSync.js.map +1 -1
- package/workflows/container-contents/container-state/purgeTreeScope.js +1 -1
- package/workflows/container-contents/container-state/purgeTreeScope.js.map +1 -1
- package/workflows/container-contents/container-state/share.js +1 -1
- package/workflows/container-contents/documentDiscoveryInputs.js +1 -1
- package/workflows/container-contents/documentDiscoveryInputs.js.map +1 -1
- package/workflows/container-contents/documentInfo.d.ts +1 -1
- package/workflows/container-contents/documentInfo.js.map +1 -1
- package/workflows/container-contents/documentLinks.d.ts +1 -1
- package/workflows/container-contents/documentLinks.js +1 -1
- package/workflows/container-contents/documentLinks.js.map +1 -1
- package/workflows/container-contents/documentMoveIntentSync.js +1 -1
- package/workflows/container-contents/documentMoveIntentSync.js.map +1 -1
- package/workflows/container-contents/documentPurge.d.ts +1 -1
- package/workflows/container-contents/documentPurge.js +1 -1
- package/workflows/container-contents/documentPurge.js.map +1 -1
- package/workflows/container-contents/documentQueries/rows.js +1 -1
- package/workflows/container-contents/documentQueries/rows.js.map +1 -1
- package/workflows/container-contents/metadata.d.ts +1 -1
- package/workflows/container-contents/metadataMutationPreparation.js +1 -1
- package/workflows/container-contents/metadataMutationPreparation.js.map +1 -1
- package/workflows/container-contents/metadataRemoteSync.d.ts +1 -1
- package/workflows/container-contents/metadataSyncErrors.js.map +1 -1
- package/workflows/container-contents/projectionKeys.d.ts +1 -1
- package/workflows/container-contents/syncLane.d.ts +1 -1
- package/workflows/container-contents/syncLane.js.map +1 -1
- package/workflows/containers/child/carriedDescendantRekeys.js +1 -1
- package/workflows/containers/child/create.d.ts +1 -1
- package/workflows/containers/child/create.js +2 -2
- package/workflows/containers/child/create.js.map +1 -1
- package/workflows/containers/child/createProjection.js +1 -1
- package/workflows/containers/child/createProjection.js.map +1 -1
- package/workflows/containers/child/createSubmission.d.ts +2 -2
- package/workflows/containers/child/createSubmission.js.map +1 -1
- package/workflows/containers/child/move.d.ts +2 -2
- package/workflows/containers/child/move.js +2 -2
- package/workflows/containers/child/move.js.map +1 -1
- package/workflows/containers/child/moveWraps.js +1 -1
- package/workflows/containers/child/mutationRequestCore.js +1 -1
- package/workflows/containers/child/mutationRequestCore.js.map +1 -1
- package/workflows/containers/child/mutationSubmit.js.map +1 -1
- package/workflows/containers/child/recite.js.map +1 -1
- package/workflows/containers/child/recitePlan.js +1 -1
- package/workflows/containers/child/recitePlan.js.map +1 -1
- package/workflows/containers/child/rekey.d.ts +1 -1
- package/workflows/containers/child/rekey.js +2 -2
- package/workflows/containers/child/rekey.js.map +1 -1
- package/workflows/containers/child/rekeyProjection.js +1 -1
- package/workflows/containers/child/rekeyProjection.js.map +1 -1
- package/workflows/containers/child/rekeyRemote.d.ts +2 -2
- package/workflows/containers/child/rekeyRemote.js.map +1 -1
- package/workflows/containers/child/revoke.d.ts +2 -2
- package/workflows/containers/child/revoke.js +2 -2
- package/workflows/containers/child/revoke.js.map +1 -1
- package/workflows/containers/child/rotationPrincipalPolicies.js +1 -1
- package/workflows/containers/child/runtimeCurrentGroupShare.js +1 -1
- package/workflows/containers/child/share.d.ts +2 -2
- package/workflows/containers/child/share.js +1 -1
- package/workflows/containers/child/share.js.map +1 -1
- package/workflows/containers/child/shareAncestorRepair.js.map +1 -1
- package/workflows/containers/child/shareMaterialization.d.ts +1 -1
- package/workflows/containers/child/sharePlanCore.d.ts +1 -1
- package/workflows/containers/child/sharePlanCore.js +1 -1
- package/workflows/containers/root/create.js +1 -1
- package/workflows/containers/root/create.js.map +1 -1
- package/workflows/containers/root/initialGroupPolicy.js +1 -1
- package/workflows/containers/root/initialGroupPolicy.js.map +1 -1
- package/workflows/documents/create.d.ts +1 -1
- package/workflows/documents/create.js +1 -1
- package/workflows/documents/documentMutationPreparation.js +1 -1
- package/workflows/documents/documentMutationPreparation.js.map +1 -1
- package/workflows/documents/historyContent.js +1 -1
- package/workflows/documents/historyContent.js.map +1 -1
- package/workflows/documents/linkSet.js +1 -1
- package/workflows/documents/linkSet.js.map +1 -1
- package/workflows/documents/linkSetAuthority.js +1 -1
- package/workflows/documents/linkSetBlobRewraps.js +2 -2
- package/workflows/documents/linkSetBlobRewraps.js.map +1 -1
- package/workflows/documents/linkSetRemote.d.ts +1 -1
- package/workflows/documents/linkSetRemote.js +1 -1
- package/workflows/documents/orphanBlobReclaims.js +1 -1
- package/workflows/documents/orphanBlobReclaims.js.map +1 -1
- package/workflows/documents/projectionKeys.d.ts +1 -1
- package/workflows/documents/purge.d.ts +1 -1
- package/workflows/documents/purge.js +2 -2
- package/workflows/documents/purge.js.map +1 -1
- package/workflows/documents/readOnlySync.d.ts +1 -1
- package/workflows/documents/readOnlySync.js +1 -1
- package/workflows/documents/readOnlySync.js.map +1 -1
- package/workflows/documents/sync.js +1 -1
- package/workflows/documents/syncContainerRekeyPreparation.js +1 -1
- package/workflows/documents/syncLane.d.ts +1 -1
- package/workflows/documents/syncLane.js.map +1 -1
- package/workflows/documents/syncPlanIdentity.js +1 -1
- package/workflows/documents/syncPlanIdentity.js.map +1 -1
- package/workflows/documents/syncRepairAccess.js +1 -1
- package/workflows/documents/syncSubmittedResult.js +1 -1
- package/workflows/organizations/authoredPrincipalPolicyWarmer.js +1 -1
- package/workflows/organizations/authoredPrincipalPolicyWarmer.js.map +1 -1
- package/workflows/organizations/containerGrantRevocation.d.ts +2 -2
- package/workflows/organizations/containerGrantRevocation.js.map +1 -1
- package/workflows/organizations/createCurrentOrganizationGroup.js.map +1 -1
- package/workflows/organizations/currentOrganizationGroupNames.js.map +1 -1
- package/workflows/organizations/currentPolicyMutationAcknowledgement.js +1 -1
- package/workflows/organizations/currentPolicyMutationAcknowledgement.js.map +1 -1
- package/workflows/organizations/groupCreation.d.ts +1 -1
- package/workflows/organizations/groupCreation.js.map +1 -1
- package/workflows/organizations/groupMetadataAccess.d.ts +1 -1
- package/workflows/organizations/groupMetadataContainerAuthority.js.map +1 -1
- package/workflows/organizations/groupMetadataRuntime.js.map +1 -1
- package/workflows/organizations/groupNameUniqueness.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationAcknowledgement.js +1 -1
- package/workflows/organizations/groupPolicyMutationAcknowledgement.js.map +1 -1
- package/workflows/organizations/groupPolicyRequests.js.map +1 -1
- package/workflows/organizations/loadPolicyHistoryDetails.js.map +1 -1
- package/workflows/organizations/organizationGroupDirectory.js.map +1 -1
- package/workflows/organizations/organizationProfile.js +1 -1
- package/workflows/organizations/organizationProfile.js.map +1 -1
- package/workflows/organizations/policyHistoryCache.js.map +1 -1
- package/workflows/organizations/principalContainerRematerialization.js +1 -1
- package/workflows/organizations/principalContainerRematerializationPlanning.js.map +1 -1
- package/workflows/organizations/principalMutationJournalManagement.js +1 -1
- package/workflows/organizations/principalMutationJournalManagement.js.map +1 -1
- package/workflows/organizations/principalMutationReceipt.js +1 -1
- package/workflows/organizations/principalMutationReceipt.js.map +1 -1
- package/workflows/organizations/principalPolicy.d.ts +1 -1
- package/workflows/organizations/principalPolicy.js.map +1 -1
- package/workflows/organizations/principalPolicyReceiptArtifacts.js +1 -1
- package/workflows/organizations/principalPolicyReceiptArtifacts.js.map +1 -1
- package/workflows/organizations/rosterProfileContainer.js +1 -1
- package/workflows/organizations/rosterProfileContainer.js.map +1 -1
- package/workflows/principals/policyCache.d.ts +1 -1
- package/workflows/principals/policyCache.js +2 -2
- package/workflows/principals/policyCache.js.map +1 -1
- package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
- package/workflows/principals/runtimePolicyWarmer.js +1 -1
- package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
- package/workflows/registration/persistRegistrationBootstrap.js +1 -1
- package/workflows/registration/persistRegistrationBootstrap.js.map +1 -1
- package/workflows/runtimeInput.d.ts +3 -3
- package/workflows/runtimeInput.js.map +1 -1
- package/workflows/sync/index.d.ts +2 -1
- package/workflows/sync/index.js +2 -1
- package/workflows/sync/index.js.map +1 -1
- package/client/blobs.js.map +0 -1
- package/client/containerContents.js.map +0 -1
- package/client/containerContentsTypes.js +0 -2
- package/client/containerContentsTypes.js.map +0 -1
- package/client/containerDocumentDiscovery.js.map +0 -1
- package/client/database.js.map +0 -1
- package/client/deviceFirst.js.map +0 -1
- package/client/documents.js.map +0 -1
- package/client/identity.js.map +0 -1
- package/client/identityKeyPackage.js.map +0 -1
- package/client/principalHistoryProtection.js.map +0 -1
- package/client/principalMutationApi.js.map +0 -1
- package/client/principalMutationDispatch.js.map +0 -1
- package/client/reconciledDocumentContentPull.js.map +0 -1
- package/client/rootContainerAdoption.js.map +0 -1
- package/client/securityIncidents.js.map +0 -1
- package/client/userIdentities.js.map +0 -1
- package/client/workflowRuntime.js.map +0 -1
- package/data/keyingCanonicalJson.js.map +0 -1
- package/data/keyingProjectionVerification.d.ts +0 -9
- package/data/keyingProjectionVerification.js.map +0 -1
- /package/client/{fileSaver.d.ts → host/fileSaver.d.ts} +0 -0
- /package/client/{fileSaver.js → host/fileSaver.js} +0 -0
- /package/client/{fileSaver.js.map → host/fileSaver.js.map} +0 -0
- /package/client/{logger.d.ts → host/logger.d.ts} +0 -0
- /package/client/{logger.js → host/logger.js} +0 -0
- /package/client/{logger.js.map → host/logger.js.map} +0 -0
- /package/client/{apiVersion.d.ts → runtime/apiVersion.d.ts} +0 -0
- /package/client/{apiVersion.js → runtime/apiVersion.js} +0 -0
- /package/client/{apiVersion.js.map → runtime/apiVersion.js.map} +0 -0
- /package/client/{events.d.ts → runtime/events.d.ts} +0 -0
- /package/client/{events.js → runtime/events.js} +0 -0
- /package/client/{events.js.map → runtime/events.js.map} +0 -0
- /package/client/{listenerSet.js → runtime/listenerSet.js} +0 -0
- /package/client/{listenerSet.js.map → runtime/listenerSet.js.map} +0 -0
- /package/client/{network.d.ts → runtime/network.d.ts} +0 -0
- /package/client/{network.js → runtime/network.js} +0 -0
- /package/client/{network.js.map → runtime/network.js.map} +0 -0
- /package/client/{principalMutationDeadline.js → runtime/principalMutationDeadline.js} +0 -0
- /package/client/{principalMutationDeadline.js.map → runtime/principalMutationDeadline.js.map} +0 -0
- /package/client/{rootContainerAdoption.js → runtime/rootContainerAdoption.js} +0 -0
- /package/client/{syncBillingGate.d.ts → runtime/syncBillingGate.d.ts} +0 -0
- /package/client/{syncBillingGate.js → runtime/syncBillingGate.js} +0 -0
- /package/client/{syncBillingGate.js.map → runtime/syncBillingGate.js.map} +0 -0
- /package/data/{blobContracts.d.ts → blobs/blobContracts.d.ts} +0 -0
- /package/data/{blobContracts.js → blobs/blobContracts.js} +0 -0
- /package/data/{blobContracts.js.map → blobs/blobContracts.js.map} +0 -0
- /package/data/{accessLevel.js → keying/accessLevel.js} +0 -0
- /package/data/{accessLevel.js.map → keying/accessLevel.js.map} +0 -0
- /package/data/{stableUuid.js → keying/stableUuid.js} +0 -0
- /package/data/{stableUuid.js.map → keying/stableUuid.js.map} +0 -0
- /package/data/{principalPolicyStates.js → principals/principalPolicyStates.js} +0 -0
- /package/data/{principalPolicyStates.js.map → principals/principalPolicyStates.js.map} +0 -0
- /package/data/{domainScope.d.ts → shared/domainScope.d.ts} +0 -0
- /package/data/{domainScope.js → shared/domainScope.js} +0 -0
- /package/data/{domainScope.js.map → shared/domainScope.js.map} +0 -0
- /package/data/{errorMessage.js → shared/errorMessage.js} +0 -0
- /package/data/{errorMessage.js.map → shared/errorMessage.js.map} +0 -0
- /package/data/{recordReaders.d.ts → shared/recordReaders.d.ts} +0 -0
- /package/data/{recordReaders.js → shared/recordReaders.js} +0 -0
- /package/data/{recordReaders.js.map → shared/recordReaders.js.map} +0 -0
- /package/data/{securityIncidents.js → shared/securityIncidents.js} +0 -0
- /package/data/{securityIncidents.js.map → shared/securityIncidents.js.map} +0 -0
- /package/data/{crdtPeerSeed.js → sync/crdtPeerSeed.js} +0 -0
- /package/data/{crdtPeerSeed.js.map → sync/crdtPeerSeed.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detach.js","sourceRoot":"","sources":["detach.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,kCAAkC,EAAE,MAAM,4CAA4C,CAAC;AAKhG,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"detach.js","sourceRoot":"","sources":["detach.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,kCAAkC,EAAE,MAAM,4CAA4C,CAAC;AAKhG,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,gCAAgC,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,EAC7C,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,EACN,UAAU,EACV,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,EAC7B,OAAO,EACP,mBAAmB,EACnB,wBAAwB,EACxB,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EACnC,MAAM,EACN,YAAY,EACZ,+BAA+B,EAC/B,gBAAgB,GACc;IAC9B,MAAM,QAAQ,GAAG,MAAM,mCAAmC,CAAC;QACzD,SAAS;QACT,UAAU;QACV,UAAU,EAAE,wBAAwB;QACpC,OAAO;QACP,mBAAmB;QACnB,YAAY;QACZ,+BAA+B;QAC/B,wBAAwB,EAAE,gCAAgC,CACxD,wBAAwB,EACxB,4BAA4B,CAC7B;QACD,gBAAgB;KACjB,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,GACpE,QAAQ,CAAC;IAEX,MAAM,QAAQ,GAAG,4BAA4B,CAAC,wBAAwB,CAAC,CAAC;IACxE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,6BAA6B,CAAC;QAC1D,MAAM;QACN,SAAS;QACT,MAAM;QACN,UAAU;QACV,OAAO;QACP,gBAAgB;QAChB,QAAQ;QACR,MAAM;QACN,4BAA4B,EAAE,QAAQ;KACvC,CAAC,CAAC;IACH,MAAM,OAAO,GAAgC;QAC3C,KAAK,EAAE,mBAAmB,CAAC,KAAK,EAAE,8BAA8B,CAAC;QACjE,IAAI,EAAE,mBAAmB,CAAC,IAAI,EAAE,6BAA6B,CAAC;QAC9D,4BAA4B,EAAE,QAAQ;KACvC,CAAC;IACF,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,oBAAoB,CACnD,MAAM,EACN,SAAS,EACT,OAAO,EACP;QACE,qCAAqC,EAAE,gBAAgB,CAAC,cAAc;KACvE,CACF,CAAC;IACF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IACD,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAElD,kCAAkC,CAAC;QACjC,SAAS;QACT,MAAM;QACN,UAAU;QACV,QAAQ;QACR,MAAM;KACP,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;QACP,QAAQ;QACR,gBAAgB,EAAE,wBAAwB;KAC3C,CAAC;AACJ,CAAC","sourcesContent":["import type { BlobAttachmentDetachRequest } from \"@tearleads/validators/request\";\nimport { signBlobAttachmentDetachEvent } from \"../../data/documents/blob/shared/events\";\nimport { assertBlobAttachmentDetachResponse } from \"../../data/documents/blob/shared/responses\";\nimport type {\n DetachDocumentAttachmentInput,\n DetachDocumentAttachmentResult,\n} from \"../../data/documents/blob/shared/types\";\nimport { authorizingContainerPathRefs } from \"../../data/documents/shared/projection\";\nimport { readCanonicalRecord } from \"../../data/keying/canonicalJson\";\nimport { requireProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { resolveBlobMutationWriterProjection } from \"./writerProjection\";\n\nexport async function detachDocumentAttachment({\n apiClient,\n author,\n bindingId,\n blobId,\n documentId,\n eventId = crypto.randomUUID(),\n execSql,\n isRemoteSyncBlocked,\n resolveProjectionUserKey,\n signedAt = new Date().toISOString(),\n slotId,\n stillCurrent,\n warmReferencedPrincipalPolicies,\n writerProjection,\n}: DetachDocumentAttachmentInput): Promise<DetachDocumentAttachmentResult | null> {\n const resolved = await resolveBlobMutationWriterProjection({\n apiClient,\n documentId,\n errorLabel: \"Blob attachment detach\",\n execSql,\n isRemoteSyncBlocked,\n stillCurrent,\n warmReferencedPrincipalPolicies,\n resolveProjectionUserKey: requireProjectionUserKeyResolver(\n resolveProjectionUserKey,\n \"Document attachment detach\",\n ),\n writerProjection,\n });\n if (!resolved) {\n return null;\n }\n const { manifestIdentity, writerProjection: resolvedWriterProjection } =\n resolved;\n\n const pathRefs = authorizingContainerPathRefs(resolvedWriterProjection);\n const { body, event } = await signBlobAttachmentDetachEvent({\n author,\n bindingId,\n blobId,\n documentId,\n eventId,\n manifestIdentity,\n signedAt,\n slotId,\n authorizingContainerPathRefs: pathRefs,\n });\n const request: BlobAttachmentDetachRequest = {\n event: readCanonicalRecord(event, \"Blob attachment detach event\"),\n body: readCanonicalRecord(body, \"Blob attachment detach body\"),\n authorizingContainerPathRefs: pathRefs,\n };\n assertProjectionVerificationCurrent(stillCurrent);\n const response = await apiClient.detachBlobAttachment(\n blobId,\n bindingId,\n request,\n {\n expectedPaymentRequiredOrganizationId: manifestIdentity.organizationId,\n },\n );\n if (!response) {\n return null;\n }\n assertProjectionVerificationCurrent(stillCurrent);\n\n assertBlobAttachmentDetachResponse({\n bindingId,\n blobId,\n documentId,\n response,\n slotId,\n });\n\n return {\n request,\n response,\n writerProjection: resolvedWriterProjection,\n };\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { BlobBytesResponse, RequestResultOptions } from "../../internal/api-client/index.js";
|
|
2
2
|
import type { BlobAttachmentSummary, DocumentWriterProjectionResponse, ListDocumentAttachmentsResponse } from "../../internal/validators/response/index.js";
|
|
3
|
-
import type { BlobBytes } from "../../data/blobContracts.js";
|
|
3
|
+
import type { BlobBytes } from "../../data/blobs/blobContracts.js";
|
|
4
4
|
import type { DocumentAttachment } from "../../data/documents/documentContent.js";
|
|
5
|
-
import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../data/keyingProjectionVerification.js";
|
|
6
|
-
import type { SecurityIncidentReporter } from "../../data/securityIncidents.js";
|
|
5
|
+
import type { ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer } from "../../data/keyingProjectionVerification/index.js";
|
|
6
|
+
import type { SecurityIncidentReporter } from "../../data/shared/securityIncidents.js";
|
|
7
7
|
import type { ExecSql } from "../../data/sqlite/sqlSchema.js";
|
|
8
8
|
interface DocumentAttachmentHydrationApi {
|
|
9
9
|
evictDocumentWriterProjection?(documentId: string): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { bytesToHex } from "../../internal/crypto/index.js";
|
|
2
2
|
import { runBlobTransfer } from "../../data/blobs/transferPool.js";
|
|
3
3
|
import { attachmentContentSha256 } from "../../data/documents/attachmentContentIdentity.js";
|
|
4
|
-
import { errorMessage } from "../../data/errorMessage.js";
|
|
4
|
+
import { errorMessage } from "../../data/shared/errorMessage.js";
|
|
5
5
|
import { createAttachmentDecryptor } from "./attachmentDecryptor.js";
|
|
6
6
|
import { collectHydrationResults } from "./hydrationResults.js";
|
|
7
7
|
import { readAttachmentTransfer } from "./readAttachmentTransfer.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["hydrate.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BlobBytesResponse,\n RequestResultOptions,\n} from \"@tearleads/api-client\";\nimport { bytesToHex } from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentSummary,\n DocumentWriterProjectionResponse,\n ListDocumentAttachmentsResponse,\n} from \"@tearleads/validators/response\";\nimport type { BlobBytes } from \"../../data/blobContracts\";\nimport { runBlobTransfer } from \"../../data/blobs/transferPool\";\nimport { attachmentContentSha256 } from \"../../data/documents/attachmentContentIdentity\";\nimport type { DocumentAttachment } from \"../../data/documents/documentContent\";\nimport { errorMessage } from \"../../data/errorMessage\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { createAttachmentDecryptor } from \"./attachmentDecryptor\";\nimport { collectHydrationResults } from \"./hydrationResults\";\nimport { readAttachmentTransfer } from \"./readAttachmentTransfer\";\n\ninterface DocumentAttachmentHydrationApi {\n evictDocumentWriterProjection?(documentId: string): void;\n getBlobBytes(\n blobId: string,\n options?: RequestResultOptions,\n ): Promise<BlobBytesResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n listDocumentAttachments(\n documentId: string,\n ): Promise<ListDocumentAttachmentsResponse | null>;\n}\n\ninterface HydratedDocumentAttachmentBlob {\n attachment: DocumentAttachment;\n binding: BlobAttachmentSummary;\n bytes: BlobBytes;\n /** Plaintext digest of `bytes`. */\n contentSha256: string;\n /**\n * The served binding is validly signed but its plaintext digest differs\n * from the digest the document content records for the slot. Set only when\n * the slot held no local bytes: the bind and the content update carrying\n * its digest are two server writes, and an uploader lost between them must\n * not leave the attachment permanently invisible. Never a security incident;\n * an honest crash window is indistinguishable from a served rollback.\n */\n intentMismatch: boolean;\n storageKey: string;\n}\n\ninterface DocumentAttachmentHydrationContext {\n apiClient: DocumentAttachmentHydrationApi;\n documentId: string;\n execSql: ExecSql;\n localBlobIdBySlotId?:\n | Readonly<Record<string, string | null | undefined>>\n | undefined;\n localStorageKeyBySlotId?: Readonly<Record<string, string | undefined>>;\n log?: ((message: string) => void) | undefined;\n logPrefix?: string | undefined;\n /**\n * Served bindings already downloaded and refused for a held copy, keyed per\n * (slot, binding, intent). Populated here; a later pass skips the download\n * until the binding or the document intent changes.\n */\n rejectedServedBindings?: Set<string> | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n reportSecurityIncident?: SecurityIncidentReporter | undefined;\n targetSecretKey: Uint8Array;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}\n\nfunction servedBindingRejectionKey(\n attachment: DocumentAttachment,\n binding: BlobAttachmentSummary,\n): string {\n return JSON.stringify([\n attachment.slotId,\n binding.bindingId,\n attachment.contentSha256,\n ]);\n}\n\ninterface DocumentAttachmentHydrationTarget {\n attachment: DocumentAttachment;\n binding: BlobAttachmentSummary;\n}\n\ninterface LoadedDocumentAttachmentBlob\n extends DocumentAttachmentHydrationTarget {\n encryptedBytes: Uint8Array<ArrayBuffer>;\n}\n\ninterface LoadedDocumentAttachmentBlobBytes {\n blobId: string;\n encryptedBytes: Uint8Array<ArrayBuffer>;\n}\n\nasync function hasExpectedBlobSha256(\n blob: BlobBytesResponse,\n encryptedBytes: Uint8Array<ArrayBuffer>,\n): Promise<boolean> {\n const blobDigest = new Uint8Array(\n await crypto.subtle.digest(\"SHA-256\", encryptedBytes),\n );\n\n return bytesToHex(blobDigest) === blob.sha256;\n}\n\nfunction shouldHydrateAttachment(input: {\n attachment: DocumentAttachment;\n binding: BlobAttachmentSummary;\n localBlobIdBySlotId:\n | Readonly<Record<string, string | null | undefined>>\n | undefined;\n localStorageKeyBySlotId:\n | Readonly<Record<string, string | undefined>>\n | undefined;\n rejectedServedBindings: ReadonlySet<string> | undefined;\n}): boolean {\n const slotId = input.attachment.slotId;\n const localStorageKey = input.localStorageKeyBySlotId?.[slotId];\n // An empty slot always hydrates: a rejection only ever protected a held\n // copy, so once that copy is gone the served binding is shown (flagged).\n if (!localStorageKey) {\n return true;\n }\n if (\n input.rejectedServedBindings?.has(\n servedBindingRejectionKey(input.attachment, input.binding),\n )\n ) {\n return false;\n }\n\n const localBlobId = input.localBlobIdBySlotId?.[slotId];\n return localBlobId !== null && localBlobId !== input.binding.blobId;\n}\n\nasync function loadDocumentAttachmentBlob(\n input: DocumentAttachmentHydrationContext & {\n binding: BlobAttachmentSummary;\n signal: AbortSignal;\n progress: () => void;\n },\n): Promise<LoadedDocumentAttachmentBlobBytes | null> {\n const { apiClient, binding, log } = input;\n const logPrefix = input.logPrefix ?? \"Documents\";\n if (input.stillCurrent?.() === false) return null;\n input.signal.throwIfAborted();\n const blob = await apiClient.getBlobBytes(binding.blobId, {\n signal: input.signal,\n });\n if (!blob) {\n return null;\n }\n\n let encryptedBytes: Uint8Array<ArrayBuffer>;\n try {\n encryptedBytes = await readAttachmentTransfer(\n blob,\n input.signal,\n input.progress,\n );\n } catch (error) {\n log?.(\n `${logPrefix}: blob ${binding.blobId} failed to stream during hydration: ${errorMessage(\n error,\n )}`,\n );\n return null;\n }\n\n if (encryptedBytes.byteLength !== blob.byteLength) {\n log?.(\n `${logPrefix}: blob ${binding.blobId} byte length mismatch during hydration.`,\n );\n return null;\n }\n\n if (!(await hasExpectedBlobSha256(blob, encryptedBytes))) {\n log?.(\n `${logPrefix}: blob ${binding.blobId} sha256 mismatch during hydration.`,\n );\n return null;\n }\n\n input.signal.throwIfAborted();\n return {\n blobId: binding.blobId,\n encryptedBytes,\n };\n}\n\nasync function loadUniqueDocumentAttachmentBlobs(\n input: DocumentAttachmentHydrationContext & {\n hydrationTargets: ReadonlyArray<DocumentAttachmentHydrationTarget>;\n },\n): Promise<ReadonlyMap<string, LoadedDocumentAttachmentBlobBytes>> {\n const targetsByBlobId = new Map<string, DocumentAttachmentHydrationTarget>();\n for (const target of input.hydrationTargets) {\n if (!targetsByBlobId.has(target.binding.blobId)) {\n targetsByBlobId.set(target.binding.blobId, target);\n }\n }\n\n const loadedBlobs = await collectHydrationResults({\n ...input,\n tasks: Array.from(targetsByBlobId.values()).map((target) => ({\n blobId: target.binding.blobId,\n run: () =>\n runBlobTransfer(input.apiClient, (signal, progress) =>\n loadDocumentAttachmentBlob({\n ...input,\n binding: target.binding,\n signal,\n progress,\n }),\n ),\n })),\n });\n\n return new Map(\n loadedBlobs.flatMap((loaded) =>\n loaded ? [[loaded.blobId, loaded] as const] : [],\n ),\n );\n}\n\nfunction applyLoadedBlobBytesToHydrationTargets(\n hydrationTargets: ReadonlyArray<DocumentAttachmentHydrationTarget>,\n loadedBlobsByBlobId: ReadonlyMap<string, LoadedDocumentAttachmentBlobBytes>,\n): LoadedDocumentAttachmentBlob[] {\n return hydrationTargets.flatMap((target) => {\n const loaded = loadedBlobsByBlobId.get(target.binding.blobId);\n return loaded\n ? [\n {\n ...target,\n encryptedBytes: loaded.encryptedBytes,\n },\n ]\n : [];\n });\n}\n\nasync function decryptLoadedDocumentAttachmentBlob(\n input: DocumentAttachmentHydrationContext & {\n loaded: LoadedDocumentAttachmentBlob;\n decryptAttachment: ReturnType<typeof createAttachmentDecryptor>;\n writerProjection: DocumentWriterProjectionResponse;\n },\n): Promise<HydratedDocumentAttachmentBlob | null> {\n const bytes = await input.decryptAttachment({\n binding: input.loaded.binding,\n encryptedBytes: input.loaded.encryptedBytes,\n expectedDocumentId: input.documentId,\n expectedSlotId: input.loaded.attachment.slotId,\n execSql: input.execSql,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n targetSecretKey: input.targetSecretKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n writerProjection: input.writerProjection,\n });\n\n const { attachment, binding } = input.loaded;\n const contentSha256 = await attachmentContentSha256(bytes);\n const intentMismatch = contentSha256 !== attachment.contentSha256;\n const logPrefix = input.logPrefix ?? \"Documents\";\n if (intentMismatch && input.localStorageKeyBySlotId?.[attachment.slotId]) {\n // Never replace a held copy with bytes the document does not record.\n input.rejectedServedBindings?.add(\n servedBindingRejectionKey(attachment, binding),\n );\n input.log?.(\n `${logPrefix}: served attachment bytes differ from the current document content; keeping the held copy.`,\n );\n return null;\n }\n if (intentMismatch) {\n input.log?.(\n `${logPrefix}: served attachment bytes differ from the current document content; showing them flagged.`,\n );\n }\n return {\n attachment,\n binding,\n bytes,\n contentSha256,\n intentMismatch,\n storageKey: `blob-${binding.blobId}`,\n };\n}\n\nexport async function hydrateDocumentAttachmentBlobs(\n input: DocumentAttachmentHydrationContext & {\n attachments: ReadonlyArray<DocumentAttachment>;\n /** No binding target remains unchecked or unavailable in this pass. */\n onBindingsChecked?: () => void;\n },\n): Promise<HydratedDocumentAttachmentBlob[] | null> {\n const attachmentBindings = await input.apiClient.listDocumentAttachments(\n input.documentId,\n );\n if (!attachmentBindings) {\n return null;\n }\n\n const bindingBySlotId = new Map(\n attachmentBindings.map((binding) => [binding.slotId, binding]),\n );\n const hydrationTargets: DocumentAttachmentHydrationTarget[] =\n input.attachments.flatMap((attachment) => {\n const binding = bindingBySlotId.get(attachment.slotId);\n return binding &&\n shouldHydrateAttachment({\n attachment,\n binding,\n localBlobIdBySlotId: input.localBlobIdBySlotId,\n localStorageKeyBySlotId: input.localStorageKeyBySlotId,\n rejectedServedBindings: input.rejectedServedBindings,\n })\n ? [{ attachment, binding }]\n : [];\n });\n if (hydrationTargets.length === 0) {\n input.onBindingsChecked?.();\n return [];\n }\n\n const loadedBlobs = applyLoadedBlobBytesToHydrationTargets(\n hydrationTargets,\n await loadUniqueDocumentAttachmentBlobs({\n ...input,\n hydrationTargets,\n }),\n );\n if (loadedBlobs.length === 0) {\n return [];\n }\n\n const writerProjection = await input.apiClient.getDocumentWriterProjection(\n input.documentId,\n );\n if (!writerProjection) {\n const logPrefix = input.logPrefix ?? \"Documents\";\n input.log?.(\n `${logPrefix}: cannot hydrate attachments for document ${input.documentId} without a writer projection.`,\n );\n return [];\n }\n\n const decryptAttachment = createAttachmentDecryptor(\n input.apiClient,\n input.documentId,\n );\n const hydrated = await collectHydrationResults({\n ...input,\n tasks: loadedBlobs.map((loaded) => ({\n blobId: loaded.binding.blobId,\n run: () =>\n decryptLoadedDocumentAttachmentBlob({\n ...input,\n decryptAttachment,\n loaded,\n writerProjection,\n }),\n })),\n });\n const complete = hydrated.filter(\n (item): item is HydratedDocumentAttachmentBlob => item !== null,\n );\n if (complete.length === hydrationTargets.length) input.onBindingsChecked?.();\n return complete;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["hydrate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAO/C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AAMzF,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAyDlE,SAAS,yBAAyB,CAChC,UAA8B,EAC9B,OAA8B;IAE9B,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,UAAU,CAAC,MAAM;QACjB,OAAO,CAAC,SAAS;QACjB,UAAU,CAAC,aAAa;KACzB,CAAC,CAAC;AACL,CAAC;AAiBD,KAAK,UAAU,qBAAqB,CAClC,IAAuB,EACvB,cAAuC;IAEvC,MAAM,UAAU,GAAG,IAAI,UAAU,CAC/B,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CACtD,CAAC;IAEF,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC;AAChD,CAAC;AAED,SAAS,uBAAuB,CAAC,KAUhC;IACC,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;IACvC,MAAM,eAAe,GAAG,KAAK,CAAC,uBAAuB,EAAE,CAAC,MAAM,CAAC,CAAC;IAChE,wEAAwE;IACxE,yEAAyE;IACzE,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IACE,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAC/B,yBAAyB,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAC3D,EACD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,mBAAmB,EAAE,CAAC,MAAM,CAAC,CAAC;IACxD,OAAO,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;AACtE,CAAC;AAED,KAAK,UAAU,0BAA0B,CACvC,KAIC;IAED,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,WAAW,CAAC;IACjD,IAAI,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAClD,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE;QACxD,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,cAAuC,CAAC;IAC5C,IAAI,CAAC;QACH,cAAc,GAAG,MAAM,sBAAsB,CAC3C,IAAI,EACJ,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,QAAQ,CACf,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,EAAE,CACH,GAAG,SAAS,UAAU,OAAO,CAAC,MAAM,uCAAuC,YAAY,CACrF,KAAK,CACN,EAAE,CACJ,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,cAAc,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;QAClD,GAAG,EAAE,CACH,GAAG,SAAS,UAAU,OAAO,CAAC,MAAM,yCAAyC,CAC9E,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,qBAAqB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QACzD,GAAG,EAAE,CACH,GAAG,SAAS,UAAU,OAAO,CAAC,MAAM,oCAAoC,CACzE,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;IAC9B,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,cAAc;KACf,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,iCAAiC,CAC9C,KAEC;IAED,MAAM,eAAe,GAAG,IAAI,GAAG,EAA6C,CAAC;IAC7E,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;QAC5C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAChD,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,uBAAuB,CAAC;QAChD,GAAG,KAAK;QACR,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC3D,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;YAC7B,GAAG,EAAE,GAAG,EAAE,CACR,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CACpD,0BAA0B,CAAC;gBACzB,GAAG,KAAK;gBACR,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,MAAM;gBACN,QAAQ;aACT,CAAC,CACH;SACJ,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,OAAO,IAAI,GAAG,CACZ,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CACjD,CACF,CAAC;AACJ,CAAC;AAED,SAAS,sCAAsC,CAC7C,gBAAkE,EAClE,mBAA2E;IAE3E,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACzC,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9D,OAAO,MAAM;YACX,CAAC,CAAC;gBACE;oBACE,GAAG,MAAM;oBACT,cAAc,EAAE,MAAM,CAAC,cAAc;iBACtC;aACF;YACH,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,mCAAmC,CAChD,KAIC;IAED,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC1C,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;QAC7B,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,cAAc;QAC3C,kBAAkB,EAAE,KAAK,CAAC,UAAU;QACpC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM;QAC9C,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;QACxD,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;QACtE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;KACzC,CAAC,CAAC;IAEH,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;IAC7C,MAAM,aAAa,GAAG,MAAM,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,cAAc,GAAG,aAAa,KAAK,UAAU,CAAC,aAAa,CAAC;IAClE,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,WAAW,CAAC;IACjD,IAAI,cAAc,IAAI,KAAK,CAAC,uBAAuB,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzE,qEAAqE;QACrE,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAC/B,yBAAyB,CAAC,UAAU,EAAE,OAAO,CAAC,CAC/C,CAAC;QACF,KAAK,CAAC,GAAG,EAAE,CACT,GAAG,SAAS,4FAA4F,CACzG,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,cAAc,EAAE,CAAC;QACnB,KAAK,CAAC,GAAG,EAAE,CACT,GAAG,SAAS,2FAA2F,CACxG,CAAC;IACJ,CAAC;IACD,OAAO;QACL,UAAU;QACV,OAAO;QACP,KAAK;QACL,aAAa;QACb,cAAc;QACd,UAAU,EAAE,QAAQ,OAAO,CAAC,MAAM,EAAE;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,KAIC;IAED,MAAM,kBAAkB,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,uBAAuB,CACtE,KAAK,CAAC,UAAU,CACjB,CAAC;IACF,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,kBAAkB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAC/D,CAAC;IACF,MAAM,gBAAgB,GACpB,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;QACvC,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACvD,OAAO,OAAO;YACZ,uBAAuB,CAAC;gBACtB,UAAU;gBACV,OAAO;gBACP,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;gBAC9C,uBAAuB,EAAE,KAAK,CAAC,uBAAuB;gBACtD,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;aACrD,CAAC;YACF,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;YAC3B,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;IACL,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,WAAW,GAAG,sCAAsC,CACxD,gBAAgB,EAChB,MAAM,iCAAiC,CAAC;QACtC,GAAG,KAAK;QACR,gBAAgB;KACjB,CAAC,CACH,CAAC;IACF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,2BAA2B,CACxE,KAAK,CAAC,UAAU,CACjB,CAAC;IACF,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,WAAW,CAAC;QACjD,KAAK,CAAC,GAAG,EAAE,CACT,GAAG,SAAS,6CAA6C,KAAK,CAAC,UAAU,+BAA+B,CACzG,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,iBAAiB,GAAG,yBAAyB,CACjD,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,UAAU,CACjB,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC;QAC7C,GAAG,KAAK;QACR,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAClC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;YAC7B,GAAG,EAAE,GAAG,EAAE,CACR,mCAAmC,CAAC;gBAClC,GAAG,KAAK;gBACR,iBAAiB;gBACjB,MAAM;gBACN,gBAAgB;aACjB,CAAC;SACL,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAC9B,CAAC,IAAI,EAA0C,EAAE,CAAC,IAAI,KAAK,IAAI,CAChE,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM;QAAE,KAAK,CAAC,iBAAiB,EAAE,EAAE,CAAC;IAC7E,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import type {\n BlobBytesResponse,\n RequestResultOptions,\n} from \"@tearleads/api-client\";\nimport { bytesToHex } from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentSummary,\n DocumentWriterProjectionResponse,\n ListDocumentAttachmentsResponse,\n} from \"@tearleads/validators/response\";\nimport type { BlobBytes } from \"../../data/blobs/blobContracts\";\nimport { runBlobTransfer } from \"../../data/blobs/transferPool\";\nimport { attachmentContentSha256 } from \"../../data/documents/attachmentContentIdentity\";\nimport type { DocumentAttachment } from \"../../data/documents/documentContent\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification\";\nimport { errorMessage } from \"../../data/shared/errorMessage\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { createAttachmentDecryptor } from \"./attachmentDecryptor\";\nimport { collectHydrationResults } from \"./hydrationResults\";\nimport { readAttachmentTransfer } from \"./readAttachmentTransfer\";\n\ninterface DocumentAttachmentHydrationApi {\n evictDocumentWriterProjection?(documentId: string): void;\n getBlobBytes(\n blobId: string,\n options?: RequestResultOptions,\n ): Promise<BlobBytesResponse | null>;\n getDocumentWriterProjection(\n documentId: string,\n ): Promise<DocumentWriterProjectionResponse | null>;\n listDocumentAttachments(\n documentId: string,\n ): Promise<ListDocumentAttachmentsResponse | null>;\n}\n\ninterface HydratedDocumentAttachmentBlob {\n attachment: DocumentAttachment;\n binding: BlobAttachmentSummary;\n bytes: BlobBytes;\n /** Plaintext digest of `bytes`. */\n contentSha256: string;\n /**\n * The served binding is validly signed but its plaintext digest differs\n * from the digest the document content records for the slot. Set only when\n * the slot held no local bytes: the bind and the content update carrying\n * its digest are two server writes, and an uploader lost between them must\n * not leave the attachment permanently invisible. Never a security incident;\n * an honest crash window is indistinguishable from a served rollback.\n */\n intentMismatch: boolean;\n storageKey: string;\n}\n\ninterface DocumentAttachmentHydrationContext {\n apiClient: DocumentAttachmentHydrationApi;\n documentId: string;\n execSql: ExecSql;\n localBlobIdBySlotId?:\n | Readonly<Record<string, string | null | undefined>>\n | undefined;\n localStorageKeyBySlotId?: Readonly<Record<string, string | undefined>>;\n log?: ((message: string) => void) | undefined;\n logPrefix?: string | undefined;\n /**\n * Served bindings already downloaded and refused for a held copy, keyed per\n * (slot, binding, intent). Populated here; a later pass skips the download\n * until the binding or the document intent changes.\n */\n rejectedServedBindings?: Set<string> | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n reportSecurityIncident?: SecurityIncidentReporter | undefined;\n targetSecretKey: Uint8Array;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}\n\nfunction servedBindingRejectionKey(\n attachment: DocumentAttachment,\n binding: BlobAttachmentSummary,\n): string {\n return JSON.stringify([\n attachment.slotId,\n binding.bindingId,\n attachment.contentSha256,\n ]);\n}\n\ninterface DocumentAttachmentHydrationTarget {\n attachment: DocumentAttachment;\n binding: BlobAttachmentSummary;\n}\n\ninterface LoadedDocumentAttachmentBlob\n extends DocumentAttachmentHydrationTarget {\n encryptedBytes: Uint8Array<ArrayBuffer>;\n}\n\ninterface LoadedDocumentAttachmentBlobBytes {\n blobId: string;\n encryptedBytes: Uint8Array<ArrayBuffer>;\n}\n\nasync function hasExpectedBlobSha256(\n blob: BlobBytesResponse,\n encryptedBytes: Uint8Array<ArrayBuffer>,\n): Promise<boolean> {\n const blobDigest = new Uint8Array(\n await crypto.subtle.digest(\"SHA-256\", encryptedBytes),\n );\n\n return bytesToHex(blobDigest) === blob.sha256;\n}\n\nfunction shouldHydrateAttachment(input: {\n attachment: DocumentAttachment;\n binding: BlobAttachmentSummary;\n localBlobIdBySlotId:\n | Readonly<Record<string, string | null | undefined>>\n | undefined;\n localStorageKeyBySlotId:\n | Readonly<Record<string, string | undefined>>\n | undefined;\n rejectedServedBindings: ReadonlySet<string> | undefined;\n}): boolean {\n const slotId = input.attachment.slotId;\n const localStorageKey = input.localStorageKeyBySlotId?.[slotId];\n // An empty slot always hydrates: a rejection only ever protected a held\n // copy, so once that copy is gone the served binding is shown (flagged).\n if (!localStorageKey) {\n return true;\n }\n if (\n input.rejectedServedBindings?.has(\n servedBindingRejectionKey(input.attachment, input.binding),\n )\n ) {\n return false;\n }\n\n const localBlobId = input.localBlobIdBySlotId?.[slotId];\n return localBlobId !== null && localBlobId !== input.binding.blobId;\n}\n\nasync function loadDocumentAttachmentBlob(\n input: DocumentAttachmentHydrationContext & {\n binding: BlobAttachmentSummary;\n signal: AbortSignal;\n progress: () => void;\n },\n): Promise<LoadedDocumentAttachmentBlobBytes | null> {\n const { apiClient, binding, log } = input;\n const logPrefix = input.logPrefix ?? \"Documents\";\n if (input.stillCurrent?.() === false) return null;\n input.signal.throwIfAborted();\n const blob = await apiClient.getBlobBytes(binding.blobId, {\n signal: input.signal,\n });\n if (!blob) {\n return null;\n }\n\n let encryptedBytes: Uint8Array<ArrayBuffer>;\n try {\n encryptedBytes = await readAttachmentTransfer(\n blob,\n input.signal,\n input.progress,\n );\n } catch (error) {\n log?.(\n `${logPrefix}: blob ${binding.blobId} failed to stream during hydration: ${errorMessage(\n error,\n )}`,\n );\n return null;\n }\n\n if (encryptedBytes.byteLength !== blob.byteLength) {\n log?.(\n `${logPrefix}: blob ${binding.blobId} byte length mismatch during hydration.`,\n );\n return null;\n }\n\n if (!(await hasExpectedBlobSha256(blob, encryptedBytes))) {\n log?.(\n `${logPrefix}: blob ${binding.blobId} sha256 mismatch during hydration.`,\n );\n return null;\n }\n\n input.signal.throwIfAborted();\n return {\n blobId: binding.blobId,\n encryptedBytes,\n };\n}\n\nasync function loadUniqueDocumentAttachmentBlobs(\n input: DocumentAttachmentHydrationContext & {\n hydrationTargets: ReadonlyArray<DocumentAttachmentHydrationTarget>;\n },\n): Promise<ReadonlyMap<string, LoadedDocumentAttachmentBlobBytes>> {\n const targetsByBlobId = new Map<string, DocumentAttachmentHydrationTarget>();\n for (const target of input.hydrationTargets) {\n if (!targetsByBlobId.has(target.binding.blobId)) {\n targetsByBlobId.set(target.binding.blobId, target);\n }\n }\n\n const loadedBlobs = await collectHydrationResults({\n ...input,\n tasks: Array.from(targetsByBlobId.values()).map((target) => ({\n blobId: target.binding.blobId,\n run: () =>\n runBlobTransfer(input.apiClient, (signal, progress) =>\n loadDocumentAttachmentBlob({\n ...input,\n binding: target.binding,\n signal,\n progress,\n }),\n ),\n })),\n });\n\n return new Map(\n loadedBlobs.flatMap((loaded) =>\n loaded ? [[loaded.blobId, loaded] as const] : [],\n ),\n );\n}\n\nfunction applyLoadedBlobBytesToHydrationTargets(\n hydrationTargets: ReadonlyArray<DocumentAttachmentHydrationTarget>,\n loadedBlobsByBlobId: ReadonlyMap<string, LoadedDocumentAttachmentBlobBytes>,\n): LoadedDocumentAttachmentBlob[] {\n return hydrationTargets.flatMap((target) => {\n const loaded = loadedBlobsByBlobId.get(target.binding.blobId);\n return loaded\n ? [\n {\n ...target,\n encryptedBytes: loaded.encryptedBytes,\n },\n ]\n : [];\n });\n}\n\nasync function decryptLoadedDocumentAttachmentBlob(\n input: DocumentAttachmentHydrationContext & {\n loaded: LoadedDocumentAttachmentBlob;\n decryptAttachment: ReturnType<typeof createAttachmentDecryptor>;\n writerProjection: DocumentWriterProjectionResponse;\n },\n): Promise<HydratedDocumentAttachmentBlob | null> {\n const bytes = await input.decryptAttachment({\n binding: input.loaded.binding,\n encryptedBytes: input.loaded.encryptedBytes,\n expectedDocumentId: input.documentId,\n expectedSlotId: input.loaded.attachment.slotId,\n execSql: input.execSql,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n targetSecretKey: input.targetSecretKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n writerProjection: input.writerProjection,\n });\n\n const { attachment, binding } = input.loaded;\n const contentSha256 = await attachmentContentSha256(bytes);\n const intentMismatch = contentSha256 !== attachment.contentSha256;\n const logPrefix = input.logPrefix ?? \"Documents\";\n if (intentMismatch && input.localStorageKeyBySlotId?.[attachment.slotId]) {\n // Never replace a held copy with bytes the document does not record.\n input.rejectedServedBindings?.add(\n servedBindingRejectionKey(attachment, binding),\n );\n input.log?.(\n `${logPrefix}: served attachment bytes differ from the current document content; keeping the held copy.`,\n );\n return null;\n }\n if (intentMismatch) {\n input.log?.(\n `${logPrefix}: served attachment bytes differ from the current document content; showing them flagged.`,\n );\n }\n return {\n attachment,\n binding,\n bytes,\n contentSha256,\n intentMismatch,\n storageKey: `blob-${binding.blobId}`,\n };\n}\n\nexport async function hydrateDocumentAttachmentBlobs(\n input: DocumentAttachmentHydrationContext & {\n attachments: ReadonlyArray<DocumentAttachment>;\n /** No binding target remains unchecked or unavailable in this pass. */\n onBindingsChecked?: () => void;\n },\n): Promise<HydratedDocumentAttachmentBlob[] | null> {\n const attachmentBindings = await input.apiClient.listDocumentAttachments(\n input.documentId,\n );\n if (!attachmentBindings) {\n return null;\n }\n\n const bindingBySlotId = new Map(\n attachmentBindings.map((binding) => [binding.slotId, binding]),\n );\n const hydrationTargets: DocumentAttachmentHydrationTarget[] =\n input.attachments.flatMap((attachment) => {\n const binding = bindingBySlotId.get(attachment.slotId);\n return binding &&\n shouldHydrateAttachment({\n attachment,\n binding,\n localBlobIdBySlotId: input.localBlobIdBySlotId,\n localStorageKeyBySlotId: input.localStorageKeyBySlotId,\n rejectedServedBindings: input.rejectedServedBindings,\n })\n ? [{ attachment, binding }]\n : [];\n });\n if (hydrationTargets.length === 0) {\n input.onBindingsChecked?.();\n return [];\n }\n\n const loadedBlobs = applyLoadedBlobBytesToHydrationTargets(\n hydrationTargets,\n await loadUniqueDocumentAttachmentBlobs({\n ...input,\n hydrationTargets,\n }),\n );\n if (loadedBlobs.length === 0) {\n return [];\n }\n\n const writerProjection = await input.apiClient.getDocumentWriterProjection(\n input.documentId,\n );\n if (!writerProjection) {\n const logPrefix = input.logPrefix ?? \"Documents\";\n input.log?.(\n `${logPrefix}: cannot hydrate attachments for document ${input.documentId} without a writer projection.`,\n );\n return [];\n }\n\n const decryptAttachment = createAttachmentDecryptor(\n input.apiClient,\n input.documentId,\n );\n const hydrated = await collectHydrationResults({\n ...input,\n tasks: loadedBlobs.map((loaded) => ({\n blobId: loaded.binding.blobId,\n run: () =>\n decryptLoadedDocumentAttachmentBlob({\n ...input,\n decryptAttachment,\n loaded,\n writerProjection,\n }),\n })),\n });\n const complete = hydrated.filter(\n (item): item is HydratedDocumentAttachmentBlob => item !== null,\n );\n if (complete.length === hydrationTargets.length) input.onBindingsChecked?.();\n return complete;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydrationResults.js","sourceRoot":"","sources":["hydrationResults.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,sCAAsC,EAAE,MAAM,+CAA+C,CAAC;AAGvG,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAI,KAIhD;IACC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CACvC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CACtC,CAAC;IACF,MAAM,MAAM,GAAQ,EAAE,CAAC;IACvB,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAClD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,+BAA+B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChD,sCAAsC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,yCAAyC,CAC7C,OAAO,CAAC,MAAM,EACd,KAAK,CAAC,sBAAsB,EAC5B;YACE,SAAS,EAAE,oBAAoB;YAC/B,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,IAAI;SAC7C,CACF,CAAC;QACF,KAAK,CAAC,GAAG,EAAE,CAAC,2DAA2D,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import {\n reportKeyingVerificationErrorInCauseChain,\n rethrowDatabaseUnavailableError,\n} from \"../../data/keyingProjectionVerification/error\";\nimport { rethrowProjectionVerificationCancelled } from \"../../data/keyingProjectionVerification/types\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\n\n/** One unavailable or invalid attachment does not suppress independent successes. */\nexport async function collectHydrationResults<T>(input: {\n tasks: readonly { blobId: string; run: () => Promise<T> }[];\n reportSecurityIncident?: SecurityIncidentReporter | undefined;\n log?: ((message: string) => void) | undefined;\n}): Promise<T[]> {\n const outcomes = await Promise.allSettled(\n input.tasks.map((task) => task.run()),\n );\n const values: T[] = [];\n for (const [index, outcome] of outcomes.entries()) {\n if (outcome.status === \"fulfilled\") {\n values.push(outcome.value);\n continue;\n }\n rethrowDatabaseUnavailableError(outcome.reason);\n rethrowProjectionVerificationCancelled(outcome.reason);\n await reportKeyingVerificationErrorInCauseChain(\n outcome.reason,\n input.reportSecurityIncident,\n {\n operation: \"hydrate_attachment\",\n objectKind: \"blob\",\n objectId: input.tasks[index]?.blobId ?? null,\n },\n );\n input.log?.(\"Documents: an attachment is unavailable during hydration.\");\n }\n return values;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hydrationResults.js","sourceRoot":"","sources":["hydrationResults.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,sCAAsC,EAAE,MAAM,+CAA+C,CAAC;AAGvG,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAI,KAIhD;IACC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CACvC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CACtC,CAAC;IACF,MAAM,MAAM,GAAQ,EAAE,CAAC;IACvB,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAClD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,+BAA+B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChD,sCAAsC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,yCAAyC,CAC7C,OAAO,CAAC,MAAM,EACd,KAAK,CAAC,sBAAsB,EAC5B;YACE,SAAS,EAAE,oBAAoB;YAC/B,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,IAAI;SAC7C,CACF,CAAC;QACF,KAAK,CAAC,GAAG,EAAE,CAAC,2DAA2D,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import {\n reportKeyingVerificationErrorInCauseChain,\n rethrowDatabaseUnavailableError,\n} from \"../../data/keyingProjectionVerification/error\";\nimport { rethrowProjectionVerificationCancelled } from \"../../data/keyingProjectionVerification/types\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\n\n/** One unavailable or invalid attachment does not suppress independent successes. */\nexport async function collectHydrationResults<T>(input: {\n tasks: readonly { blobId: string; run: () => Promise<T> }[];\n reportSecurityIncident?: SecurityIncidentReporter | undefined;\n log?: ((message: string) => void) | undefined;\n}): Promise<T[]> {\n const outcomes = await Promise.allSettled(\n input.tasks.map((task) => task.run()),\n );\n const values: T[] = [];\n for (const [index, outcome] of outcomes.entries()) {\n if (outcome.status === \"fulfilled\") {\n values.push(outcome.value);\n continue;\n }\n rethrowDatabaseUnavailableError(outcome.reason);\n rethrowProjectionVerificationCancelled(outcome.reason);\n await reportKeyingVerificationErrorInCauseChain(\n outcome.reason,\n input.reportSecurityIncident,\n {\n operation: \"hydrate_attachment\",\n objectKind: \"blob\",\n objectId: input.tasks[index]?.blobId ?? null,\n },\n );\n input.log?.(\"Documents: an attachment is unavailable during hydration.\");\n }\n return values;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { BlobByteSource, BlobByteSourceInput, BlobBytes, BlobStore, } from "../../data/blobContracts.js";
|
|
2
|
-
export { blobByteSourceInputLength, createBlobByteSource, readBlobByteSource, } from "../../data/blobContracts.js";
|
|
1
|
+
export type { BlobByteSource, BlobByteSourceInput, BlobBytes, BlobStore, } from "../../data/blobs/blobContracts.js";
|
|
2
|
+
export { blobByteSourceInputLength, createBlobByteSource, readBlobByteSource, } from "../../data/blobs/blobContracts.js";
|
|
3
3
|
export { createBlobStore } from "../../data/blobs/createBlobStore.js";
|
|
4
4
|
export type { EncryptedBlobStoreCipher, EncryptedBlobStoreKey, EncryptedBlobStoreOptions, WrapEncryptedBlobStoreOptions, } from "../../data/blobs/encryptedBlobStore.js";
|
|
5
5
|
export { createEncryptedBlobStore, createLazyEncryptedBlobStore, wrapEncryptedBlobStore, } from "../../data/blobs/encryptedBlobStore.js";
|
package/workflows/blobs/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { blobByteSourceInputLength, createBlobByteSource, readBlobByteSource, } from "../../data/blobContracts.js";
|
|
1
|
+
export { blobByteSourceInputLength, createBlobByteSource, readBlobByteSource, } from "../../data/blobs/blobContracts.js";
|
|
2
2
|
export { createBlobStore } from "../../data/blobs/createBlobStore.js";
|
|
3
3
|
export { createEncryptedBlobStore, createLazyEncryptedBlobStore, wrapEncryptedBlobStore, } from "../../data/blobs/encryptedBlobStore.js";
|
|
4
4
|
export { createMemoryBlobStore } from "../../data/blobs/memoryBlobStore.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAOnE,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAMpE,OAAO,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,8BAA8B,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC","sourcesContent":["export type {\n BlobByteSource,\n BlobByteSourceInput,\n BlobBytes,\n BlobStore,\n} from \"../../data/blobs/blobContracts\";\nexport {\n blobByteSourceInputLength,\n createBlobByteSource,\n readBlobByteSource,\n} from \"../../data/blobs/blobContracts\";\nexport { createBlobStore } from \"../../data/blobs/createBlobStore\";\nexport type {\n EncryptedBlobStoreCipher,\n EncryptedBlobStoreKey,\n EncryptedBlobStoreOptions,\n WrapEncryptedBlobStoreOptions,\n} from \"../../data/blobs/encryptedBlobStore\";\nexport {\n createEncryptedBlobStore,\n createLazyEncryptedBlobStore,\n wrapEncryptedBlobStore,\n} from \"../../data/blobs/encryptedBlobStore\";\nexport { createMemoryBlobStore } from \"../../data/blobs/memoryBlobStore\";\nexport { purgeOpfsBlobStore } from \"../../data/blobs/opfsBlobStore\";\nexport type {\n MultipartStageResolvedListener,\n MultipartUploadProgress,\n MultipartUploadProgressListener,\n} from \"../../data/documents/blob/shared/types\";\nexport { decryptDocumentAttachmentBlob } from \"./decrypt\";\nexport { hydrateDocumentAttachmentBlobs } from \"./hydrate\";\nexport { uploadDocumentAttachment } from \"./upload\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multipartFirstParts.js","sourceRoot":"","sources":["multipartFirstParts.ts"],"names":[],"mappings":"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","sourcesContent":["import { describeMultipartBlobPart } from \"@tearleads/api-client\";\nimport { bytesToHex } from \"@tearleads/crypto\";\nimport type { InitiateMultipartBlobStageResponse } from \"@tearleads/validators/response\";\nimport {\n MAX_INITIATE_PART_UPLOADS,\n type MultipartBlobPartDescriptor,\n type MultipartBlobPartUploadSource,\n} from \"@tearleads/validators/util\";\nimport type { BlobBytes } from \"../../data/blobContracts\";\nimport {\n acquireBlobTransferPermit,\n type BlobTransferPermit,\n tryAcquireBlobTransferPermit,\n} from \"../../data/blobs/transferPool\";\nimport type { BlobEncryptionPlan } from \"../../data/documents/blob/shared/crypto\";\n\nexport interface PreparedMultipartPart {\n readonly bytes: BlobBytes;\n readonly sha256: string;\n}\n\n/**\n * A first part's bytes and the transfer-pool permit that pays for them: the\n * bytes exist before their upload can start, so they hold a slot of the\n * client's byte-I/O bound until the upload that sends them releases it.\n */\nexport interface PreparedFirstPart extends PreparedMultipartPart {\n readonly permit: BlobTransferPermit;\n}\n\n/**\n * The parts a new stage's upload starts with, encrypted once up front: their\n * descriptors ride on the stage initiation, and their bytes are handed to the\n * upload workers instead of being encrypted a second time.\n */\nexport interface MultipartFirstParts {\n readonly descriptors: readonly MultipartBlobPartDescriptor[];\n readonly prepared: Map<number, PreparedFirstPart>;\n}\n\n/** Return the pool slots of first parts no upload consumed. */\nexport function releasePreparedParts(\n prepared: Map<number, PreparedFirstPart>,\n): void {\n for (const part of prepared.values()) {\n part.permit.release();\n }\n prepared.clear();\n}\n\n/**\n * One permit is awaited; more are taken only if free right now. Two uploads\n * each waiting for a second slot while holding a first could otherwise\n * deadlock the pool, since a held slot frees only when its part uploads.\n */\nasync function acquireFirstPartPermits(\n client: object,\n limit: number,\n): Promise<BlobTransferPermit[]> {\n const permits = [await acquireBlobTransferPermit(client)];\n while (permits.length < limit) {\n const permit = tryAcquireBlobTransferPermit(client);\n if (!permit) break;\n permits.push(permit);\n }\n return permits;\n}\n\n/**\n * Where each part's bytes go. Sources the stage initiation issued are used\n * once; a store that cannot sign (`api`) needs no per-part authorization at\n * all, and a part with no source authorizes just before it is sent.\n */\nexport interface MultipartPartSources {\n readonly apiTransport: boolean;\n readonly issued: Map<number, MultipartBlobPartUploadSource>;\n}\n\nexport async function sha256BytesHex(bytes: BlobBytes): Promise<string> {\n return bytesToHex(\n new Uint8Array(await crypto.subtle.digest(\"SHA-256\", bytes)),\n );\n}\n\nexport async function prepareFirstMultipartParts(\n client: object,\n encryption: BlobEncryptionPlan,\n concurrency: number,\n): Promise<MultipartFirstParts> {\n const permits = await acquireFirstPartPermits(\n client,\n Math.min(encryption.partCount, concurrency, MAX_INITIATE_PART_UPLOADS),\n );\n const descriptors: MultipartBlobPartDescriptor[] = [];\n const prepared = new Map<number, PreparedFirstPart>();\n try {\n for (const [partIndex, permit] of permits.entries()) {\n const bytes = await encryption.encryptPart(partIndex);\n if (bytes.byteLength !== encryption.getPartByteLength(partIndex)) {\n throw new Error(\n `Encrypted blob part ${partIndex + 1} byte length mismatch: expected ${encryption.getPartByteLength(partIndex).toLocaleString()}, received ${bytes.byteLength.toLocaleString()}.`,\n );\n }\n const sha256 = await sha256BytesHex(bytes);\n prepared.set(partIndex, { bytes, permit, sha256 });\n descriptors.push(describeMultipartBlobPart(partIndex + 1, bytes));\n }\n } catch (error) {\n for (const permit of permits) permit.release();\n throw error;\n }\n return { descriptors, prepared };\n}\n\n/**\n * The initiation must return exactly one source per described part, for that\n * part's number, length, and checksum, and every source of one stage must use\n * the same transport.\n */\nexport function readIssuedPartSources(\n descriptors: readonly MultipartBlobPartDescriptor[],\n stage: Pick<InitiateMultipartBlobStageResponse, \"partUploads\">,\n): MultipartPartSources {\n const issued = new Map<number, MultipartBlobPartUploadSource>();\n const kinds = new Set(stage.partUploads.map((upload) => upload.source.kind));\n const matches =\n stage.partUploads.length === descriptors.length &&\n kinds.size === 1 &&\n descriptors.every((descriptor, index) => {\n const upload = stage.partUploads[index];\n return (\n upload?.partNumber === descriptor.partNumber &&\n upload.byteLength === descriptor.byteLength &&\n upload.contentMd5 === descriptor.contentMd5\n );\n });\n if (!matches) {\n throw new Error(\n \"Multipart blob stage initiation part uploads do not match its request.\",\n );\n }\n for (const upload of stage.partUploads) {\n issued.set(upload.partNumber, upload.source);\n }\n return { apiTransport: kinds.has(\"api\"), issued };\n}\n\n/** Use each issued source once; retries and later parts authorize anew. */\nexport function takePartSource(\n sources: MultipartPartSources,\n partNumber: number,\n): MultipartBlobPartUploadSource | undefined {\n const issued = sources.issued.get(partNumber);\n sources.issued.delete(partNumber);\n return issued ?? (sources.apiTransport ? { kind: \"api\" } : undefined);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"multipartFirstParts.js","sourceRoot":"","sources":["multipartFirstParts.ts"],"names":[],"mappings":"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","sourcesContent":["import { describeMultipartBlobPart } from \"@tearleads/api-client\";\nimport { bytesToHex } from \"@tearleads/crypto\";\nimport type { InitiateMultipartBlobStageResponse } from \"@tearleads/validators/response\";\nimport {\n MAX_INITIATE_PART_UPLOADS,\n type MultipartBlobPartDescriptor,\n type MultipartBlobPartUploadSource,\n} from \"@tearleads/validators/util\";\nimport type { BlobBytes } from \"../../data/blobs/blobContracts\";\nimport {\n acquireBlobTransferPermit,\n type BlobTransferPermit,\n tryAcquireBlobTransferPermit,\n} from \"../../data/blobs/transferPool\";\nimport type { BlobEncryptionPlan } from \"../../data/documents/blob/shared/crypto\";\n\nexport interface PreparedMultipartPart {\n readonly bytes: BlobBytes;\n readonly sha256: string;\n}\n\n/**\n * A first part's bytes and the transfer-pool permit that pays for them: the\n * bytes exist before their upload can start, so they hold a slot of the\n * client's byte-I/O bound until the upload that sends them releases it.\n */\nexport interface PreparedFirstPart extends PreparedMultipartPart {\n readonly permit: BlobTransferPermit;\n}\n\n/**\n * The parts a new stage's upload starts with, encrypted once up front: their\n * descriptors ride on the stage initiation, and their bytes are handed to the\n * upload workers instead of being encrypted a second time.\n */\nexport interface MultipartFirstParts {\n readonly descriptors: readonly MultipartBlobPartDescriptor[];\n readonly prepared: Map<number, PreparedFirstPart>;\n}\n\n/** Return the pool slots of first parts no upload consumed. */\nexport function releasePreparedParts(\n prepared: Map<number, PreparedFirstPart>,\n): void {\n for (const part of prepared.values()) {\n part.permit.release();\n }\n prepared.clear();\n}\n\n/**\n * One permit is awaited; more are taken only if free right now. Two uploads\n * each waiting for a second slot while holding a first could otherwise\n * deadlock the pool, since a held slot frees only when its part uploads.\n */\nasync function acquireFirstPartPermits(\n client: object,\n limit: number,\n): Promise<BlobTransferPermit[]> {\n const permits = [await acquireBlobTransferPermit(client)];\n while (permits.length < limit) {\n const permit = tryAcquireBlobTransferPermit(client);\n if (!permit) break;\n permits.push(permit);\n }\n return permits;\n}\n\n/**\n * Where each part's bytes go. Sources the stage initiation issued are used\n * once; a store that cannot sign (`api`) needs no per-part authorization at\n * all, and a part with no source authorizes just before it is sent.\n */\nexport interface MultipartPartSources {\n readonly apiTransport: boolean;\n readonly issued: Map<number, MultipartBlobPartUploadSource>;\n}\n\nexport async function sha256BytesHex(bytes: BlobBytes): Promise<string> {\n return bytesToHex(\n new Uint8Array(await crypto.subtle.digest(\"SHA-256\", bytes)),\n );\n}\n\nexport async function prepareFirstMultipartParts(\n client: object,\n encryption: BlobEncryptionPlan,\n concurrency: number,\n): Promise<MultipartFirstParts> {\n const permits = await acquireFirstPartPermits(\n client,\n Math.min(encryption.partCount, concurrency, MAX_INITIATE_PART_UPLOADS),\n );\n const descriptors: MultipartBlobPartDescriptor[] = [];\n const prepared = new Map<number, PreparedFirstPart>();\n try {\n for (const [partIndex, permit] of permits.entries()) {\n const bytes = await encryption.encryptPart(partIndex);\n if (bytes.byteLength !== encryption.getPartByteLength(partIndex)) {\n throw new Error(\n `Encrypted blob part ${partIndex + 1} byte length mismatch: expected ${encryption.getPartByteLength(partIndex).toLocaleString()}, received ${bytes.byteLength.toLocaleString()}.`,\n );\n }\n const sha256 = await sha256BytesHex(bytes);\n prepared.set(partIndex, { bytes, permit, sha256 });\n descriptors.push(describeMultipartBlobPart(partIndex + 1, bytes));\n }\n } catch (error) {\n for (const permit of permits) permit.release();\n throw error;\n }\n return { descriptors, prepared };\n}\n\n/**\n * The initiation must return exactly one source per described part, for that\n * part's number, length, and checksum, and every source of one stage must use\n * the same transport.\n */\nexport function readIssuedPartSources(\n descriptors: readonly MultipartBlobPartDescriptor[],\n stage: Pick<InitiateMultipartBlobStageResponse, \"partUploads\">,\n): MultipartPartSources {\n const issued = new Map<number, MultipartBlobPartUploadSource>();\n const kinds = new Set(stage.partUploads.map((upload) => upload.source.kind));\n const matches =\n stage.partUploads.length === descriptors.length &&\n kinds.size === 1 &&\n descriptors.every((descriptor, index) => {\n const upload = stage.partUploads[index];\n return (\n upload?.partNumber === descriptor.partNumber &&\n upload.byteLength === descriptor.byteLength &&\n upload.contentMd5 === descriptor.contentMd5\n );\n });\n if (!matches) {\n throw new Error(\n \"Multipart blob stage initiation part uploads do not match its request.\",\n );\n }\n for (const upload of stage.partUploads) {\n issued.set(upload.partNumber, upload.source);\n }\n return { apiTransport: kinds.has(\"api\"), issued };\n}\n\n/** Use each issued source once; retries and later parts authorize anew. */\nexport function takePartSource(\n sources: MultipartPartSources,\n partNumber: number,\n): MultipartBlobPartUploadSource | undefined {\n const issued = sources.issued.get(partNumber);\n sources.issued.delete(partNumber);\n return issued ?? (sources.apiTransport ? { kind: \"api\" } : undefined);\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import { KeyingVerificationError } from "../../internal/crypto/index.js";
|
|
|
2
2
|
import { assertBlobContentKeyBundleTargetHash } from "../../data/documents/blob/shared/responses.js";
|
|
3
3
|
import { assertDocumentWriterProjectionConsistent } from "../../data/documents/shared/projection.js";
|
|
4
4
|
import { projectionVerificationOptions } from "../../data/documents/shared/types.js";
|
|
5
|
-
import { requireProjectionUserKeyResolver, } from "../../data/keyingProjectionVerification.js";
|
|
5
|
+
import { requireProjectionUserKeyResolver, } from "../../data/keyingProjectionVerification/index.js";
|
|
6
6
|
import { assertAttachmentBindingVerified } from "./attachmentBindingVerification.js";
|
|
7
7
|
import { assertBlobWrapScopeVerified } from "./verifiedWrapScope.js";
|
|
8
8
|
/** Retaining an existing envelope does not propagate a key to a new recipient. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computeBlobAccessManifestHash, computeBlobContentKeyTargetHash, } from "../../internal/crypto/index.js";
|
|
2
|
-
import { createBlobByteSource, } from "../../data/blobContracts.js";
|
|
2
|
+
import { createBlobByteSource, } from "../../data/blobs/blobContracts.js";
|
|
3
3
|
import { prepareBlobEncryption } from "../../data/documents/blob/shared/crypto.js";
|
|
4
4
|
import { signBlobAttachmentEvent, signBlobAttachmentWriteHeader, } from "../../data/documents/blob/shared/events.js";
|
|
5
5
|
import { verifiedBlobWrapTargetsFromDocumentProjection, wrapBlobContentKey, } from "../../data/documents/blob/shared/projection.js";
|
|
@@ -7,8 +7,8 @@ import { assertBlobAttachmentBindResponse } from "../../data/documents/blob/shar
|
|
|
7
7
|
import { authorizingContainerPathRefs } from "../../data/documents/shared/projection.js";
|
|
8
8
|
import { uniqueSortedStrings } from "../../data/documents/shared/readers.js";
|
|
9
9
|
import { projectionVerificationOptions, } from "../../data/documents/shared/types.js";
|
|
10
|
-
import { readCanonicalRecord } from "../../data/
|
|
11
|
-
import { requireProjectionUserKeyResolver } from "../../data/keyingProjectionVerification.js";
|
|
10
|
+
import { readCanonicalRecord } from "../../data/keying/canonicalJson.js";
|
|
11
|
+
import { requireProjectionUserKeyResolver } from "../../data/keyingProjectionVerification/index.js";
|
|
12
12
|
import { shouldRetryWithFreshProjection } from "../documents/syncFailureClassification.js";
|
|
13
13
|
import { resolveMultipartUploadOptions } from "./automaticMultipartUpload.js";
|
|
14
14
|
import { stageMultipartBlobAttachment } from "./multipartUpload.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","sourceRoot":"","sources":["upload.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccessEvent,\n AttachmentBindAccessEventBody,\n WriteHeader,\n} from \"@tearleads/crypto\";\nimport {\n computeBlobAccessManifestHash,\n computeBlobContentKeyTargetHash,\n} from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentBindRequest,\n BlobContentKeyBundleRequest,\n} from \"@tearleads/validators/request\";\nimport type { BlobAttachmentBindResponse } from \"@tearleads/validators/response\";\nimport {\n type BlobByteSource,\n createBlobByteSource,\n} from \"../../data/blobContracts\";\nimport type { BlobSourceSnapshot } from \"../../data/documents/blob/shared/blobSourceSnapshot\";\nimport { prepareBlobEncryption } from \"../../data/documents/blob/shared/crypto\";\nimport {\n signBlobAttachmentEvent,\n signBlobAttachmentWriteHeader,\n} from \"../../data/documents/blob/shared/events\";\nimport {\n verifiedBlobWrapTargetsFromDocumentProjection,\n wrapBlobContentKey,\n} from \"../../data/documents/blob/shared/projection\";\nimport { assertBlobAttachmentBindResponse } from \"../../data/documents/blob/shared/responses\";\nimport type {\n BlobAttachmentApi,\n BlobAttachmentMaterial,\n MultipartStageResolvedListener,\n MultipartUploadProgressListener,\n UploadDocumentAttachmentInput,\n UploadDocumentAttachmentResult,\n} from \"../../data/documents/blob/shared/types\";\nimport { authorizingContainerPathRefs } from \"../../data/documents/shared/projection\";\nimport { uniqueSortedStrings } from \"../../data/documents/shared/readers\";\nimport {\n type DocumentCreateAuthor,\n type ProjectionVerificationOptions,\n projectionVerificationOptions,\n} from \"../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../data/keyingCanonicalJson\";\nimport { requireProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { shouldRetryWithFreshProjection } from \"../documents/syncFailureClassification\";\nimport { resolveMultipartUploadOptions } from \"./automaticMultipartUpload\";\nimport { stageMultipartBlobAttachment } from \"./multipartUpload\";\nimport { resolveBlobMutationWriterProjection } from \"./writerProjection\";\n\nasync function buildBlobAttachmentMaterial(\n input: {\n apiClient: BlobAttachmentApi;\n bindingId: string;\n blobId: string;\n contentKey: Uint8Array;\n contentKeyEpoch: number;\n documentId: string;\n execSql?: ExecSql | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n nonceSeed?: Uint8Array | undefined;\n partSize: number;\n source: BlobByteSource;\n sourceSnapshot?: BlobSourceSnapshot | undefined;\n targetSecretKey: Uint8Array;\n writerProjection?: UploadDocumentAttachmentInput[\"writerProjection\"];\n } & ProjectionVerificationOptions,\n): Promise<BlobAttachmentMaterial | null> {\n const resolved = await resolveBlobMutationWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n errorLabel: \"Blob attachment\",\n execSql: input.execSql,\n isRemoteSyncBlocked: input.isRemoteSyncBlocked,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n if (!resolved) {\n return null;\n }\n const { manifestIdentity, writerProjection } = resolved;\n\n const targets = verifiedBlobWrapTargetsFromDocumentProjection({\n bindingId: input.bindingId,\n documentId: input.documentId,\n writerProjection,\n });\n const targetHash = await computeBlobContentKeyTargetHash(targets);\n const contentKeyBundle: BlobContentKeyBundleRequest = {\n contentKeyEpoch: input.contentKeyEpoch,\n targetHash,\n targets: await wrapBlobContentKey({\n blobId: input.blobId,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n execSql: input.execSql,\n secretKey: input.targetSecretKey,\n targets,\n writerProjection,\n ...projectionVerificationOptions(input),\n }),\n };\n const encrypted = await prepareBlobEncryption({\n blobId: input.blobId,\n chunkSize: input.partSize,\n contentKey: input.contentKey,\n contentKeyBundle,\n nonceSeed: input.nonceSeed,\n organizationId: manifestIdentity.organizationId,\n source: input.source,\n sourceSnapshot: input.sourceSnapshot,\n });\n const blobAccessManifestHash = await computeBlobAccessManifestHash({\n version: 1,\n blobId: input.blobId,\n organizationId: manifestIdentity.organizationId,\n activeBindingIds: [input.bindingId],\n documentManifestHashes: [manifestIdentity.manifestHash],\n linkedContainerManifestHashes: uniqueSortedStrings(\n targets.map((target) => target.containerManifestHash),\n ),\n linkedContainerKeyEpochIds: uniqueSortedStrings(\n targets.map((target) => target.containerKeyEpochId),\n ),\n blobKeyTargetHash: targetHash,\n });\n\n return {\n blobAccessManifestHash,\n contentKeyBundle,\n encrypted,\n manifestIdentity,\n targetHash,\n targets,\n writerProjection,\n };\n}\n\nfunction blobAttachmentBindRequest(input: {\n body: AttachmentBindAccessEventBody;\n event: AccessEvent;\n material: BlobAttachmentMaterial;\n stageId: string;\n writeHeader: WriteHeader;\n}): BlobAttachmentBindRequest {\n return {\n event: readCanonicalRecord(input.event, \"Blob attachment bind event\"),\n body: readCanonicalRecord(input.body, \"Blob attachment bind body\"),\n authorizingContainerPathRefs: authorizingContainerPathRefs(\n input.material.writerProjection,\n ),\n contentKeyBundle: input.material.contentKeyBundle,\n stagedBlob: {\n stageId: input.stageId,\n writeHeader: readCanonicalRecord(\n input.writeHeader,\n \"Blob attachment write header\",\n ),\n },\n };\n}\n\nasync function stageAndBindBlobAttachment(input: {\n apiClient: BlobAttachmentApi;\n author: DocumentCreateAuthor;\n bindingId: string;\n blobId: string;\n contentKeyEpoch: number;\n documentId: string;\n eventId: string;\n expectedBindingId: string | null;\n material: BlobAttachmentMaterial;\n multipart: NonNullable<UploadDocumentAttachmentInput[\"multipart\"]>;\n onMultipartProgress?: MultipartUploadProgressListener | undefined;\n onStageResolved?: MultipartStageResolvedListener | undefined;\n onStageUnavailable?: ((stageId: string) => Promise<void>) | undefined;\n signedAt: string;\n slotId: string;\n}): Promise<{\n request: BlobAttachmentBindRequest;\n response: BlobAttachmentBindResponse;\n sha256: string;\n byteLength: number;\n writeHeader: WriteHeader;\n writeHeaderHash: string;\n} | null> {\n const { body, event } = await signBlobAttachmentEvent({\n author: input.author,\n bindingId: input.bindingId,\n blobId: input.blobId,\n documentId: input.documentId,\n eventId: input.eventId,\n expectedBindingId: input.expectedBindingId,\n manifestIdentity: input.material.manifestIdentity,\n signedAt: input.signedAt,\n slotId: input.slotId,\n authorizingContainerPathRefs: authorizingContainerPathRefs(\n input.material.writerProjection,\n ),\n });\n const { writeHeader, writeHeaderHash } = await signBlobAttachmentWriteHeader({\n authorizingContainerPathRefs: authorizingContainerPathRefs(\n input.material.writerProjection,\n ),\n author: input.author,\n blobAccessManifestHash: input.material.blobAccessManifestHash,\n blobId: input.blobId,\n contentKeyEpoch: input.contentKeyEpoch,\n encrypted: input.material.encrypted,\n manifestIdentity: input.material.manifestIdentity,\n signedAt: input.signedAt,\n targetHash: input.material.targetHash,\n });\n const stageId = await stageMultipartBlobAttachment({\n organizationId: input.material.manifestIdentity.organizationId,\n apiClient: input.apiClient,\n encryption: input.material.encrypted,\n multipart: input.multipart,\n onMultipartProgress: input.onMultipartProgress,\n onStageResolved: input.onStageResolved,\n onStageUnavailable: input.onStageUnavailable,\n });\n if (!stageId) {\n return null;\n }\n\n const request = blobAttachmentBindRequest({\n body,\n event,\n material: input.material,\n stageId,\n writeHeader,\n });\n const response = await input.apiClient.bindBlobAttachment(\n input.blobId,\n request,\n {\n expectedPaymentRequiredOrganizationId:\n input.material.manifestIdentity.organizationId,\n },\n );\n if (!response) {\n return null;\n }\n\n await assertBlobAttachmentBindResponse({\n body,\n bindingId: input.bindingId,\n blobAccessManifestHash: input.material.blobAccessManifestHash,\n blobId: input.blobId,\n contentKeyBundle: input.material.contentKeyBundle,\n documentId: input.documentId,\n event,\n manifestIdentity: input.material.manifestIdentity,\n response,\n slotId: input.slotId,\n targetHash: input.material.targetHash,\n targets: input.material.targets,\n writeHeader,\n writeHeaderHash,\n });\n\n return {\n request,\n response,\n sha256: input.material.encrypted.sha256,\n byteLength: input.material.encrypted.byteLength,\n writeHeader,\n writeHeaderHash,\n };\n}\n\ninterface PreparedUploadDocumentAttachmentInput\n extends UploadDocumentAttachmentInput {\n readonly sourceSnapshot?: BlobSourceSnapshot | undefined;\n readonly onStageUnavailable?:\n | ((stageId: string) => Promise<void>)\n | undefined;\n}\n\nasync function uploadDocumentAttachmentImpl({\n apiClient,\n author,\n blobId = crypto.randomUUID(),\n bindingId = crypto.randomUUID(),\n bytes,\n contentKey = crypto.getRandomValues(new Uint8Array(32)),\n contentKeyEpoch = 1,\n documentId,\n eventId = crypto.randomUUID(),\n execSql,\n expectedBindingId,\n isRemoteSyncBlocked,\n nonceSeed,\n multipart,\n onMultipartProgress,\n onStageResolved,\n onStageUnavailable,\n resolveProjectionUserKey,\n signedAt = new Date().toISOString(),\n slotId,\n sourceSnapshot,\n targetSecretKey,\n warmReferencedPrincipalPolicies,\n writerProjection,\n}: PreparedUploadDocumentAttachmentInput): Promise<UploadDocumentAttachmentResult | null> {\n if (contentKey.byteLength !== 32) {\n throw new Error(\"Blob content key must be 32 bytes\");\n }\n const resolveProjectionUserKeyForUpload = requireProjectionUserKeyResolver(\n resolveProjectionUserKey,\n \"Document attachment upload\",\n );\n const resolvedMultipart = resolveMultipartUploadOptions(multipart);\n const source = createBlobByteSource(bytes);\n\n const buildMaterial = (\n freshWriterProjection: UploadDocumentAttachmentInput[\"writerProjection\"],\n ) =>\n buildBlobAttachmentMaterial({\n apiClient,\n bindingId,\n blobId,\n contentKey,\n contentKeyEpoch,\n documentId,\n execSql,\n isRemoteSyncBlocked,\n nonceSeed,\n partSize: resolvedMultipart.partSize,\n resolveProjectionUserKey: resolveProjectionUserKeyForUpload,\n source,\n sourceSnapshot,\n targetSecretKey,\n warmReferencedPrincipalPolicies,\n writerProjection: freshWriterProjection,\n });\n let material: BlobAttachmentMaterial | null;\n try {\n material = await buildMaterial(writerProjection);\n } catch (error) {\n if (\n !apiClient.evictDocumentWriterProjection ||\n !shouldRetryWithFreshProjection(\n error,\n (message) =>\n message.startsWith(\"Container writer projection KEK\") &&\n message.includes(\"could not be unwrapped\"),\n )\n ) {\n throw error;\n }\n\n // The attachment binds to this document; only its projection was stale, so\n // evict just it rather than wiping the whole projection cache.\n apiClient.evictDocumentWriterProjection(documentId);\n material = await buildMaterial(undefined);\n }\n if (!material) {\n return null;\n }\n const result = await stageAndBindBlobAttachment({\n apiClient,\n author,\n bindingId,\n blobId,\n contentKeyEpoch,\n documentId,\n eventId,\n expectedBindingId,\n material,\n multipart: resolvedMultipart,\n onMultipartProgress,\n onStageResolved,\n onStageUnavailable,\n signedAt,\n slotId,\n });\n if (!result) {\n return null;\n }\n\n return {\n blobId,\n bindingId,\n writerProjection: material.writerProjection,\n ...result,\n };\n}\n\nexport function uploadDocumentAttachment(\n input: UploadDocumentAttachmentInput,\n): Promise<UploadDocumentAttachmentResult | null> {\n return uploadDocumentAttachmentImpl({ ...input, sourceSnapshot: undefined });\n}\n\n/** Internal upload path for a source snapshot produced by `inspectBlobSource`. */\nexport function uploadPreparedDocumentAttachment(\n input: PreparedUploadDocumentAttachmentInput,\n): Promise<UploadDocumentAttachmentResult | null> {\n return uploadDocumentAttachmentImpl(input);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["upload.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccessEvent,\n AttachmentBindAccessEventBody,\n WriteHeader,\n} from \"@tearleads/crypto\";\nimport {\n computeBlobAccessManifestHash,\n computeBlobContentKeyTargetHash,\n} from \"@tearleads/crypto\";\nimport type {\n BlobAttachmentBindRequest,\n BlobContentKeyBundleRequest,\n} from \"@tearleads/validators/request\";\nimport type { BlobAttachmentBindResponse } from \"@tearleads/validators/response\";\nimport {\n type BlobByteSource,\n createBlobByteSource,\n} from \"../../data/blobs/blobContracts\";\nimport type { BlobSourceSnapshot } from \"../../data/documents/blob/shared/blobSourceSnapshot\";\nimport { prepareBlobEncryption } from \"../../data/documents/blob/shared/crypto\";\nimport {\n signBlobAttachmentEvent,\n signBlobAttachmentWriteHeader,\n} from \"../../data/documents/blob/shared/events\";\nimport {\n verifiedBlobWrapTargetsFromDocumentProjection,\n wrapBlobContentKey,\n} from \"../../data/documents/blob/shared/projection\";\nimport { assertBlobAttachmentBindResponse } from \"../../data/documents/blob/shared/responses\";\nimport type {\n BlobAttachmentApi,\n BlobAttachmentMaterial,\n MultipartStageResolvedListener,\n MultipartUploadProgressListener,\n UploadDocumentAttachmentInput,\n UploadDocumentAttachmentResult,\n} from \"../../data/documents/blob/shared/types\";\nimport { authorizingContainerPathRefs } from \"../../data/documents/shared/projection\";\nimport { uniqueSortedStrings } from \"../../data/documents/shared/readers\";\nimport {\n type DocumentCreateAuthor,\n type ProjectionVerificationOptions,\n projectionVerificationOptions,\n} from \"../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../data/keying/canonicalJson\";\nimport { requireProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { shouldRetryWithFreshProjection } from \"../documents/syncFailureClassification\";\nimport { resolveMultipartUploadOptions } from \"./automaticMultipartUpload\";\nimport { stageMultipartBlobAttachment } from \"./multipartUpload\";\nimport { resolveBlobMutationWriterProjection } from \"./writerProjection\";\n\nasync function buildBlobAttachmentMaterial(\n input: {\n apiClient: BlobAttachmentApi;\n bindingId: string;\n blobId: string;\n contentKey: Uint8Array;\n contentKeyEpoch: number;\n documentId: string;\n execSql?: ExecSql | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n nonceSeed?: Uint8Array | undefined;\n partSize: number;\n source: BlobByteSource;\n sourceSnapshot?: BlobSourceSnapshot | undefined;\n targetSecretKey: Uint8Array;\n writerProjection?: UploadDocumentAttachmentInput[\"writerProjection\"];\n } & ProjectionVerificationOptions,\n): Promise<BlobAttachmentMaterial | null> {\n const resolved = await resolveBlobMutationWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n errorLabel: \"Blob attachment\",\n execSql: input.execSql,\n isRemoteSyncBlocked: input.isRemoteSyncBlocked,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n if (!resolved) {\n return null;\n }\n const { manifestIdentity, writerProjection } = resolved;\n\n const targets = verifiedBlobWrapTargetsFromDocumentProjection({\n bindingId: input.bindingId,\n documentId: input.documentId,\n writerProjection,\n });\n const targetHash = await computeBlobContentKeyTargetHash(targets);\n const contentKeyBundle: BlobContentKeyBundleRequest = {\n contentKeyEpoch: input.contentKeyEpoch,\n targetHash,\n targets: await wrapBlobContentKey({\n blobId: input.blobId,\n contentKey: input.contentKey,\n contentKeyEpoch: input.contentKeyEpoch,\n execSql: input.execSql,\n secretKey: input.targetSecretKey,\n targets,\n writerProjection,\n ...projectionVerificationOptions(input),\n }),\n };\n const encrypted = await prepareBlobEncryption({\n blobId: input.blobId,\n chunkSize: input.partSize,\n contentKey: input.contentKey,\n contentKeyBundle,\n nonceSeed: input.nonceSeed,\n organizationId: manifestIdentity.organizationId,\n source: input.source,\n sourceSnapshot: input.sourceSnapshot,\n });\n const blobAccessManifestHash = await computeBlobAccessManifestHash({\n version: 1,\n blobId: input.blobId,\n organizationId: manifestIdentity.organizationId,\n activeBindingIds: [input.bindingId],\n documentManifestHashes: [manifestIdentity.manifestHash],\n linkedContainerManifestHashes: uniqueSortedStrings(\n targets.map((target) => target.containerManifestHash),\n ),\n linkedContainerKeyEpochIds: uniqueSortedStrings(\n targets.map((target) => target.containerKeyEpochId),\n ),\n blobKeyTargetHash: targetHash,\n });\n\n return {\n blobAccessManifestHash,\n contentKeyBundle,\n encrypted,\n manifestIdentity,\n targetHash,\n targets,\n writerProjection,\n };\n}\n\nfunction blobAttachmentBindRequest(input: {\n body: AttachmentBindAccessEventBody;\n event: AccessEvent;\n material: BlobAttachmentMaterial;\n stageId: string;\n writeHeader: WriteHeader;\n}): BlobAttachmentBindRequest {\n return {\n event: readCanonicalRecord(input.event, \"Blob attachment bind event\"),\n body: readCanonicalRecord(input.body, \"Blob attachment bind body\"),\n authorizingContainerPathRefs: authorizingContainerPathRefs(\n input.material.writerProjection,\n ),\n contentKeyBundle: input.material.contentKeyBundle,\n stagedBlob: {\n stageId: input.stageId,\n writeHeader: readCanonicalRecord(\n input.writeHeader,\n \"Blob attachment write header\",\n ),\n },\n };\n}\n\nasync function stageAndBindBlobAttachment(input: {\n apiClient: BlobAttachmentApi;\n author: DocumentCreateAuthor;\n bindingId: string;\n blobId: string;\n contentKeyEpoch: number;\n documentId: string;\n eventId: string;\n expectedBindingId: string | null;\n material: BlobAttachmentMaterial;\n multipart: NonNullable<UploadDocumentAttachmentInput[\"multipart\"]>;\n onMultipartProgress?: MultipartUploadProgressListener | undefined;\n onStageResolved?: MultipartStageResolvedListener | undefined;\n onStageUnavailable?: ((stageId: string) => Promise<void>) | undefined;\n signedAt: string;\n slotId: string;\n}): Promise<{\n request: BlobAttachmentBindRequest;\n response: BlobAttachmentBindResponse;\n sha256: string;\n byteLength: number;\n writeHeader: WriteHeader;\n writeHeaderHash: string;\n} | null> {\n const { body, event } = await signBlobAttachmentEvent({\n author: input.author,\n bindingId: input.bindingId,\n blobId: input.blobId,\n documentId: input.documentId,\n eventId: input.eventId,\n expectedBindingId: input.expectedBindingId,\n manifestIdentity: input.material.manifestIdentity,\n signedAt: input.signedAt,\n slotId: input.slotId,\n authorizingContainerPathRefs: authorizingContainerPathRefs(\n input.material.writerProjection,\n ),\n });\n const { writeHeader, writeHeaderHash } = await signBlobAttachmentWriteHeader({\n authorizingContainerPathRefs: authorizingContainerPathRefs(\n input.material.writerProjection,\n ),\n author: input.author,\n blobAccessManifestHash: input.material.blobAccessManifestHash,\n blobId: input.blobId,\n contentKeyEpoch: input.contentKeyEpoch,\n encrypted: input.material.encrypted,\n manifestIdentity: input.material.manifestIdentity,\n signedAt: input.signedAt,\n targetHash: input.material.targetHash,\n });\n const stageId = await stageMultipartBlobAttachment({\n organizationId: input.material.manifestIdentity.organizationId,\n apiClient: input.apiClient,\n encryption: input.material.encrypted,\n multipart: input.multipart,\n onMultipartProgress: input.onMultipartProgress,\n onStageResolved: input.onStageResolved,\n onStageUnavailable: input.onStageUnavailable,\n });\n if (!stageId) {\n return null;\n }\n\n const request = blobAttachmentBindRequest({\n body,\n event,\n material: input.material,\n stageId,\n writeHeader,\n });\n const response = await input.apiClient.bindBlobAttachment(\n input.blobId,\n request,\n {\n expectedPaymentRequiredOrganizationId:\n input.material.manifestIdentity.organizationId,\n },\n );\n if (!response) {\n return null;\n }\n\n await assertBlobAttachmentBindResponse({\n body,\n bindingId: input.bindingId,\n blobAccessManifestHash: input.material.blobAccessManifestHash,\n blobId: input.blobId,\n contentKeyBundle: input.material.contentKeyBundle,\n documentId: input.documentId,\n event,\n manifestIdentity: input.material.manifestIdentity,\n response,\n slotId: input.slotId,\n targetHash: input.material.targetHash,\n targets: input.material.targets,\n writeHeader,\n writeHeaderHash,\n });\n\n return {\n request,\n response,\n sha256: input.material.encrypted.sha256,\n byteLength: input.material.encrypted.byteLength,\n writeHeader,\n writeHeaderHash,\n };\n}\n\ninterface PreparedUploadDocumentAttachmentInput\n extends UploadDocumentAttachmentInput {\n readonly sourceSnapshot?: BlobSourceSnapshot | undefined;\n readonly onStageUnavailable?:\n | ((stageId: string) => Promise<void>)\n | undefined;\n}\n\nasync function uploadDocumentAttachmentImpl({\n apiClient,\n author,\n blobId = crypto.randomUUID(),\n bindingId = crypto.randomUUID(),\n bytes,\n contentKey = crypto.getRandomValues(new Uint8Array(32)),\n contentKeyEpoch = 1,\n documentId,\n eventId = crypto.randomUUID(),\n execSql,\n expectedBindingId,\n isRemoteSyncBlocked,\n nonceSeed,\n multipart,\n onMultipartProgress,\n onStageResolved,\n onStageUnavailable,\n resolveProjectionUserKey,\n signedAt = new Date().toISOString(),\n slotId,\n sourceSnapshot,\n targetSecretKey,\n warmReferencedPrincipalPolicies,\n writerProjection,\n}: PreparedUploadDocumentAttachmentInput): Promise<UploadDocumentAttachmentResult | null> {\n if (contentKey.byteLength !== 32) {\n throw new Error(\"Blob content key must be 32 bytes\");\n }\n const resolveProjectionUserKeyForUpload = requireProjectionUserKeyResolver(\n resolveProjectionUserKey,\n \"Document attachment upload\",\n );\n const resolvedMultipart = resolveMultipartUploadOptions(multipart);\n const source = createBlobByteSource(bytes);\n\n const buildMaterial = (\n freshWriterProjection: UploadDocumentAttachmentInput[\"writerProjection\"],\n ) =>\n buildBlobAttachmentMaterial({\n apiClient,\n bindingId,\n blobId,\n contentKey,\n contentKeyEpoch,\n documentId,\n execSql,\n isRemoteSyncBlocked,\n nonceSeed,\n partSize: resolvedMultipart.partSize,\n resolveProjectionUserKey: resolveProjectionUserKeyForUpload,\n source,\n sourceSnapshot,\n targetSecretKey,\n warmReferencedPrincipalPolicies,\n writerProjection: freshWriterProjection,\n });\n let material: BlobAttachmentMaterial | null;\n try {\n material = await buildMaterial(writerProjection);\n } catch (error) {\n if (\n !apiClient.evictDocumentWriterProjection ||\n !shouldRetryWithFreshProjection(\n error,\n (message) =>\n message.startsWith(\"Container writer projection KEK\") &&\n message.includes(\"could not be unwrapped\"),\n )\n ) {\n throw error;\n }\n\n // The attachment binds to this document; only its projection was stale, so\n // evict just it rather than wiping the whole projection cache.\n apiClient.evictDocumentWriterProjection(documentId);\n material = await buildMaterial(undefined);\n }\n if (!material) {\n return null;\n }\n const result = await stageAndBindBlobAttachment({\n apiClient,\n author,\n bindingId,\n blobId,\n contentKeyEpoch,\n documentId,\n eventId,\n expectedBindingId,\n material,\n multipart: resolvedMultipart,\n onMultipartProgress,\n onStageResolved,\n onStageUnavailable,\n signedAt,\n slotId,\n });\n if (!result) {\n return null;\n }\n\n return {\n blobId,\n bindingId,\n writerProjection: material.writerProjection,\n ...result,\n };\n}\n\nexport function uploadDocumentAttachment(\n input: UploadDocumentAttachmentInput,\n): Promise<UploadDocumentAttachmentResult | null> {\n return uploadDocumentAttachmentImpl({ ...input, sourceSnapshot: undefined });\n}\n\n/** Internal upload path for a source snapshot produced by `inspectBlobSource`. */\nexport function uploadPreparedDocumentAttachment(\n input: PreparedUploadDocumentAttachmentInput,\n): Promise<UploadDocumentAttachmentResult | null> {\n return uploadDocumentAttachmentImpl(input);\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { KeyingVerificationError, } from "../../../internal/crypto/index.js";
|
|
2
|
-
import { errorMessage } from "../../../data/errorMessage.js";
|
|
3
2
|
import { verifiedContainerCreateManifest } from "../../../data/keyingProjectionVerification/containerCreateManifest.js";
|
|
4
3
|
import { verifyContainerDestinationProjection } from "../../../data/keyingProjectionVerification/containerDestinationVerification.js";
|
|
5
4
|
import { isKeyingVerificationError, reportKeyingVerificationErrorInCauseChain, } from "../../../data/keyingProjectionVerification/error.js";
|
|
5
|
+
import { errorMessage } from "../../../data/shared/errorMessage.js";
|
|
6
6
|
import { createRuntimePrincipalPolicyWarmer } from "../../principals/runtimePolicyWarmer.js";
|
|
7
7
|
import { settleContainerCreateIntent } from "./createIntentSettlement.js";
|
|
8
8
|
const LABEL = "Container create conflict";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAdoption.js","sourceRoot":"","sources":["createAdoption.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type KeyingVerificationCode,\n KeyingVerificationError,\n} from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { errorMessage } from \"../../../data/errorMessage\";\nimport { verifiedContainerCreateManifest } from \"../../../data/keyingProjectionVerification/containerCreateManifest\";\nimport { verifyContainerDestinationProjection } from \"../../../data/keyingProjectionVerification/containerDestinationVerification\";\nimport {\n isKeyingVerificationError,\n reportKeyingVerificationErrorInCauseChain,\n} from \"../../../data/keyingProjectionVerification/error\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../principals/runtimePolicyWarmer\";\nimport type { ContainerState } from \"../remoteHydration\";\nimport { settleContainerCreateIntent } from \"./createIntentSettlement\";\nimport type {\n AdoptedContainerPlacement,\n ContainerCreateIntentSyncInput,\n ContainerCreateIntentSyncState,\n} from \"./types\";\n\nconst LABEL = \"Container create conflict\";\n\n/** The recorded error that parks an intent whose listed create is foreign. */\nexport const CONTAINER_CREATE_ADOPTION_REFUSED =\n \"Container create adoption was refused\";\n\n/**\n * The listed create's signed identity is not this device's pending create: its\n * signed create names another signer, another organization, or a root. An honest server never lists that under the\n * id this device minted, and no later read can change those signed facts, so\n * the intent parks instead of re-verifying.\n */\nclass ForeignContainerCreateError extends KeyingVerificationError {}\n\nfunction foreignCreate(\n code: KeyingVerificationCode,\n message: string,\n): ForeignContainerCreateError {\n return new ForeignContainerCreateError(code, `${LABEL} ${message}`);\n}\n\nasync function verifyAdoptableProjection(input: {\n readonly containerId: string;\n readonly expectedOrganizationId: string;\n readonly projection: ContainerWriterProjectionResponse;\n readonly sessionUserId: string;\n readonly state: ContainerCreateIntentSyncState;\n}): Promise<AdoptedContainerPlacement> {\n const { projection } = input;\n if (\n projection.containerId !== input.containerId ||\n projection.organizationId !== input.expectedOrganizationId\n ) {\n // The envelope is unsigned: a corrupt read is retried, not parked.\n throw new KeyingVerificationError(\n \"object_mismatch\",\n `${LABEL} projection has the wrong identity`,\n );\n }\n const { path, verifiedByHash } = await verifyContainerDestinationProjection({\n execSql: input.state.runtime.infra.execSql,\n projection,\n resolveUserKey: input.state.resolveProjectionUserKey,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.state.runtime,\n ),\n });\n const head = path.at(-1);\n // One read naming another container says nothing signed about this id.\n if (!head || head.state.containerId !== input.containerId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n `${LABEL} projection names another container`,\n );\n }\n const create = verifiedContainerCreateManifest({\n head,\n label: LABEL,\n verifiedByHash,\n });\n if (create.event.event.signerUserId !== input.sessionUserId) {\n throw foreignCreate(\"signer_mismatch\", \"was signed by another user\");\n }\n if (create.state.organizationId !== input.expectedOrganizationId) {\n throw foreignCreate(\"object_mismatch\", \"belongs to another organization\");\n }\n const createdParentId = create.state.parentContainerId;\n const currentParentId = head.state.parentContainerId;\n if (createdParentId === null || currentParentId === null) {\n throw foreignCreate(\"object_mismatch\", \"is an organization root\");\n }\n return { createdParentId, currentParentId };\n}\n\n/**\n * A pending create whose container the listing already carries is adopted\n * only when the container's signed epoch-1 `container.create` is this user's,\n * in the intended organization (#2365 finding 26). Listing metadata is\n * unsigned: a create by another writer that collides on the pending id, or one\n * a dishonest server invents, must not become this device's container.\n * Documents apply the same rule (`workflows/documents/createAdoption.ts`).\n *\n * Returns where the create committed and where the verified head sits now.\n * The user may have moved the pending container since, which rewrites its\n * intent's parent; that is a move still owed, not a mismatch.\n */\nasync function assertContainerCreateAdoptable(input: {\n readonly containerId: string;\n readonly expectedOrganizationId: string;\n readonly state: ContainerCreateIntentSyncState;\n}): Promise<AdoptedContainerPlacement> {\n const { runtime } = input.state;\n const sessionUserId = runtime.auth.userId;\n // Without a session user there is no signer to compare: not tampering.\n if (!sessionUserId) {\n throw new Error(`${LABEL} needs a signed-in session user`);\n }\n const projection = await runtime.apiClient.getContainerWriterProjection(\n input.containerId,\n );\n if (!projection) {\n throw new Error(`${LABEL} is unavailable to verify`);\n }\n try {\n return await verifyAdoptableProjection({\n ...input,\n projection,\n sessionUserId,\n });\n } catch (error) {\n // Never re-serve a cached projection that failed verification.\n if (isKeyingVerificationError(error)) {\n runtime.apiClient.evictContainerWriterProjection(input.containerId);\n }\n throw error;\n }\n}\n\nfunction verifyListedContainerCreate(input: {\n readonly intent: ContainerCreateIntentSyncInput[\"intent\"];\n readonly parentState: ContainerState;\n readonly state: ContainerCreateIntentSyncState;\n}): Promise<AdoptedContainerPlacement> {\n const adoption = {\n containerId: input.intent.containerId,\n expectedOrganizationId: input.parentState.container.organizationId,\n };\n return input.state.verifyCreateAdoption\n ? input.state.verifyCreateAdoption(adoption)\n : assertContainerCreateAdoptable({ ...adoption, state: input.state });\n}\n\n/** Settles a verified adoption against the row hydration installed. */\nasync function markContainerCreateIntentAdopted(input: {\n containerState: ContainerState;\n placement: AdoptedContainerPlacement;\n syncInput: ContainerCreateIntentSyncInput;\n}): Promise<boolean> {\n const { containerState, placement, syncInput } = input;\n const remoteMetadataDocumentId = containerState.record.documentId;\n const remoteMetadataAccessStateHash = containerState.record.accessStateHash;\n\n if (!remoteMetadataDocumentId || !remoteMetadataAccessStateHash) {\n return false;\n }\n return settleContainerCreateIntent({\n createdParentContainerId: placement.createdParentId,\n desiredParentContainerId: syncInput.intent.parentContainerId,\n intent: syncInput.intent,\n isCurrent: syncInput.isCurrent,\n remoteContainerId: containerState.container.id,\n remoteMetadataAccessStateHash,\n remoteMetadataDocumentId,\n state: syncInput.state,\n supersededMovePreviousParentId: placement.currentParentId,\n });\n}\n\n/**\n * Records a failed adoption and leaves the lane's other intents to proceed. A\n * foreign create parks the intent: its signed facts never change, so later\n * passes neither re-read it nor report it again. Any other failure retries.\n */\nasync function recordAdoptionFailure(input: {\n readonly error: unknown;\n readonly organizationId: string;\n readonly syncInput: ContainerCreateIntentSyncInput;\n}): Promise<\"abandoned\" | \"failed\"> {\n const { intent, isCurrent, state } = input.syncInput;\n if (!isCurrent()) return \"abandoned\";\n await reportKeyingVerificationErrorInCauseChain(\n input.error,\n state.runtime.util.reportSecurityIncident,\n {\n objectId: intent.containerId,\n objectKind: \"container\",\n operation: \"container.create.replay\",\n organizationId: input.organizationId,\n },\n );\n if (!isCurrent()) return \"abandoned\";\n const action =\n input.error instanceof ForeignContainerCreateError\n ? CONTAINER_CREATE_ADOPTION_REFUSED\n : \"Container create adoption verification failed\";\n await state.persistence.recordCreateIntentRevisionError(\n state.runtime.infra.execSql,\n {\n containerId: intent.containerId,\n expectedIntentId: intent.id,\n expectedUpdatedAt: intent.updatedAt,\n message: `${action}: ${errorMessage(input.error)}`,\n stillCurrent: isCurrent,\n },\n );\n return isCurrent() ? \"failed\" : \"abandoned\";\n}\n\n/**\n * Adopts a pending create the listing already carries, once its signed create\n * proves it is this device's. A parked refusal stays blocked without a read.\n */\nexport async function syncListedContainerCreate(input: {\n readonly containerState: ContainerState;\n readonly parentState: ContainerState;\n readonly syncInput: ContainerCreateIntentSyncInput;\n}): Promise<\"abandoned\" | \"blocked\" | \"created\" | \"failed\"> {\n const { containerState, parentState, syncInput } = input;\n const { intent, isCurrent, state } = syncInput;\n if (intent.lastError?.startsWith(CONTAINER_CREATE_ADOPTION_REFUSED)) {\n return \"blocked\";\n }\n let placement: AdoptedContainerPlacement;\n try {\n placement = await verifyListedContainerCreate({\n intent,\n parentState,\n state,\n });\n } catch (error) {\n return recordAdoptionFailure({\n error,\n organizationId: parentState.container.organizationId,\n syncInput,\n });\n }\n const marked = await markContainerCreateIntentAdopted({\n containerState,\n placement,\n syncInput,\n });\n if (!marked) return isCurrent() ? \"blocked\" : \"abandoned\";\n // The folder now sits elsewhere; list it there rather than waiting for the\n // next poll to correct the local parent.\n if (placement.currentParentId !== intent.parentContainerId) {\n syncInput.requestRemoteReconciliation(placement.currentParentId);\n }\n return \"created\";\n}\n"]}
|
|
1
|
+
{"version":3,"file":"createAdoption.js","sourceRoot":"","sources":["createAdoption.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type KeyingVerificationCode,\n KeyingVerificationError,\n} from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { verifiedContainerCreateManifest } from \"../../../data/keyingProjectionVerification/containerCreateManifest\";\nimport { verifyContainerDestinationProjection } from \"../../../data/keyingProjectionVerification/containerDestinationVerification\";\nimport {\n isKeyingVerificationError,\n reportKeyingVerificationErrorInCauseChain,\n} from \"../../../data/keyingProjectionVerification/error\";\nimport { errorMessage } from \"../../../data/shared/errorMessage\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../principals/runtimePolicyWarmer\";\nimport type { ContainerState } from \"../remoteHydration\";\nimport { settleContainerCreateIntent } from \"./createIntentSettlement\";\nimport type {\n AdoptedContainerPlacement,\n ContainerCreateIntentSyncInput,\n ContainerCreateIntentSyncState,\n} from \"./types\";\n\nconst LABEL = \"Container create conflict\";\n\n/** The recorded error that parks an intent whose listed create is foreign. */\nexport const CONTAINER_CREATE_ADOPTION_REFUSED =\n \"Container create adoption was refused\";\n\n/**\n * The listed create's signed identity is not this device's pending create: its\n * signed create names another signer, another organization, or a root. An honest server never lists that under the\n * id this device minted, and no later read can change those signed facts, so\n * the intent parks instead of re-verifying.\n */\nclass ForeignContainerCreateError extends KeyingVerificationError {}\n\nfunction foreignCreate(\n code: KeyingVerificationCode,\n message: string,\n): ForeignContainerCreateError {\n return new ForeignContainerCreateError(code, `${LABEL} ${message}`);\n}\n\nasync function verifyAdoptableProjection(input: {\n readonly containerId: string;\n readonly expectedOrganizationId: string;\n readonly projection: ContainerWriterProjectionResponse;\n readonly sessionUserId: string;\n readonly state: ContainerCreateIntentSyncState;\n}): Promise<AdoptedContainerPlacement> {\n const { projection } = input;\n if (\n projection.containerId !== input.containerId ||\n projection.organizationId !== input.expectedOrganizationId\n ) {\n // The envelope is unsigned: a corrupt read is retried, not parked.\n throw new KeyingVerificationError(\n \"object_mismatch\",\n `${LABEL} projection has the wrong identity`,\n );\n }\n const { path, verifiedByHash } = await verifyContainerDestinationProjection({\n execSql: input.state.runtime.infra.execSql,\n projection,\n resolveUserKey: input.state.resolveProjectionUserKey,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.state.runtime,\n ),\n });\n const head = path.at(-1);\n // One read naming another container says nothing signed about this id.\n if (!head || head.state.containerId !== input.containerId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n `${LABEL} projection names another container`,\n );\n }\n const create = verifiedContainerCreateManifest({\n head,\n label: LABEL,\n verifiedByHash,\n });\n if (create.event.event.signerUserId !== input.sessionUserId) {\n throw foreignCreate(\"signer_mismatch\", \"was signed by another user\");\n }\n if (create.state.organizationId !== input.expectedOrganizationId) {\n throw foreignCreate(\"object_mismatch\", \"belongs to another organization\");\n }\n const createdParentId = create.state.parentContainerId;\n const currentParentId = head.state.parentContainerId;\n if (createdParentId === null || currentParentId === null) {\n throw foreignCreate(\"object_mismatch\", \"is an organization root\");\n }\n return { createdParentId, currentParentId };\n}\n\n/**\n * A pending create whose container the listing already carries is adopted\n * only when the container's signed epoch-1 `container.create` is this user's,\n * in the intended organization (#2365 finding 26). Listing metadata is\n * unsigned: a create by another writer that collides on the pending id, or one\n * a dishonest server invents, must not become this device's container.\n * Documents apply the same rule (`workflows/documents/createAdoption.ts`).\n *\n * Returns where the create committed and where the verified head sits now.\n * The user may have moved the pending container since, which rewrites its\n * intent's parent; that is a move still owed, not a mismatch.\n */\nasync function assertContainerCreateAdoptable(input: {\n readonly containerId: string;\n readonly expectedOrganizationId: string;\n readonly state: ContainerCreateIntentSyncState;\n}): Promise<AdoptedContainerPlacement> {\n const { runtime } = input.state;\n const sessionUserId = runtime.auth.userId;\n // Without a session user there is no signer to compare: not tampering.\n if (!sessionUserId) {\n throw new Error(`${LABEL} needs a signed-in session user`);\n }\n const projection = await runtime.apiClient.getContainerWriterProjection(\n input.containerId,\n );\n if (!projection) {\n throw new Error(`${LABEL} is unavailable to verify`);\n }\n try {\n return await verifyAdoptableProjection({\n ...input,\n projection,\n sessionUserId,\n });\n } catch (error) {\n // Never re-serve a cached projection that failed verification.\n if (isKeyingVerificationError(error)) {\n runtime.apiClient.evictContainerWriterProjection(input.containerId);\n }\n throw error;\n }\n}\n\nfunction verifyListedContainerCreate(input: {\n readonly intent: ContainerCreateIntentSyncInput[\"intent\"];\n readonly parentState: ContainerState;\n readonly state: ContainerCreateIntentSyncState;\n}): Promise<AdoptedContainerPlacement> {\n const adoption = {\n containerId: input.intent.containerId,\n expectedOrganizationId: input.parentState.container.organizationId,\n };\n return input.state.verifyCreateAdoption\n ? input.state.verifyCreateAdoption(adoption)\n : assertContainerCreateAdoptable({ ...adoption, state: input.state });\n}\n\n/** Settles a verified adoption against the row hydration installed. */\nasync function markContainerCreateIntentAdopted(input: {\n containerState: ContainerState;\n placement: AdoptedContainerPlacement;\n syncInput: ContainerCreateIntentSyncInput;\n}): Promise<boolean> {\n const { containerState, placement, syncInput } = input;\n const remoteMetadataDocumentId = containerState.record.documentId;\n const remoteMetadataAccessStateHash = containerState.record.accessStateHash;\n\n if (!remoteMetadataDocumentId || !remoteMetadataAccessStateHash) {\n return false;\n }\n return settleContainerCreateIntent({\n createdParentContainerId: placement.createdParentId,\n desiredParentContainerId: syncInput.intent.parentContainerId,\n intent: syncInput.intent,\n isCurrent: syncInput.isCurrent,\n remoteContainerId: containerState.container.id,\n remoteMetadataAccessStateHash,\n remoteMetadataDocumentId,\n state: syncInput.state,\n supersededMovePreviousParentId: placement.currentParentId,\n });\n}\n\n/**\n * Records a failed adoption and leaves the lane's other intents to proceed. A\n * foreign create parks the intent: its signed facts never change, so later\n * passes neither re-read it nor report it again. Any other failure retries.\n */\nasync function recordAdoptionFailure(input: {\n readonly error: unknown;\n readonly organizationId: string;\n readonly syncInput: ContainerCreateIntentSyncInput;\n}): Promise<\"abandoned\" | \"failed\"> {\n const { intent, isCurrent, state } = input.syncInput;\n if (!isCurrent()) return \"abandoned\";\n await reportKeyingVerificationErrorInCauseChain(\n input.error,\n state.runtime.util.reportSecurityIncident,\n {\n objectId: intent.containerId,\n objectKind: \"container\",\n operation: \"container.create.replay\",\n organizationId: input.organizationId,\n },\n );\n if (!isCurrent()) return \"abandoned\";\n const action =\n input.error instanceof ForeignContainerCreateError\n ? CONTAINER_CREATE_ADOPTION_REFUSED\n : \"Container create adoption verification failed\";\n await state.persistence.recordCreateIntentRevisionError(\n state.runtime.infra.execSql,\n {\n containerId: intent.containerId,\n expectedIntentId: intent.id,\n expectedUpdatedAt: intent.updatedAt,\n message: `${action}: ${errorMessage(input.error)}`,\n stillCurrent: isCurrent,\n },\n );\n return isCurrent() ? \"failed\" : \"abandoned\";\n}\n\n/**\n * Adopts a pending create the listing already carries, once its signed create\n * proves it is this device's. A parked refusal stays blocked without a read.\n */\nexport async function syncListedContainerCreate(input: {\n readonly containerState: ContainerState;\n readonly parentState: ContainerState;\n readonly syncInput: ContainerCreateIntentSyncInput;\n}): Promise<\"abandoned\" | \"blocked\" | \"created\" | \"failed\"> {\n const { containerState, parentState, syncInput } = input;\n const { intent, isCurrent, state } = syncInput;\n if (intent.lastError?.startsWith(CONTAINER_CREATE_ADOPTION_REFUSED)) {\n return \"blocked\";\n }\n let placement: AdoptedContainerPlacement;\n try {\n placement = await verifyListedContainerCreate({\n intent,\n parentState,\n state,\n });\n } catch (error) {\n return recordAdoptionFailure({\n error,\n organizationId: parentState.container.organizationId,\n syncInput,\n });\n }\n const marked = await markContainerCreateIntentAdopted({\n containerState,\n placement,\n syncInput,\n });\n if (!marked) return isCurrent() ? \"blocked\" : \"abandoned\";\n // The folder now sits elsewhere; list it there rather than waiting for the\n // next poll to correct the local parent.\n if (placement.currentParentId !== intent.parentContainerId) {\n syncInput.requestRemoteReconciliation(placement.currentParentId);\n }\n return \"created\";\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { bytesToBase64 } from "../../../internal/encoding/index.js";
|
|
2
2
|
import { createInitializedContainerMetadataDocument } from "../../../data/containers/containerMetadataDocument.js";
|
|
3
3
|
import { createPendingUpdateFields } from "../../../data/documents/documentSync.js";
|
|
4
|
-
import { deriveStableUuidV4Shaped } from "../../../data/stableUuid.js";
|
|
4
|
+
import { deriveStableUuidV4Shaped } from "../../../data/keying/stableUuid.js";
|
|
5
5
|
import { defaultContainerContentsPersistence } from "../containerPersistence.js";
|
|
6
6
|
import { CONTAINER_ALREADY_COMMITTED } from "./createWithMetadata.js";
|
|
7
7
|
import { loadContainerWriterProjectionForState } from "./projectionCache.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createChild.js","sourceRoot":"","sources":["createChild.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport { createInitializedContainerMetadataDocument } from \"../../../data/containers/containerMetadataDocument\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport type { ProjectionUserKeyResolver } from \"../../../data/keyingProjectionVerification\";\nimport { deriveStableUuidV4Shaped } from \"../../../data/stableUuid\";\nimport type {\n ContainerContentsPersistence,\n ContainerDocumentRecord as DocumentRecord,\n} from \"../containerPersistence\";\nimport { defaultContainerContentsPersistence } from \"../containerPersistence\";\nimport type { ContainerState } from \"../remoteHydration\";\nimport { CONTAINER_ALREADY_COMMITTED } from \"./createWithMetadata\";\nimport { loadContainerWriterProjectionForState } from \"./projectionCache\";\nimport { createRemoteContainer } from \"./remote\";\nimport type {\n ContainerMetadataDocumentState,\n ContainerWorkflowRuntime,\n CreatedChildContainerState,\n} from \"./types\";\n\nconst SYSTEM_CONTAINER_ID_NAMESPACE_BYTES = new Uint8Array([\n 0xc5, 0x5e, 0x8f, 0x2e, 0x3d, 0x82, 0x4b, 0x4d, 0x8d, 0xbd, 0x0d, 0xd2, 0xd3,\n 0x60, 0xb3, 0x6d,\n]);\n\n/**\n * Derives a stable, UUID-shaped container id for a built-in system slot.\n *\n * The namespace digest makes each slot idempotent across stale store snapshots.\n * The UUID version and variant bits are normalized to a v4 shape because remote\n * container APIs currently validate container ids with the same v4 UUID contract\n * they use for random user-created containers.\n */\nfunction deriveSystemContainerId(input: {\n parentContainerId: string;\n systemSlot: ContainerSystemSlot;\n}): Promise<string> {\n return deriveStableUuidV4Shaped(\n SYSTEM_CONTAINER_ID_NAMESPACE_BYTES,\n `${input.parentContainerId}\\u0000${input.systemSlot}`,\n );\n}\n\nasync function createChildContainerId(\n parentContainerId: string,\n systemSlot: ContainerSystemSlot | null | undefined,\n): Promise<string> {\n return systemSlot\n ? deriveSystemContainerId({ parentContainerId, systemSlot })\n : crypto.randomUUID();\n}\n\nasync function buildRemoteContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n trimmedName: string;\n}): Promise<ContainerState | null> {\n const {\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n trimmedName,\n } = input;\n const parentProjection = await loadContainerWriterProjectionForState({\n containerState: parentState,\n runtime,\n });\n if (!parentProjection) {\n return null;\n }\n\n const created = await createRemoteContainer({\n systemSlot,\n containerId: childId,\n parentContainerId: parentState.container.id,\n parentProjection,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n });\n\n if (!created || created === CONTAINER_ALREADY_COMMITTED) {\n // A benign manifest-exists conflict means the container is already committed\n // remotely (a lost create response). This eager path cannot rebuild its\n // committed metadata state, so leave the create intent to reconcile it via\n // hydration rather than fabricating a local record from a missing response.\n return null;\n }\n\n return {\n container: {\n id: created.containerId,\n // The creator owns a newly-created container until the server reconciles.\n effectiveAccessLevel: \"admin\",\n organizationId: created.organizationId,\n parentId: created.parentId,\n metadataDocumentId: created.metadataDocumentId,\n systemSlot: created.systemSlot,\n name: trimmedName,\n icon,\n createdAt: created.createdAt,\n serverCreatedAt: created.createdAt,\n serverUpdatedAt: created.updatedAt,\n updatedAt: created.updatedAt,\n },\n doc,\n record: {\n ...initialRecord,\n accessEpoch: 1,\n accessStateHash: created.accessManifestHash,\n ...created.persistedMetadataState,\n },\n };\n}\n\nfunction buildLocalContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n trimmedName: string;\n}): ContainerState {\n const {\n systemSlot,\n childId,\n doc,\n icon,\n initialRecord,\n parentState,\n trimmedName,\n } = input;\n\n return {\n container: {\n id: childId,\n effectiveAccessLevel: \"admin\",\n organizationId: parentState.container.organizationId,\n parentId: parentState.container.id,\n metadataDocumentId: null,\n systemSlot: systemSlot ?? null,\n name: trimmedName,\n icon,\n },\n doc,\n record: initialRecord,\n };\n}\n\nfunction createInitialChildContainerDocumentRecord(input: {\n childId: string;\n initialUpdate: Uint8Array;\n}): DocumentRecord {\n return {\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n id: input.childId,\n lastCommitLsn: null,\n metadataUpdates: bytesToBase64(input.initialUpdate),\n snapshotEndVersion: \"\",\n };\n}\n\nfunction resolveAtomicChildContainerSave(\n persistence: ContainerContentsPersistence,\n): NonNullable<\n ContainerContentsPersistence[\"saveContainerWithPendingUpdate\"]\n> | null {\n const saveContainerWithPendingUpdate =\n persistence.saveContainerWithPendingUpdate;\n if (!saveContainerWithPendingUpdate) return null;\n const inheritedSqlAtomicSave =\n saveContainerWithPendingUpdate ===\n defaultContainerContentsPersistence.saveContainerWithPendingUpdate &&\n (persistence.saveContainer !==\n defaultContainerContentsPersistence.saveContainer ||\n persistence.enqueuePendingUpdate !==\n defaultContainerContentsPersistence.enqueuePendingUpdate);\n return inheritedSqlAtomicSave ? null : saveContainerWithPendingUpdate;\n}\n\nasync function persistCreatedChildContainer(input: {\n containerState: ContainerState;\n initialUpdate: Uint8Array;\n persistence: ContainerContentsPersistence;\n queueRemoteSync: boolean;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean | null> {\n const { containerState, persistence, queueRemoteSync, runtime } = input;\n const createIntent =\n queueRemoteSync &&\n !containerState.record.documentId &&\n containerState.container.parentId\n ? { parentContainerId: containerState.container.parentId }\n : undefined;\n const shouldRequestSync =\n queueRemoteSync &&\n (!containerState.record.documentId ||\n Boolean(containerState.record.contentKeyBundle));\n const saveOptions =\n createIntent || input.stillCurrent\n ? {\n ...(createIntent ? { createIntent } : {}),\n stillCurrent: input.stillCurrent,\n }\n : undefined;\n const pendingUpdate = shouldRequestSync\n ? createPendingUpdateFields(input.initialUpdate)\n : null;\n if (pendingUpdate) {\n const saveContainerWithPendingUpdate =\n resolveAtomicChildContainerSave(persistence);\n if (!saveContainerWithPendingUpdate) return null;\n containerState.container = await saveContainerWithPendingUpdate(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n { ...saveOptions, pendingUpdate },\n );\n } else {\n containerState.container = await persistence.saveContainer(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n saveOptions,\n );\n }\n return input.stillCurrent?.() === false ? null : shouldRequestSync;\n}\n\nexport async function createChildContainerState(input: {\n systemSlot?: ContainerSystemSlot | null | undefined;\n createRemote: boolean;\n icon?: string | null | undefined;\n name: string;\n parentState: ContainerState;\n persistence: ContainerContentsPersistence;\n queueRemoteSync?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<CreatedChildContainerState | null> {\n const {\n createRemote,\n systemSlot,\n name,\n parentState,\n persistence,\n queueRemoteSync = true,\n resolveProjectionUserKey,\n runtime,\n } = input;\n const trimmedName = name.trim();\n if (!trimmedName) {\n return null;\n }\n\n const icon = input.icon?.trim() || null;\n const childId = await createChildContainerId(\n parentState.container.id,\n systemSlot,\n );\n const { doc, initialUpdate } =\n await createInitializedContainerMetadataDocument(childId, {\n icon,\n name: trimmedName,\n });\n const initialRecord = createInitialChildContainerDocumentRecord({\n childId,\n initialUpdate,\n });\n if (input.stillCurrent?.() === false) return null;\n // An initial metadata update and its container identity are one durable unit.\n // Refuse before any remote create when an adapter cannot provide\n // that atomic operation; a SQLite transaction cannot roll back adapter-owned\n // side effects.\n if (queueRemoteSync && !resolveAtomicChildContainerSave(persistence)) {\n return null;\n }\n\n const remoteChildState = createRemote\n ? await buildRemoteContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent: input.stillCurrent,\n trimmedName,\n })\n : null;\n const containerState =\n remoteChildState ??\n buildLocalContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n trimmedName,\n });\n const shouldRequestSync = await persistCreatedChildContainer({\n containerState,\n initialUpdate,\n persistence,\n queueRemoteSync,\n runtime,\n stillCurrent: input.stillCurrent,\n });\n if (shouldRequestSync === null) return null;\n\n return {\n containerState,\n initialUpdate,\n shouldRequestSync,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"createChild.js","sourceRoot":"","sources":["createChild.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,0CAA0C,EAAE,MAAM,oDAAoD,CAAC;AAChH,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAM3E,OAAO,EAAE,mCAAmC,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,qCAAqC,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAOjD,MAAM,mCAAmC,GAAG,IAAI,UAAU,CAAC;IACzD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC5E,IAAI,EAAE,IAAI,EAAE,IAAI;CACjB,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,SAAS,uBAAuB,CAAC,KAGhC;IACC,OAAO,wBAAwB,CAC7B,mCAAmC,EACnC,GAAG,KAAK,CAAC,iBAAiB,SAAS,KAAK,CAAC,UAAU,EAAE,CACtD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,iBAAyB,EACzB,UAAkD;IAElD,OAAO,UAAU;QACf,CAAC,CAAC,uBAAuB,CAAC,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC;QAC5D,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;AAC1B,CAAC;AAED,KAAK,UAAU,+CAA+C,CAAC,KAW9D;IACC,MAAM,EACJ,OAAO,EACP,IAAI,EACJ,UAAU,EACV,GAAG,EACH,aAAa,EACb,WAAW,EACX,wBAAwB,EACxB,OAAO,EACP,YAAY,EACZ,WAAW,GACZ,GAAG,KAAK,CAAC;IACV,MAAM,gBAAgB,GAAG,MAAM,qCAAqC,CAAC;QACnE,cAAc,EAAE,WAAW;QAC3B,OAAO;KACR,CAAC,CAAC;IACH,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC;QAC1C,UAAU;QACV,WAAW,EAAE,OAAO;QACpB,iBAAiB,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE;QAC3C,gBAAgB;QAChB,wBAAwB;QACxB,OAAO;QACP,YAAY;KACb,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,2BAA2B,EAAE,CAAC;QACxD,6EAA6E;QAC7E,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,SAAS,EAAE;YACT,EAAE,EAAE,OAAO,CAAC,WAAW;YACvB,0EAA0E;YAC1E,oBAAoB,EAAE,OAAO;YAC7B,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;YAC9C,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,IAAI,EAAE,WAAW;YACjB,IAAI;YACJ,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,eAAe,EAAE,OAAO,CAAC,SAAS;YAClC,eAAe,EAAE,OAAO,CAAC,SAAS;YAClC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B;QACD,GAAG;QACH,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,OAAO,CAAC,kBAAkB;YAC3C,GAAG,OAAO,CAAC,sBAAsB;SAClC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,8CAA8C,CAAC,KAQvD;IACC,MAAM,EACJ,UAAU,EACV,OAAO,EACP,GAAG,EACH,IAAI,EACJ,aAAa,EACb,WAAW,EACX,WAAW,GACZ,GAAG,KAAK,CAAC;IAEV,OAAO;QACL,SAAS,EAAE;YACT,EAAE,EAAE,OAAO;YACX,oBAAoB,EAAE,OAAO;YAC7B,cAAc,EAAE,WAAW,CAAC,SAAS,CAAC,cAAc;YACpD,QAAQ,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE;YAClC,kBAAkB,EAAE,IAAI;YACxB,UAAU,EAAE,UAAU,IAAI,IAAI;YAC9B,IAAI,EAAE,WAAW;YACjB,IAAI;SACL;QACD,GAAG;QACH,MAAM,EAAE,aAAa;KACtB,CAAC;AACJ,CAAC;AAED,SAAS,yCAAyC,CAAC,KAGlD;IACC,OAAO;QACL,WAAW,EAAE,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,gBAAgB,EAAE,IAAI;QACtB,UAAU,EAAE,IAAI;QAChB,kBAAkB,EAAE,IAAI;QACxB,sBAAsB,EAAE,IAAI;QAC5B,EAAE,EAAE,KAAK,CAAC,OAAO;QACjB,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC;QACnD,kBAAkB,EAAE,EAAE;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,WAAyC;IAIzC,MAAM,8BAA8B,GAClC,WAAW,CAAC,8BAA8B,CAAC;IAC7C,IAAI,CAAC,8BAA8B;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,sBAAsB,GAC1B,8BAA8B;QAC5B,mCAAmC,CAAC,8BAA8B;QACpE,CAAC,WAAW,CAAC,aAAa;YACxB,mCAAmC,CAAC,aAAa;YACjD,WAAW,CAAC,oBAAoB;gBAC9B,mCAAmC,CAAC,oBAAoB,CAAC,CAAC;IAChE,OAAO,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,8BAA8B,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,4BAA4B,CAAC,KAO3C;IACC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IACxE,MAAM,YAAY,GAChB,eAAe;QACf,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU;QACjC,cAAc,CAAC,SAAS,CAAC,QAAQ;QAC/B,CAAC,CAAC,EAAE,iBAAiB,EAAE,cAAc,CAAC,SAAS,CAAC,QAAQ,EAAE;QAC1D,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,iBAAiB,GACrB,eAAe;QACf,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU;YAChC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACrD,MAAM,WAAW,GACf,YAAY,IAAI,KAAK,CAAC,YAAY;QAChC,CAAC,CAAC;YACE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC;QACH,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,aAAa,GAAG,iBAAiB;QACrC,CAAC,CAAC,yBAAyB,CAAC,KAAK,CAAC,aAAa,CAAC;QAChD,CAAC,CAAC,IAAI,CAAC;IACT,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,8BAA8B,GAClC,+BAA+B,CAAC,WAAW,CAAC,CAAC;QAC/C,IAAI,CAAC,8BAA8B;YAAE,OAAO,IAAI,CAAC;QACjD,cAAc,CAAC,SAAS,GAAG,MAAM,8BAA8B,CAC7D,OAAO,CAAC,KAAK,CAAC,OAAO,EACrB,cAAc,CAAC,SAAS,EACxB,cAAc,CAAC,MAAM,EACrB,EAAE,GAAG,WAAW,EAAE,aAAa,EAAE,CAClC,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,SAAS,GAAG,MAAM,WAAW,CAAC,aAAa,CACxD,OAAO,CAAC,KAAK,CAAC,OAAO,EACrB,cAAc,CAAC,SAAS,EACxB,cAAc,CAAC,MAAM,EACrB,WAAW,CACZ,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAW/C;IACC,MAAM,EACJ,YAAY,EACZ,UAAU,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,eAAe,GAAG,IAAI,EACtB,wBAAwB,EACxB,OAAO,GACR,GAAG,KAAK,CAAC;IACV,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAC1C,WAAW,CAAC,SAAS,CAAC,EAAE,EACxB,UAAU,CACX,CAAC;IACF,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,GAC1B,MAAM,0CAA0C,CAAC,OAAO,EAAE;QACxD,IAAI;QACJ,IAAI,EAAE,WAAW;KAClB,CAAC,CAAC;IACL,MAAM,aAAa,GAAG,yCAAyC,CAAC;QAC9D,OAAO;QACP,aAAa;KACd,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAClD,8EAA8E;IAC9E,iEAAiE;IACjE,6EAA6E;IAC7E,gBAAgB;IAChB,IAAI,eAAe,IAAI,CAAC,+BAA+B,CAAC,WAAW,CAAC,EAAE,CAAC;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,gBAAgB,GAAG,YAAY;QACnC,CAAC,CAAC,MAAM,+CAA+C,CAAC;YACpD,OAAO;YACP,IAAI;YACJ,UAAU;YACV,GAAG;YACH,aAAa;YACb,WAAW;YACX,wBAAwB;YACxB,OAAO;YACP,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW;SACZ,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,cAAc,GAClB,gBAAgB;QAChB,8CAA8C,CAAC;YAC7C,OAAO;YACP,IAAI;YACJ,UAAU;YACV,GAAG;YACH,aAAa;YACb,WAAW;YACX,WAAW;SACZ,CAAC,CAAC;IACL,MAAM,iBAAiB,GAAG,MAAM,4BAA4B,CAAC;QAC3D,cAAc;QACd,aAAa;QACb,WAAW;QACX,eAAe;QACf,OAAO;QACP,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAC;IACH,IAAI,iBAAiB,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE5C,OAAO;QACL,cAAc;QACd,aAAa;QACb,iBAAiB;KAClB,CAAC;AACJ,CAAC","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport { createInitializedContainerMetadataDocument } from \"../../../data/containers/containerMetadataDocument\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport { deriveStableUuidV4Shaped } from \"../../../data/keying/stableUuid\";\nimport type { ProjectionUserKeyResolver } from \"../../../data/keyingProjectionVerification\";\nimport type {\n ContainerContentsPersistence,\n ContainerDocumentRecord as DocumentRecord,\n} from \"../containerPersistence\";\nimport { defaultContainerContentsPersistence } from \"../containerPersistence\";\nimport type { ContainerState } from \"../remoteHydration\";\nimport { CONTAINER_ALREADY_COMMITTED } from \"./createWithMetadata\";\nimport { loadContainerWriterProjectionForState } from \"./projectionCache\";\nimport { createRemoteContainer } from \"./remote\";\nimport type {\n ContainerMetadataDocumentState,\n ContainerWorkflowRuntime,\n CreatedChildContainerState,\n} from \"./types\";\n\nconst SYSTEM_CONTAINER_ID_NAMESPACE_BYTES = new Uint8Array([\n 0xc5, 0x5e, 0x8f, 0x2e, 0x3d, 0x82, 0x4b, 0x4d, 0x8d, 0xbd, 0x0d, 0xd2, 0xd3,\n 0x60, 0xb3, 0x6d,\n]);\n\n/**\n * Derives a stable, UUID-shaped container id for a built-in system slot.\n *\n * The namespace digest makes each slot idempotent across stale store snapshots.\n * The UUID version and variant bits are normalized to a v4 shape because remote\n * container APIs currently validate container ids with the same v4 UUID contract\n * they use for random user-created containers.\n */\nfunction deriveSystemContainerId(input: {\n parentContainerId: string;\n systemSlot: ContainerSystemSlot;\n}): Promise<string> {\n return deriveStableUuidV4Shaped(\n SYSTEM_CONTAINER_ID_NAMESPACE_BYTES,\n `${input.parentContainerId}\\u0000${input.systemSlot}`,\n );\n}\n\nasync function createChildContainerId(\n parentContainerId: string,\n systemSlot: ContainerSystemSlot | null | undefined,\n): Promise<string> {\n return systemSlot\n ? deriveSystemContainerId({ parentContainerId, systemSlot })\n : crypto.randomUUID();\n}\n\nasync function buildRemoteContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n trimmedName: string;\n}): Promise<ContainerState | null> {\n const {\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n trimmedName,\n } = input;\n const parentProjection = await loadContainerWriterProjectionForState({\n containerState: parentState,\n runtime,\n });\n if (!parentProjection) {\n return null;\n }\n\n const created = await createRemoteContainer({\n systemSlot,\n containerId: childId,\n parentContainerId: parentState.container.id,\n parentProjection,\n resolveProjectionUserKey,\n runtime,\n stillCurrent,\n });\n\n if (!created || created === CONTAINER_ALREADY_COMMITTED) {\n // A benign manifest-exists conflict means the container is already committed\n // remotely (a lost create response). This eager path cannot rebuild its\n // committed metadata state, so leave the create intent to reconcile it via\n // hydration rather than fabricating a local record from a missing response.\n return null;\n }\n\n return {\n container: {\n id: created.containerId,\n // The creator owns a newly-created container until the server reconciles.\n effectiveAccessLevel: \"admin\",\n organizationId: created.organizationId,\n parentId: created.parentId,\n metadataDocumentId: created.metadataDocumentId,\n systemSlot: created.systemSlot,\n name: trimmedName,\n icon,\n createdAt: created.createdAt,\n serverCreatedAt: created.createdAt,\n serverUpdatedAt: created.updatedAt,\n updatedAt: created.updatedAt,\n },\n doc,\n record: {\n ...initialRecord,\n accessEpoch: 1,\n accessStateHash: created.accessManifestHash,\n ...created.persistedMetadataState,\n },\n };\n}\n\nfunction buildLocalContainerContentsChildContainerState(input: {\n childId: string;\n icon: string | null;\n systemSlot?: ContainerSystemSlot | null | undefined;\n doc: ContainerMetadataDocumentState;\n initialRecord: DocumentRecord;\n parentState: ContainerState;\n trimmedName: string;\n}): ContainerState {\n const {\n systemSlot,\n childId,\n doc,\n icon,\n initialRecord,\n parentState,\n trimmedName,\n } = input;\n\n return {\n container: {\n id: childId,\n effectiveAccessLevel: \"admin\",\n organizationId: parentState.container.organizationId,\n parentId: parentState.container.id,\n metadataDocumentId: null,\n systemSlot: systemSlot ?? null,\n name: trimmedName,\n icon,\n },\n doc,\n record: initialRecord,\n };\n}\n\nfunction createInitialChildContainerDocumentRecord(input: {\n childId: string;\n initialUpdate: Uint8Array;\n}): DocumentRecord {\n return {\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n id: input.childId,\n lastCommitLsn: null,\n metadataUpdates: bytesToBase64(input.initialUpdate),\n snapshotEndVersion: \"\",\n };\n}\n\nfunction resolveAtomicChildContainerSave(\n persistence: ContainerContentsPersistence,\n): NonNullable<\n ContainerContentsPersistence[\"saveContainerWithPendingUpdate\"]\n> | null {\n const saveContainerWithPendingUpdate =\n persistence.saveContainerWithPendingUpdate;\n if (!saveContainerWithPendingUpdate) return null;\n const inheritedSqlAtomicSave =\n saveContainerWithPendingUpdate ===\n defaultContainerContentsPersistence.saveContainerWithPendingUpdate &&\n (persistence.saveContainer !==\n defaultContainerContentsPersistence.saveContainer ||\n persistence.enqueuePendingUpdate !==\n defaultContainerContentsPersistence.enqueuePendingUpdate);\n return inheritedSqlAtomicSave ? null : saveContainerWithPendingUpdate;\n}\n\nasync function persistCreatedChildContainer(input: {\n containerState: ContainerState;\n initialUpdate: Uint8Array;\n persistence: ContainerContentsPersistence;\n queueRemoteSync: boolean;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<boolean | null> {\n const { containerState, persistence, queueRemoteSync, runtime } = input;\n const createIntent =\n queueRemoteSync &&\n !containerState.record.documentId &&\n containerState.container.parentId\n ? { parentContainerId: containerState.container.parentId }\n : undefined;\n const shouldRequestSync =\n queueRemoteSync &&\n (!containerState.record.documentId ||\n Boolean(containerState.record.contentKeyBundle));\n const saveOptions =\n createIntent || input.stillCurrent\n ? {\n ...(createIntent ? { createIntent } : {}),\n stillCurrent: input.stillCurrent,\n }\n : undefined;\n const pendingUpdate = shouldRequestSync\n ? createPendingUpdateFields(input.initialUpdate)\n : null;\n if (pendingUpdate) {\n const saveContainerWithPendingUpdate =\n resolveAtomicChildContainerSave(persistence);\n if (!saveContainerWithPendingUpdate) return null;\n containerState.container = await saveContainerWithPendingUpdate(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n { ...saveOptions, pendingUpdate },\n );\n } else {\n containerState.container = await persistence.saveContainer(\n runtime.infra.execSql,\n containerState.container,\n containerState.record,\n saveOptions,\n );\n }\n return input.stillCurrent?.() === false ? null : shouldRequestSync;\n}\n\nexport async function createChildContainerState(input: {\n systemSlot?: ContainerSystemSlot | null | undefined;\n createRemote: boolean;\n icon?: string | null | undefined;\n name: string;\n parentState: ContainerState;\n persistence: ContainerContentsPersistence;\n queueRemoteSync?: boolean | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n runtime: ContainerWorkflowRuntime;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<CreatedChildContainerState | null> {\n const {\n createRemote,\n systemSlot,\n name,\n parentState,\n persistence,\n queueRemoteSync = true,\n resolveProjectionUserKey,\n runtime,\n } = input;\n const trimmedName = name.trim();\n if (!trimmedName) {\n return null;\n }\n\n const icon = input.icon?.trim() || null;\n const childId = await createChildContainerId(\n parentState.container.id,\n systemSlot,\n );\n const { doc, initialUpdate } =\n await createInitializedContainerMetadataDocument(childId, {\n icon,\n name: trimmedName,\n });\n const initialRecord = createInitialChildContainerDocumentRecord({\n childId,\n initialUpdate,\n });\n if (input.stillCurrent?.() === false) return null;\n // An initial metadata update and its container identity are one durable unit.\n // Refuse before any remote create when an adapter cannot provide\n // that atomic operation; a SQLite transaction cannot roll back adapter-owned\n // side effects.\n if (queueRemoteSync && !resolveAtomicChildContainerSave(persistence)) {\n return null;\n }\n\n const remoteChildState = createRemote\n ? await buildRemoteContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n resolveProjectionUserKey,\n runtime,\n stillCurrent: input.stillCurrent,\n trimmedName,\n })\n : null;\n const containerState =\n remoteChildState ??\n buildLocalContainerContentsChildContainerState({\n childId,\n icon,\n systemSlot,\n doc,\n initialRecord,\n parentState,\n trimmedName,\n });\n const shouldRequestSync = await persistCreatedChildContainer({\n containerState,\n initialUpdate,\n persistence,\n queueRemoteSync,\n runtime,\n stillCurrent: input.stillCurrent,\n });\n if (shouldRequestSync === null) return null;\n\n return {\n containerState,\n initialUpdate,\n shouldRequestSync,\n };\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ContainerPathTooDeepError } from "../../../data/containers/shared/containerPathLimits.js";
|
|
2
|
-
import { errorMessage } from "../../../data/errorMessage.js";
|
|
3
2
|
import { reportAndRethrowKeyingVerificationError } from "../../../data/keyingProjectionVerification/error.js";
|
|
4
3
|
import { ContainerCreateIntentSupersededError } from "../../../data/persistence/container-contents/containerIntentPersistence.js";
|
|
4
|
+
import { errorMessage } from "../../../data/shared/errorMessage.js";
|
|
5
5
|
import { createDetachedContainerMetadataState, installDetachedContainerMetadataState, } from "../metadataStateIsolation.js";
|
|
6
6
|
import { hasRemoteContainerMetadataState } from "../remoteHydration/reconciliation.js";
|
|
7
7
|
import { syncListedContainerCreate } from "./createAdoption.js";
|