@tearleads/client-sdk 0.1.79 → 0.1.80

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 (143) hide show
  1. package/client/deviceFirst/index.d.ts +1 -1
  2. package/client/deviceFirst/index.js +1 -1
  3. package/client/deviceFirst/index.js.map +1 -1
  4. package/client/runtime/principalMutationApi.js +1 -1
  5. package/client/runtime/principalMutationApi.js.map +1 -1
  6. package/client/runtime/principalMutationDispatch.js +1 -1
  7. package/client/runtime/principalMutationDispatch.js.map +1 -1
  8. package/client/runtime/rootContainerAdoption.js.map +1 -1
  9. package/client/runtime/workflowRuntime.d.ts +1 -1
  10. package/client/runtime/workflowRuntime.js.map +1 -1
  11. package/client/session/sessionPurgeRecovery.js +1 -1
  12. package/client/session/sessionPurgeRecovery.js.map +1 -1
  13. package/data/blobs/attachments/projection.js +2 -3
  14. package/data/blobs/attachments/projection.js.map +1 -1
  15. package/data/documents/documentConstants.d.ts +1 -0
  16. package/data/documents/documentConstants.js +1 -0
  17. package/data/documents/documentConstants.js.map +1 -1
  18. package/data/documents/shared/containerKek/containerKekEntryVerification.d.ts +3 -0
  19. package/data/documents/shared/containerKek/index.d.ts +5 -0
  20. package/data/documents/shared/containerKek/index.js +9 -0
  21. package/data/documents/shared/containerKek/index.js.map +1 -0
  22. package/data/documents/shared/projection/index.d.ts +1 -1
  23. package/data/documents/shared/projection/index.js +1 -1
  24. package/data/documents/shared/projection/index.js.map +1 -1
  25. package/data/documents/shared/sync/syncResponseAuthorization.js +1 -1
  26. package/data/documents/shared/sync/syncResponseAuthorization.js.map +1 -1
  27. package/data/keyingProjectionVerification/container/containerCreateManifest.d.ts +12 -0
  28. package/data/keyingProjectionVerification/container/containerDestinationVerification.d.ts +16 -0
  29. package/data/keyingProjectionVerification/index.d.ts +4 -0
  30. package/data/keyingProjectionVerification/index.js +5 -1
  31. package/data/keyingProjectionVerification/index.js.map +1 -1
  32. package/data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence.d.ts +3 -0
  33. package/data/keyingProjectionVerification/principalPolicy/principalPolicyVerification.d.ts +24 -0
  34. package/data/persistence/container-contents/documentPlacement.js +1 -1
  35. package/data/persistence/container-contents/documentPlacement.js.map +1 -1
  36. package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js +1 -1
  37. package/data/persistence/documents/containerDocumentTombstoneHoldsPersistence.js.map +1 -1
  38. package/data/persistence/documents/documentsPersistence.d.ts +1 -1
  39. package/data/persistence/documents/documentsPersistence.js +2 -3
  40. package/data/persistence/documents/documentsPersistence.js.map +1 -1
  41. package/data/persistence/documents/internal/containerDocumentTombstones.js +1 -1
  42. package/data/persistence/documents/internal/containerDocumentTombstones.js.map +1 -1
  43. package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js +1 -1
  44. package/data/persistence/documents/internal/createDocumentWithHistoryCheckpoint.js.map +1 -1
  45. package/data/persistence/documents/internal/documentDeletionPersistence.js +1 -1
  46. package/data/persistence/documents/internal/documentDeletionPersistence.js.map +1 -1
  47. package/data/persistence/documents/internal/documentMutationPersistence.js +1 -1
  48. package/data/persistence/documents/internal/documentMutationPersistence.js.map +1 -1
  49. package/data/persistence/documents/internal/documentProjectionRows.js +1 -2
  50. package/data/persistence/documents/internal/documentProjectionRows.js.map +1 -1
  51. package/data/persistence/documents/internal/documentPullContinuationPersistence.js +1 -1
  52. package/data/persistence/documents/internal/documentPullContinuationPersistence.js.map +1 -1
  53. package/data/persistence/documents/internal/documentRows.js +1 -2
  54. package/data/persistence/documents/internal/documentRows.js.map +1 -1
  55. package/data/persistence/documents/internal/orphanSideRows.js +1 -1
  56. package/data/persistence/documents/internal/orphanSideRows.js.map +1 -1
  57. package/data/persistence/documents/internal/pendingCreateAdoption.js +1 -1
  58. package/data/persistence/documents/internal/pendingCreateAdoption.js.map +1 -1
  59. package/data/persistence/documents/internal/rowQueryPersistence.js +1 -1
  60. package/data/persistence/documents/internal/rowQueryPersistence.js.map +1 -1
  61. package/package.json +1 -1
  62. package/stores/local-projection/localProjectionStore.d.ts +1 -1
  63. package/stores/local-projection/localProjectionStore.js +1 -1
  64. package/stores/local-projection/localProjectionStore.js.map +1 -1
  65. package/stores/local-projection/registry.d.ts +1 -1
  66. package/stores/local-projection/registry.js.map +1 -1
  67. package/stores/local-projection/types.d.ts +1 -1
  68. package/stores/local-projection/types.js.map +1 -1
  69. package/workflows/blobs/hydration/decrypt.js +1 -2
  70. package/workflows/blobs/hydration/decrypt.js.map +1 -1
  71. package/workflows/blobs/hydration/hydrate.d.ts +1 -1
  72. package/workflows/blobs/hydration/hydrate.js.map +1 -1
  73. package/workflows/container-contents/container-state/create/createAdoption.js +1 -2
  74. package/workflows/container-contents/container-state/create/createAdoption.js.map +1 -1
  75. package/workflows/container-contents/container-state/purge/purgeTreeScope.js +1 -1
  76. package/workflows/container-contents/container-state/purge/purgeTreeScope.js.map +1 -1
  77. package/workflows/container-contents/info/documentInfo.js +1 -1
  78. package/workflows/container-contents/info/documentInfo.js.map +1 -1
  79. package/workflows/container-contents/metadata/index.js +1 -2
  80. package/workflows/container-contents/metadata/index.js.map +1 -1
  81. package/workflows/container-contents/metadata/metadataMutationPreparation.js +1 -1
  82. package/workflows/container-contents/metadata/metadataMutationPreparation.js.map +1 -1
  83. package/workflows/container-contents/metadata/metadataPullContinuationInvalidation.js +1 -1
  84. package/workflows/container-contents/metadata/metadataPullContinuationInvalidation.js.map +1 -1
  85. package/workflows/container-contents/metadata/metadataSyncErrors.js +1 -1
  86. package/workflows/container-contents/metadata/metadataSyncErrors.js.map +1 -1
  87. package/workflows/container-contents/metadata/metadataSyncSettlement.d.ts +1 -1
  88. package/workflows/container-contents/metadata/metadataSyncSettlement.js.map +1 -1
  89. package/workflows/container-contents/metadata/metadataTypes.d.ts +1 -1
  90. package/workflows/container-contents/metadata/metadataTypes.js.map +1 -1
  91. package/workflows/container-contents/pendingWrites/index.js +1 -1
  92. package/workflows/container-contents/pendingWrites/index.js.map +1 -1
  93. package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js +1 -3
  94. package/workflows/container-contents/remoteHydration/destination/verifiedDestination.js.map +1 -1
  95. package/workflows/containers/child/create/index.js +1 -1
  96. package/workflows/containers/child/create/index.js.map +1 -1
  97. package/workflows/containers/child/move/moveRotation.js +1 -1
  98. package/workflows/containers/child/move/moveRotation.js.map +1 -1
  99. package/workflows/containers/child/move/moveWraps.js +1 -1
  100. package/workflows/containers/child/move/moveWraps.js.map +1 -1
  101. package/workflows/containers/child/rekey/rekeyProjection.js +1 -1
  102. package/workflows/containers/child/rekey/rekeyProjection.js.map +1 -1
  103. package/workflows/containers/child/rotation/rotationContext.js +1 -2
  104. package/workflows/containers/child/rotation/rotationContext.js.map +1 -1
  105. package/workflows/containers/child/share/shareAncestorRepair.js +1 -2
  106. package/workflows/containers/child/share/shareAncestorRepair.js.map +1 -1
  107. package/workflows/containers/index.d.ts +2 -3
  108. package/workflows/containers/index.js +1 -2
  109. package/workflows/containers/index.js.map +1 -1
  110. package/workflows/containers/writeRefusal.js +1 -1
  111. package/workflows/containers/writeRefusal.js.map +1 -1
  112. package/workflows/documents/linkSet/linkSetProjectionSeed.js +1 -1
  113. package/workflows/documents/linkSet/linkSetProjectionSeed.js.map +1 -1
  114. package/workflows/documents/syncRekeys/syncAutomaticContainerRekeys.js +1 -1
  115. package/workflows/documents/syncRekeys/syncAutomaticContainerRekeys.js.map +1 -1
  116. package/workflows/organizations/groupMetadata/groupMetadataAccess.js +1 -1
  117. package/workflows/organizations/groupMetadata/groupMetadataAccess.js.map +1 -1
  118. package/workflows/organizations/provisioning/createOrganization.d.ts +1 -1
  119. package/workflows/organizations/provisioning/createOrganization.js +1 -1
  120. package/workflows/organizations/provisioning/createOrganization.js.map +1 -1
  121. package/workflows/organizations/provisioning/organizationProvisioningAttempt.d.ts +1 -1
  122. package/workflows/organizations/provisioning/organizationProvisioningAttempt.js.map +1 -1
  123. package/workflows/organizations/readModel/listLocalOrganizations.js +1 -1
  124. package/workflows/organizations/readModel/listLocalOrganizations.js.map +1 -1
  125. package/workflows/registration/index.d.ts +2 -1
  126. package/workflows/registration/index.js +2 -1
  127. package/workflows/registration/index.js.map +1 -1
  128. package/workflows/registration/organizationProvisioning.d.ts +39 -0
  129. package/workflows/registration/organizationProvisioning.js +211 -0
  130. package/workflows/registration/organizationProvisioning.js.map +1 -0
  131. package/workflows/registration/organizationProvisioningArtifacts.d.ts +2 -3
  132. package/workflows/registration/organizationProvisioningArtifacts.js.map +1 -1
  133. package/workflows/registration/provisioningBootstrapBuilders.d.ts +3 -3
  134. package/workflows/registration/provisioningBootstrapBuilders.js +3 -4
  135. package/workflows/registration/provisioningBootstrapBuilders.js.map +1 -1
  136. package/workflows/registration/registerIdentity.d.ts +2 -39
  137. package/workflows/registration/registerIdentity.js +2 -207
  138. package/workflows/registration/registerIdentity.js.map +1 -1
  139. package/workflows/sync/remoteResetPlans.js +2 -2
  140. package/workflows/sync/remoteResetPlans.js.map +1 -1
  141. package/data/persistence/documents/internal/constants.d.ts +0 -1
  142. package/data/persistence/documents/internal/constants.js +0 -2
  143. package/data/persistence/documents/internal/constants.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"moveRotation.js","sourceRoot":"","sources":["moveRotation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerKekKeyring,\n ContainerKekKeyringEntry,\n ContainerKekPredecessorBridge,\n} from \"@tearleads/crypto\";\nimport {\n createContainerKekPredecessorBridge,\n KeyingVerificationError,\n normalizeContainerKekKeyring,\n openContainerKekKeyring,\n sealContainerKekKeyring,\n} from \"@tearleads/crypto\";\nimport type { ContainerKekResponse } from \"@tearleads/validators/response\";\nimport { resolveContainerKekEpochId } from \"../../../../data/containers/shared/events\";\nimport { verifyContainerKekEntries } from \"../../../../data/documents/shared/containerKek/containerKekEntryVerification\";\n\n/**\n * A rotation must never launder history it did not verify: an\n * authenticated-but-poisoned keyring (sealed by a prior authorized writer\n * with wrong material) would otherwise be re-signed under the honest\n * rotator's event. Every entry is checked against the material-id its\n * ordinal commits to before it is sealed forward; entry i is key epoch\n * i + 1.\n */\nexport async function verifyKeyringEntriesForSeal(\n containerId: string,\n entries: readonly ContainerKekKeyringEntry[],\n /**\n * The epoch ids the KEK's signed history commits to, wherever the\n * projection served it (`signedHistoryEpochIds`). A self-consistent forgery\n * passes the material check but cannot also make a real id disappear, so an\n * honest rotation never re-signs one. The KEK's own served history alone is\n * not enough: a server can serve it under another KEK (#2365 finding 32).\n */\n signedEpochIds: ReadonlySet<string>,\n): Promise<void> {\n await verifyContainerKekEntries(containerId, entries);\n const entryIds = new Set(entries.map((entry) => entry.containerKeyEpochId));\n for (const historicalId of signedEpochIds) {\n if (!entryIds.has(historicalId)) {\n // Classified like the reader's and the override's refusal of it.\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Container KEK keyring omits an epoch its manifest history commits to\",\n );\n }\n }\n}\n\n/**\n * Re-seals the container's key history for a rotation: the previous\n * keyring's entries plus the retiring key, under the new epoch's key. One\n * decrypt and one seal regardless of container age.\n */\nexport async function sealRotationKeyring(input: {\n containerId: string;\n currentKek: ContainerKekResponse;\n currentKeyMaterial: Uint8Array;\n keyEpoch: number;\n signedEpochIds: ReadonlySet<string>;\n successorContainerKey: Uint8Array;\n successorContainerKeyEpochId: string;\n}): Promise<ContainerKekKeyring> {\n const previousEntries = input.currentKek.keyring\n ? await openContainerKekKeyring({\n keyEpoch: input.currentKek.containerKeyEpoch,\n keyring: normalizeContainerKekKeyring(input.currentKek.keyring),\n successorContainerKey: input.currentKeyMaterial,\n })\n : [];\n await verifyKeyringEntriesForSeal(\n input.containerId,\n previousEntries,\n input.signedEpochIds,\n );\n return sealContainerKekKeyring({\n containerId: input.containerId,\n entries: [\n ...previousEntries,\n {\n containerKeyEpochId: input.currentKek.containerKeyEpochId,\n keyMaterial: input.currentKeyMaterial,\n },\n ],\n keyEpoch: input.keyEpoch,\n successorContainerKey: input.successorContainerKey,\n successorContainerKeyEpochId: input.successorContainerKeyEpochId,\n });\n}\n\n/**\n * Mints one container KEK rotation: fresh entropy for the new epoch, the\n * write-once bridge to the retiring epoch, and the re-sealed keyring.\n */\nexport async function buildContainerRotationArtifacts(input: {\n containerId: string;\n currentKek: ContainerKekResponse;\n currentKeyMaterial: Uint8Array;\n keyEpoch: number;\n override?: string | undefined;\n signedEpochIds: ReadonlySet<string>;\n}): Promise<{\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n keyring: ContainerKekKeyring;\n predecessorBridge: ContainerKekPredecessorBridge;\n}> {\n const containerKey = crypto.getRandomValues(new Uint8Array(32));\n const containerKeyEpochId = await resolveContainerKekEpochId({\n containerId: input.containerId,\n keyEpoch: input.keyEpoch,\n keyMaterial: containerKey,\n override: input.override,\n });\n const predecessorBridge = await createContainerKekPredecessorBridge({\n containerId: input.containerId,\n predecessorContainerKey: input.currentKeyMaterial,\n predecessorContainerKeyEpochId: input.currentKek.containerKeyEpochId,\n successorContainerKey: containerKey,\n successorContainerKeyEpochId: containerKeyEpochId,\n });\n const keyring = await sealRotationKeyring({\n containerId: input.containerId,\n currentKek: input.currentKek,\n currentKeyMaterial: input.currentKeyMaterial,\n keyEpoch: input.keyEpoch,\n signedEpochIds: input.signedEpochIds,\n successorContainerKey: containerKey,\n successorContainerKeyEpochId: containerKeyEpochId,\n });\n return { containerKey, containerKeyEpochId, keyring, predecessorBridge };\n}\n"]}
1
+ {"version":3,"file":"moveRotation.js","sourceRoot":"","sources":["moveRotation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerKekKeyring,\n ContainerKekKeyringEntry,\n ContainerKekPredecessorBridge,\n} from \"@tearleads/crypto\";\nimport {\n createContainerKekPredecessorBridge,\n KeyingVerificationError,\n normalizeContainerKekKeyring,\n openContainerKekKeyring,\n sealContainerKekKeyring,\n} from \"@tearleads/crypto\";\nimport type { ContainerKekResponse } from \"@tearleads/validators/response\";\nimport { resolveContainerKekEpochId } from \"../../../../data/containers/shared/events\";\nimport { verifyContainerKekEntries } from \"../../../../data/documents/shared/containerKek\";\n\n/**\n * A rotation must never launder history it did not verify: an\n * authenticated-but-poisoned keyring (sealed by a prior authorized writer\n * with wrong material) would otherwise be re-signed under the honest\n * rotator's event. Every entry is checked against the material-id its\n * ordinal commits to before it is sealed forward; entry i is key epoch\n * i + 1.\n */\nexport async function verifyKeyringEntriesForSeal(\n containerId: string,\n entries: readonly ContainerKekKeyringEntry[],\n /**\n * The epoch ids the KEK's signed history commits to, wherever the\n * projection served it (`signedHistoryEpochIds`). A self-consistent forgery\n * passes the material check but cannot also make a real id disappear, so an\n * honest rotation never re-signs one. The KEK's own served history alone is\n * not enough: a server can serve it under another KEK (#2365 finding 32).\n */\n signedEpochIds: ReadonlySet<string>,\n): Promise<void> {\n await verifyContainerKekEntries(containerId, entries);\n const entryIds = new Set(entries.map((entry) => entry.containerKeyEpochId));\n for (const historicalId of signedEpochIds) {\n if (!entryIds.has(historicalId)) {\n // Classified like the reader's and the override's refusal of it.\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Container KEK keyring omits an epoch its manifest history commits to\",\n );\n }\n }\n}\n\n/**\n * Re-seals the container's key history for a rotation: the previous\n * keyring's entries plus the retiring key, under the new epoch's key. One\n * decrypt and one seal regardless of container age.\n */\nexport async function sealRotationKeyring(input: {\n containerId: string;\n currentKek: ContainerKekResponse;\n currentKeyMaterial: Uint8Array;\n keyEpoch: number;\n signedEpochIds: ReadonlySet<string>;\n successorContainerKey: Uint8Array;\n successorContainerKeyEpochId: string;\n}): Promise<ContainerKekKeyring> {\n const previousEntries = input.currentKek.keyring\n ? await openContainerKekKeyring({\n keyEpoch: input.currentKek.containerKeyEpoch,\n keyring: normalizeContainerKekKeyring(input.currentKek.keyring),\n successorContainerKey: input.currentKeyMaterial,\n })\n : [];\n await verifyKeyringEntriesForSeal(\n input.containerId,\n previousEntries,\n input.signedEpochIds,\n );\n return sealContainerKekKeyring({\n containerId: input.containerId,\n entries: [\n ...previousEntries,\n {\n containerKeyEpochId: input.currentKek.containerKeyEpochId,\n keyMaterial: input.currentKeyMaterial,\n },\n ],\n keyEpoch: input.keyEpoch,\n successorContainerKey: input.successorContainerKey,\n successorContainerKeyEpochId: input.successorContainerKeyEpochId,\n });\n}\n\n/**\n * Mints one container KEK rotation: fresh entropy for the new epoch, the\n * write-once bridge to the retiring epoch, and the re-sealed keyring.\n */\nexport async function buildContainerRotationArtifacts(input: {\n containerId: string;\n currentKek: ContainerKekResponse;\n currentKeyMaterial: Uint8Array;\n keyEpoch: number;\n override?: string | undefined;\n signedEpochIds: ReadonlySet<string>;\n}): Promise<{\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n keyring: ContainerKekKeyring;\n predecessorBridge: ContainerKekPredecessorBridge;\n}> {\n const containerKey = crypto.getRandomValues(new Uint8Array(32));\n const containerKeyEpochId = await resolveContainerKekEpochId({\n containerId: input.containerId,\n keyEpoch: input.keyEpoch,\n keyMaterial: containerKey,\n override: input.override,\n });\n const predecessorBridge = await createContainerKekPredecessorBridge({\n containerId: input.containerId,\n predecessorContainerKey: input.currentKeyMaterial,\n predecessorContainerKeyEpochId: input.currentKek.containerKeyEpochId,\n successorContainerKey: containerKey,\n successorContainerKeyEpochId: containerKeyEpochId,\n });\n const keyring = await sealRotationKeyring({\n containerId: input.containerId,\n currentKek: input.currentKek,\n currentKeyMaterial: input.currentKeyMaterial,\n keyEpoch: input.keyEpoch,\n signedEpochIds: input.signedEpochIds,\n successorContainerKey: containerKey,\n successorContainerKeyEpochId: containerKeyEpochId,\n });\n return { containerKey, containerKeyEpochId, keyring, predecessorBridge };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { uniquePrincipalPolicies } from "../../../../data/containers/shared/principalPolicies.js";
2
2
  import { readContainerState } from "../../../../data/containers/shared/projection.js";
3
- import { assertContainerKekPathCurrent } from "../../../../data/documents/shared/containerKek/containerKekCurrency.js";
3
+ import { assertContainerKekPathCurrent } from "../../../../data/documents/shared/containerKek/index.js";
4
4
  import { collectContainerWriterProjectionPrincipalPolicies, } from "../../../../data/keyingProjectionVerification/index.js";
5
5
  import { buildContainerRotationWraps } from "../rotation/rotationWraps.js";
6
6
  export async function collectContainerMovePrincipalPolicies(input) {
@@ -1 +1 @@
1
- {"version":3,"file":"moveWraps.js","sourceRoot":"","sources":["moveWraps.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sDAAsD,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,qEAAqE,CAAC;AACpH,OAAO,EACL,iDAAiD,GAGlD,MAAM,+CAA+C,CAAC;AAGvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,qCAAqC,CAAC,KAO3D;IACC,MAAM,CAAC,cAAc,EAAE,yBAAyB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpE,iDAAiD,CAAC;YAChD,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,UAAU,EAAE,KAAK,CAAC,kBAAkB;YACpC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;SACvE,CAAC;QACF,iDAAiD,CAAC;YAChD,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,UAAU,EAAE,KAAK,CAAC,2BAA2B;YAC7C,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;SACvE,CAAC;KACH,CAAC,CAAC;IACH,OAAO,uBAAuB,CAAC;QAC7B,GAAG,cAAc;QACjB,GAAG,yBAAyB;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAa7C;IACC,6BAA6B,CAC3B,KAAK,CAAC,2BAA2B,CAAC,aAAa,CAChD,CAAC;IACF,MAAM,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAClD,MAAM,cAAc,GAAG,KAAK,CAAC,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,cAAc;QACjB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,OAAO;QACL,iBAAiB;QACjB,GAAG,CAAC,MAAM,2BAA2B,CAAC;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;YAC9C,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,gBAAgB;YAChC,SAAS,EAAE,KAAK,CAAC,oBAAoB;YACrC,eAAe,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC,qBAAqB;YACzE,iBAAiB;YACjB,cAAc,EAAE,KAAK,CAAC,wBAAwB;YAC9C,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC","sourcesContent":["import type { ContainerAccessManifestState } from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { uniquePrincipalPolicies } from \"../../../../data/containers/shared/principalPolicies\";\nimport { readContainerState } from \"../../../../data/containers/shared/projection\";\nimport { assertContainerKekPathCurrent } from \"../../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport {\n collectContainerWriterProjectionPrincipalPolicies,\n type ProjectionUserKeyResolver,\n type ReferencedPrincipalPolicyWarmer,\n} from \"../../../../data/keyingProjectionVerification\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../../../data/principals/principalPolicyEvidence\";\nimport type { ExecSql } from \"../../../../data/sqlite/sqlSchema\";\nimport { buildContainerRotationWraps } from \"../rotation/rotationWraps\";\n\nexport async function collectContainerMovePrincipalPolicies(input: {\n destinationParentProjection: ContainerWriterProjectionResponse;\n execSql: ExecSql;\n previousProjection: ContainerWriterProjectionResponse;\n resolveUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<PrincipalPolicyCurrentEvidence[]> {\n const [sourcePolicies, destinationParentPolicies] = await Promise.all([\n collectContainerWriterProjectionPrincipalPolicies({\n execSql: input.execSql,\n projection: input.previousProjection,\n resolveUserKey: input.resolveUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n collectContainerWriterProjectionPrincipalPolicies({\n execSql: input.execSql,\n projection: input.destinationParentProjection,\n resolveUserKey: input.resolveUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n ]);\n return uniquePrincipalPolicies([\n ...sourcePolicies,\n ...destinationParentPolicies,\n ]);\n}\n\nexport async function buildContainerMoveWraps(input: {\n principalPolicies: readonly PrincipalPolicyCurrentEvidence[];\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n destinationParentKek: ContainerKekResponse;\n destinationParentProjection: ContainerWriterProjectionResponse;\n execSql: ExecSql;\n manifestHash: string;\n previousProjection: ContainerWriterProjectionResponse;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n state: ContainerAccessManifestState;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}) {\n assertContainerKekPathCurrent(\n input.destinationParentProjection.containerKeks,\n );\n const principalPolicies = input.principalPolicies;\n const parentManifest = input.destinationParentProjection.path.at(-1);\n if (!parentManifest)\n throw new Error(\"Container move destination parent is missing\");\n return {\n principalPolicies,\n ...(await buildContainerRotationWraps({\n containerKey: input.containerKey,\n containerKeyEpochId: input.containerKeyEpochId,\n manifestHash: input.manifestHash,\n operationLabel: \"Container move\",\n parentKek: input.destinationParentKek,\n parentPublicKey: readContainerState(parentManifest).containerKeyPublicKey,\n principalPolicies,\n resolveUserKey: input.resolveProjectionUserKey,\n state: input.state,\n })),\n };\n}\n"]}
1
+ {"version":3,"file":"moveWraps.js","sourceRoot":"","sources":["moveWraps.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sDAAsD,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,gDAAgD,CAAC;AAC/F,OAAO,EACL,iDAAiD,GAGlD,MAAM,+CAA+C,CAAC;AAGvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,qCAAqC,CAAC,KAO3D;IACC,MAAM,CAAC,cAAc,EAAE,yBAAyB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpE,iDAAiD,CAAC;YAChD,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,UAAU,EAAE,KAAK,CAAC,kBAAkB;YACpC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;SACvE,CAAC;QACF,iDAAiD,CAAC;YAChD,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,UAAU,EAAE,KAAK,CAAC,2BAA2B;YAC7C,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;SACvE,CAAC;KACH,CAAC,CAAC;IACH,OAAO,uBAAuB,CAAC;QAC7B,GAAG,cAAc;QACjB,GAAG,yBAAyB;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAa7C;IACC,6BAA6B,CAC3B,KAAK,CAAC,2BAA2B,CAAC,aAAa,CAChD,CAAC;IACF,MAAM,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAClD,MAAM,cAAc,GAAG,KAAK,CAAC,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,cAAc;QACjB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,OAAO;QACL,iBAAiB;QACjB,GAAG,CAAC,MAAM,2BAA2B,CAAC;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;YAC9C,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,cAAc,EAAE,gBAAgB;YAChC,SAAS,EAAE,KAAK,CAAC,oBAAoB;YACrC,eAAe,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC,qBAAqB;YACzE,iBAAiB;YACjB,cAAc,EAAE,KAAK,CAAC,wBAAwB;YAC9C,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC","sourcesContent":["import type { ContainerAccessManifestState } from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { uniquePrincipalPolicies } from \"../../../../data/containers/shared/principalPolicies\";\nimport { readContainerState } from \"../../../../data/containers/shared/projection\";\nimport { assertContainerKekPathCurrent } from \"../../../../data/documents/shared/containerKek\";\nimport {\n collectContainerWriterProjectionPrincipalPolicies,\n type ProjectionUserKeyResolver,\n type ReferencedPrincipalPolicyWarmer,\n} from \"../../../../data/keyingProjectionVerification\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../../../data/principals/principalPolicyEvidence\";\nimport type { ExecSql } from \"../../../../data/sqlite/sqlSchema\";\nimport { buildContainerRotationWraps } from \"../rotation/rotationWraps\";\n\nexport async function collectContainerMovePrincipalPolicies(input: {\n destinationParentProjection: ContainerWriterProjectionResponse;\n execSql: ExecSql;\n previousProjection: ContainerWriterProjectionResponse;\n resolveUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<PrincipalPolicyCurrentEvidence[]> {\n const [sourcePolicies, destinationParentPolicies] = await Promise.all([\n collectContainerWriterProjectionPrincipalPolicies({\n execSql: input.execSql,\n projection: input.previousProjection,\n resolveUserKey: input.resolveUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n collectContainerWriterProjectionPrincipalPolicies({\n execSql: input.execSql,\n projection: input.destinationParentProjection,\n resolveUserKey: input.resolveUserKey,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }),\n ]);\n return uniquePrincipalPolicies([\n ...sourcePolicies,\n ...destinationParentPolicies,\n ]);\n}\n\nexport async function buildContainerMoveWraps(input: {\n principalPolicies: readonly PrincipalPolicyCurrentEvidence[];\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n destinationParentKek: ContainerKekResponse;\n destinationParentProjection: ContainerWriterProjectionResponse;\n execSql: ExecSql;\n manifestHash: string;\n previousProjection: ContainerWriterProjectionResponse;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n state: ContainerAccessManifestState;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}) {\n assertContainerKekPathCurrent(\n input.destinationParentProjection.containerKeks,\n );\n const principalPolicies = input.principalPolicies;\n const parentManifest = input.destinationParentProjection.path.at(-1);\n if (!parentManifest)\n throw new Error(\"Container move destination parent is missing\");\n return {\n principalPolicies,\n ...(await buildContainerRotationWraps({\n containerKey: input.containerKey,\n containerKeyEpochId: input.containerKeyEpochId,\n manifestHash: input.manifestHash,\n operationLabel: \"Container move\",\n parentKek: input.destinationParentKek,\n parentPublicKey: readContainerState(parentManifest).containerKeyPublicKey,\n principalPolicies,\n resolveUserKey: input.resolveProjectionUserKey,\n state: input.state,\n })),\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { computeContainerKekRecipientTargetHash, computeContainerKeyEpochHash, } from "../../../../internal/crypto/index.js";
2
2
  import { canonicalKeyingJsonString, readCanonicalRecord, readCanonicalRecords, } from "../../../../data/keying/canonicalJson.js";
3
- import { mergeProjectionPolicyEvidence } from "../../../../data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence.js";
3
+ import { mergeProjectionPolicyEvidence } from "../../../../data/keyingProjectionVerification/index.js";
4
4
  const speculativeProjections = new WeakSet();
5
5
  export function isSpeculativeContainerWriterProjection(projection) {
6
6
  return speculativeProjections.has(projection);
@@ -1 +1 @@
1
- {"version":3,"file":"rekeyProjection.js","sourceRoot":"","sources":["rekeyProjection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerKekRecipientTarget,\n computeContainerKekRecipientTargetHash,\n computeContainerKeyEpochHash,\n} from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type {\n MaterializedContainerRekeyPlan,\n MaterializedContainerSharePlan,\n} from \"../../../../data/containers/shared/types\";\nimport {\n canonicalKeyingJsonString,\n readCanonicalRecord,\n readCanonicalRecords,\n} from \"../../../../data/keying/canonicalJson\";\nimport { mergeProjectionPolicyEvidence } from \"../../../../data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence\";\n\nconst speculativeProjections = new WeakSet<ContainerWriterProjectionResponse>();\n\nexport function isSpeculativeContainerWriterProjection(\n projection: ContainerWriterProjectionResponse,\n): boolean {\n return speculativeProjections.has(projection);\n}\n\n/**\n * What any rotation plan (rekey, revoke, move) holds in common: enough to say\n * what its container's path entry will be once the server accepts it.\n */\nexport interface RotationPlanArtifacts {\n readonly body: object;\n readonly containerId: string;\n readonly containerKeyEpochId: string;\n readonly event: MaterializedContainerRekeyPlan[\"plan\"][\"event\"];\n readonly eventHash: string;\n readonly keyEpoch: MaterializedContainerRekeyPlan[\"plan\"][\"keyEpoch\"];\n readonly manifest: MaterializedContainerRekeyPlan[\"plan\"][\"manifest\"];\n readonly manifestHash: string;\n readonly previousManifest: MaterializedContainerRekeyPlan[\"plan\"][\"previousManifest\"];\n readonly keyring: MaterializedContainerRekeyPlan[\"plan\"][\"keyring\"];\n readonly state: MaterializedContainerRekeyPlan[\"plan\"][\"state\"];\n readonly wraps: MaterializedContainerRekeyPlan[\"plan\"][\"wraps\"];\n}\n\nfunction recipientTargets(\n plan: Pick<RotationPlanArtifacts, \"wraps\">,\n): ContainerKekRecipientTarget[] {\n return plan.wraps\n .map((wrap) => ({\n recipientId: wrap.recipientId,\n recipientKeyEpochId: wrap.recipientKeyEpochId,\n recipientKeyFingerprint: wrap.recipientKeyFingerprint,\n recipientKind: wrap.recipientKind,\n }))\n .sort((left, right) =>\n canonicalKeyingJsonString(\n left,\n \"Container rekey recipient\",\n ).localeCompare(\n canonicalKeyingJsonString(right, \"Container rekey recipient\"),\n ),\n );\n}\n\n/**\n * The projection a rotation will leave behind, before the server has accepted\n * it. `ancestors` is the path above the container afterwards: unchanged for a\n * rekey or revoke, the destination parent's path for a move.\n */\nexport async function containerWriterProjectionFromRotationPlan(input: {\n ancestors?: Pick<\n ContainerWriterProjectionResponse,\n \"containerKeks\" | \"path\" | \"policyEvidence\"\n >;\n plan: RotationPlanArtifacts;\n previousProjection: ContainerWriterProjectionResponse;\n}): Promise<ContainerWriterProjectionResponse> {\n const { plan } = input;\n const previousManifest = input.previousProjection.path.at(-1);\n const previousKek = input.previousProjection.containerKeks.at(-1);\n if (\n !previousManifest ||\n !previousKek ||\n previousManifest.manifestHash !== plan.previousManifest.manifestHash ||\n previousKek.containerId !== plan.containerId\n ) {\n throw new Error(\"Container rekey projection predecessor mismatch\");\n }\n const targets = recipientTargets(plan);\n const nextManifest = {\n event: {\n body: readCanonicalRecord(plan.body, \"Container rekey body\"),\n event: readCanonicalRecord(plan.event, \"Container rekey event\"),\n eventHash: plan.eventHash,\n },\n manifest: readCanonicalRecord(plan.manifest, \"Container rekey manifest\"),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Container rekey state\"),\n };\n const nextKek = {\n accessManifestHash: plan.manifestHash,\n containerId: plan.containerId,\n containerKeyEpoch: plan.keyEpoch.keyEpoch,\n containerKeyEpochId: plan.containerKeyEpochId,\n containerManifestHistory: [\n previousManifest,\n ...previousKek.containerManifestHistory,\n ],\n keyEpoch: readCanonicalRecord(plan.keyEpoch, \"Container rekey key epoch\"),\n keyEpochHash: await computeContainerKeyEpochHash(plan.keyEpoch),\n keyring: { ...plan.keyring },\n keyTargetHash: await computeContainerKekRecipientTargetHash(targets),\n parentContainerKeyEpochId: plan.keyEpoch.parentContainerKeyEpochId,\n recipientTargets: readCanonicalRecords(\n targets,\n \"Container rekey recipient targets\",\n ),\n wraps: readCanonicalRecords(plan.wraps, \"Container rekey wraps\"),\n };\n const ancestors = input.ancestors ?? {\n containerKeks: input.previousProjection.containerKeks.slice(0, -1),\n path: input.previousProjection.path.slice(0, -1),\n };\n const projection = {\n ...input.previousProjection,\n policyEvidence: mergeProjectionPolicyEvidence([\n input.previousProjection.policyEvidence,\n ...(input.ancestors ? [input.ancestors.policyEvidence] : []),\n ]),\n path: [...ancestors.path, nextManifest],\n containerKeks: [...ancestors.containerKeks, nextKek],\n };\n speculativeProjections.add(projection);\n return projection;\n}\n\nexport function containerWriterProjectionFromRekeyPlan(input: {\n materializedPlan: Pick<\n MaterializedContainerRekeyPlan,\n \"containerKey\" | \"plan\"\n >;\n previousProjection: ContainerWriterProjectionResponse;\n}): Promise<ContainerWriterProjectionResponse> {\n return containerWriterProjectionFromRotationPlan({\n plan: input.materializedPlan.plan,\n previousProjection: input.previousProjection,\n });\n}\n\n/**\n * A descendant's served projection, re-rooted on rotations the server has not\n * accepted yet: `rotated` replaces the path down to and including its own\n * container. Null when the descendant does not sit below that container.\n */\nexport function rebaseContainerWriterProjection(\n descendant: ContainerWriterProjectionResponse,\n rotated: Pick<\n ContainerWriterProjectionResponse,\n \"containerKeks\" | \"path\" | \"policyEvidence\"\n >,\n): ContainerWriterProjectionResponse | null {\n const rotatedId = rotated.containerKeks.at(-1)?.containerId;\n const index = descendant.containerKeks.findIndex(\n (kek) => kek.containerId === rotatedId,\n );\n if (rotatedId === undefined || index < 0) return null;\n if (index === descendant.containerKeks.length - 1) return null;\n const projection = {\n ...descendant,\n policyEvidence: mergeProjectionPolicyEvidence([\n descendant.policyEvidence,\n rotated.policyEvidence,\n ]),\n path: [...rotated.path, ...descendant.path.slice(index + 1)],\n containerKeks: [\n ...rotated.containerKeks,\n ...descendant.containerKeks.slice(index + 1),\n ],\n };\n speculativeProjections.add(projection);\n return projection;\n}\n\n/** A grant keeps its key epoch while advancing the manifest and recipient wraps. */\nexport async function containerWriterProjectionFromSharePlan(input: {\n plan: MaterializedContainerSharePlan[\"plan\"];\n previousProjection: ContainerWriterProjectionResponse;\n}): Promise<ContainerWriterProjectionResponse> {\n const { plan, previousProjection } = input;\n const previous = previousProjection.path.at(-1);\n const kek = previousProjection.containerKeks.at(-1);\n if (\n !previous ||\n !kek ||\n previous.manifestHash !== plan.previousManifest.manifestHash ||\n kek.containerId !== plan.containerId\n )\n throw new Error(\"Container grant projection predecessor mismatch\");\n const targets = recipientTargets({ wraps: plan.wraps });\n const projection = {\n ...previousProjection,\n path: [\n ...previousProjection.path.slice(0, -1),\n {\n event: {\n body: readCanonicalRecord(plan.body, \"Container grant body\"),\n event: readCanonicalRecord(plan.event, \"Container grant event\"),\n eventHash: plan.eventHash,\n },\n manifest: readCanonicalRecord(\n plan.manifest,\n \"Container grant manifest\",\n ),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Container grant state\"),\n },\n ],\n containerKeks: [\n ...previousProjection.containerKeks.slice(0, -1),\n {\n ...kek,\n accessManifestHash: plan.manifestHash,\n containerManifestHistory: [previous, ...kek.containerManifestHistory],\n keyTargetHash: await computeContainerKekRecipientTargetHash(targets),\n recipientTargets: readCanonicalRecords(\n targets,\n \"Container grant targets\",\n ),\n wraps: readCanonicalRecords(plan.wraps, \"Container grant wraps\"),\n },\n ],\n };\n speculativeProjections.add(projection);\n return projection;\n}\n"]}
1
+ {"version":3,"file":"rekeyProjection.js","sourceRoot":"","sources":["rekeyProjection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerKekRecipientTarget,\n computeContainerKekRecipientTargetHash,\n computeContainerKeyEpochHash,\n} from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport type {\n MaterializedContainerRekeyPlan,\n MaterializedContainerSharePlan,\n} from \"../../../../data/containers/shared/types\";\nimport {\n canonicalKeyingJsonString,\n readCanonicalRecord,\n readCanonicalRecords,\n} from \"../../../../data/keying/canonicalJson\";\nimport { mergeProjectionPolicyEvidence } from \"../../../../data/keyingProjectionVerification\";\n\nconst speculativeProjections = new WeakSet<ContainerWriterProjectionResponse>();\n\nexport function isSpeculativeContainerWriterProjection(\n projection: ContainerWriterProjectionResponse,\n): boolean {\n return speculativeProjections.has(projection);\n}\n\n/**\n * What any rotation plan (rekey, revoke, move) holds in common: enough to say\n * what its container's path entry will be once the server accepts it.\n */\nexport interface RotationPlanArtifacts {\n readonly body: object;\n readonly containerId: string;\n readonly containerKeyEpochId: string;\n readonly event: MaterializedContainerRekeyPlan[\"plan\"][\"event\"];\n readonly eventHash: string;\n readonly keyEpoch: MaterializedContainerRekeyPlan[\"plan\"][\"keyEpoch\"];\n readonly manifest: MaterializedContainerRekeyPlan[\"plan\"][\"manifest\"];\n readonly manifestHash: string;\n readonly previousManifest: MaterializedContainerRekeyPlan[\"plan\"][\"previousManifest\"];\n readonly keyring: MaterializedContainerRekeyPlan[\"plan\"][\"keyring\"];\n readonly state: MaterializedContainerRekeyPlan[\"plan\"][\"state\"];\n readonly wraps: MaterializedContainerRekeyPlan[\"plan\"][\"wraps\"];\n}\n\nfunction recipientTargets(\n plan: Pick<RotationPlanArtifacts, \"wraps\">,\n): ContainerKekRecipientTarget[] {\n return plan.wraps\n .map((wrap) => ({\n recipientId: wrap.recipientId,\n recipientKeyEpochId: wrap.recipientKeyEpochId,\n recipientKeyFingerprint: wrap.recipientKeyFingerprint,\n recipientKind: wrap.recipientKind,\n }))\n .sort((left, right) =>\n canonicalKeyingJsonString(\n left,\n \"Container rekey recipient\",\n ).localeCompare(\n canonicalKeyingJsonString(right, \"Container rekey recipient\"),\n ),\n );\n}\n\n/**\n * The projection a rotation will leave behind, before the server has accepted\n * it. `ancestors` is the path above the container afterwards: unchanged for a\n * rekey or revoke, the destination parent's path for a move.\n */\nexport async function containerWriterProjectionFromRotationPlan(input: {\n ancestors?: Pick<\n ContainerWriterProjectionResponse,\n \"containerKeks\" | \"path\" | \"policyEvidence\"\n >;\n plan: RotationPlanArtifacts;\n previousProjection: ContainerWriterProjectionResponse;\n}): Promise<ContainerWriterProjectionResponse> {\n const { plan } = input;\n const previousManifest = input.previousProjection.path.at(-1);\n const previousKek = input.previousProjection.containerKeks.at(-1);\n if (\n !previousManifest ||\n !previousKek ||\n previousManifest.manifestHash !== plan.previousManifest.manifestHash ||\n previousKek.containerId !== plan.containerId\n ) {\n throw new Error(\"Container rekey projection predecessor mismatch\");\n }\n const targets = recipientTargets(plan);\n const nextManifest = {\n event: {\n body: readCanonicalRecord(plan.body, \"Container rekey body\"),\n event: readCanonicalRecord(plan.event, \"Container rekey event\"),\n eventHash: plan.eventHash,\n },\n manifest: readCanonicalRecord(plan.manifest, \"Container rekey manifest\"),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Container rekey state\"),\n };\n const nextKek = {\n accessManifestHash: plan.manifestHash,\n containerId: plan.containerId,\n containerKeyEpoch: plan.keyEpoch.keyEpoch,\n containerKeyEpochId: plan.containerKeyEpochId,\n containerManifestHistory: [\n previousManifest,\n ...previousKek.containerManifestHistory,\n ],\n keyEpoch: readCanonicalRecord(plan.keyEpoch, \"Container rekey key epoch\"),\n keyEpochHash: await computeContainerKeyEpochHash(plan.keyEpoch),\n keyring: { ...plan.keyring },\n keyTargetHash: await computeContainerKekRecipientTargetHash(targets),\n parentContainerKeyEpochId: plan.keyEpoch.parentContainerKeyEpochId,\n recipientTargets: readCanonicalRecords(\n targets,\n \"Container rekey recipient targets\",\n ),\n wraps: readCanonicalRecords(plan.wraps, \"Container rekey wraps\"),\n };\n const ancestors = input.ancestors ?? {\n containerKeks: input.previousProjection.containerKeks.slice(0, -1),\n path: input.previousProjection.path.slice(0, -1),\n };\n const projection = {\n ...input.previousProjection,\n policyEvidence: mergeProjectionPolicyEvidence([\n input.previousProjection.policyEvidence,\n ...(input.ancestors ? [input.ancestors.policyEvidence] : []),\n ]),\n path: [...ancestors.path, nextManifest],\n containerKeks: [...ancestors.containerKeks, nextKek],\n };\n speculativeProjections.add(projection);\n return projection;\n}\n\nexport function containerWriterProjectionFromRekeyPlan(input: {\n materializedPlan: Pick<\n MaterializedContainerRekeyPlan,\n \"containerKey\" | \"plan\"\n >;\n previousProjection: ContainerWriterProjectionResponse;\n}): Promise<ContainerWriterProjectionResponse> {\n return containerWriterProjectionFromRotationPlan({\n plan: input.materializedPlan.plan,\n previousProjection: input.previousProjection,\n });\n}\n\n/**\n * A descendant's served projection, re-rooted on rotations the server has not\n * accepted yet: `rotated` replaces the path down to and including its own\n * container. Null when the descendant does not sit below that container.\n */\nexport function rebaseContainerWriterProjection(\n descendant: ContainerWriterProjectionResponse,\n rotated: Pick<\n ContainerWriterProjectionResponse,\n \"containerKeks\" | \"path\" | \"policyEvidence\"\n >,\n): ContainerWriterProjectionResponse | null {\n const rotatedId = rotated.containerKeks.at(-1)?.containerId;\n const index = descendant.containerKeks.findIndex(\n (kek) => kek.containerId === rotatedId,\n );\n if (rotatedId === undefined || index < 0) return null;\n if (index === descendant.containerKeks.length - 1) return null;\n const projection = {\n ...descendant,\n policyEvidence: mergeProjectionPolicyEvidence([\n descendant.policyEvidence,\n rotated.policyEvidence,\n ]),\n path: [...rotated.path, ...descendant.path.slice(index + 1)],\n containerKeks: [\n ...rotated.containerKeks,\n ...descendant.containerKeks.slice(index + 1),\n ],\n };\n speculativeProjections.add(projection);\n return projection;\n}\n\n/** A grant keeps its key epoch while advancing the manifest and recipient wraps. */\nexport async function containerWriterProjectionFromSharePlan(input: {\n plan: MaterializedContainerSharePlan[\"plan\"];\n previousProjection: ContainerWriterProjectionResponse;\n}): Promise<ContainerWriterProjectionResponse> {\n const { plan, previousProjection } = input;\n const previous = previousProjection.path.at(-1);\n const kek = previousProjection.containerKeks.at(-1);\n if (\n !previous ||\n !kek ||\n previous.manifestHash !== plan.previousManifest.manifestHash ||\n kek.containerId !== plan.containerId\n )\n throw new Error(\"Container grant projection predecessor mismatch\");\n const targets = recipientTargets({ wraps: plan.wraps });\n const projection = {\n ...previousProjection,\n path: [\n ...previousProjection.path.slice(0, -1),\n {\n event: {\n body: readCanonicalRecord(plan.body, \"Container grant body\"),\n event: readCanonicalRecord(plan.event, \"Container grant event\"),\n eventHash: plan.eventHash,\n },\n manifest: readCanonicalRecord(\n plan.manifest,\n \"Container grant manifest\",\n ),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Container grant state\"),\n },\n ],\n containerKeks: [\n ...previousProjection.containerKeks.slice(0, -1),\n {\n ...kek,\n accessManifestHash: plan.manifestHash,\n containerManifestHistory: [previous, ...kek.containerManifestHistory],\n keyTargetHash: await computeContainerKekRecipientTargetHash(targets),\n recipientTargets: readCanonicalRecords(\n targets,\n \"Container grant targets\",\n ),\n wraps: readCanonicalRecords(plan.wraps, \"Container grant wraps\"),\n },\n ],\n };\n speculativeProjections.add(projection);\n return projection;\n}\n"]}
@@ -1,6 +1,5 @@
1
1
  import { getParentKekForTarget, getParentWrappingPublicKey, getTargetContainerContext, readContainerState, } from "../../../../data/containers/shared/projection.js";
2
- import { assertContainerKekPathCurrent } from "../../../../data/documents/shared/containerKek/containerKekCurrency.js";
3
- import { signedHistoryEpochIds } from "../../../../data/documents/shared/containerKek/containerKekPathHistory.js";
2
+ import { assertContainerKekPathCurrent, signedHistoryEpochIds, } from "../../../../data/documents/shared/containerKek/index.js";
4
3
  import { unwrapContainerKekPath } from "../../../../data/documents/shared/projection/index.js";
5
4
  import { projectionVerificationOptions } from "../../../../data/documents/shared/types.js";
6
5
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"rotationContext.js","sourceRoot":"","sources":["rotationContext.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,+CAA+C,CAAC;AAEvD,OAAO,EAAE,6BAA6B,EAAE,MAAM,qEAAqE,CAAC;AACpH,OAAO,EAAE,qBAAqB,EAAE,MAAM,wEAAwE,CAAC;AAC/G,OAAO,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAiBxF;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAA6C,EAC7C,cAAoE;IAEpE,MAAM,MAAM,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACrD,OAAO;QACL,GAAG,MAAM;QACT,cAAc,EAAE,qBAAqB,CAAC;YACpC,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY;YAC9C,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,cAAc;SACf,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,aAA8C,EAC9C,GAAsD,EACtD,KAAa;IAEb,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC/D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,6BAA6B,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAkBC,EACD,cAAsB;IAQtB,2FAA2F;IAC3F,6BAA6B,CAC3B,KAAK,CAAC,kBAAkB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CACpD,CAAC;IACF,MAAM,cAAc,GAAG,IAAI,GAAG,EAA2C,CAAC;IAC1E,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC;QACjD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,8BAA8B,EAAE,KAAK,CAAC,8BAA8B;QACpE,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;QAChD,UAAU,EAAE,KAAK,CAAC,kBAAkB;QACpC,SAAS,EAAE,KAAK,CAAC,eAAe;QAChC,cAAc;QACd,GAAG,6BAA6B,CAAC,KAAK,CAAC;KACxC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAC9E,MAAM,uBAAuB,GAAG,mBAAmB,CACjD,aAAa,EACb,MAAM,CAAC,GAAG,EACV,aAAa,cAAc,cAAc,CAC1C,CAAC;IACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,IAAI,aAAa,CAAC,cAAc,KAAK,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,aAAa,cAAc,+BAA+B,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClE,MAAM,eAAe,GAAG,0BAA0B,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC7E,OAAO;QACL,SAAS;QACT,eAAe;QACf,uBAAuB;QACvB,aAAa;QACb,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import type { VerifiedContainerAccessManifest } from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n getParentKekForTarget,\n getParentWrappingPublicKey,\n getTargetContainerContext,\n readContainerState,\n} from \"../../../../data/containers/shared/projection\";\nimport type { ContainerMutationAuthor } from \"../../../../data/containers/shared/types\";\nimport { assertContainerKekPathCurrent } from \"../../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { signedHistoryEpochIds } from \"../../../../data/documents/shared/containerKek/containerKekPathHistory\";\nimport { unwrapContainerKekPath } from \"../../../../data/documents/shared/projection\";\nimport { projectionVerificationOptions } from \"../../../../data/documents/shared/types\";\nimport type {\n PrincipalPolicyCache,\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../../data/keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../../data/sqlite/sqlSchema\";\n\n/**\n * A rotation's target container, with the epoch ids its verified lineage\n * names wherever the projection served it; the re-sealed keyring is anchored\n * to them (#2365 finding 32).\n */\nexport type SignedRotationTarget = ReturnType<\n typeof getTargetContainerContext\n> & { readonly signedEpochIds: ReadonlySet<string> };\n\n/**\n * The projection's target with its signed lineage ids, read from the manifests\n * this rotation's own verification recorded. Every rotation that re-seals a\n * keyring builds its target here, so none can skip the anchor.\n */\nexport function signedRotationTarget(\n projection: ContainerWriterProjectionResponse,\n verifiedByHash: ReadonlyMap<string, VerifiedContainerAccessManifest>,\n): SignedRotationTarget {\n const target = getTargetContainerContext(projection);\n return {\n ...target,\n signedEpochIds: signedHistoryEpochIds({\n headManifestHash: target.manifest.manifestHash,\n kek: target.kek,\n verifiedByHash,\n }),\n };\n}\n\nexport function requireUnwrappedKek(\n keksByEpochId: ReadonlyMap<string, Uint8Array>,\n kek: Pick<ContainerKekResponse, \"containerKeyEpochId\">,\n label: string,\n): Uint8Array {\n const keyMaterial = keksByEpochId.get(kek.containerKeyEpochId);\n if (!keyMaterial) {\n throw new Error(`${label} KEK could not be unwrapped`);\n }\n return keyMaterial;\n}\n\n/**\n * The shared rotation prologue for rekey and revoke: unwrap the projection's\n * KEK path, require the predecessor key, check the author's organization, and\n * surface the authenticated parent public key when one exists.\n */\nexport async function resolveRotationContext(\n input: {\n author: ContainerMutationAuthor;\n execSql: ExecSql;\n /**\n * Keys of epochs the projection names that no wrap on it opens for this\n * signer yet: the ones a batch minted above and has not committed.\n */\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n previousProjection: ContainerWriterProjectionResponse;\n /** Verified policies the path may cite before they are stored locally. */\n principalPolicyCache?: PrincipalPolicyCache | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n },\n operationLabel: string,\n): Promise<{\n parentKek: ReturnType<typeof getParentKekForTarget>;\n parentPublicKey: string | null;\n predecessorContainerKey: Uint8Array;\n previousState: ReturnType<typeof readContainerState>;\n target: SignedRotationTarget;\n}> {\n // The target may need repair, but wrapping its successor requires a current parent prefix.\n assertContainerKekPathCurrent(\n input.previousProjection.containerKeks.slice(0, -1),\n );\n const verifiedByHash = new Map<string, VerifiedContainerAccessManifest>();\n const keksByEpochId = await unwrapContainerKekPath({\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n principalPolicyCache: input.principalPolicyCache,\n projection: input.previousProjection,\n secretKey: input.targetSecretKey,\n verifiedByHash,\n ...projectionVerificationOptions(input),\n });\n const target = signedRotationTarget(input.previousProjection, verifiedByHash);\n const predecessorContainerKey = requireUnwrappedKek(\n keksByEpochId,\n target.kek,\n `Container ${operationLabel} predecessor`,\n );\n const previousState = readContainerState(target.manifest);\n if (previousState.organizationId !== input.author.organizationId) {\n throw new Error(`Container ${operationLabel} author organization mismatch`);\n }\n\n const parentKek = getParentKekForTarget(input.previousProjection);\n const parentPublicKey = getParentWrappingPublicKey(input.previousProjection);\n return {\n parentKek,\n parentPublicKey,\n predecessorContainerKey,\n previousState,\n target,\n };\n}\n"]}
1
+ {"version":3,"file":"rotationContext.js","sourceRoot":"","sources":["rotationContext.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,+CAA+C,CAAC;AAEvD,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,GACtB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AAiBxF;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAA6C,EAC7C,cAAoE;IAEpE,MAAM,MAAM,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACrD,OAAO;QACL,GAAG,MAAM;QACT,cAAc,EAAE,qBAAqB,CAAC;YACpC,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC,YAAY;YAC9C,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,cAAc;SACf,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,aAA8C,EAC9C,GAAsD,EACtD,KAAa;IAEb,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC/D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,6BAA6B,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAkBC,EACD,cAAsB;IAQtB,2FAA2F;IAC3F,6BAA6B,CAC3B,KAAK,CAAC,kBAAkB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CACpD,CAAC;IACF,MAAM,cAAc,GAAG,IAAI,GAAG,EAA2C,CAAC;IAC1E,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC;QACjD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,8BAA8B,EAAE,KAAK,CAAC,8BAA8B;QACpE,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;QAChD,UAAU,EAAE,KAAK,CAAC,kBAAkB;QACpC,SAAS,EAAE,KAAK,CAAC,eAAe;QAChC,cAAc;QACd,GAAG,6BAA6B,CAAC,KAAK,CAAC;KACxC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAC9E,MAAM,uBAAuB,GAAG,mBAAmB,CACjD,aAAa,EACb,MAAM,CAAC,GAAG,EACV,aAAa,cAAc,cAAc,CAC1C,CAAC;IACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,IAAI,aAAa,CAAC,cAAc,KAAK,KAAK,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,aAAa,cAAc,+BAA+B,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClE,MAAM,eAAe,GAAG,0BAA0B,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC7E,OAAO;QACL,SAAS;QACT,eAAe;QACf,uBAAuB;QACvB,aAAa;QACb,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import type { VerifiedContainerAccessManifest } from \"@tearleads/crypto\";\nimport type {\n ContainerKekResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n getParentKekForTarget,\n getParentWrappingPublicKey,\n getTargetContainerContext,\n readContainerState,\n} from \"../../../../data/containers/shared/projection\";\nimport type { ContainerMutationAuthor } from \"../../../../data/containers/shared/types\";\nimport {\n assertContainerKekPathCurrent,\n signedHistoryEpochIds,\n} from \"../../../../data/documents/shared/containerKek\";\nimport { unwrapContainerKekPath } from \"../../../../data/documents/shared/projection\";\nimport { projectionVerificationOptions } from \"../../../../data/documents/shared/types\";\nimport type {\n PrincipalPolicyCache,\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../../data/keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../../data/sqlite/sqlSchema\";\n\n/**\n * A rotation's target container, with the epoch ids its verified lineage\n * names wherever the projection served it; the re-sealed keyring is anchored\n * to them (#2365 finding 32).\n */\nexport type SignedRotationTarget = ReturnType<\n typeof getTargetContainerContext\n> & { readonly signedEpochIds: ReadonlySet<string> };\n\n/**\n * The projection's target with its signed lineage ids, read from the manifests\n * this rotation's own verification recorded. Every rotation that re-seals a\n * keyring builds its target here, so none can skip the anchor.\n */\nexport function signedRotationTarget(\n projection: ContainerWriterProjectionResponse,\n verifiedByHash: ReadonlyMap<string, VerifiedContainerAccessManifest>,\n): SignedRotationTarget {\n const target = getTargetContainerContext(projection);\n return {\n ...target,\n signedEpochIds: signedHistoryEpochIds({\n headManifestHash: target.manifest.manifestHash,\n kek: target.kek,\n verifiedByHash,\n }),\n };\n}\n\nexport function requireUnwrappedKek(\n keksByEpochId: ReadonlyMap<string, Uint8Array>,\n kek: Pick<ContainerKekResponse, \"containerKeyEpochId\">,\n label: string,\n): Uint8Array {\n const keyMaterial = keksByEpochId.get(kek.containerKeyEpochId);\n if (!keyMaterial) {\n throw new Error(`${label} KEK could not be unwrapped`);\n }\n return keyMaterial;\n}\n\n/**\n * The shared rotation prologue for rekey and revoke: unwrap the projection's\n * KEK path, require the predecessor key, check the author's organization, and\n * surface the authenticated parent public key when one exists.\n */\nexport async function resolveRotationContext(\n input: {\n author: ContainerMutationAuthor;\n execSql: ExecSql;\n /**\n * Keys of epochs the projection names that no wrap on it opens for this\n * signer yet: the ones a batch minted above and has not committed.\n */\n knownContainerKeks?: ReadonlyMap<string, Uint8Array> | undefined;\n persistVerificationCheckpoints?: boolean | undefined;\n previousProjection: ContainerWriterProjectionResponse;\n /** Verified policies the path may cite before they are stored locally. */\n principalPolicyCache?: PrincipalPolicyCache | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n },\n operationLabel: string,\n): Promise<{\n parentKek: ReturnType<typeof getParentKekForTarget>;\n parentPublicKey: string | null;\n predecessorContainerKey: Uint8Array;\n previousState: ReturnType<typeof readContainerState>;\n target: SignedRotationTarget;\n}> {\n // The target may need repair, but wrapping its successor requires a current parent prefix.\n assertContainerKekPathCurrent(\n input.previousProjection.containerKeks.slice(0, -1),\n );\n const verifiedByHash = new Map<string, VerifiedContainerAccessManifest>();\n const keksByEpochId = await unwrapContainerKekPath({\n execSql: input.execSql,\n knownContainerKeks: input.knownContainerKeks,\n persistVerificationCheckpoints: input.persistVerificationCheckpoints,\n principalPolicyCache: input.principalPolicyCache,\n projection: input.previousProjection,\n secretKey: input.targetSecretKey,\n verifiedByHash,\n ...projectionVerificationOptions(input),\n });\n const target = signedRotationTarget(input.previousProjection, verifiedByHash);\n const predecessorContainerKey = requireUnwrappedKek(\n keksByEpochId,\n target.kek,\n `Container ${operationLabel} predecessor`,\n );\n const previousState = readContainerState(target.manifest);\n if (previousState.organizationId !== input.author.organizationId) {\n throw new Error(`Container ${operationLabel} author organization mismatch`);\n }\n\n const parentKek = getParentKekForTarget(input.previousProjection);\n const parentPublicKey = getParentWrappingPublicKey(input.previousProjection);\n return {\n parentKek,\n parentPublicKey,\n predecessorContainerKey,\n previousState,\n target,\n };\n}\n"]}
@@ -1,6 +1,5 @@
1
1
  import { ContainerAuthorAccessError } from "../../../../data/containers/shared/authorAccess.js";
2
- import { ContainerKekRepairInaccessibleError } from "../../../../data/documents/shared/containerKek/containerKekCurrency.js";
3
- import { ContainerKekTargetUnreachableError } from "../../../../data/documents/shared/containerKek/containerKekPath.js";
2
+ import { ContainerKekRepairInaccessibleError, ContainerKekTargetUnreachableError, } from "../../../../data/documents/shared/containerKek/index.js";
4
3
  import { rekeyRemoteContainer } from "../rekey/rekeyRemote.js";
5
4
  function carriesDirectGrant(projection) {
6
5
  const directGrants = Reflect.get(Object(projection.path.at(-1)?.state), "directGrants");
@@ -1 +1 @@
1
- {"version":3,"file":"shareAncestorRepair.js","sourceRoot":"","sources":["shareAncestorRepair.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAM7F,OAAO,EAAE,mCAAmC,EAAE,MAAM,qEAAqE,CAAC;AAC1H,OAAO,EAAE,kCAAkC,EAAE,MAAM,iEAAiE,CAAC;AAOrH,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,SAAS,kBAAkB,CACzB,UAA6C;IAE7C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAC9B,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EACrC,cAAc,CACf,CAAC;IACF,OAAO,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;AAChE,CAAC;AAED,oFAAoF;AACpF,SAAS,iBAAiB,CACxB,UAA6C;IAE7C,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC;IACtC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IACE,GAAG;YACH,GAAG,CAAC,yBAAyB,KAAK,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,mBAAmB,EACtE,CAAC;YACD,OAAO,GAAG,CAAC,WAAW,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,KAYpD;IACC,MAAM,EAAE,cAAc,EAAE,oBAAoB,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC;IACjE,IAAI,UAAU,GAAG,KAAK,CAAC,kBAAkB,CAAC;IAC1C,yEAAyE;IACzE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACxE,MAAM,YAAY,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,YAAY,KAAK,IAAI;YAAE,OAAO,UAAU,CAAC;QAC7C,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,sEAAsE;YACtE,MAAM,IAAI,KAAK,CACb,sEAAsE,CACvE,CAAC;QACJ,CAAC;QACD,qEAAqE;QACrE,wEAAwE;QACxE,wEAAwE;QACxE,yCAAyC;QACzC,MAAM,aAAa,GACjB,YAAY,KAAK,KAAK,CAAC,WAAW,IAAI,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC;YAC1C,SAAS,EAAE;gBACT,4BAA4B,EAAE,CAAC,WAAW,EAAE,EAAE,CAC5C,KAAK,CAAC,SAAS,CAAC,4BAA4B,CAAC,WAAW,CAAC;gBAC3D,eAAe,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;gBACtE,cAAc,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;gBACpD,GAAG,CAAC,oBAAoB;oBACtB,CAAC,CAAC,EAAE,oBAAoB,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;oBACtE,CAAC,CAAC,EAAE,CAAC;aACR;YACD,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,WAAW,EAAE,YAAY;YACzB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;YACxD,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;SACvE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC1B,MAAM,UAAU,GACd,KAAK,YAAY,0BAA0B;gBAC3C,KAAK,YAAY,kCAAkC,CAAC;YACtD,IAAI,UAAU,IAAI,aAAa;gBAAE,OAAO,IAAI,CAAC;YAC7C,MAAM,UAAU;gBACd,CAAC,CAAC,IAAI,mCAAmC,CAAC,YAAY,CAAC;gBACvD,CAAC,CAAC,KAAK,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,IAAI,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC;QAClD,IAAI,CAAC,QAAQ;YAAE,OAAO,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,4BAA4B,CAClE,KAAK,CAAC,WAAW,CAClB,CAAC;QACF,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAC5B,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;IACD,OAAO,iBAAiB,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC","sourcesContent":["import type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { ContainerAuthorAccessError } from \"../../../../data/containers/shared/authorAccess\";\nimport type {\n ContainerMutationAuthor,\n ContainerRekeyApi,\n ContainerShareApi,\n} from \"../../../../data/containers/shared/types\";\nimport { ContainerKekRepairInaccessibleError } from \"../../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { ContainerKekTargetUnreachableError } from \"../../../../data/documents/shared/containerKek/containerKekPath\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../../data/keyingProjectionVerification\";\nimport type { SecurityIncidentReporter } from \"../../../../data/shared/securityIncidents\";\nimport type { ExecSql } from \"../../../../data/sqlite/sqlSchema\";\nimport { rekeyRemoteContainer } from \"../rekey/rekeyRemote\";\n\nfunction carriesDirectGrant(\n projection: ContainerWriterProjectionResponse,\n): boolean {\n const directGrants = Reflect.get(\n Object(projection.path.at(-1)?.state),\n \"directGrants\",\n );\n return Array.isArray(directGrants) && directGrants.length > 0;\n}\n\n/** The first level on the path, the container included, pinning a retired epoch. */\nfunction firstStaleLevelId(\n projection: ContainerWriterProjectionResponse,\n): string | null {\n const keks = projection.containerKeks;\n for (let index = 1; index < keks.length; index += 1) {\n const kek = keks[index];\n if (\n kek &&\n kek.parentContainerKeyEpochId !== keks[index - 1]?.containerKeyEpochId\n ) {\n return kek.containerId;\n }\n }\n return null;\n}\n\n/**\n * Repair a stale path down to and including a container before granting on it\n * (#2340).\n *\n * A chain with no grant beneath it may sit lazily stale after an ancestor\n * rotation, since nobody's writes depend on it. The first grant changes that:\n * its grantee could never re-key the levels above its container, so the server\n * refuses a first grant below a stale chain. The container's own edge must be\n * current too, because a grant cites the parent's current epoch and the\n * container's key epoch has to pin it. The sharer administers the container\n * through a grant at or above it, and the levels above that grant are already\n * current, so every stale level here is one the sharer can re-key. These\n * repairs are standalone and need not be atomic with the grant: a repair never\n * strands anyone.\n *\n * Every share does this, not only a first grant, which is all the server\n * insists on. A container that already carries a grant is stale only past the\n * carried-rekey cap, and its grantees are then parked behind exactly these\n * levels; the sharer is already here and able.\n */\nexport async function projectionWithCurrentAncestors(input: {\n apiClient: ContainerShareApi &\n Partial<Pick<ContainerRekeyApi, \"rekeyContainer\" | \"rekeyContainerResult\">>;\n author: ContainerMutationAuthor;\n containerId: string;\n execSql: ExecSql;\n previousProjection: ContainerWriterProjectionResponse;\n reportSecurityIncident: SecurityIncidentReporter;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<ContainerWriterProjectionResponse | null> {\n const { rekeyContainer, rekeyContainerResult } = input.apiClient;\n let projection = input.previousProjection;\n // Each round repairs one level, and a path has a bounded number of them.\n for (let round = 0; round < projection.containerKeks.length; round += 1) {\n const staleLevelId = firstStaleLevelId(projection);\n if (staleLevelId === null) return projection;\n if (!rekeyContainer) {\n // Not a repair someone else owes: the adapter simply cannot make one.\n throw new Error(\n \"Container share must re-key a stale path, which needs rekeyContainer\",\n );\n }\n // This sharer may be unable to re-key a level above a container that\n // already carries a grant, stale past the carried-rekey cap. The server\n // asks a current chain only of a first grant, so it decides rather than\n // this blocking a grant it would accept.\n const serverDecides =\n staleLevelId !== input.containerId && carriesDirectGrant(projection);\n const repaired = await rekeyRemoteContainer({\n apiClient: {\n getContainerWriterProjection: (containerId) =>\n input.apiClient.getContainerWriterProjection(containerId),\n reciteContainer: (...args) => input.apiClient.reciteContainer(...args),\n rekeyContainer: rekeyContainer.bind(input.apiClient),\n ...(rekeyContainerResult\n ? { rekeyContainerResult: rekeyContainerResult.bind(input.apiClient) }\n : {}),\n },\n author: input.author,\n containerId: staleLevelId,\n execSql: input.execSql,\n reportSecurityIncident: input.reportSecurityIncident,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }).catch((error: unknown) => {\n const outOfReach =\n error instanceof ContainerAuthorAccessError ||\n error instanceof ContainerKekTargetUnreachableError;\n if (outOfReach && serverDecides) return null;\n throw outOfReach\n ? new ContainerKekRepairInaccessibleError(staleLevelId)\n : error;\n });\n if (input.stillCurrent?.() === false) return null;\n if (!repaired) return serverDecides ? projection : null;\n const refreshed = await input.apiClient.getContainerWriterProjection(\n input.containerId,\n );\n if (!refreshed) return null;\n projection = refreshed;\n }\n return firstStaleLevelId(projection) === null ? projection : null;\n}\n"]}
1
+ {"version":3,"file":"shareAncestorRepair.js","sourceRoot":"","sources":["shareAncestorRepair.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { ContainerAuthorAccessError } from \"../../../../data/containers/shared/authorAccess\";\nimport type {\n ContainerMutationAuthor,\n ContainerRekeyApi,\n ContainerShareApi,\n} from \"../../../../data/containers/shared/types\";\nimport {\n ContainerKekRepairInaccessibleError,\n ContainerKekTargetUnreachableError,\n} from \"../../../../data/documents/shared/containerKek\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../../data/keyingProjectionVerification\";\nimport type { SecurityIncidentReporter } from \"../../../../data/shared/securityIncidents\";\nimport type { ExecSql } from \"../../../../data/sqlite/sqlSchema\";\nimport { rekeyRemoteContainer } from \"../rekey/rekeyRemote\";\n\nfunction carriesDirectGrant(\n projection: ContainerWriterProjectionResponse,\n): boolean {\n const directGrants = Reflect.get(\n Object(projection.path.at(-1)?.state),\n \"directGrants\",\n );\n return Array.isArray(directGrants) && directGrants.length > 0;\n}\n\n/** The first level on the path, the container included, pinning a retired epoch. */\nfunction firstStaleLevelId(\n projection: ContainerWriterProjectionResponse,\n): string | null {\n const keks = projection.containerKeks;\n for (let index = 1; index < keks.length; index += 1) {\n const kek = keks[index];\n if (\n kek &&\n kek.parentContainerKeyEpochId !== keks[index - 1]?.containerKeyEpochId\n ) {\n return kek.containerId;\n }\n }\n return null;\n}\n\n/**\n * Repair a stale path down to and including a container before granting on it\n * (#2340).\n *\n * A chain with no grant beneath it may sit lazily stale after an ancestor\n * rotation, since nobody's writes depend on it. The first grant changes that:\n * its grantee could never re-key the levels above its container, so the server\n * refuses a first grant below a stale chain. The container's own edge must be\n * current too, because a grant cites the parent's current epoch and the\n * container's key epoch has to pin it. The sharer administers the container\n * through a grant at or above it, and the levels above that grant are already\n * current, so every stale level here is one the sharer can re-key. These\n * repairs are standalone and need not be atomic with the grant: a repair never\n * strands anyone.\n *\n * Every share does this, not only a first grant, which is all the server\n * insists on. A container that already carries a grant is stale only past the\n * carried-rekey cap, and its grantees are then parked behind exactly these\n * levels; the sharer is already here and able.\n */\nexport async function projectionWithCurrentAncestors(input: {\n apiClient: ContainerShareApi &\n Partial<Pick<ContainerRekeyApi, \"rekeyContainer\" | \"rekeyContainerResult\">>;\n author: ContainerMutationAuthor;\n containerId: string;\n execSql: ExecSql;\n previousProjection: ContainerWriterProjectionResponse;\n reportSecurityIncident: SecurityIncidentReporter;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<ContainerWriterProjectionResponse | null> {\n const { rekeyContainer, rekeyContainerResult } = input.apiClient;\n let projection = input.previousProjection;\n // Each round repairs one level, and a path has a bounded number of them.\n for (let round = 0; round < projection.containerKeks.length; round += 1) {\n const staleLevelId = firstStaleLevelId(projection);\n if (staleLevelId === null) return projection;\n if (!rekeyContainer) {\n // Not a repair someone else owes: the adapter simply cannot make one.\n throw new Error(\n \"Container share must re-key a stale path, which needs rekeyContainer\",\n );\n }\n // This sharer may be unable to re-key a level above a container that\n // already carries a grant, stale past the carried-rekey cap. The server\n // asks a current chain only of a first grant, so it decides rather than\n // this blocking a grant it would accept.\n const serverDecides =\n staleLevelId !== input.containerId && carriesDirectGrant(projection);\n const repaired = await rekeyRemoteContainer({\n apiClient: {\n getContainerWriterProjection: (containerId) =>\n input.apiClient.getContainerWriterProjection(containerId),\n reciteContainer: (...args) => input.apiClient.reciteContainer(...args),\n rekeyContainer: rekeyContainer.bind(input.apiClient),\n ...(rekeyContainerResult\n ? { rekeyContainerResult: rekeyContainerResult.bind(input.apiClient) }\n : {}),\n },\n author: input.author,\n containerId: staleLevelId,\n execSql: input.execSql,\n reportSecurityIncident: input.reportSecurityIncident,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: input.stillCurrent,\n targetSecretKey: input.targetSecretKey,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n }).catch((error: unknown) => {\n const outOfReach =\n error instanceof ContainerAuthorAccessError ||\n error instanceof ContainerKekTargetUnreachableError;\n if (outOfReach && serverDecides) return null;\n throw outOfReach\n ? new ContainerKekRepairInaccessibleError(staleLevelId)\n : error;\n });\n if (input.stillCurrent?.() === false) return null;\n if (!repaired) return serverDecides ? projection : null;\n const refreshed = await input.apiClient.getContainerWriterProjection(\n input.containerId,\n );\n if (!refreshed) return null;\n projection = refreshed;\n }\n return firstStaleLevelId(projection) === null ? projection : null;\n}\n"]}
@@ -2,9 +2,8 @@ export { ContainerAuthorAccessError } from "../../data/containers/shared/authorA
2
2
  export { ContainerPathTooDeepError } from "../../data/containers/shared/containerPathLimits.js";
3
3
  export type { ContainerReciteApi } from "../../data/containers/shared/reciteApi.js";
4
4
  export type { ContainerMutationAuthor, MaterializedContainerRekeyPlan, } from "../../data/containers/shared/types.js";
5
- export { ContainerKekRepairInaccessibleError, ContainerKekRepairRequiredError, } from "../../data/documents/shared/containerKek/containerKekCurrency.js";
6
- export type { AggregatedContainerKekLog, KeyringRebuildResult, } from "../../data/documents/shared/containerKek/keyringRebuild.js";
7
- export { fetchContainerKekLog, HistoricalWrapUnavailableError, type HistoricalWrapUnavailableReason, rebuildKeyringEntriesFromLog, recoverKeyringEntryFromWraps, } from "../../data/documents/shared/containerKek/keyringRebuild.js";
5
+ export type { AggregatedContainerKekLog, KeyringRebuildResult, } from "../../data/documents/shared/containerKek/index.js";
6
+ export { ContainerKekRepairInaccessibleError, ContainerKekRepairRequiredError, fetchContainerKekLog, HistoricalWrapUnavailableError, type HistoricalWrapUnavailableReason, rebuildKeyringEntriesFromLog, recoverKeyringEntryFromWraps, } from "../../data/documents/shared/containerKek/index.js";
8
7
  export { isProjectionVerificationCancelledError } from "../../data/keyingProjectionVerification/types.js";
9
8
  export { buildContainerCreatePlan, buildMaterializedContainerCreatePlan, childContainerWriterProjectionFromCreatePlan, createRemoteContainer, } from "./child/create/index.js";
10
9
  export { type AppliedContainerMove, moveRemoteContainer, replayRemoteContainerMove, } from "./child/move/index.js";
@@ -4,8 +4,7 @@ export { ContainerAuthorAccessError } from "../../data/containers/shared/authorA
4
4
  // A create or move past the readable path length; `code` is
5
5
  // `container_path_too_deep`. Queued moves are abandoned, queued creates wait.
6
6
  export { ContainerPathTooDeepError } from "../../data/containers/shared/containerPathLimits.js";
7
- export { ContainerKekRepairInaccessibleError, ContainerKekRepairRequiredError, } from "../../data/documents/shared/containerKek/containerKekCurrency.js";
8
- export { fetchContainerKekLog, HistoricalWrapUnavailableError, rebuildKeyringEntriesFromLog, recoverKeyringEntryFromWraps, } from "../../data/documents/shared/containerKek/keyringRebuild.js";
7
+ export { ContainerKekRepairInaccessibleError, ContainerKekRepairRequiredError, fetchContainerKekLog, HistoricalWrapUnavailableError, rebuildKeyringEntriesFromLog, recoverKeyringEntryFromWraps, } from "../../data/documents/shared/containerKek/index.js";
9
8
  // A share's projection verification can be cancelled by a newer generation
10
9
  // underneath the caller; hosts filter that outcome from their own reporting.
11
10
  export { isProjectionVerificationCancelledError } from "../../data/keyingProjectionVerification/types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,iEAAiE;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,4DAA4D;AAC5D,8EAA8E;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kDAAkD,CAAC;AAM7F,OAAO,EACL,mCAAmC,EACnC,+BAA+B,GAChC,MAAM,+DAA+D,CAAC;AAKvE,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAE9B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,yDAAyD,CAAC;AACjE,2EAA2E;AAC3E,6EAA6E;AAC7E,OAAO,EAAE,sCAAsC,EAAE,MAAM,+CAA+C,CAAC;AACvG,OAAO,EACL,wBAAwB,EACxB,oCAAoC,EACpC,4CAA4C,EAC5C,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,+EAA+E;AAC/E,OAAO,EACL,mCAAmC,EACnC,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mCAAmC,EAAE,MAAM,eAAe,CAAC;AACpE,8EAA8E;AAC9E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,sCAAsC,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mCAAmC,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,uCAAuC,EACvC,qDAAqD,GACtD,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,4BAA4B,EAC5B,2CAA2C,GAC5C,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,6BAA6B,GAC9B,MAAM,gBAAgB,CAAC","sourcesContent":["// Refusals the SDK raises before it encrypts or sends a container-scoped\n// write; hosts classify them with classifyContainerWriteRefusal.\nexport { ContainerAuthorAccessError } from \"../../data/containers/shared/authorAccess\";\n// A create or move past the readable path length; `code` is\n// `container_path_too_deep`. Queued moves are abandoned, queued creates wait.\nexport { ContainerPathTooDeepError } from \"../../data/containers/shared/containerPathLimits\";\nexport type { ContainerReciteApi } from \"../../data/containers/shared/reciteApi\";\nexport type {\n ContainerMutationAuthor,\n MaterializedContainerRekeyPlan,\n} from \"../../data/containers/shared/types\";\nexport {\n ContainerKekRepairInaccessibleError,\n ContainerKekRepairRequiredError,\n} from \"../../data/documents/shared/containerKek/containerKekCurrency\";\nexport type {\n AggregatedContainerKekLog,\n KeyringRebuildResult,\n} from \"../../data/documents/shared/containerKek/keyringRebuild\";\nexport {\n fetchContainerKekLog,\n HistoricalWrapUnavailableError,\n type HistoricalWrapUnavailableReason,\n rebuildKeyringEntriesFromLog,\n recoverKeyringEntryFromWraps,\n} from \"../../data/documents/shared/containerKek/keyringRebuild\";\n// A share's projection verification can be cancelled by a newer generation\n// underneath the caller; hosts filter that outcome from their own reporting.\nexport { isProjectionVerificationCancelledError } from \"../../data/keyingProjectionVerification/types\";\nexport {\n buildContainerCreatePlan,\n buildMaterializedContainerCreatePlan,\n childContainerWriterProjectionFromCreatePlan,\n createRemoteContainer,\n} from \"./child/create\";\nexport {\n type AppliedContainerMove,\n moveRemoteContainer,\n replayRemoteContainerMove,\n} from \"./child/move\";\n// Organizations' group shares submit and acknowledge their container mutation.\nexport {\n submitAcknowledgedContainerMutation,\n submitPlainContainerMutation,\n} from \"./child/mutationSubmit\";\nexport { buildMaterializedContainerRekeyPlan } from \"./child/rekey\";\n// A rebuilt keyring override that a concurrent rotation outdated: rebuild it.\nexport { ContainerKeyringOverrideStaleError } from \"./child/rekey/keyringOverrideLineage\";\nexport { containerWriterProjectionFromRekeyPlan } from \"./child/rekey/rekeyProjection\";\nexport { rekeyRemoteContainer } from \"./child/rekey/rekeyRemote\";\nexport {\n buildMaterializedContainerRevokePlan,\n revokeRemoteContainer,\n} from \"./child/revoke\";\nexport { shareRemoteContainer } from \"./child/share\";\nexport { buildMaterializedContainerSharePlan } from \"./child/share/shareMaterialization\";\nexport { referencedPrincipalHeadFromPolicy } from \"./child/share/sharePlanCore\";\nexport { resolveShareProjection } from \"./child/share/shareProjection\";\nexport {\n readContainerMutationMetadataDocumentId,\n referencedPrincipalHeadsFromContainerMutationResponse,\n} from \"./mutationResponse\";\nexport {\n buildRootContainerCreatePlan,\n rootContainerWriterProjectionFromCreatePlan,\n} from \"./root/create\";\nexport {\n type ContainerWriteRefusal,\n classifyContainerWriteRefusal,\n} from \"./writeRefusal\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,iEAAiE;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,4DAA4D;AAC5D,8EAA8E;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kDAAkD,CAAC;AAU7F,OAAO,EACL,mCAAmC,EACnC,+BAA+B,EAC/B,oBAAoB,EACpB,8BAA8B,EAE9B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,0CAA0C,CAAC;AAClD,2EAA2E;AAC3E,6EAA6E;AAC7E,OAAO,EAAE,sCAAsC,EAAE,MAAM,+CAA+C,CAAC;AACvG,OAAO,EACL,wBAAwB,EACxB,oCAAoC,EACpC,4CAA4C,EAC5C,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,+EAA+E;AAC/E,OAAO,EACL,mCAAmC,EACnC,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mCAAmC,EAAE,MAAM,eAAe,CAAC;AACpE,8EAA8E;AAC9E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,sCAAsC,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mCAAmC,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,uCAAuC,EACvC,qDAAqD,GACtD,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,4BAA4B,EAC5B,2CAA2C,GAC5C,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,6BAA6B,GAC9B,MAAM,gBAAgB,CAAC","sourcesContent":["// Refusals the SDK raises before it encrypts or sends a container-scoped\n// write; hosts classify them with classifyContainerWriteRefusal.\nexport { ContainerAuthorAccessError } from \"../../data/containers/shared/authorAccess\";\n// A create or move past the readable path length; `code` is\n// `container_path_too_deep`. Queued moves are abandoned, queued creates wait.\nexport { ContainerPathTooDeepError } from \"../../data/containers/shared/containerPathLimits\";\nexport type { ContainerReciteApi } from \"../../data/containers/shared/reciteApi\";\nexport type {\n ContainerMutationAuthor,\n MaterializedContainerRekeyPlan,\n} from \"../../data/containers/shared/types\";\nexport type {\n AggregatedContainerKekLog,\n KeyringRebuildResult,\n} from \"../../data/documents/shared/containerKek\";\nexport {\n ContainerKekRepairInaccessibleError,\n ContainerKekRepairRequiredError,\n fetchContainerKekLog,\n HistoricalWrapUnavailableError,\n type HistoricalWrapUnavailableReason,\n rebuildKeyringEntriesFromLog,\n recoverKeyringEntryFromWraps,\n} from \"../../data/documents/shared/containerKek\";\n// A share's projection verification can be cancelled by a newer generation\n// underneath the caller; hosts filter that outcome from their own reporting.\nexport { isProjectionVerificationCancelledError } from \"../../data/keyingProjectionVerification/types\";\nexport {\n buildContainerCreatePlan,\n buildMaterializedContainerCreatePlan,\n childContainerWriterProjectionFromCreatePlan,\n createRemoteContainer,\n} from \"./child/create\";\nexport {\n type AppliedContainerMove,\n moveRemoteContainer,\n replayRemoteContainerMove,\n} from \"./child/move\";\n// Organizations' group shares submit and acknowledge their container mutation.\nexport {\n submitAcknowledgedContainerMutation,\n submitPlainContainerMutation,\n} from \"./child/mutationSubmit\";\nexport { buildMaterializedContainerRekeyPlan } from \"./child/rekey\";\n// A rebuilt keyring override that a concurrent rotation outdated: rebuild it.\nexport { ContainerKeyringOverrideStaleError } from \"./child/rekey/keyringOverrideLineage\";\nexport { containerWriterProjectionFromRekeyPlan } from \"./child/rekey/rekeyProjection\";\nexport { rekeyRemoteContainer } from \"./child/rekey/rekeyRemote\";\nexport {\n buildMaterializedContainerRevokePlan,\n revokeRemoteContainer,\n} from \"./child/revoke\";\nexport { shareRemoteContainer } from \"./child/share\";\nexport { buildMaterializedContainerSharePlan } from \"./child/share/shareMaterialization\";\nexport { referencedPrincipalHeadFromPolicy } from \"./child/share/sharePlanCore\";\nexport { resolveShareProjection } from \"./child/share/shareProjection\";\nexport {\n readContainerMutationMetadataDocumentId,\n referencedPrincipalHeadsFromContainerMutationResponse,\n} from \"./mutationResponse\";\nexport {\n buildRootContainerCreatePlan,\n rootContainerWriterProjectionFromCreatePlan,\n} from \"./root/create\";\nexport {\n type ContainerWriteRefusal,\n classifyContainerWriteRefusal,\n} from \"./writeRefusal\";\n"]}
@@ -1,5 +1,5 @@
1
1
  import { ContainerAuthorAccessError } from "../../data/containers/shared/authorAccess.js";
2
- import { ContainerKekRepairInaccessibleError, ContainerKekRepairRequiredError, } from "../../data/documents/shared/containerKek/containerKekCurrency.js";
2
+ import { ContainerKekRepairInaccessibleError, ContainerKekRepairRequiredError, } from "../../data/documents/shared/containerKek/index.js";
3
3
  function namedError(error, name) {
4
4
  return error instanceof Error && error.name === name;
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"writeRefusal.js","sourceRoot":"","sources":["writeRefusal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EACL,mCAAmC,EACnC,+BAA+B,GAChC,MAAM,+DAA+D,CAAC;AAkBvE,SAAS,UAAU,CAAC,KAAc,EAAE,IAAY;IAC9C,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AACvD,CAAC;AAED,mFAAmF;AACnF,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC;IAC9D,OAAO,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAC9D,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,6BAA6B,CAC3C,KAAc;IAEd,0EAA0E;IAC1E,IACE,KAAK,YAAY,mCAAmC;QACpD,UAAU,CAAC,KAAK,EAAE,qCAAqC,CAAC,EACxD,CAAC;QACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,CAAC;IACD,IACE,KAAK,YAAY,+BAA+B;QAChD,UAAU,CAAC,KAAK,EAAE,iCAAiC,CAAC,EACpD,CAAC;QACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC;IACD,IACE,KAAK,YAAY,0BAA0B;QAC3C,UAAU,CAAC,KAAK,EAAE,4BAA4B,CAAC,EAC/C,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { ContainerAuthorAccessError } from \"../../data/containers/shared/authorAccess\";\nimport {\n ContainerKekRepairInaccessibleError,\n ContainerKekRepairRequiredError,\n} from \"../../data/documents/shared/containerKek/containerKekCurrency\";\n\n/**\n * Why the SDK refused to author a container-scoped write before anything was\n * encrypted or sent:\n *\n * - `repair-required`: the path cites a retired ancestor key epoch. Retry; this\n * writer's next document sync pass, or a peer, re-keys it parent-first.\n * - `repair-inaccessible`: the same, but the stale container is one this writer\n * can neither re-key nor be given the key for. Queued changes stay queued and\n * sync once a member with access to `containerId` repairs it.\n * - `unauthorized`: the signed path grants this signer too little access.\n */\nexport type ContainerWriteRefusal =\n | { readonly kind: \"repair-required\"; readonly containerId: string }\n | { readonly kind: \"repair-inaccessible\"; readonly containerId: string }\n | { readonly kind: \"unauthorized\" };\n\nfunction namedError(error: unknown, name: string): error is Error {\n return error instanceof Error && error.name === name;\n}\n\n/** A same-named error from elsewhere may lack the field; never say \"undefined\". */\nfunction repairContainerId(error: unknown): string | null {\n const containerId = Reflect.get(Object(error), \"containerId\");\n return typeof containerId === \"string\" && containerId.length > 0\n ? containerId\n : null;\n}\n\n/** Null for anything else, including keying-verification failures. */\nexport function classifyContainerWriteRefusal(\n error: unknown,\n): ContainerWriteRefusal | null {\n // Match by name as well: a host bundling the SDK twice holds two classes.\n if (\n error instanceof ContainerKekRepairInaccessibleError ||\n namedError(error, \"ContainerKekRepairInaccessibleError\")\n ) {\n const containerId = repairContainerId(error);\n return containerId ? { kind: \"repair-inaccessible\", containerId } : null;\n }\n if (\n error instanceof ContainerKekRepairRequiredError ||\n namedError(error, \"ContainerKekRepairRequiredError\")\n ) {\n const containerId = repairContainerId(error);\n return containerId ? { kind: \"repair-required\", containerId } : null;\n }\n if (\n error instanceof ContainerAuthorAccessError ||\n namedError(error, \"ContainerAuthorAccessError\")\n ) {\n return { kind: \"unauthorized\" };\n }\n return null;\n}\n"]}
1
+ {"version":3,"file":"writeRefusal.js","sourceRoot":"","sources":["writeRefusal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EACL,mCAAmC,EACnC,+BAA+B,GAChC,MAAM,0CAA0C,CAAC;AAkBlD,SAAS,UAAU,CAAC,KAAc,EAAE,IAAY;IAC9C,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AACvD,CAAC;AAED,mFAAmF;AACnF,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC;IAC9D,OAAO,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAC9D,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,6BAA6B,CAC3C,KAAc;IAEd,0EAA0E;IAC1E,IACE,KAAK,YAAY,mCAAmC;QACpD,UAAU,CAAC,KAAK,EAAE,qCAAqC,CAAC,EACxD,CAAC;QACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,CAAC;IACD,IACE,KAAK,YAAY,+BAA+B;QAChD,UAAU,CAAC,KAAK,EAAE,iCAAiC,CAAC,EACpD,CAAC;QACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC;IACD,IACE,KAAK,YAAY,0BAA0B;QAC3C,UAAU,CAAC,KAAK,EAAE,4BAA4B,CAAC,EAC/C,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { ContainerAuthorAccessError } from \"../../data/containers/shared/authorAccess\";\nimport {\n ContainerKekRepairInaccessibleError,\n ContainerKekRepairRequiredError,\n} from \"../../data/documents/shared/containerKek\";\n\n/**\n * Why the SDK refused to author a container-scoped write before anything was\n * encrypted or sent:\n *\n * - `repair-required`: the path cites a retired ancestor key epoch. Retry; this\n * writer's next document sync pass, or a peer, re-keys it parent-first.\n * - `repair-inaccessible`: the same, but the stale container is one this writer\n * can neither re-key nor be given the key for. Queued changes stay queued and\n * sync once a member with access to `containerId` repairs it.\n * - `unauthorized`: the signed path grants this signer too little access.\n */\nexport type ContainerWriteRefusal =\n | { readonly kind: \"repair-required\"; readonly containerId: string }\n | { readonly kind: \"repair-inaccessible\"; readonly containerId: string }\n | { readonly kind: \"unauthorized\" };\n\nfunction namedError(error: unknown, name: string): error is Error {\n return error instanceof Error && error.name === name;\n}\n\n/** A same-named error from elsewhere may lack the field; never say \"undefined\". */\nfunction repairContainerId(error: unknown): string | null {\n const containerId = Reflect.get(Object(error), \"containerId\");\n return typeof containerId === \"string\" && containerId.length > 0\n ? containerId\n : null;\n}\n\n/** Null for anything else, including keying-verification failures. */\nexport function classifyContainerWriteRefusal(\n error: unknown,\n): ContainerWriteRefusal | null {\n // Match by name as well: a host bundling the SDK twice holds two classes.\n if (\n error instanceof ContainerKekRepairInaccessibleError ||\n namedError(error, \"ContainerKekRepairInaccessibleError\")\n ) {\n const containerId = repairContainerId(error);\n return containerId ? { kind: \"repair-inaccessible\", containerId } : null;\n }\n if (\n error instanceof ContainerKekRepairRequiredError ||\n namedError(error, \"ContainerKekRepairRequiredError\")\n ) {\n const containerId = repairContainerId(error);\n return containerId ? { kind: \"repair-required\", containerId } : null;\n }\n if (\n error instanceof ContainerAuthorAccessError ||\n namedError(error, \"ContainerAuthorAccessError\")\n ) {\n return { kind: \"unauthorized\" };\n }\n return null;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { assertDocumentWriterProjectionConsistent } from "../../../data/documents/shared/projection/index.js";
2
- import { mergeProjectionPolicyEvidence } from "../../../data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence.js";
2
+ import { mergeProjectionPolicyEvidence } from "../../../data/keyingProjectionVerification/index.js";
3
3
  function uniqueManifestBundles(bundles) {
4
4
  const byHash = new Map();
5
5
  for (const bundle of bundles) {
@@ -1 +1 @@
1
- {"version":3,"file":"linkSetProjectionSeed.js","sourceRoot":"","sources":["linkSetProjectionSeed.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccessManifestBundleWireResponse,\n ContainerKeyingPathResponse,\n ContainerWriterProjectionResponse,\n DocumentLinkSetMutationResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport type { DocumentLinkSetMutationOperation } from \"../../../data/documents/shared/types\";\nimport { mergeProjectionPolicyEvidence } from \"../../../data/keyingProjectionVerification/principalPolicy/mergeProjectionPolicyEvidence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\n\ninterface DocumentLinkSetProjectionSeedApi {\n primeDocumentWriterProjection(\n documentId: string,\n projection: DocumentWriterProjectionResponse,\n ): void;\n}\n\nfunction uniqueManifestBundles(\n bundles: readonly AccessManifestBundleWireResponse[],\n): AccessManifestBundleWireResponse[] {\n const byHash = new Map<string, AccessManifestBundleWireResponse>();\n for (const bundle of bundles) {\n if (!byHash.has(bundle.manifestHash)) {\n byHash.set(bundle.manifestHash, bundle);\n }\n }\n\n return [...byHash.values()];\n}\n\nfunction uniqueManifestPaths(\n paths: readonly (readonly AccessManifestBundleWireResponse[])[],\n): AccessManifestBundleWireResponse[][] {\n const byLeafHash = new Map<string, AccessManifestBundleWireResponse[]>();\n for (const path of paths) {\n const leafHash = path.at(-1)?.manifestHash;\n if (!leafHash || byLeafHash.has(leafHash)) {\n continue;\n }\n\n byLeafHash.set(leafHash, [...path]);\n }\n\n return [...byLeafHash.values()];\n}\n\nfunction containerProjectionManifestHistory(\n projection: ContainerKeyingPathResponse,\n): AccessManifestBundleWireResponse[] {\n return projection.containerKeks.flatMap(\n (kek) => kek.containerManifestHistory,\n );\n}\n\nfunction documentProjectionContainerPaths(\n projection: DocumentWriterProjectionResponse,\n): AccessManifestBundleWireResponse[][] {\n return uniqueManifestPaths([\n ...projection.documentManifestContainerPaths,\n ...projection.authorizingContainerPaths.map((path) => path.path),\n ]);\n}\n\nfunction documentProjectionContainerHistory(input: {\n priorProjection: DocumentWriterProjectionResponse;\n targetContainerProjection: ContainerWriterProjectionResponse;\n}): AccessManifestBundleWireResponse[] {\n const priorContainerPaths = documentProjectionContainerPaths(\n input.priorProjection,\n );\n const priorAuthorizingContainerProjections =\n input.priorProjection.authorizingContainerPaths;\n\n return uniqueManifestBundles([\n ...input.priorProjection.documentContainerManifestHistory,\n ...priorContainerPaths.flat(),\n ...priorAuthorizingContainerProjections.flatMap((projection) => [\n ...projection.path,\n ...containerProjectionManifestHistory(projection),\n ]),\n ...input.targetContainerProjection.path,\n ...containerProjectionManifestHistory(input.targetContainerProjection),\n ]);\n}\n\n/**\n * Reconstruct the post-mutation writer projection from a link/unlink response.\n * The response carries the fresh manifest, content-key bundle, and KEK targets;\n * the authorizing container paths change by exactly one entry — link appends\n * the target container's projection, unlink drops it (keyed by containerId).\n * Link does not rotate the content key (only unlink does), but either way the\n * bundle/targets the next write needs come straight from the response. The\n * caller verifies this projection for internal consistency before seeding it,\n * so a wrong reconstruction is discarded rather than cached.\n */\nfunction linkSetWriterProjectionFromResponse(input: {\n operation: DocumentLinkSetMutationOperation;\n priorProjection: DocumentWriterProjectionResponse;\n response: DocumentLinkSetMutationResponse;\n targetContainerId: string;\n targetContainerProjection: ContainerWriterProjectionResponse;\n}): DocumentWriterProjectionResponse {\n // The target container's authorizing path is replaced wholesale: link adds\n // the fresh target projection back, unlink leaves it dropped.\n const retainedPaths = input.priorProjection.authorizingContainerPaths.filter(\n (path) => path.containerId !== input.targetContainerId,\n );\n const authorizingContainerPaths =\n input.operation === \"link\"\n ? [...retainedPaths, input.targetContainerProjection]\n : retainedPaths;\n const documentManifestContainerPaths = uniqueManifestPaths([\n ...documentProjectionContainerPaths(input.priorProjection),\n input.targetContainerProjection.path,\n ]);\n return {\n policyEvidence: mergeProjectionPolicyEvidence([\n input.priorProjection.policyEvidence,\n input.targetContainerProjection.policyEvidence,\n ]),\n authorizingContainerPaths,\n contentKeyBundle: input.response.contentKeyBundle,\n documentId: input.response.id,\n documentContainerManifestHistory: documentProjectionContainerHistory({\n priorProjection: input.priorProjection,\n targetContainerProjection: input.targetContainerProjection,\n }),\n documentKekTargets: input.response.documentKekTargets,\n documentManifest: input.response.accessManifest,\n documentManifestContainerPaths,\n documentManifestHistory: [\n input.priorProjection.documentManifest,\n ...input.priorProjection.documentManifestHistory,\n ],\n };\n}\n\n/**\n * Reconstruct and seed the post-mutation writer projection so the first read\n * after a link/unlink resolves locally instead of a cold GET. Gates the seed on\n * the projection's internal consistency (manifest hash ↔ content-key bundle ↔\n * KEK targets ↔ linked containers); on any mismatch the seed is skipped and the\n * next read falls back to a fetch — the seed is an optimization, never a\n * correctness dependency. The expensive per-path signature re-verification is\n * deliberately not run here: the server already verified the mutation, and the\n * next read re-verifies the projection before any write.\n */\nexport async function seedLinkSetWriterProjection(input: {\n apiClient: DocumentLinkSetProjectionSeedApi;\n execSql?: ExecSql | undefined;\n operation: DocumentLinkSetMutationOperation;\n priorProjection: DocumentWriterProjectionResponse;\n response: DocumentLinkSetMutationResponse;\n targetContainerId: string;\n targetContainerProjection: ContainerWriterProjectionResponse;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<void> {\n const projection = linkSetWriterProjectionFromResponse({\n operation: input.operation,\n priorProjection: input.priorProjection,\n response: input.response,\n targetContainerId: input.targetContainerId,\n targetContainerProjection: input.targetContainerProjection,\n });\n try {\n await assertDocumentWriterProjectionConsistent(projection, {\n execSql: input.execSql,\n trustedLocalProjection: true,\n });\n } catch {\n return;\n }\n if (input.stillCurrent?.() === false) return;\n input.apiClient.primeDocumentWriterProjection(input.response.id, projection);\n}\n"]}
1
+ {"version":3,"file":"linkSetProjectionSeed.js","sourceRoot":"","sources":["linkSetProjectionSeed.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccessManifestBundleWireResponse,\n ContainerKeyingPathResponse,\n ContainerWriterProjectionResponse,\n DocumentLinkSetMutationResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport type { DocumentLinkSetMutationOperation } from \"../../../data/documents/shared/types\";\nimport { mergeProjectionPolicyEvidence } from \"../../../data/keyingProjectionVerification\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\n\ninterface DocumentLinkSetProjectionSeedApi {\n primeDocumentWriterProjection(\n documentId: string,\n projection: DocumentWriterProjectionResponse,\n ): void;\n}\n\nfunction uniqueManifestBundles(\n bundles: readonly AccessManifestBundleWireResponse[],\n): AccessManifestBundleWireResponse[] {\n const byHash = new Map<string, AccessManifestBundleWireResponse>();\n for (const bundle of bundles) {\n if (!byHash.has(bundle.manifestHash)) {\n byHash.set(bundle.manifestHash, bundle);\n }\n }\n\n return [...byHash.values()];\n}\n\nfunction uniqueManifestPaths(\n paths: readonly (readonly AccessManifestBundleWireResponse[])[],\n): AccessManifestBundleWireResponse[][] {\n const byLeafHash = new Map<string, AccessManifestBundleWireResponse[]>();\n for (const path of paths) {\n const leafHash = path.at(-1)?.manifestHash;\n if (!leafHash || byLeafHash.has(leafHash)) {\n continue;\n }\n\n byLeafHash.set(leafHash, [...path]);\n }\n\n return [...byLeafHash.values()];\n}\n\nfunction containerProjectionManifestHistory(\n projection: ContainerKeyingPathResponse,\n): AccessManifestBundleWireResponse[] {\n return projection.containerKeks.flatMap(\n (kek) => kek.containerManifestHistory,\n );\n}\n\nfunction documentProjectionContainerPaths(\n projection: DocumentWriterProjectionResponse,\n): AccessManifestBundleWireResponse[][] {\n return uniqueManifestPaths([\n ...projection.documentManifestContainerPaths,\n ...projection.authorizingContainerPaths.map((path) => path.path),\n ]);\n}\n\nfunction documentProjectionContainerHistory(input: {\n priorProjection: DocumentWriterProjectionResponse;\n targetContainerProjection: ContainerWriterProjectionResponse;\n}): AccessManifestBundleWireResponse[] {\n const priorContainerPaths = documentProjectionContainerPaths(\n input.priorProjection,\n );\n const priorAuthorizingContainerProjections =\n input.priorProjection.authorizingContainerPaths;\n\n return uniqueManifestBundles([\n ...input.priorProjection.documentContainerManifestHistory,\n ...priorContainerPaths.flat(),\n ...priorAuthorizingContainerProjections.flatMap((projection) => [\n ...projection.path,\n ...containerProjectionManifestHistory(projection),\n ]),\n ...input.targetContainerProjection.path,\n ...containerProjectionManifestHistory(input.targetContainerProjection),\n ]);\n}\n\n/**\n * Reconstruct the post-mutation writer projection from a link/unlink response.\n * The response carries the fresh manifest, content-key bundle, and KEK targets;\n * the authorizing container paths change by exactly one entry — link appends\n * the target container's projection, unlink drops it (keyed by containerId).\n * Link does not rotate the content key (only unlink does), but either way the\n * bundle/targets the next write needs come straight from the response. The\n * caller verifies this projection for internal consistency before seeding it,\n * so a wrong reconstruction is discarded rather than cached.\n */\nfunction linkSetWriterProjectionFromResponse(input: {\n operation: DocumentLinkSetMutationOperation;\n priorProjection: DocumentWriterProjectionResponse;\n response: DocumentLinkSetMutationResponse;\n targetContainerId: string;\n targetContainerProjection: ContainerWriterProjectionResponse;\n}): DocumentWriterProjectionResponse {\n // The target container's authorizing path is replaced wholesale: link adds\n // the fresh target projection back, unlink leaves it dropped.\n const retainedPaths = input.priorProjection.authorizingContainerPaths.filter(\n (path) => path.containerId !== input.targetContainerId,\n );\n const authorizingContainerPaths =\n input.operation === \"link\"\n ? [...retainedPaths, input.targetContainerProjection]\n : retainedPaths;\n const documentManifestContainerPaths = uniqueManifestPaths([\n ...documentProjectionContainerPaths(input.priorProjection),\n input.targetContainerProjection.path,\n ]);\n return {\n policyEvidence: mergeProjectionPolicyEvidence([\n input.priorProjection.policyEvidence,\n input.targetContainerProjection.policyEvidence,\n ]),\n authorizingContainerPaths,\n contentKeyBundle: input.response.contentKeyBundle,\n documentId: input.response.id,\n documentContainerManifestHistory: documentProjectionContainerHistory({\n priorProjection: input.priorProjection,\n targetContainerProjection: input.targetContainerProjection,\n }),\n documentKekTargets: input.response.documentKekTargets,\n documentManifest: input.response.accessManifest,\n documentManifestContainerPaths,\n documentManifestHistory: [\n input.priorProjection.documentManifest,\n ...input.priorProjection.documentManifestHistory,\n ],\n };\n}\n\n/**\n * Reconstruct and seed the post-mutation writer projection so the first read\n * after a link/unlink resolves locally instead of a cold GET. Gates the seed on\n * the projection's internal consistency (manifest hash ↔ content-key bundle ↔\n * KEK targets ↔ linked containers); on any mismatch the seed is skipped and the\n * next read falls back to a fetch — the seed is an optimization, never a\n * correctness dependency. The expensive per-path signature re-verification is\n * deliberately not run here: the server already verified the mutation, and the\n * next read re-verifies the projection before any write.\n */\nexport async function seedLinkSetWriterProjection(input: {\n apiClient: DocumentLinkSetProjectionSeedApi;\n execSql?: ExecSql | undefined;\n operation: DocumentLinkSetMutationOperation;\n priorProjection: DocumentWriterProjectionResponse;\n response: DocumentLinkSetMutationResponse;\n targetContainerId: string;\n targetContainerProjection: ContainerWriterProjectionResponse;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<void> {\n const projection = linkSetWriterProjectionFromResponse({\n operation: input.operation,\n priorProjection: input.priorProjection,\n response: input.response,\n targetContainerId: input.targetContainerId,\n targetContainerProjection: input.targetContainerProjection,\n });\n try {\n await assertDocumentWriterProjectionConsistent(projection, {\n execSql: input.execSql,\n trustedLocalProjection: true,\n });\n } catch {\n return;\n }\n if (input.stillCurrent?.() === false) return;\n input.apiClient.primeDocumentWriterProjection(input.response.id, projection);\n}\n"]}
@@ -5,7 +5,7 @@ import { ContainerKekRepairInaccessibleError } from "../../../data/documents/sha
5
5
  import { ContainerKekTargetUnreachableError } from "../../../data/documents/shared/containerKek/containerKekPath.js";
6
6
  import { documentContainerProjections } from "../../../data/keyingProjectionVerification/document/documentContainerProjections.js";
7
7
  import { assertProjectionVerificationCurrent } from "../../../data/keyingProjectionVerification/types.js";
8
- import { buildMaterializedContainerRekeyPlan } from "../../containers/child/rekey/index.js";
8
+ import { buildMaterializedContainerRekeyPlan } from "../../containers/index.js";
9
9
  import { DocumentAncestorRepairAbandonedError } from "../syncFailures/syncRepairAbandon.js";
10
10
  import { hasOtherLinkedWriteAccess } from "../syncFailures/syncRepairAccess.js";
11
11
  import { applyContainerRekeyPlan } from "./syncContainerRekeyProjection.js";
@@ -1 +1 @@
1
- {"version":3,"file":"syncAutomaticContainerRekeys.js","sourceRoot":"","sources":["syncAutomaticContainerRekeys.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport type {\n ContainerWriterProjectionResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { MAX_INLINE_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport { ContainerAuthorAccessError } from \"../../../data/containers/shared/authorAccess\";\nimport type { MaterializedContainerRekeyPlan } from \"../../../data/containers/shared/types\";\nimport { ContainerKekRepairInaccessibleError } from \"../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { ContainerKekTargetUnreachableError } from \"../../../data/documents/shared/containerKek/containerKekPath\";\nimport { documentContainerProjections } from \"../../../data/keyingProjectionVerification/document/documentContainerProjections\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { buildMaterializedContainerRekeyPlan } from \"../../containers/child/rekey\";\nimport type { SyncRemoteDocumentInput } from \"../sync/readOnlySync\";\nimport { DocumentAncestorRepairAbandonedError } from \"../syncFailures/syncRepairAbandon\";\nimport { hasOtherLinkedWriteAccess } from \"../syncFailures/syncRepairAccess\";\nimport { applyContainerRekeyPlan } from \"./syncContainerRekeyProjection\";\n\ninterface StaleContainer {\n /** The stale container is the one the document itself is linked into. */\n readonly isPathTarget: boolean;\n readonly projection: ContainerWriterProjectionResponse;\n}\n\nfunction firstStaleContainer(\n projection: DocumentWriterProjectionResponse,\n): StaleContainer | null {\n for (const path of documentContainerProjections(projection)) {\n for (let index = 1; index < path.containerKeks.length; index += 1) {\n const parent = path.containerKeks[index - 1];\n const child = path.containerKeks[index];\n if (!parent || !child)\n throw new Error(\"Container KEK path is incomplete\");\n if (child.parentContainerKeyEpochId === parent.containerKeyEpochId) {\n continue;\n }\n return {\n isPathTarget: index === path.containerKeks.length - 1,\n projection: {\n ...path,\n containerId: child.containerId,\n containerKeks: path.containerKeks.slice(0, index + 1),\n path: path.path.slice(0, index + 1),\n },\n };\n }\n }\n return null;\n}\n\n/**\n * The stale container is not this writer's to re-key: no wrap on the verified\n * path opens it, or the signed path grants the signer no write access there.\n * Both are judged against the path sliced at the stale container, so a grant\n * held only further down never counts — exactly the API's `container.rekey`\n * rule. Anything else (keyring damage, a forged path) stays an error.\n *\n * A target's write refusal is handled separately: another linked target may\n * still authorize the document write. Key unwrap failures on a target stay\n * errors, because this path's readable grant should open its own key.\n */\nfunction isRepairInaccessible(error: unknown, stale: StaleContainer): boolean {\n if (stale.isPathTarget) return false;\n return (\n error instanceof ContainerAuthorAccessError ||\n (error instanceof ContainerKekTargetUnreachableError &&\n error.containerId === stale.projection.containerId)\n );\n}\n\n/** Prepare parent-first repairs; the sync transaction commits them with the write. */\nexport async function buildAutomaticContainerRekeys(\n sync: SyncRemoteDocumentInput,\n initialProjection: DocumentWriterProjectionResponse,\n): Promise<{ plans: MaterializedContainerRekeyPlan[]; hasMore: boolean }> {\n const plans: MaterializedContainerRekeyPlan[] = [];\n const plannedIds = new Set<string>();\n let projection = initialProjection;\n for (;;) {\n const stale = firstStaleContainer(projection);\n if (!stale) return { plans, hasMore: false };\n const previousProjection = stale.projection;\n if (plans.length >= MAX_INLINE_CONTAINER_REKEYS) {\n return { plans, hasMore: true };\n }\n // Use the shared cancellation sentinel: syncRemoteDocument converts only\n // that to a graceful null, so a plain Error would report a routine\n // generation flip mid-repair as a real sync failure.\n assertProjectionVerificationCurrent(sync.stillCurrent);\n if (plannedIds.has(previousProjection.containerId)) {\n // Abandon like every other routine repair failure: two linked paths\n // disagreeing about a container is a concurrent-rotation race, not a\n // defect, and a raw Error would crash the sync lane instead.\n throw new DocumentAncestorRepairAbandonedError(\"peer-rotation\");\n }\n // Assert rather than adopt: resolveRotationContext compares the verified\n // manifest's organization against the author's, so substituting the path's\n // own organization here would make that the only cross-org check and leave\n // it comparing a server-supplied value with itself.\n if (previousProjection.organizationId !== sync.author.organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Document ancestor repair crosses the author's organization\",\n );\n }\n const planned = await buildMaterializedContainerRekeyPlan({\n author: sync.author,\n persistVerificationCheckpoints: false,\n previousProjection,\n signedAt: sync.signedAt,\n targetSecretKey: sync.targetSecretKey,\n resolveProjectionUserKey: sync.resolveProjectionUserKey,\n stillCurrent: sync.stillCurrent,\n warmReferencedPrincipalPolicies: sync.warmReferencedPrincipalPolicies,\n execSql: sync.execSql,\n }).catch(async (error: unknown) => {\n if (error instanceof ContainerAuthorAccessError && stale.isPathTarget) {\n if (\n await hasOtherLinkedWriteAccess(\n sync,\n initialProjection,\n previousProjection.containerId,\n )\n ) {\n throw new ContainerKekRepairInaccessibleError(\n previousProjection.containerId,\n );\n }\n await sync.onTerminalSubmitFailure?.({\n code: error.code,\n message: error.message,\n ok: false,\n report: () => undefined,\n status: error.status,\n });\n throw new DocumentAncestorRepairAbandonedError(\"refused\");\n }\n // Repairs run parent-first and access inherits downward, so only the\n // first stale container can be out of reach. Retry-classified like any\n // stale path: one refetch sees a repair a capable member already made.\n throw isRepairInaccessible(error, stale)\n ? new ContainerKekRepairInaccessibleError(\n previousProjection.containerId,\n )\n : error;\n });\n plannedIds.add(previousProjection.containerId);\n plans.push(planned);\n projection = await applyContainerRekeyPlan(projection, planned);\n }\n}\n"]}
1
+ {"version":3,"file":"syncAutomaticContainerRekeys.js","sourceRoot":"","sources":["syncAutomaticContainerRekeys.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport type {\n ContainerWriterProjectionResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { MAX_INLINE_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport { ContainerAuthorAccessError } from \"../../../data/containers/shared/authorAccess\";\nimport type { MaterializedContainerRekeyPlan } from \"../../../data/containers/shared/types\";\nimport { ContainerKekRepairInaccessibleError } from \"../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { ContainerKekTargetUnreachableError } from \"../../../data/documents/shared/containerKek/containerKekPath\";\nimport { documentContainerProjections } from \"../../../data/keyingProjectionVerification/document/documentContainerProjections\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { buildMaterializedContainerRekeyPlan } from \"../../containers\";\nimport type { SyncRemoteDocumentInput } from \"../sync/readOnlySync\";\nimport { DocumentAncestorRepairAbandonedError } from \"../syncFailures/syncRepairAbandon\";\nimport { hasOtherLinkedWriteAccess } from \"../syncFailures/syncRepairAccess\";\nimport { applyContainerRekeyPlan } from \"./syncContainerRekeyProjection\";\n\ninterface StaleContainer {\n /** The stale container is the one the document itself is linked into. */\n readonly isPathTarget: boolean;\n readonly projection: ContainerWriterProjectionResponse;\n}\n\nfunction firstStaleContainer(\n projection: DocumentWriterProjectionResponse,\n): StaleContainer | null {\n for (const path of documentContainerProjections(projection)) {\n for (let index = 1; index < path.containerKeks.length; index += 1) {\n const parent = path.containerKeks[index - 1];\n const child = path.containerKeks[index];\n if (!parent || !child)\n throw new Error(\"Container KEK path is incomplete\");\n if (child.parentContainerKeyEpochId === parent.containerKeyEpochId) {\n continue;\n }\n return {\n isPathTarget: index === path.containerKeks.length - 1,\n projection: {\n ...path,\n containerId: child.containerId,\n containerKeks: path.containerKeks.slice(0, index + 1),\n path: path.path.slice(0, index + 1),\n },\n };\n }\n }\n return null;\n}\n\n/**\n * The stale container is not this writer's to re-key: no wrap on the verified\n * path opens it, or the signed path grants the signer no write access there.\n * Both are judged against the path sliced at the stale container, so a grant\n * held only further down never counts — exactly the API's `container.rekey`\n * rule. Anything else (keyring damage, a forged path) stays an error.\n *\n * A target's write refusal is handled separately: another linked target may\n * still authorize the document write. Key unwrap failures on a target stay\n * errors, because this path's readable grant should open its own key.\n */\nfunction isRepairInaccessible(error: unknown, stale: StaleContainer): boolean {\n if (stale.isPathTarget) return false;\n return (\n error instanceof ContainerAuthorAccessError ||\n (error instanceof ContainerKekTargetUnreachableError &&\n error.containerId === stale.projection.containerId)\n );\n}\n\n/** Prepare parent-first repairs; the sync transaction commits them with the write. */\nexport async function buildAutomaticContainerRekeys(\n sync: SyncRemoteDocumentInput,\n initialProjection: DocumentWriterProjectionResponse,\n): Promise<{ plans: MaterializedContainerRekeyPlan[]; hasMore: boolean }> {\n const plans: MaterializedContainerRekeyPlan[] = [];\n const plannedIds = new Set<string>();\n let projection = initialProjection;\n for (;;) {\n const stale = firstStaleContainer(projection);\n if (!stale) return { plans, hasMore: false };\n const previousProjection = stale.projection;\n if (plans.length >= MAX_INLINE_CONTAINER_REKEYS) {\n return { plans, hasMore: true };\n }\n // Use the shared cancellation sentinel: syncRemoteDocument converts only\n // that to a graceful null, so a plain Error would report a routine\n // generation flip mid-repair as a real sync failure.\n assertProjectionVerificationCurrent(sync.stillCurrent);\n if (plannedIds.has(previousProjection.containerId)) {\n // Abandon like every other routine repair failure: two linked paths\n // disagreeing about a container is a concurrent-rotation race, not a\n // defect, and a raw Error would crash the sync lane instead.\n throw new DocumentAncestorRepairAbandonedError(\"peer-rotation\");\n }\n // Assert rather than adopt: resolveRotationContext compares the verified\n // manifest's organization against the author's, so substituting the path's\n // own organization here would make that the only cross-org check and leave\n // it comparing a server-supplied value with itself.\n if (previousProjection.organizationId !== sync.author.organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Document ancestor repair crosses the author's organization\",\n );\n }\n const planned = await buildMaterializedContainerRekeyPlan({\n author: sync.author,\n persistVerificationCheckpoints: false,\n previousProjection,\n signedAt: sync.signedAt,\n targetSecretKey: sync.targetSecretKey,\n resolveProjectionUserKey: sync.resolveProjectionUserKey,\n stillCurrent: sync.stillCurrent,\n warmReferencedPrincipalPolicies: sync.warmReferencedPrincipalPolicies,\n execSql: sync.execSql,\n }).catch(async (error: unknown) => {\n if (error instanceof ContainerAuthorAccessError && stale.isPathTarget) {\n if (\n await hasOtherLinkedWriteAccess(\n sync,\n initialProjection,\n previousProjection.containerId,\n )\n ) {\n throw new ContainerKekRepairInaccessibleError(\n previousProjection.containerId,\n );\n }\n await sync.onTerminalSubmitFailure?.({\n code: error.code,\n message: error.message,\n ok: false,\n report: () => undefined,\n status: error.status,\n });\n throw new DocumentAncestorRepairAbandonedError(\"refused\");\n }\n // Repairs run parent-first and access inherits downward, so only the\n // first stale container can be out of reach. Retry-classified like any\n // stale path: one refetch sees a repair a capable member already made.\n throw isRepairInaccessible(error, stale)\n ? new ContainerKekRepairInaccessibleError(\n previousProjection.containerId,\n )\n : error;\n });\n plannedIds.add(previousProjection.containerId);\n plans.push(planned);\n projection = await applyContainerRekeyPlan(projection, planned);\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { decryptGroupMetadata, readGroupMetadata, } from "../../../internal/crypto/index.js";
2
2
  import { deriveOrganizationMetadataContainerSystemSlot } from "../../../internal/validators/containerSystemSlot.js";
3
3
  import { getTargetContainerContext, readContainerState, } from "../../../data/containers/shared/projection.js";
4
- import { unwrapContainerKekPath } from "../../../data/documents/shared/containerKek/containerKekPath.js";
4
+ import { unwrapContainerKekPath } from "../../../data/documents/shared/containerKek/index.js";
5
5
  import { assertProjectionVerificationCurrent } from "../../../data/keyingProjectionVerification/types.js";
6
6
  import { loadContainers } from "../../../data/persistence/container-contents/containerPersistence.js";
7
7
  import { withMetadataRootReload } from "./groupMetadataErrors.js";
@@ -1 +1 @@
1
- {"version":3,"file":"groupMetadataAccess.js","sourceRoot":"","sources":["groupMetadataAccess.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerAccessManifestState,\n decryptGroupMetadata,\n type GroupMetadataKey,\n type ReferencedPrincipalHead,\n readGroupMetadata,\n} from \"@tearleads/crypto\";\nimport { deriveOrganizationMetadataContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n getTargetContainerContext,\n readContainerState,\n} from \"../../../data/containers/shared/projection\";\nimport { unwrapContainerKekPath } from \"../../../data/documents/shared/containerKek/containerKekPath\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { loadContainers } from \"../../../data/persistence/container-contents/containerPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport type { GroupPolicyNameReader } from \"../principalPolicy/principalPolicyRequest\";\nimport { withMetadataRootReload } from \"./groupMetadataErrors\";\n\nexport interface GroupMetadataAccessInput {\n readonly apiClient: {\n evictContainerWriterProjection(containerId: string): void;\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n };\n readonly verifyMetadataContainer: (\n state: ContainerAccessManifestState,\n organizationReference?: ReferencedPrincipalHead | undefined,\n ) => Promise<void>;\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly targetSecretKey: Uint8Array;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}\n\n/**\n * A group's signed name does not open under the metadata key it cites, or opens\n * to an invalid name. Every reader holding that key gets the same result. The\n * API checks the citation but can never check the ciphertext, so a dishonest\n * admin can sign such a name; directory walks isolate the group instead of\n * failing every name in the organization.\n */\nexport class GroupMetadataUnreadableError extends Error {\n constructor(groupId: string, cause: unknown) {\n super(`Group ${groupId} metadata cannot be decrypted`, { cause });\n this.name = \"GroupMetadataUnreadableError\";\n }\n}\n\nfunction loadMetadataKeyring(\n input: GroupMetadataAccessInput,\n containerId: string,\n) {\n return withMetadataRootReload(\n () => loadMetadataKeyringOnce(input, containerId),\n () => input.apiClient.evictContainerWriterProjection(containerId),\n );\n}\n\nasync function loadMetadataKeyringOnce(\n input: GroupMetadataAccessInput,\n containerId: string,\n) {\n const projection =\n await input.apiClient.getContainerWriterProjection(containerId);\n if (!projection) return null;\n if (\n projection.containerId !== containerId ||\n projection.organizationId !== input.organizationId\n )\n throw new Error(\"Group metadata container is unavailable\");\n const target = getTargetContainerContext(projection);\n const state = readContainerState(target.manifest);\n const slot = await deriveOrganizationMetadataContainerSystemSlot({\n organizationId: input.organizationId,\n });\n if (\n state.organizationId !== input.organizationId ||\n state.systemSlot !== slot ||\n state.parentContainerId !== null\n )\n throw new Error(\n \"Group metadata requires the signed organization metadata container\",\n );\n await input.verifyMetadataContainer(\n state,\n projection.policyEvidence.organization?.head,\n );\n assertProjectionVerificationCurrent(input.stillCurrent);\n const keys = await unwrapContainerKekPath({\n ...input,\n projection,\n secretKey: input.targetSecretKey,\n });\n assertProjectionVerificationCurrent(input.stillCurrent);\n const keyMaterial = keys.get(target.kek.containerKeyEpochId);\n if (!keyMaterial)\n throw new Error(\"Group metadata container key is unavailable\");\n return {\n current: {\n organizationId: input.organizationId,\n containerId,\n containerKeyEpochId: target.kek.containerKeyEpochId,\n keyMaterial,\n },\n keys,\n };\n}\n\n/** Uses the shared metadata container's authenticated keyring, including old epochs. */\nexport function createGroupMetadataAccess(input: GroupMetadataAccessInput) {\n const loads = new Map<\n string,\n Promise<{\n current: GroupMetadataKey;\n keys: ReadonlyMap<string, Uint8Array>;\n } | null>\n >();\n function loaded(containerId: string) {\n let pending = loads.get(containerId);\n if (!pending) {\n pending = loadMetadataKeyring(input, containerId);\n loads.set(containerId, pending);\n }\n return pending;\n }\n const readName: GroupPolicyNameReader = async (bundle) => {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const metadata = readGroupMetadata(bundle.currentPayload.ciphertext);\n if (\"role\" in metadata)\n return metadata.role === \"admins\" ? \"Admins\" : \"Members\";\n if (\n metadata.organizationId !== input.organizationId ||\n metadata.groupId !== bundle.currentState.principalId ||\n bundle.currentState.principalType !== \"group\"\n )\n throw new Error(\"Group metadata scope does not match its signed group\");\n const keyring = await loaded(metadata.containerId);\n const keyMaterial = keyring?.keys.get(metadata.containerKeyEpochId);\n if (!keyMaterial)\n throw new Error(\"Group metadata historical key is unavailable\");\n try {\n return await decryptGroupMetadata({\n key: { ...metadata, keyMaterial },\n groupId: bundle.currentState.principalId,\n payload: bundle.currentPayload.ciphertext,\n });\n } catch (cause) {\n throw new GroupMetadataUnreadableError(\n bundle.currentState.principalId,\n cause,\n );\n }\n };\n return {\n readName,\n async loadEncryptionKey(): Promise<GroupMetadataKey> {\n const slot = await deriveOrganizationMetadataContainerSystemSlot({\n organizationId: input.organizationId,\n });\n const containers = await loadContainers(input.execSql);\n const container = containers.find(\n (row) =>\n row.organizationId === input.organizationId &&\n row.systemSlot === slot,\n );\n if (!container)\n throw new Error(\n \"Organization metadata container has not been discovered\",\n );\n const keyring = await loaded(container.id);\n if (!keyring) throw new Error(\"Group metadata container is unavailable\");\n return keyring.current;\n },\n };\n}\n"]}
1
+ {"version":3,"file":"groupMetadataAccess.js","sourceRoot":"","sources":["groupMetadataAccess.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type ContainerAccessManifestState,\n decryptGroupMetadata,\n type GroupMetadataKey,\n type ReferencedPrincipalHead,\n readGroupMetadata,\n} from \"@tearleads/crypto\";\nimport { deriveOrganizationMetadataContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n getTargetContainerContext,\n readContainerState,\n} from \"../../../data/containers/shared/projection\";\nimport { unwrapContainerKekPath } from \"../../../data/documents/shared/containerKek\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { loadContainers } from \"../../../data/persistence/container-contents/containerPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport type { GroupPolicyNameReader } from \"../principalPolicy/principalPolicyRequest\";\nimport { withMetadataRootReload } from \"./groupMetadataErrors\";\n\nexport interface GroupMetadataAccessInput {\n readonly apiClient: {\n evictContainerWriterProjection(containerId: string): void;\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n };\n readonly verifyMetadataContainer: (\n state: ContainerAccessManifestState,\n organizationReference?: ReferencedPrincipalHead | undefined,\n ) => Promise<void>;\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n readonly targetSecretKey: Uint8Array;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}\n\n/**\n * A group's signed name does not open under the metadata key it cites, or opens\n * to an invalid name. Every reader holding that key gets the same result. The\n * API checks the citation but can never check the ciphertext, so a dishonest\n * admin can sign such a name; directory walks isolate the group instead of\n * failing every name in the organization.\n */\nexport class GroupMetadataUnreadableError extends Error {\n constructor(groupId: string, cause: unknown) {\n super(`Group ${groupId} metadata cannot be decrypted`, { cause });\n this.name = \"GroupMetadataUnreadableError\";\n }\n}\n\nfunction loadMetadataKeyring(\n input: GroupMetadataAccessInput,\n containerId: string,\n) {\n return withMetadataRootReload(\n () => loadMetadataKeyringOnce(input, containerId),\n () => input.apiClient.evictContainerWriterProjection(containerId),\n );\n}\n\nasync function loadMetadataKeyringOnce(\n input: GroupMetadataAccessInput,\n containerId: string,\n) {\n const projection =\n await input.apiClient.getContainerWriterProjection(containerId);\n if (!projection) return null;\n if (\n projection.containerId !== containerId ||\n projection.organizationId !== input.organizationId\n )\n throw new Error(\"Group metadata container is unavailable\");\n const target = getTargetContainerContext(projection);\n const state = readContainerState(target.manifest);\n const slot = await deriveOrganizationMetadataContainerSystemSlot({\n organizationId: input.organizationId,\n });\n if (\n state.organizationId !== input.organizationId ||\n state.systemSlot !== slot ||\n state.parentContainerId !== null\n )\n throw new Error(\n \"Group metadata requires the signed organization metadata container\",\n );\n await input.verifyMetadataContainer(\n state,\n projection.policyEvidence.organization?.head,\n );\n assertProjectionVerificationCurrent(input.stillCurrent);\n const keys = await unwrapContainerKekPath({\n ...input,\n projection,\n secretKey: input.targetSecretKey,\n });\n assertProjectionVerificationCurrent(input.stillCurrent);\n const keyMaterial = keys.get(target.kek.containerKeyEpochId);\n if (!keyMaterial)\n throw new Error(\"Group metadata container key is unavailable\");\n return {\n current: {\n organizationId: input.organizationId,\n containerId,\n containerKeyEpochId: target.kek.containerKeyEpochId,\n keyMaterial,\n },\n keys,\n };\n}\n\n/** Uses the shared metadata container's authenticated keyring, including old epochs. */\nexport function createGroupMetadataAccess(input: GroupMetadataAccessInput) {\n const loads = new Map<\n string,\n Promise<{\n current: GroupMetadataKey;\n keys: ReadonlyMap<string, Uint8Array>;\n } | null>\n >();\n function loaded(containerId: string) {\n let pending = loads.get(containerId);\n if (!pending) {\n pending = loadMetadataKeyring(input, containerId);\n loads.set(containerId, pending);\n }\n return pending;\n }\n const readName: GroupPolicyNameReader = async (bundle) => {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const metadata = readGroupMetadata(bundle.currentPayload.ciphertext);\n if (\"role\" in metadata)\n return metadata.role === \"admins\" ? \"Admins\" : \"Members\";\n if (\n metadata.organizationId !== input.organizationId ||\n metadata.groupId !== bundle.currentState.principalId ||\n bundle.currentState.principalType !== \"group\"\n )\n throw new Error(\"Group metadata scope does not match its signed group\");\n const keyring = await loaded(metadata.containerId);\n const keyMaterial = keyring?.keys.get(metadata.containerKeyEpochId);\n if (!keyMaterial)\n throw new Error(\"Group metadata historical key is unavailable\");\n try {\n return await decryptGroupMetadata({\n key: { ...metadata, keyMaterial },\n groupId: bundle.currentState.principalId,\n payload: bundle.currentPayload.ciphertext,\n });\n } catch (cause) {\n throw new GroupMetadataUnreadableError(\n bundle.currentState.principalId,\n cause,\n );\n }\n };\n return {\n readName,\n async loadEncryptionKey(): Promise<GroupMetadataKey> {\n const slot = await deriveOrganizationMetadataContainerSystemSlot({\n organizationId: input.organizationId,\n });\n const containers = await loadContainers(input.execSql);\n const container = containers.find(\n (row) =>\n row.organizationId === input.organizationId &&\n row.systemSlot === slot,\n );\n if (!container)\n throw new Error(\n \"Organization metadata container has not been discovered\",\n );\n const keyring = await loaded(container.id);\n if (!keyring) throw new Error(\"Group metadata container is unavailable\");\n return keyring.current;\n },\n };\n}\n"]}
@@ -3,8 +3,8 @@ import type { CreateOrganizationRequest } from "../../../internal/validators/req
3
3
  import type { CreateOrganizationResponse } from "../../../internal/validators/response/index.js";
4
4
  import type { DocumentProjectorRegistryInput } from "../../../data/documents/documentKinds.js";
5
5
  import type { ExecSqlClientLike } from "../../../data/sqlite/sqlSchema.js";
6
+ import { type ProvisionedSystemContainerSpec } from "../../registration/organizationProvisioning.js";
6
7
  import type { ProvisionedPrincipalHistoryPrimer } from "../../registration/provisionedPrincipalHistory.js";
7
- import { type ProvisionedSystemContainerSpec } from "../../registration/registerIdentity.js";
8
8
  import { removeNativeSubscriptionRestoreProvisioningAttempt } from "./organizationProvisioningAttempt.js";
9
9
  export { removeNativeSubscriptionRestoreProvisioningAttempt };
10
10
  export interface CreateOrganizationApi {
@@ -1,6 +1,6 @@
1
1
  import { signOrganizationReplacementAuthorization, } from "../../../internal/crypto/index.js";
2
2
  import { createExecSql } from "../../../data/sqlite/sqlSchema.js";
3
- import { buildOrganizationProvisioningArtifacts, persistOrganizationProvisioningState, } from "../../registration/registerIdentity.js";
3
+ import { buildOrganizationProvisioningArtifacts, persistOrganizationProvisioningState, } from "../../registration/organizationProvisioning.js";
4
4
  import { makeOrganizationProvisioningAttemptDurable, removeNativeSubscriptionRestoreProvisioningAttempt, } from "./organizationProvisioningAttempt.js";
5
5
  import { pinOrganizationReplacementResponse } from "./organizationReplacementVerification.js";
6
6
  export { removeNativeSubscriptionRestoreProvisioningAttempt };