@tearleads/client-sdk 0.1.25 → 0.1.27

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.
Files changed (47) hide show
  1. package/README.md +6 -0
  2. package/client/Tearleads.js +9 -1
  3. package/client/Tearleads.js.map +1 -1
  4. package/data/persistence/documents/internal/attachmentStagingPersistence.js +3 -1
  5. package/data/persistence/documents/internal/attachmentStagingPersistence.js.map +1 -1
  6. package/data/persistence/documents/internal/syncQueuePersistence.js +8 -5
  7. package/data/persistence/documents/internal/syncQueuePersistence.js.map +1 -1
  8. package/internal/validators/operation/blobBytes.d.ts +1 -1
  9. package/internal/validators/util/blob.d.ts +6 -1
  10. package/internal/validators/util/blob.js +7 -2
  11. package/internal/validators/util/blob.js.map +1 -1
  12. package/internal/validators/util/containerKekKeyringWire.d.ts +1 -1
  13. package/internal/validators/util/containerKekKeyringWire.js +1 -1
  14. package/internal/validators/util/containerKekKeyringWire.js.map +1 -1
  15. package/internal/validators/util/documentSyncLimits.js +6 -4
  16. package/internal/validators/util/documentSyncLimits.js.map +1 -1
  17. package/package.json +1 -1
  18. package/stores/documents/documentStore/attachmentStaging.js +24 -13
  19. package/stores/documents/documentStore/attachmentStaging.js.map +1 -1
  20. package/stores/documents/documentStore/attachments.js +6 -4
  21. package/stores/documents/documentStore/attachments.js.map +1 -1
  22. package/workflows/container-contents/container-state/purgeTree.js +18 -6
  23. package/workflows/container-contents/container-state/purgeTree.js.map +1 -1
  24. package/workflows/container-contents/container-state/purgeTreeContainerDeletion.js +6 -1
  25. package/workflows/container-contents/container-state/purgeTreeContainerDeletion.js.map +1 -1
  26. package/workflows/container-contents/container-state/purgeTreeScope.js +20 -3
  27. package/workflows/container-contents/container-state/purgeTreeScope.js.map +1 -1
  28. package/workflows/container-contents/documentLinks.d.ts +3 -2
  29. package/workflows/container-contents/documentLinks.js +1 -1
  30. package/workflows/container-contents/documentLinks.js.map +1 -1
  31. package/workflows/container-contents/documentPurge.d.ts +2 -1
  32. package/workflows/container-contents/documentPurge.js +1 -1
  33. package/workflows/container-contents/documentPurge.js.map +1 -1
  34. package/workflows/documents/linkSet.d.ts +2 -1
  35. package/workflows/documents/linkSet.js +2 -2
  36. package/workflows/documents/linkSet.js.map +1 -1
  37. package/workflows/documents/linkSetRemote.d.ts +2 -1
  38. package/workflows/documents/linkSetRemote.js +1 -1
  39. package/workflows/documents/linkSetRemote.js.map +1 -1
  40. package/workflows/documents/purge.d.ts +3 -2
  41. package/workflows/documents/purge.js +3 -3
  42. package/workflows/documents/purge.js.map +1 -1
  43. package/workflows/documents/subtreePurgeScope.d.ts +8 -0
  44. package/workflows/documents/subtreePurgeScope.js +12 -5
  45. package/workflows/documents/subtreePurgeScope.js.map +1 -1
  46. package/workflows/organizations/reconcileAcknowledgedPrincipalCurrent.js +22 -17
  47. package/workflows/organizations/reconcileAcknowledgedPrincipalCurrent.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"purge.js","sourceRoot":"","sources":["purge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computeAccessEventBodyHash,\n type DocumentPurgeAccessEventBody,\n KeyingVerificationError,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type { DocumentPurgeRequest } from \"@tearleads/validators/request\";\nimport {\n DOCUMENT_NOT_FOUND_ERROR_CODE,\n type DocumentPurgeProofResponse,\n type DocumentPurgeResponse,\n type DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n containerPathRefs,\n readLinkedContainerIdsFromDocumentManifest,\n} from \"../../data/documents/shared/projection\";\nimport {\n assertDocumentManifestBundleConsistent,\n readManifestContainerId,\n} from \"../../data/documents/shared/readers\";\nimport type {\n DocumentCreateAuthor,\n DocumentSyncApi,\n} from \"../../data/documents/shared/types\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n} from \"../../data/keyingCanonicalJson\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification\";\nimport {\n verifyDocumentPurgeProof,\n verifyDocumentPurgeProofBaseline,\n verifyDocumentWriterProjection,\n} from \"../../data/keyingProjectionVerification\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { documentContainerProjections } from \"../../data/keyingProjectionVerification/documentContainerProjections\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport { assertSubtreePurgePath } from \"./subtreePurgeScope\";\n\ninterface DocumentPurgeApi {\n getDocumentPurgeProof(\n documentId: string,\n options?: {\n readonly documentCheckpointManifestHash?: string;\n },\n requestOptions?: {\n readonly expectedPaymentRequiredOrganizationId?: string;\n },\n ): Promise<DocumentPurgeProofResponse | null>;\n getDocumentWriterProjectionResult: NonNullable<\n DocumentSyncApi[\"getDocumentWriterProjectionResult\"]\n >;\n purgeDocument(\n documentId: string,\n request: DocumentPurgeRequest,\n options?: {\n readonly expectedPaymentRequiredOrganizationId?: string;\n },\n ): Promise<DocumentPurgeResponse | null>;\n}\n\nconst REMOTE_DOCUMENT_ALREADY_PURGED = Symbol(\"remoteDocumentAlreadyPurged\");\n\nasync function loadAuthenticatedDocumentPurgeProof(input: {\n readonly apiClient: Pick<DocumentSyncApi, \"getDocumentPurgeProof\">;\n readonly documentId: string;\n readonly execSql: ExecSql;\n readonly expectedOrganizationId: string;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): Promise<DocumentPurgeProofResponse | null> {\n if (!input.apiClient.getDocumentPurgeProof) {\n throw new ProjectionDependencyUnavailableError(\n \"Remote document deletion is missing a purge-proof endpoint\",\n );\n }\n const initialProof = await input.apiClient.getDocumentPurgeProof(\n input.documentId,\n undefined,\n {\n expectedPaymentRequiredOrganizationId: input.expectedOrganizationId,\n },\n );\n if (!initialProof) {\n // ApiClient returns null for transport, HTTP and response-shape failures.\n // Even after a deletion hint, absence cannot prove signed-data tampering.\n // Keep local data and defer deletion until an actual proof verifies.\n return null;\n }\n await verifyDocumentPurgeProofBaseline({\n execSql: input.execSql,\n expectedDocumentId: input.documentId,\n expectedOrganizationId: input.expectedOrganizationId,\n proof: initialProof,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n // The current API returns complete history to recorded readers. Otherwise\n // its terminal snapshot needs an exact local pin; a floor refetch cannot\n // grant missing observation authority.\n return initialProof;\n}\n\nasync function resolveDocumentPurgeWriterProjection(input: {\n readonly apiClient: DocumentPurgeApi;\n readonly documentId: string;\n}): Promise<\n | DocumentWriterProjectionResponse\n | typeof REMOTE_DOCUMENT_ALREADY_PURGED\n | null\n> {\n const result = await input.apiClient.getDocumentWriterProjectionResult(\n input.documentId,\n { reportErrors: false },\n );\n if (result.ok) {\n return result.data;\n }\n if (result.status === 404 && result.code === DOCUMENT_NOT_FOUND_ERROR_CODE) {\n return REMOTE_DOCUMENT_ALREADY_PURGED;\n }\n result.report();\n return null;\n}\n\nexport async function buildDocumentPurgeRequest(input: {\n readonly author: DocumentCreateAuthor;\n readonly expectedSubtreeRootId?: string | undefined;\n readonly eventId?: string | undefined;\n readonly signedAt?: string | undefined;\n readonly writerProjection: DocumentWriterProjectionResponse;\n}): Promise<DocumentPurgeRequest> {\n const identity = await assertDocumentManifestBundleConsistent({\n bundle: input.writerProjection.documentManifest,\n label: \"Document purge predecessor\",\n });\n if (identity.documentId !== input.writerProjection.documentId) {\n throw new Error(\"Document purge projection identity mismatch\");\n }\n if (identity.organizationId !== input.author.organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Document purge author organization mismatch\",\n );\n }\n const linkedContainerIds = readLinkedContainerIdsFromDocumentManifest(\n input.writerProjection,\n );\n if (linkedContainerIds.length !== 1) {\n throw new Error(\"Document purge requires exactly one linked container\");\n }\n const [containerId] = linkedContainerIds;\n const authorizingProjection = documentContainerProjections(\n input.writerProjection,\n ).find((projection) => {\n const leaf = projection.path.at(-1);\n return leaf && readManifestContainerId(leaf) === containerId;\n });\n const containerManifestHash =\n authorizingProjection?.path.at(-1)?.manifestHash;\n if (!authorizingProjection || !containerId || !containerManifestHash) {\n throw new Error(\"Document purge authorization path is unavailable\");\n }\n assertSubtreePurgePath(\n authorizingProjection.path,\n input.expectedSubtreeRootId,\n );\n const authorizingContainerManifestHashes = authorizingProjection.path.map(\n (bundle) => bundle.manifestHash,\n );\n const body: DocumentPurgeAccessEventBody = {\n authorizingContainerManifestHashes,\n containerId,\n containerManifestHash,\n documentManifestHash: input.writerProjection.documentManifest.manifestHash,\n eventType: \"document.purge\",\n };\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId ?? crypto.randomUUID(),\n eventType: \"document.purge\",\n objectKind: \"document\",\n objectId: input.writerProjection.documentId,\n organizationId: input.author.organizationId,\n previousManifestHash: input.writerProjection.documentManifest.manifestHash,\n dependencyManifestHashes: authorizingContainerManifestHashes,\n bodyHash: await computeAccessEventBodyHash(\n readCanonicalJson(body, \"Document purge body\"),\n ),\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt ?? new Date().toISOString(),\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n authorizingContainerPathRefs: containerPathRefs(authorizingProjection.path),\n body: readCanonicalRecord(body, \"Document purge body\"),\n event: readCanonicalRecord(event, \"Document purge event\"),\n };\n}\n\nexport function createVerifiedRemoteDocumentDeletionHandler(input: {\n readonly apiClient: Pick<DocumentSyncApi, \"getDocumentPurgeProof\">;\n readonly execSql: ExecSql;\n readonly expectedOrganizationId: string;\n readonly onVerifiedDeletion: (input: {\n readonly commitPurgeProof: (transactionExecSql: ExecSql) => Promise<void>;\n readonly documentId: string;\n }) => Promise<void> | void;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): (deleted: { readonly documentId: string }) => Promise<void> {\n return async ({ documentId }) => {\n const proof = await loadAuthenticatedDocumentPurgeProof({\n apiClient: input.apiClient,\n documentId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n if (!proof) {\n throw new ProjectionDependencyUnavailableError(\n \"Remote document deletion is missing its signed purge proof\",\n );\n }\n const verified = await verifyDocumentPurgeProof({\n execSql: input.execSql,\n expectedDocumentId: documentId,\n expectedOrganizationId: input.expectedOrganizationId,\n proof,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n await input.onVerifiedDeletion({\n commitPurgeProof: verified.commitCheckpoints,\n documentId,\n });\n };\n}\n\nexport async function purgeRemoteDocument(input: {\n readonly beforeSubmit?: (() => Promise<boolean>) | undefined;\n readonly apiClient: DocumentPurgeApi;\n readonly author: DocumentCreateAuthor;\n readonly documentId: string;\n readonly expectedSubtreeRootId?: string | undefined;\n readonly execSql: ExecSql;\n readonly onVerifiedPurge: (input: {\n readonly commitPurgeProof: (transactionExecSql: ExecSql) => Promise<void>;\n }) => Promise<void> | void;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): Promise<DocumentPurgeResponse | null> {\n const writerProjection = await resolveDocumentPurgeWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n });\n if (!writerProjection) {\n return null;\n }\n if (writerProjection === REMOTE_DOCUMENT_ALREADY_PURGED) {\n const proof = await loadAuthenticatedDocumentPurgeProof({\n apiClient: input.apiClient,\n documentId: input.documentId,\n execSql: input.execSql,\n expectedOrganizationId: input.author.organizationId,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n if (!proof) {\n throw new ProjectionDependencyUnavailableError(\n \"Purged remote document is missing its signed purge proof\",\n );\n }\n const verified = await verifyDocumentPurgeProof({\n execSql: input.execSql,\n expectedDocumentId: input.documentId,\n expectedOrganizationId: input.author.organizationId,\n proof,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n await input.onVerifiedPurge({\n commitPurgeProof: verified.commitCheckpoints,\n });\n return { ...proof, reclaimedBlobStorageKeys: [] };\n }\n await verifyDocumentWriterProjection({\n execSql: input.execSql,\n projection: writerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n const request = await buildDocumentPurgeRequest({\n author: input.author,\n expectedSubtreeRootId: input.expectedSubtreeRootId,\n writerProjection,\n });\n if (input.beforeSubmit && !(await input.beforeSubmit())) return null;\n if (input.stillCurrent?.() === false) return null;\n const response = await input.apiClient.purgeDocument(\n input.documentId,\n request,\n {\n expectedPaymentRequiredOrganizationId: input.author.organizationId,\n },\n );\n if (!response) {\n return null;\n }\n const verified = await verifyDocumentPurgeProof({\n execSql: input.execSql,\n expectedDocumentId: input.documentId,\n expectedOrganizationId: input.author.organizationId,\n proof: response,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n await input.onVerifiedPurge({\n commitPurgeProof: verified.commitCheckpoints,\n });\n return response;\n}\n"]}
1
+ {"version":3,"file":"purge.js","sourceRoot":"","sources":["purge.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computeAccessEventBodyHash,\n type DocumentPurgeAccessEventBody,\n KeyingVerificationError,\n signAccessEvent,\n type UnsignedAccessEvent,\n} from \"@tearleads/crypto\";\nimport type { DocumentPurgeRequest } from \"@tearleads/validators/request\";\nimport {\n DOCUMENT_NOT_FOUND_ERROR_CODE,\n type DocumentPurgeProofResponse,\n type DocumentPurgeResponse,\n type DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n containerPathRefs,\n readLinkedContainerIdsFromDocumentManifest,\n} from \"../../data/documents/shared/projection\";\nimport {\n assertDocumentManifestBundleConsistent,\n readManifestContainerId,\n} from \"../../data/documents/shared/readers\";\nimport type {\n DocumentCreateAuthor,\n DocumentSyncApi,\n} from \"../../data/documents/shared/types\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n} from \"../../data/keyingCanonicalJson\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification\";\nimport {\n verifyDocumentPurgeProof,\n verifyDocumentPurgeProofBaseline,\n verifyDocumentWriterProjection,\n} from \"../../data/keyingProjectionVerification\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { documentContainerProjections } from \"../../data/keyingProjectionVerification/documentContainerProjections\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n assertSubtreePurgePath,\n type SubtreePurgeRoot,\n} from \"./subtreePurgeScope\";\n\ninterface DocumentPurgeApi {\n getDocumentPurgeProof(\n documentId: string,\n options?: {\n readonly documentCheckpointManifestHash?: string;\n },\n requestOptions?: {\n readonly expectedPaymentRequiredOrganizationId?: string;\n },\n ): Promise<DocumentPurgeProofResponse | null>;\n getDocumentWriterProjectionResult: NonNullable<\n DocumentSyncApi[\"getDocumentWriterProjectionResult\"]\n >;\n purgeDocument(\n documentId: string,\n request: DocumentPurgeRequest,\n options?: {\n readonly expectedPaymentRequiredOrganizationId?: string;\n },\n ): Promise<DocumentPurgeResponse | null>;\n}\n\nconst REMOTE_DOCUMENT_ALREADY_PURGED = Symbol(\"remoteDocumentAlreadyPurged\");\n\nasync function loadAuthenticatedDocumentPurgeProof(input: {\n readonly apiClient: Pick<DocumentSyncApi, \"getDocumentPurgeProof\">;\n readonly documentId: string;\n readonly execSql: ExecSql;\n readonly expectedOrganizationId: string;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): Promise<DocumentPurgeProofResponse | null> {\n if (!input.apiClient.getDocumentPurgeProof) {\n throw new ProjectionDependencyUnavailableError(\n \"Remote document deletion is missing a purge-proof endpoint\",\n );\n }\n const initialProof = await input.apiClient.getDocumentPurgeProof(\n input.documentId,\n undefined,\n {\n expectedPaymentRequiredOrganizationId: input.expectedOrganizationId,\n },\n );\n if (!initialProof) {\n // ApiClient returns null for transport, HTTP and response-shape failures.\n // Even after a deletion hint, absence cannot prove signed-data tampering.\n // Keep local data and defer deletion until an actual proof verifies.\n return null;\n }\n await verifyDocumentPurgeProofBaseline({\n execSql: input.execSql,\n expectedDocumentId: input.documentId,\n expectedOrganizationId: input.expectedOrganizationId,\n proof: initialProof,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n // The current API returns complete history to recorded readers. Otherwise\n // its terminal snapshot needs an exact local pin; a floor refetch cannot\n // grant missing observation authority.\n return initialProof;\n}\n\nasync function resolveDocumentPurgeWriterProjection(input: {\n readonly apiClient: DocumentPurgeApi;\n readonly documentId: string;\n}): Promise<\n | DocumentWriterProjectionResponse\n | typeof REMOTE_DOCUMENT_ALREADY_PURGED\n | null\n> {\n const result = await input.apiClient.getDocumentWriterProjectionResult(\n input.documentId,\n { reportErrors: false },\n );\n if (result.ok) {\n return result.data;\n }\n if (result.status === 404 && result.code === DOCUMENT_NOT_FOUND_ERROR_CODE) {\n return REMOTE_DOCUMENT_ALREADY_PURGED;\n }\n result.report();\n return null;\n}\n\nexport async function buildDocumentPurgeRequest(input: {\n readonly author: DocumentCreateAuthor;\n readonly expectedSubtreeRoot?: SubtreePurgeRoot | undefined;\n readonly eventId?: string | undefined;\n readonly signedAt?: string | undefined;\n readonly writerProjection: DocumentWriterProjectionResponse;\n}): Promise<DocumentPurgeRequest> {\n const identity = await assertDocumentManifestBundleConsistent({\n bundle: input.writerProjection.documentManifest,\n label: \"Document purge predecessor\",\n });\n if (identity.documentId !== input.writerProjection.documentId) {\n throw new Error(\"Document purge projection identity mismatch\");\n }\n if (identity.organizationId !== input.author.organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Document purge author organization mismatch\",\n );\n }\n const linkedContainerIds = readLinkedContainerIdsFromDocumentManifest(\n input.writerProjection,\n );\n if (linkedContainerIds.length !== 1) {\n throw new Error(\"Document purge requires exactly one linked container\");\n }\n const [containerId] = linkedContainerIds;\n const authorizingProjection = documentContainerProjections(\n input.writerProjection,\n ).find((projection) => {\n const leaf = projection.path.at(-1);\n return leaf && readManifestContainerId(leaf) === containerId;\n });\n const containerManifestHash =\n authorizingProjection?.path.at(-1)?.manifestHash;\n if (!authorizingProjection || !containerId || !containerManifestHash) {\n throw new Error(\"Document purge authorization path is unavailable\");\n }\n assertSubtreePurgePath(authorizingProjection.path, input.expectedSubtreeRoot);\n const authorizingContainerManifestHashes = authorizingProjection.path.map(\n (bundle) => bundle.manifestHash,\n );\n const body: DocumentPurgeAccessEventBody = {\n authorizingContainerManifestHashes,\n containerId,\n containerManifestHash,\n documentManifestHash: input.writerProjection.documentManifest.manifestHash,\n eventType: \"document.purge\",\n };\n const unsignedEvent: UnsignedAccessEvent = {\n version: 1,\n eventId: input.eventId ?? crypto.randomUUID(),\n eventType: \"document.purge\",\n objectKind: \"document\",\n objectId: input.writerProjection.documentId,\n organizationId: input.author.organizationId,\n previousManifestHash: input.writerProjection.documentManifest.manifestHash,\n dependencyManifestHashes: authorizingContainerManifestHashes,\n bodyHash: await computeAccessEventBodyHash(\n readCanonicalJson(body, \"Document purge body\"),\n ),\n signerUserId: input.author.signerUserId,\n signerDeviceId: input.author.signerDeviceId,\n signerKeyFingerprint: input.author.signerKeyFingerprint,\n signedAt: input.signedAt ?? new Date().toISOString(),\n };\n const event = await signAccessEvent(\n unsignedEvent,\n input.author.signerPrivateKey,\n );\n\n return {\n authorizingContainerPathRefs: containerPathRefs(authorizingProjection.path),\n body: readCanonicalRecord(body, \"Document purge body\"),\n event: readCanonicalRecord(event, \"Document purge event\"),\n };\n}\n\nexport function createVerifiedRemoteDocumentDeletionHandler(input: {\n readonly apiClient: Pick<DocumentSyncApi, \"getDocumentPurgeProof\">;\n readonly execSql: ExecSql;\n readonly expectedOrganizationId: string;\n readonly onVerifiedDeletion: (input: {\n readonly commitPurgeProof: (transactionExecSql: ExecSql) => Promise<void>;\n readonly documentId: string;\n }) => Promise<void> | void;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): (deleted: { readonly documentId: string }) => Promise<void> {\n return async ({ documentId }) => {\n const proof = await loadAuthenticatedDocumentPurgeProof({\n apiClient: input.apiClient,\n documentId,\n execSql: input.execSql,\n expectedOrganizationId: input.expectedOrganizationId,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n if (!proof) {\n throw new ProjectionDependencyUnavailableError(\n \"Remote document deletion is missing its signed purge proof\",\n );\n }\n const verified = await verifyDocumentPurgeProof({\n execSql: input.execSql,\n expectedDocumentId: documentId,\n expectedOrganizationId: input.expectedOrganizationId,\n proof,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n await input.onVerifiedDeletion({\n commitPurgeProof: verified.commitCheckpoints,\n documentId,\n });\n };\n}\n\nexport async function purgeRemoteDocument(input: {\n readonly beforeSubmit?: (() => Promise<boolean>) | undefined;\n readonly apiClient: DocumentPurgeApi;\n readonly author: DocumentCreateAuthor;\n readonly documentId: string;\n readonly expectedSubtreeRoot?: SubtreePurgeRoot | undefined;\n readonly execSql: ExecSql;\n readonly onVerifiedPurge: (input: {\n readonly commitPurgeProof: (transactionExecSql: ExecSql) => Promise<void>;\n }) => Promise<void> | void;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): Promise<DocumentPurgeResponse | null> {\n const writerProjection = await resolveDocumentPurgeWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n });\n if (!writerProjection) {\n return null;\n }\n if (writerProjection === REMOTE_DOCUMENT_ALREADY_PURGED) {\n const proof = await loadAuthenticatedDocumentPurgeProof({\n apiClient: input.apiClient,\n documentId: input.documentId,\n execSql: input.execSql,\n expectedOrganizationId: input.author.organizationId,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n if (!proof) {\n throw new ProjectionDependencyUnavailableError(\n \"Purged remote document is missing its signed purge proof\",\n );\n }\n const verified = await verifyDocumentPurgeProof({\n execSql: input.execSql,\n expectedDocumentId: input.documentId,\n expectedOrganizationId: input.author.organizationId,\n proof,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n await input.onVerifiedPurge({\n commitPurgeProof: verified.commitCheckpoints,\n });\n return { ...proof, reclaimedBlobStorageKeys: [] };\n }\n await verifyDocumentWriterProjection({\n execSql: input.execSql,\n projection: writerProjection,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n const request = await buildDocumentPurgeRequest({\n author: input.author,\n expectedSubtreeRoot: input.expectedSubtreeRoot,\n writerProjection,\n });\n if (input.beforeSubmit && !(await input.beforeSubmit())) return null;\n if (input.stillCurrent?.() === false) return null;\n const response = await input.apiClient.purgeDocument(\n input.documentId,\n request,\n {\n expectedPaymentRequiredOrganizationId: input.author.organizationId,\n },\n );\n if (!response) {\n return null;\n }\n const verified = await verifyDocumentPurgeProof({\n execSql: input.execSql,\n expectedDocumentId: input.documentId,\n expectedOrganizationId: input.author.organizationId,\n proof: response,\n resolveUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n await input.onVerifiedPurge({\n commitPurgeProof: verified.commitCheckpoints,\n });\n return response;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { AccessManifestBundleWireResponse } from "../../internal/validators/response/index.js";
2
+ /** The selected purge root and the parent the user selected it under. */
3
+ export interface SubtreePurgeRoot {
4
+ readonly id: string;
5
+ readonly parentId: string | null;
6
+ }
7
+ /** Check the exact verified path that the destructive request will cite. */
8
+ export declare function assertSubtreePurgePath(path: readonly AccessManifestBundleWireResponse[], root: SubtreePurgeRoot | undefined): void;
@@ -1,11 +1,18 @@
1
+ import { isPlainObject } from "../../internal/validators/isPlainObject.js";
1
2
  import { readManifestContainerId } from "../../data/documents/shared/readers.js";
3
+ function readSignedParentContainerId(bundle) {
4
+ return isPlainObject(bundle.state)
5
+ ? Reflect.get(bundle.state, "parentContainerId")
6
+ : undefined;
7
+ }
2
8
  /** Check the exact verified path that the destructive request will cite. */
3
- export function assertSubtreePurgePath(path, rootContainerId) {
4
- if (rootContainerId === undefined)
9
+ export function assertSubtreePurgePath(path, root) {
10
+ if (root === undefined)
5
11
  return;
6
- if (!path.some((bundle) => readManifestContainerId(bundle) === rootContainerId)) {
7
- // A valid move out of the selected subtree is ordinary concurrent work.
12
+ const rootBundle = path.find((bundle) => readManifestContainerId(bundle) === root.id);
13
+ // A valid move out of the selected subtree, or a settled restore of the
14
+ // selected root itself, is ordinary concurrent work.
15
+ if (!rootBundle || readSignedParentContainerId(rootBundle) !== root.parentId)
8
16
  throw new Error("Document placement is outside the requested purge subtree");
9
- }
10
17
  }
11
18
  //# sourceMappingURL=subtreePurgeScope.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subtreePurgeScope.js","sourceRoot":"","sources":["subtreePurgeScope.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE9E,4EAA4E;AAC5E,MAAM,UAAU,sBAAsB,CACpC,IAAiD,EACjD,eAAmC;IAEnC,IAAI,eAAe,KAAK,SAAS;QAAE,OAAO;IAC1C,IACE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,uBAAuB,CAAC,MAAM,CAAC,KAAK,eAAe,CAAC,EAC3E,CAAC;QACD,wEAAwE;QACxE,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import type { AccessManifestBundleWireResponse } from \"@tearleads/validators/response\";\nimport { readManifestContainerId } from \"../../data/documents/shared/readers\";\n\n/** Check the exact verified path that the destructive request will cite. */\nexport function assertSubtreePurgePath(\n path: readonly AccessManifestBundleWireResponse[],\n rootContainerId: string | undefined,\n): void {\n if (rootContainerId === undefined) return;\n if (\n !path.some((bundle) => readManifestContainerId(bundle) === rootContainerId)\n ) {\n // A valid move out of the selected subtree is ordinary concurrent work.\n throw new Error(\n \"Document placement is outside the requested purge subtree\",\n );\n }\n}\n"]}
1
+ {"version":3,"file":"subtreePurgeScope.js","sourceRoot":"","sources":["subtreePurgeScope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAQ9E,SAAS,2BAA2B,CAClC,MAAwC;IAExC,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC;QAChC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,mBAAmB,CAAC;QAChD,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,sBAAsB,CACpC,IAAiD,EACjD,IAAkC;IAElC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1B,CAAC,MAAM,EAAE,EAAE,CAAC,uBAAuB,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,EAAE,CACxD,CAAC;IACF,wEAAwE;IACxE,qDAAqD;IACrD,IAAI,CAAC,UAAU,IAAI,2BAA2B,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,QAAQ;QAC1E,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;AACN,CAAC","sourcesContent":["import { isPlainObject } from \"@tearleads/validators/isPlainObject\";\nimport type { AccessManifestBundleWireResponse } from \"@tearleads/validators/response\";\nimport { readManifestContainerId } from \"../../data/documents/shared/readers\";\n\n/** The selected purge root and the parent the user selected it under. */\nexport interface SubtreePurgeRoot {\n readonly id: string;\n readonly parentId: string | null;\n}\n\nfunction readSignedParentContainerId(\n bundle: AccessManifestBundleWireResponse,\n): unknown {\n return isPlainObject(bundle.state)\n ? Reflect.get(bundle.state, \"parentContainerId\")\n : undefined;\n}\n\n/** Check the exact verified path that the destructive request will cite. */\nexport function assertSubtreePurgePath(\n path: readonly AccessManifestBundleWireResponse[],\n root: SubtreePurgeRoot | undefined,\n): void {\n if (root === undefined) return;\n const rootBundle = path.find(\n (bundle) => readManifestContainerId(bundle) === root.id,\n );\n // A valid move out of the selected subtree, or a settled restore of the\n // selected root itself, is ordinary concurrent work.\n if (!rootBundle || readSignedParentContainerId(rootBundle) !== root.parentId)\n throw new Error(\n \"Document placement is outside the requested purge subtree\",\n );\n}\n"]}
@@ -2,9 +2,28 @@ import { KeyingVerificationError, verifyPrincipalPolicyCurrent, } from "../../in
2
2
  import { loadPrincipalPolicyCheckpoint } from "../../data/persistence/keyingCheckpointPersistence.js";
3
3
  import { loadPrincipalHistoryPrefix } from "../../data/persistence/principalHistoryPrefixPersistence.js";
4
4
  import { principalHeadMatchesReference } from "../../data/principals/organizationAuthorityDescriptor.js";
5
- import { selectRecoveredPrincipalHistory } from "../principals/principalHistoryRecoveryReferences.js";
5
+ import { PrincipalHistoryEvidenceUnavailableError, selectRecoveredPrincipalHistory, } from "../principals/principalHistoryRecoveryReferences.js";
6
6
  import { principalHistoryVerificationContext } from "../principals/principalHistoryRecoveryVerification.js";
7
7
  import { restoreAcknowledgedPrincipalPrefix } from "./acknowledgedPrincipalPredecessor.js";
8
+ /** Only the receipt is proven; a newer local pin needs scoped history covering it. */
9
+ function reconcileReceiptOnly(publication, observedPrefixProgress, checkpoint) {
10
+ // Other verified evidence, such as a document purge proof, can pin a newer
11
+ // head without advancing this scope's prefix. That is honest progress this
12
+ // receipt cannot prove membership in: retry after recovery, not a rollback.
13
+ // A genesis receipt has no predecessor, so any existing pin stays a conflict.
14
+ if (publication.predecessorStage &&
15
+ checkpoint &&
16
+ checkpoint.version > publication.policy.version)
17
+ throw new PrincipalHistoryEvidenceUnavailableError(new KeyingVerificationError("missing_dependency", "A newer local principal pin is not covered by scoped history"));
18
+ return {
19
+ ...publication,
20
+ preservePrefix: false,
21
+ observedPrefixProgress,
22
+ observedCheckpoint: checkpoint,
23
+ retainedPrefix: publication.prefix,
24
+ checkpointPolicy: publication.policy,
25
+ };
26
+ }
8
27
  /** Prove an already observed successor contains this receipt before preserving it. */
9
28
  export async function reconcileAcknowledgedPrincipalCurrent(input, publication) {
10
29
  const options = {
@@ -18,26 +37,12 @@ export async function reconcileAcknowledgedPrincipalCurrent(input, publication)
18
37
  const saved = await loadPrincipalHistoryPrefix(options.execSql, publication.prefix.scopeId);
19
38
  const observedPrefixProgress = saved?.progress ?? null;
20
39
  if (observedPrefixProgress === publication.previousPrefixProgress)
21
- return {
22
- ...publication,
23
- preservePrefix: false,
24
- observedPrefixProgress,
25
- observedCheckpoint: checkpoint,
26
- retainedPrefix: publication.prefix,
27
- checkpointPolicy: publication.policy,
28
- };
40
+ return reconcileReceiptOnly(publication, observedPrefixProgress, checkpoint);
29
41
  const restored = await restoreAcknowledgedPrincipalPrefix(options, saved);
30
42
  if (restored.previous.version < publication.policy.version) {
31
43
  if (!principalHeadMatchesReference(restored.previous.state, options.expectedHead))
32
44
  throw new KeyingVerificationError("stale_predecessor", "Acknowledgement does not extend the authenticated current prefix");
33
- return {
34
- ...publication,
35
- preservePrefix: false,
36
- observedPrefixProgress,
37
- observedCheckpoint: checkpoint,
38
- retainedPrefix: publication.prefix,
39
- checkpointPolicy: publication.policy,
40
- };
45
+ return reconcileReceiptOnly(publication, observedPrefixProgress, checkpoint);
41
46
  }
42
47
  const history = await selectRecoveredPrincipalHistory({
43
48
  options: { ...options, retainedReferences: [publication.policy.state] },
@@ -1 +1 @@
1
- {"version":3,"file":"reconcileAcknowledgedPrincipalCurrent.js","sourceRoot":"","sources":["reconcileAcknowledgedPrincipalCurrent.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAKnG,OAAO,EAAE,0BAA0B,EAAE,MAAM,0DAA0D,CAAC;AACtG,OAAO,EAAE,6BAA6B,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAAE,+BAA+B,EAAE,MAAM,kDAAkD,CAAC;AAEnG,OAAO,EAAE,mCAAmC,EAAE,MAAM,oDAAoD,CAAC;AACzG,OAAO,EAAE,kCAAkC,EAAE,MAAM,oCAAoC,CAAC;AAExF,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,qCAAqC,CACzD,KAA2C,EAC3C,WAAoD;IAEpD,MAAM,OAAO,GAAG;QACd,GAAG,KAAK;QACR,UAAU,EAAE;YACV,GAAG,KAAK,CAAC,UAAU;YACnB,OAAO,EAAE,mCAAmC,CAAC,KAAK,CAAC;SACpD;KACF,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,6BAA6B,CACpD,OAAO,CAAC,OAAO,EACf,WAAW,CAAC,MAAM,CAAC,aAAa,EAChC,WAAW,CAAC,MAAM,CAAC,WAAW,CAC/B,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,0BAA0B,CAC5C,OAAO,CAAC,OAAO,EACf,WAAW,CAAC,MAAM,CAAC,OAAO,CAC3B,CAAC;IACF,MAAM,sBAAsB,GAAG,KAAK,EAAE,QAAQ,IAAI,IAAI,CAAC;IACvD,IAAI,sBAAsB,KAAK,WAAW,CAAC,sBAAsB;QAC/D,OAAO;YACL,GAAG,WAAW;YACd,cAAc,EAAE,KAAK;YACrB,sBAAsB;YACtB,kBAAkB,EAAE,UAAU;YAC9B,cAAc,EAAE,WAAW,CAAC,MAAM;YAClC,gBAAgB,EAAE,WAAW,CAAC,MAAM;SACrC,CAAC;IACJ,MAAM,QAAQ,GAAG,MAAM,kCAAkC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1E,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC3D,IACE,CAAC,6BAA6B,CAC5B,QAAQ,CAAC,QAAQ,CAAC,KAAK,EACvB,OAAO,CAAC,YAAY,CACrB;YAED,MAAM,IAAI,uBAAuB,CAC/B,mBAAmB,EACnB,kEAAkE,CACnE,CAAC;QACJ,OAAO;YACL,GAAG,WAAW;YACd,cAAc,EAAE,KAAK;YACrB,sBAAsB;YACtB,kBAAkB,EAAE,UAAU;YAC9B,cAAc,EAAE,WAAW,CAAC,MAAM;YAClC,gBAAgB,EAAE,WAAW,CAAC,MAAM;SACrC,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,+BAA+B,CAAC;QACpD,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,kBAAkB,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACvE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO;QACnC,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,UAAU;KACX,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAAC;QAChD,OAAO,EAAE,QAAQ,CAAC,SAAS;QAC3B,OAAO;KACR,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACnC,OAAO;QACL,GAAG,WAAW;QACd,cAAc,EAAE,IAAI;QACpB,sBAAsB;QACtB,kBAAkB,EAAE,UAAU;QAC9B,cAAc,EAAE,QAAQ,CAAC,KAAK;QAC9B,gBAAgB,EAAE,MAAM,CAAC,KAAK;KAC/B,CAAC;AACJ,CAAC","sourcesContent":["import {\n KeyingVerificationError,\n verifyPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport type {\n AcknowledgedPrincipalCurrentPublication,\n ReconciledPrincipalCurrentPublication,\n} from \"../../data/persistence/principalCurrentAcknowledgementPersistence\";\nimport { loadPrincipalHistoryPrefix } from \"../../data/persistence/principalHistoryPrefixPersistence\";\nimport { principalHeadMatchesReference } from \"../../data/principals/organizationAuthorityDescriptor\";\nimport { selectRecoveredPrincipalHistory } from \"../principals/principalHistoryRecoveryReferences\";\nimport type { RecoverPrincipalPolicyHistoryOptions } from \"../principals/principalHistoryRecoveryTypes\";\nimport { principalHistoryVerificationContext } from \"../principals/principalHistoryRecoveryVerification\";\nimport { restoreAcknowledgedPrincipalPrefix } from \"./acknowledgedPrincipalPredecessor\";\n\n/** Prove an already observed successor contains this receipt before preserving it. */\nexport async function reconcileAcknowledgedPrincipalCurrent(\n input: RecoverPrincipalPolicyHistoryOptions,\n publication: AcknowledgedPrincipalCurrentPublication,\n): Promise<ReconciledPrincipalCurrentPublication> {\n const options = {\n ...input,\n protection: {\n ...input.protection,\n context: principalHistoryVerificationContext(input),\n },\n };\n const checkpoint = await loadPrincipalPolicyCheckpoint(\n options.execSql,\n publication.policy.principalType,\n publication.policy.principalId,\n );\n const saved = await loadPrincipalHistoryPrefix(\n options.execSql,\n publication.prefix.scopeId,\n );\n const observedPrefixProgress = saved?.progress ?? null;\n if (observedPrefixProgress === publication.previousPrefixProgress)\n return {\n ...publication,\n preservePrefix: false,\n observedPrefixProgress,\n observedCheckpoint: checkpoint,\n retainedPrefix: publication.prefix,\n checkpointPolicy: publication.policy,\n };\n const restored = await restoreAcknowledgedPrincipalPrefix(options, saved);\n if (restored.previous.version < publication.policy.version) {\n if (\n !principalHeadMatchesReference(\n restored.previous.state,\n options.expectedHead,\n )\n )\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"Acknowledgement does not extend the authenticated current prefix\",\n );\n return {\n ...publication,\n preservePrefix: false,\n observedPrefixProgress,\n observedCheckpoint: checkpoint,\n retainedPrefix: publication.prefix,\n checkpointPolicy: publication.policy,\n };\n }\n const history = await selectRecoveredPrincipalHistory({\n options: { ...options, retainedReferences: [publication.policy.state] },\n scopeId: publication.prefix.scopeId,\n history: restored.history,\n checkpoint,\n });\n const policy = await verifyPrincipalPolicyCurrent({\n current: restored.artifacts,\n history,\n });\n if (!policy.ok) throw policy.error;\n return {\n ...publication,\n preservePrefix: true,\n observedPrefixProgress,\n observedCheckpoint: checkpoint,\n retainedPrefix: restored.saved,\n checkpointPolicy: policy.value,\n };\n}\n"]}
1
+ {"version":3,"file":"reconcileAcknowledgedPrincipalCurrent.js","sourceRoot":"","sources":["reconcileAcknowledgedPrincipalCurrent.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAEvB,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAKnG,OAAO,EAAE,0BAA0B,EAAE,MAAM,0DAA0D,CAAC;AACtG,OAAO,EAAE,6BAA6B,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EACL,wCAAwC,EACxC,+BAA+B,GAChC,MAAM,kDAAkD,CAAC;AAE1D,OAAO,EAAE,mCAAmC,EAAE,MAAM,oDAAoD,CAAC;AACzG,OAAO,EAAE,kCAAkC,EAAE,MAAM,oCAAoC,CAAC;AAExF,sFAAsF;AACtF,SAAS,oBAAoB,CAC3B,WAAoD,EACpD,sBAAqC,EACrC,UAA4C;IAE5C,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,8EAA8E;IAC9E,IACE,WAAW,CAAC,gBAAgB;QAC5B,UAAU;QACV,UAAU,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO;QAE/C,MAAM,IAAI,wCAAwC,CAChD,IAAI,uBAAuB,CACzB,oBAAoB,EACpB,8DAA8D,CAC/D,CACF,CAAC;IACJ,OAAO;QACL,GAAG,WAAW;QACd,cAAc,EAAE,KAAK;QACrB,sBAAsB;QACtB,kBAAkB,EAAE,UAAU;QAC9B,cAAc,EAAE,WAAW,CAAC,MAAM;QAClC,gBAAgB,EAAE,WAAW,CAAC,MAAM;KACrC,CAAC;AACJ,CAAC;AAED,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,qCAAqC,CACzD,KAA2C,EAC3C,WAAoD;IAEpD,MAAM,OAAO,GAAG;QACd,GAAG,KAAK;QACR,UAAU,EAAE;YACV,GAAG,KAAK,CAAC,UAAU;YACnB,OAAO,EAAE,mCAAmC,CAAC,KAAK,CAAC;SACpD;KACF,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,6BAA6B,CACpD,OAAO,CAAC,OAAO,EACf,WAAW,CAAC,MAAM,CAAC,aAAa,EAChC,WAAW,CAAC,MAAM,CAAC,WAAW,CAC/B,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,0BAA0B,CAC5C,OAAO,CAAC,OAAO,EACf,WAAW,CAAC,MAAM,CAAC,OAAO,CAC3B,CAAC;IACF,MAAM,sBAAsB,GAAG,KAAK,EAAE,QAAQ,IAAI,IAAI,CAAC;IACvD,IAAI,sBAAsB,KAAK,WAAW,CAAC,sBAAsB;QAC/D,OAAO,oBAAoB,CACzB,WAAW,EACX,sBAAsB,EACtB,UAAU,CACX,CAAC;IACJ,MAAM,QAAQ,GAAG,MAAM,kCAAkC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1E,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC3D,IACE,CAAC,6BAA6B,CAC5B,QAAQ,CAAC,QAAQ,CAAC,KAAK,EACvB,OAAO,CAAC,YAAY,CACrB;YAED,MAAM,IAAI,uBAAuB,CAC/B,mBAAmB,EACnB,kEAAkE,CACnE,CAAC;QACJ,OAAO,oBAAoB,CACzB,WAAW,EACX,sBAAsB,EACtB,UAAU,CACX,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,+BAA+B,CAAC;QACpD,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,kBAAkB,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QACvE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO;QACnC,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,UAAU;KACX,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAAC;QAChD,OAAO,EAAE,QAAQ,CAAC,SAAS;QAC3B,OAAO;KACR,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,MAAM,CAAC,KAAK,CAAC;IACnC,OAAO;QACL,GAAG,WAAW;QACd,cAAc,EAAE,IAAI;QACpB,sBAAsB;QACtB,kBAAkB,EAAE,UAAU;QAC9B,cAAc,EAAE,QAAQ,CAAC,KAAK;QAC9B,gBAAgB,EAAE,MAAM,CAAC,KAAK;KAC/B,CAAC;AACJ,CAAC","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicyCheckpoint,\n verifyPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport type {\n AcknowledgedPrincipalCurrentPublication,\n ReconciledPrincipalCurrentPublication,\n} from \"../../data/persistence/principalCurrentAcknowledgementPersistence\";\nimport { loadPrincipalHistoryPrefix } from \"../../data/persistence/principalHistoryPrefixPersistence\";\nimport { principalHeadMatchesReference } from \"../../data/principals/organizationAuthorityDescriptor\";\nimport {\n PrincipalHistoryEvidenceUnavailableError,\n selectRecoveredPrincipalHistory,\n} from \"../principals/principalHistoryRecoveryReferences\";\nimport type { RecoverPrincipalPolicyHistoryOptions } from \"../principals/principalHistoryRecoveryTypes\";\nimport { principalHistoryVerificationContext } from \"../principals/principalHistoryRecoveryVerification\";\nimport { restoreAcknowledgedPrincipalPrefix } from \"./acknowledgedPrincipalPredecessor\";\n\n/** Only the receipt is proven; a newer local pin needs scoped history covering it. */\nfunction reconcileReceiptOnly(\n publication: AcknowledgedPrincipalCurrentPublication,\n observedPrefixProgress: string | null,\n checkpoint: PrincipalPolicyCheckpoint | null,\n): ReconciledPrincipalCurrentPublication {\n // Other verified evidence, such as a document purge proof, can pin a newer\n // head without advancing this scope's prefix. That is honest progress this\n // receipt cannot prove membership in: retry after recovery, not a rollback.\n // A genesis receipt has no predecessor, so any existing pin stays a conflict.\n if (\n publication.predecessorStage &&\n checkpoint &&\n checkpoint.version > publication.policy.version\n )\n throw new PrincipalHistoryEvidenceUnavailableError(\n new KeyingVerificationError(\n \"missing_dependency\",\n \"A newer local principal pin is not covered by scoped history\",\n ),\n );\n return {\n ...publication,\n preservePrefix: false,\n observedPrefixProgress,\n observedCheckpoint: checkpoint,\n retainedPrefix: publication.prefix,\n checkpointPolicy: publication.policy,\n };\n}\n\n/** Prove an already observed successor contains this receipt before preserving it. */\nexport async function reconcileAcknowledgedPrincipalCurrent(\n input: RecoverPrincipalPolicyHistoryOptions,\n publication: AcknowledgedPrincipalCurrentPublication,\n): Promise<ReconciledPrincipalCurrentPublication> {\n const options = {\n ...input,\n protection: {\n ...input.protection,\n context: principalHistoryVerificationContext(input),\n },\n };\n const checkpoint = await loadPrincipalPolicyCheckpoint(\n options.execSql,\n publication.policy.principalType,\n publication.policy.principalId,\n );\n const saved = await loadPrincipalHistoryPrefix(\n options.execSql,\n publication.prefix.scopeId,\n );\n const observedPrefixProgress = saved?.progress ?? null;\n if (observedPrefixProgress === publication.previousPrefixProgress)\n return reconcileReceiptOnly(\n publication,\n observedPrefixProgress,\n checkpoint,\n );\n const restored = await restoreAcknowledgedPrincipalPrefix(options, saved);\n if (restored.previous.version < publication.policy.version) {\n if (\n !principalHeadMatchesReference(\n restored.previous.state,\n options.expectedHead,\n )\n )\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"Acknowledgement does not extend the authenticated current prefix\",\n );\n return reconcileReceiptOnly(\n publication,\n observedPrefixProgress,\n checkpoint,\n );\n }\n const history = await selectRecoveredPrincipalHistory({\n options: { ...options, retainedReferences: [publication.policy.state] },\n scopeId: publication.prefix.scopeId,\n history: restored.history,\n checkpoint,\n });\n const policy = await verifyPrincipalPolicyCurrent({\n current: restored.artifacts,\n history,\n });\n if (!policy.ok) throw policy.error;\n return {\n ...publication,\n preservePrefix: true,\n observedPrefixProgress,\n observedCheckpoint: checkpoint,\n retainedPrefix: restored.saved,\n checkpointPolicy: policy.value,\n };\n}\n"]}