@tearleads/client-sdk 0.1.67 → 0.1.69

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 (52) hide show
  1. package/data/containers/shared/principalPolicies.js +8 -12
  2. package/data/containers/shared/principalPolicies.js.map +1 -1
  3. package/data/persistence/principalHistory/principalHistoryStagePersistence.d.ts +2 -0
  4. package/data/persistence/principalHistory/principalHistoryStagePersistence.js +4 -0
  5. package/data/persistence/principalHistory/principalHistoryStagePersistence.js.map +1 -1
  6. package/internal/validators/operation/attachments.d.ts +48 -8
  7. package/internal/validators/operation/auth.d.ts +456 -76
  8. package/internal/validators/operation/containerMutations.d.ts +264 -44
  9. package/internal/validators/operation/documentMutations.d.ts +72 -12
  10. package/internal/validators/operation/documentSync.d.ts +24 -4
  11. package/internal/validators/operation/organizations.d.ts +528 -88
  12. package/internal/validators/operation/principals.d.ts +96 -16
  13. package/internal/validators/request/blob.d.ts +48 -8
  14. package/internal/validators/request/container.d.ts +96 -16
  15. package/internal/validators/request/container.js +5 -2
  16. package/internal/validators/request/container.js.map +1 -1
  17. package/internal/validators/request/containerMetadata.d.ts +96 -16
  18. package/internal/validators/request/document.d.ts +60 -10
  19. package/internal/validators/request/documentSyncSchema.d.ts +24 -4
  20. package/internal/validators/request/documentSyncSchema.js +2 -1
  21. package/internal/validators/request/documentSyncSchema.js.map +1 -1
  22. package/internal/validators/request/index.d.ts +1 -0
  23. package/internal/validators/request/index.js +1 -0
  24. package/internal/validators/request/index.js.map +1 -1
  25. package/internal/validators/request/organization.d.ts +96 -16
  26. package/internal/validators/request/organizationProvisioning.d.ts +1456 -246
  27. package/internal/validators/request/principal.d.ts +120 -20
  28. package/internal/validators/request/principalPolicyRef.d.ts +42 -0
  29. package/internal/validators/request/principalPolicyRef.js +19 -0
  30. package/internal/validators/request/principalPolicyRef.js.map +1 -0
  31. package/internal/validators/request/registration.d.ts +456 -76
  32. package/internal/validators/util/containerLimits.d.ts +8 -0
  33. package/internal/validators/util/containerLimits.js +8 -0
  34. package/internal/validators/util/containerLimits.js.map +1 -1
  35. package/package.json +1 -1
  36. package/workflows/container-contents/storedContainerState.js +5 -1
  37. package/workflows/container-contents/storedContainerState.js.map +1 -1
  38. package/workflows/containers/child/mutationRequestCore.js +2 -2
  39. package/workflows/containers/child/mutationRequestCore.js.map +1 -1
  40. package/workflows/containers/child/recitePlan.js +2 -2
  41. package/workflows/containers/child/recitePlan.js.map +1 -1
  42. package/workflows/containers/root/create.js +17 -28
  43. package/workflows/containers/root/create.js.map +1 -1
  44. package/workflows/containers/root/initialGroupPolicy.js +0 -23
  45. package/workflows/containers/root/initialGroupPolicy.js.map +1 -1
  46. package/workflows/documents/syncFailures/syncPolicyRepair.js +2 -8
  47. package/workflows/documents/syncFailures/syncPolicyRepair.js.map +1 -1
  48. package/workflows/principals/recoveryOperation/supersededStageResume.js +21 -0
  49. package/workflows/principals/recoveryOperation/supersededStageResume.js.map +1 -0
  50. package/workflows/principals/runtimePolicyRecovery.js +12 -9
  51. package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
  52. package/workflows/registration/provisioningBootstrapBuilders.d.ts +12 -2
@@ -7,3 +7,11 @@ export declare const MAX_CONTAINER_PATH_LENGTH = 100;
7
7
  * bound keeps that capacity instead of letting a small body cite ~50x more.
8
8
  */
9
9
  export declare const MAX_CONTAINER_MANIFEST_HISTORY_REFS = 4096;
10
+ /**
11
+ * Maximum number of principal policy heads one container mutation may cite.
12
+ * Each citation makes the server verify that principal's stored policy, so
13
+ * the bound keeps the capacity inline signed policies (about 9.8 KiB each)
14
+ * had under the 32 MiB request ceiling instead of letting a ~170-byte reference
15
+ * multiply that work.
16
+ */
17
+ export declare const MAX_CONTAINER_PRINCIPAL_POLICY_REFS = 4096;
@@ -7,4 +7,12 @@ export const MAX_CONTAINER_PATH_LENGTH = 100;
7
7
  * bound keeps that capacity instead of letting a small body cite ~50x more.
8
8
  */
9
9
  export const MAX_CONTAINER_MANIFEST_HISTORY_REFS = 4096;
10
+ /**
11
+ * Maximum number of principal policy heads one container mutation may cite.
12
+ * Each citation makes the server verify that principal's stored policy, so
13
+ * the bound keeps the capacity inline signed policies (about 9.8 KiB each)
14
+ * had under the 32 MiB request ceiling instead of letting a ~170-byte reference
15
+ * multiply that work.
16
+ */
17
+ export const MAX_CONTAINER_PRINCIPAL_POLICY_REFS = 4096;
10
18
  //# sourceMappingURL=containerLimits.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"containerLimits.js","sourceRoot":"","sources":["containerLimits.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,IAAI,CAAC","sourcesContent":["/** Maximum number of containers in a root-to-leaf path, including both ends. */\nexport const MAX_CONTAINER_PATH_LENGTH = 100;\n\n/**\n * Maximum number of stored manifests one container mutation may cite as the\n * mutated container's history. Inline bundles (8-14 KiB each) fit about this\n * many under the 32 MiB request ceiling; a reference is ~150 bytes, so the\n * bound keeps that capacity instead of letting a small body cite ~50x more.\n */\nexport const MAX_CONTAINER_MANIFEST_HISTORY_REFS = 4096;\n"]}
1
+ {"version":3,"file":"containerLimits.js","sourceRoot":"","sources":["containerLimits.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,IAAI,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,IAAI,CAAC","sourcesContent":["/** Maximum number of containers in a root-to-leaf path, including both ends. */\nexport const MAX_CONTAINER_PATH_LENGTH = 100;\n\n/**\n * Maximum number of stored manifests one container mutation may cite as the\n * mutated container's history. Inline bundles (8-14 KiB each) fit about this\n * many under the 32 MiB request ceiling; a reference is ~150 bytes, so the\n * bound keeps that capacity instead of letting a small body cite ~50x more.\n */\nexport const MAX_CONTAINER_MANIFEST_HISTORY_REFS = 4096;\n\n/**\n * Maximum number of principal policy heads one container mutation may cite.\n * Each citation makes the server verify that principal's stored policy, so\n * the bound keeps the capacity inline signed policies (about 9.8 KiB each)\n * had under the 32 MiB request ceiling instead of letting a ~170-byte reference\n * multiply that work.\n */\nexport const MAX_CONTAINER_PRINCIPAL_POLICY_REFS = 4096;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tearleads/client-sdk",
3
- "version": "0.1.67",
3
+ "version": "0.1.69",
4
4
  "description": "React-free Tearleads client runtime: local SQLite persistence, keys, sync, encrypted blobs, and domain workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -52,7 +52,11 @@ export async function hydrateStoredContainerState(input) {
52
52
  metadataUpdates: bytesToBase64(initialUpdate),
53
53
  });
54
54
  await persistence.saveContainer(execSql, nextContainer, nextRecord);
55
- if (!container.metadataDocumentId) {
55
+ // A device-first child's first metadata waits for its create. A root's
56
+ // never does: only registration creates a root remotely, and provisioning
57
+ // commits the root's metadata itself, so a queued copy would only be
58
+ // replayed after login as duplicate ops.
59
+ if (!container.metadataDocumentId && container.parentId !== null) {
56
60
  await enqueuePendingContainerUpdate(execSql, persistence, {
57
61
  containerId: container.id,
58
62
  update: initialUpdate,
@@ -1 +1 @@
1
- {"version":3,"file":"storedContainerState.js","sourceRoot":"","sources":["storedContainerState.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport { exportAllUpdates, importUpdates } from \"@tearleads/loro\";\nimport {\n createContainerMetadataDocument,\n getDefaultContainerName,\n readContainerMetadataValue,\n writeContainerMetadataValue,\n} from \"../../data/containers/containerMetadataDocument\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n type ContainerContentsPersistence,\n type ContainerMetadataRecord,\n enqueuePendingContainerUpdate,\n type StoredContainerState,\n} from \"./containerPersistence\";\nimport type { ContainerState } from \"./remoteHydration/types\";\n\ntype SaveContainerOptions = Parameters<\n ContainerContentsPersistence[\"saveContainer\"]\n>[3];\n\nfunction createInitialContainerRecord(input: {\n container: StoredContainerState[\"container\"];\n metadataUpdates: string;\n}): ContainerMetadataRecord {\n return {\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: input.container.metadataDocumentId,\n documentKekTargets: null,\n documentManifestBundle: null,\n id: input.container.id,\n lastCommitLsn: null,\n metadataUpdates: input.metadataUpdates,\n snapshotEndVersion: \"\",\n };\n}\n\nfunction metadataProjectionChanged(\n left: StoredContainerState[\"container\"],\n right: StoredContainerState[\"container\"],\n): boolean {\n return left.icon !== right.icon || left.name !== right.name;\n}\n\nfunction replaySaveOptions(\n container: StoredContainerState[\"container\"],\n): SaveContainerOptions {\n const localUpdatedAt =\n container.localUpdatedAt ?? container.updatedAt ?? null;\n return localUpdatedAt ? { localUpdatedAt } : undefined;\n}\n\nexport async function hydrateStoredContainerState(input: {\n execSql: ExecSql;\n persistence: ContainerContentsPersistence;\n storedContainer: StoredContainerState;\n}): Promise<ContainerState> {\n const { execSql, persistence, storedContainer } = input;\n const { container } = storedContainer;\n const doc = await createContainerMetadataDocument(container.id);\n let nextContainer = container;\n let nextRecord = storedContainer.record;\n\n if (nextRecord?.metadataUpdates) {\n importUpdates(doc, [base64ToBytes(nextRecord.metadataUpdates)]);\n const metadata = readContainerMetadataValue(\n doc,\n getDefaultContainerName(container.parentId),\n );\n nextContainer = {\n ...container,\n icon: metadata.icon,\n name: metadata.name,\n };\n if (metadataProjectionChanged(container, nextContainer)) {\n await persistence.saveContainer(\n execSql,\n nextContainer,\n nextRecord,\n replaySaveOptions(container),\n );\n }\n } else {\n writeContainerMetadataValue(doc, {\n icon: container.icon,\n name: container.name,\n });\n const initialUpdate = exportAllUpdates(doc);\n nextRecord = createInitialContainerRecord({\n container,\n metadataUpdates: bytesToBase64(initialUpdate),\n });\n await persistence.saveContainer(execSql, nextContainer, nextRecord);\n\n if (!container.metadataDocumentId) {\n await enqueuePendingContainerUpdate(execSql, persistence, {\n containerId: container.id,\n update: initialUpdate,\n });\n }\n }\n\n return { container: nextContainer, doc, record: nextRecord };\n}\n\n/** Materialize a CAS winner without writing repair rows from a stale caller. */\nexport async function materializeStoredContainerStateReadOnly(input: {\n storedContainer: StoredContainerState;\n}): Promise<ContainerState | null> {\n const { container, record } = input.storedContainer;\n if (!record) return null;\n const doc = await createContainerMetadataDocument(container.id);\n let nextContainer = container;\n if (record.metadataUpdates) {\n importUpdates(doc, [base64ToBytes(record.metadataUpdates)]);\n const metadata = readContainerMetadataValue(\n doc,\n getDefaultContainerName(container.parentId),\n );\n nextContainer = { ...container, icon: metadata.icon, name: metadata.name };\n } else {\n writeContainerMetadataValue(doc, {\n icon: container.icon,\n name: container.name,\n });\n }\n return { container: nextContainer, doc, record };\n}\n"]}
1
+ {"version":3,"file":"storedContainerState.js","sourceRoot":"","sources":["storedContainerState.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport { exportAllUpdates, importUpdates } from \"@tearleads/loro\";\nimport {\n createContainerMetadataDocument,\n getDefaultContainerName,\n readContainerMetadataValue,\n writeContainerMetadataValue,\n} from \"../../data/containers/containerMetadataDocument\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport {\n type ContainerContentsPersistence,\n type ContainerMetadataRecord,\n enqueuePendingContainerUpdate,\n type StoredContainerState,\n} from \"./containerPersistence\";\nimport type { ContainerState } from \"./remoteHydration/types\";\n\ntype SaveContainerOptions = Parameters<\n ContainerContentsPersistence[\"saveContainer\"]\n>[3];\n\nfunction createInitialContainerRecord(input: {\n container: StoredContainerState[\"container\"];\n metadataUpdates: string;\n}): ContainerMetadataRecord {\n return {\n accessEpoch: 1,\n accessStateHash: null,\n contentKeyBundle: null,\n documentId: input.container.metadataDocumentId,\n documentKekTargets: null,\n documentManifestBundle: null,\n id: input.container.id,\n lastCommitLsn: null,\n metadataUpdates: input.metadataUpdates,\n snapshotEndVersion: \"\",\n };\n}\n\nfunction metadataProjectionChanged(\n left: StoredContainerState[\"container\"],\n right: StoredContainerState[\"container\"],\n): boolean {\n return left.icon !== right.icon || left.name !== right.name;\n}\n\nfunction replaySaveOptions(\n container: StoredContainerState[\"container\"],\n): SaveContainerOptions {\n const localUpdatedAt =\n container.localUpdatedAt ?? container.updatedAt ?? null;\n return localUpdatedAt ? { localUpdatedAt } : undefined;\n}\n\nexport async function hydrateStoredContainerState(input: {\n execSql: ExecSql;\n persistence: ContainerContentsPersistence;\n storedContainer: StoredContainerState;\n}): Promise<ContainerState> {\n const { execSql, persistence, storedContainer } = input;\n const { container } = storedContainer;\n const doc = await createContainerMetadataDocument(container.id);\n let nextContainer = container;\n let nextRecord = storedContainer.record;\n\n if (nextRecord?.metadataUpdates) {\n importUpdates(doc, [base64ToBytes(nextRecord.metadataUpdates)]);\n const metadata = readContainerMetadataValue(\n doc,\n getDefaultContainerName(container.parentId),\n );\n nextContainer = {\n ...container,\n icon: metadata.icon,\n name: metadata.name,\n };\n if (metadataProjectionChanged(container, nextContainer)) {\n await persistence.saveContainer(\n execSql,\n nextContainer,\n nextRecord,\n replaySaveOptions(container),\n );\n }\n } else {\n writeContainerMetadataValue(doc, {\n icon: container.icon,\n name: container.name,\n });\n const initialUpdate = exportAllUpdates(doc);\n nextRecord = createInitialContainerRecord({\n container,\n metadataUpdates: bytesToBase64(initialUpdate),\n });\n await persistence.saveContainer(execSql, nextContainer, nextRecord);\n\n // A device-first child's first metadata waits for its create. A root's\n // never does: only registration creates a root remotely, and provisioning\n // commits the root's metadata itself, so a queued copy would only be\n // replayed after login as duplicate ops.\n if (!container.metadataDocumentId && container.parentId !== null) {\n await enqueuePendingContainerUpdate(execSql, persistence, {\n containerId: container.id,\n update: initialUpdate,\n });\n }\n }\n\n return { container: nextContainer, doc, record: nextRecord };\n}\n\n/** Materialize a CAS winner without writing repair rows from a stale caller. */\nexport async function materializeStoredContainerStateReadOnly(input: {\n storedContainer: StoredContainerState;\n}): Promise<ContainerState | null> {\n const { container, record } = input.storedContainer;\n if (!record) return null;\n const doc = await createContainerMetadataDocument(container.id);\n let nextContainer = container;\n if (record.metadataUpdates) {\n importUpdates(doc, [base64ToBytes(record.metadataUpdates)]);\n const metadata = readContainerMetadataValue(\n doc,\n getDefaultContainerName(container.parentId),\n );\n nextContainer = { ...container, icon: metadata.icon, name: metadata.name };\n } else {\n writeContainerMetadataValue(doc, {\n icon: container.icon,\n name: container.name,\n });\n }\n return { container: nextContainer, doc, record };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { principalPolicyRequestRecord } from "../../../data/containers/shared/principalPolicies.js";
1
+ import { principalPolicyRef } from "../../../data/containers/shared/principalPolicies.js";
2
2
  import { containerManifestRef } from "../../../data/containers/shared/projection.js";
3
3
  import { readCanonicalRecord, readCanonicalRecords, } from "../../../data/keying/canonicalJson.js";
4
4
  export function readCanonicalRecordOrNull(value, label) {
@@ -31,7 +31,7 @@ export function containerMutationRequestCore(operation, input) {
31
31
  body: readCanonicalRecord(input.body, `${label} body`),
32
32
  expectedManifestHash: input.manifestHash,
33
33
  manifest: readCanonicalRecord(input.manifest, `${label} manifest`),
34
- principalPolicies: readCanonicalRecords(input.principalPolicies.map((policy) => principalPolicyRequestRecord(policy)), `${label} principal policies`),
34
+ principalPolicyRefs: input.principalPolicies.map(principalPolicyRef),
35
35
  keyEpoch: readCanonicalRecord(input.keyEpoch, `${label} key epoch`),
36
36
  wraps: readCanonicalRecords(input.wraps, `${label} wraps`),
37
37
  userRecipientKeys: readCanonicalRecords(input.userRecipientKeys, `${label} user recipient keys`),
@@ -1 +1 @@
1
- {"version":3,"file":"mutationRequestCore.js","sourceRoot":"","sources":["mutationRequestCore.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,4BAA4B,EAAE,MAAM,mDAAmD,CAAC;AACjG,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAG5C,MAAM,UAAU,yBAAyB,CACvC,KAAc,EACd,KAAa;IAEb,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAC1C,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,gBAA0C,EAC1C,kBAAqD;IAKrD,OAAO;QACL,mBAAmB,EAAE,oBAAoB,CAAC,gBAAgB,CAAC;QAC3D,yBAAyB,EACvB,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC;KACpD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B,CAC1C,SAAiB,EACjB,KASC;IAYD,MAAM,KAAK,GAAG,aAAa,SAAS,EAAE,CAAC;IACvC,OAAO;QACL,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC;QACzD,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;QACtD,oBAAoB,EAAE,KAAK,CAAC,YAAY;QACxC,QAAQ,EAAE,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,WAAW,CAAC;QAClE,iBAAiB,EAAE,oBAAoB,CACrC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACrC,4BAA4B,CAAC,MAAM,CAAC,CACrC,EACD,GAAG,KAAK,qBAAqB,CAC9B;QACD,QAAQ,EAAE,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,YAAY,CAAC;QACnE,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC;QAC1D,iBAAiB,EAAE,oBAAoB,CACrC,KAAK,CAAC,iBAAiB,EACvB,GAAG,KAAK,sBAAsB,CAC/B;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AccessEvent,\n AccessManifest,\n ContainerKeyEpoch,\n ContainerKeyWrap,\n ContainerUserRecipientKey,\n} from \"@tearleads/crypto\";\nimport type {\n AccessManifestBundleWire,\n ContainerMutationRequest,\n} from \"@tearleads/validators/request\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { principalPolicyRequestRecord } from \"../../../data/containers/shared/principalPolicies\";\nimport { containerManifestRef } from \"../../../data/containers/shared/projection\";\nimport {\n readCanonicalRecord,\n readCanonicalRecords,\n} from \"../../../data/keying/canonicalJson\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../../data/principals/principalPolicyEvidence\";\n\nexport function readCanonicalRecordOrNull(\n value: unknown,\n label: string,\n): Record<string, unknown> | null {\n return value === null || value === undefined\n ? null\n : readCanonicalRecord(value, label);\n}\n\n/**\n * The previous-manifest identity every non-create mutation\n * (share/rekey/revoke/move) sends alongside the core request fields: the\n * previous head and the current path, cited by hash rather than echoed.\n */\nexport function previousPathRequestFields(\n previousManifest: AccessManifestBundleWire,\n previousProjection: ContainerWriterProjectionResponse,\n): Pick<\n ContainerMutationRequest,\n \"previousManifestRef\" | \"previousContainerPathRefs\"\n> {\n return {\n previousManifestRef: containerManifestRef(previousManifest),\n previousContainerPathRefs:\n previousProjection.path.map(containerManifestRef),\n };\n}\n\n/**\n * The eight ContainerMutationRequest fields every child-container mutation\n * (create/share/rekey/revoke/move) assembles identically, labeled by\n * operation. The identity fields — previous manifest/path, manifest history,\n * predecessor bridge, keyring, and the parent KEK — genuinely differ per\n * operation and stay with each builder.\n */\nexport function containerMutationRequestCore(\n operation: string,\n input: {\n body: unknown;\n event: AccessEvent;\n keyEpoch: ContainerKeyEpoch;\n manifest: AccessManifest;\n manifestHash: string;\n principalPolicies: readonly PrincipalPolicyCurrentEvidence[];\n userRecipientKeys: readonly ContainerUserRecipientKey[];\n wraps: readonly ContainerKeyWrap[];\n },\n): Pick<\n ContainerMutationRequest,\n | \"event\"\n | \"body\"\n | \"expectedManifestHash\"\n | \"manifest\"\n | \"principalPolicies\"\n | \"keyEpoch\"\n | \"wraps\"\n | \"userRecipientKeys\"\n> {\n const label = `Container ${operation}`;\n return {\n event: readCanonicalRecord(input.event, `${label} event`),\n body: readCanonicalRecord(input.body, `${label} body`),\n expectedManifestHash: input.manifestHash,\n manifest: readCanonicalRecord(input.manifest, `${label} manifest`),\n principalPolicies: readCanonicalRecords(\n input.principalPolicies.map((policy) =>\n principalPolicyRequestRecord(policy),\n ),\n `${label} principal policies`,\n ),\n keyEpoch: readCanonicalRecord(input.keyEpoch, `${label} key epoch`),\n wraps: readCanonicalRecords(input.wraps, `${label} wraps`),\n userRecipientKeys: readCanonicalRecords(\n input.userRecipientKeys,\n `${label} user recipient keys`,\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"mutationRequestCore.js","sourceRoot":"","sources":["mutationRequestCore.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAG5C,MAAM,UAAU,yBAAyB,CACvC,KAAc,EACd,KAAa;IAEb,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAC1C,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,gBAA0C,EAC1C,kBAAqD;IAKrD,OAAO;QACL,mBAAmB,EAAE,oBAAoB,CAAC,gBAAgB,CAAC;QAC3D,yBAAyB,EACvB,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC;KACpD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B,CAC1C,SAAiB,EACjB,KASC;IAYD,MAAM,KAAK,GAAG,aAAa,SAAS,EAAE,CAAC;IACvC,OAAO;QACL,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC;QACzD,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC;QACtD,oBAAoB,EAAE,KAAK,CAAC,YAAY;QACxC,QAAQ,EAAE,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,WAAW,CAAC;QAClE,mBAAmB,EAAE,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,kBAAkB,CAAC;QACpE,QAAQ,EAAE,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,KAAK,YAAY,CAAC;QACnE,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC;QAC1D,iBAAiB,EAAE,oBAAoB,CACrC,KAAK,CAAC,iBAAiB,EACvB,GAAG,KAAK,sBAAsB,CAC/B;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AccessEvent,\n AccessManifest,\n ContainerKeyEpoch,\n ContainerKeyWrap,\n ContainerUserRecipientKey,\n} from \"@tearleads/crypto\";\nimport type {\n AccessManifestBundleWire,\n ContainerMutationRequest,\n} from \"@tearleads/validators/request\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { principalPolicyRef } from \"../../../data/containers/shared/principalPolicies\";\nimport { containerManifestRef } from \"../../../data/containers/shared/projection\";\nimport {\n readCanonicalRecord,\n readCanonicalRecords,\n} from \"../../../data/keying/canonicalJson\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../../data/principals/principalPolicyEvidence\";\n\nexport function readCanonicalRecordOrNull(\n value: unknown,\n label: string,\n): Record<string, unknown> | null {\n return value === null || value === undefined\n ? null\n : readCanonicalRecord(value, label);\n}\n\n/**\n * The previous-manifest identity every non-create mutation\n * (share/rekey/revoke/move) sends alongside the core request fields: the\n * previous head and the current path, cited by hash rather than echoed.\n */\nexport function previousPathRequestFields(\n previousManifest: AccessManifestBundleWire,\n previousProjection: ContainerWriterProjectionResponse,\n): Pick<\n ContainerMutationRequest,\n \"previousManifestRef\" | \"previousContainerPathRefs\"\n> {\n return {\n previousManifestRef: containerManifestRef(previousManifest),\n previousContainerPathRefs:\n previousProjection.path.map(containerManifestRef),\n };\n}\n\n/**\n * The eight ContainerMutationRequest fields every child-container mutation\n * (create/share/rekey/revoke/move) assembles identically, labeled by\n * operation. The identity fields — previous manifest/path, manifest history,\n * predecessor bridge, keyring, and the parent KEK — genuinely differ per\n * operation and stay with each builder.\n */\nexport function containerMutationRequestCore(\n operation: string,\n input: {\n body: unknown;\n event: AccessEvent;\n keyEpoch: ContainerKeyEpoch;\n manifest: AccessManifest;\n manifestHash: string;\n principalPolicies: readonly PrincipalPolicyCurrentEvidence[];\n userRecipientKeys: readonly ContainerUserRecipientKey[];\n wraps: readonly ContainerKeyWrap[];\n },\n): Pick<\n ContainerMutationRequest,\n | \"event\"\n | \"body\"\n | \"expectedManifestHash\"\n | \"manifest\"\n | \"principalPolicyRefs\"\n | \"keyEpoch\"\n | \"wraps\"\n | \"userRecipientKeys\"\n> {\n const label = `Container ${operation}`;\n return {\n event: readCanonicalRecord(input.event, `${label} event`),\n body: readCanonicalRecord(input.body, `${label} body`),\n expectedManifestHash: input.manifestHash,\n manifest: readCanonicalRecord(input.manifest, `${label} manifest`),\n principalPolicyRefs: input.principalPolicies.map(principalPolicyRef),\n keyEpoch: readCanonicalRecord(input.keyEpoch, `${label} key epoch`),\n wraps: readCanonicalRecords(input.wraps, `${label} wraps`),\n userRecipientKeys: readCanonicalRecords(\n input.userRecipientKeys,\n `${label} user recipient keys`,\n ),\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { computeAccessManifestHash, deriveContainerAccessManifest, KeyingVerificationError, MAX_CONTAINER_RECITATION_EPOCH, resolveContainerStatePathUserAccessLevel, } from "../../../internal/crypto/index.js";
2
2
  import { signContainerMutationEvent } from "../../../data/containers/shared/events.js";
3
- import { principalPolicyRequestRecord } from "../../../data/containers/shared/principalPolicies.js";
3
+ import { principalPolicyRef } from "../../../data/containers/shared/principalPolicies.js";
4
4
  import { containerManifestRef } from "../../../data/containers/shared/projection.js";
5
5
  import { canonicalKeyingJsonString, readCanonicalRecord, } from "../../../data/keying/canonicalJson.js";
6
6
  export function referencedRecitationPolicies(path, policies) {
@@ -53,7 +53,7 @@ export async function buildContainerRecitePlan(input) {
53
53
  expectedManifestHash: manifestHash,
54
54
  previousManifestRef: containerManifestRef(previous.bundle),
55
55
  previousContainerPathRefs: input.path.map((head) => containerManifestRef(head.bundle)),
56
- principalPolicies: referencedRecitationPolicies(input.path, input.policies).map((policy) => principalPolicyRequestRecord(policy)),
56
+ principalPolicyRefs: referencedRecitationPolicies(input.path, input.policies).map(principalPolicyRef),
57
57
  };
58
58
  return { body, event, eventHash, manifest, manifestHash, state, request };
59
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"recitePlan.js","sourceRoot":"","sources":["recitePlan.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computeAccessManifestHash,\n deriveContainerAccessManifest,\n KeyingVerificationError,\n MAX_CONTAINER_RECITATION_EPOCH,\n resolveContainerStatePathUserAccessLevel,\n} from \"@tearleads/crypto\";\nimport type { ContainerReciteRequest } from \"@tearleads/validators/request\";\nimport type { ContainerReciteResponse } from \"@tearleads/validators/response\";\nimport { signContainerMutationEvent } from \"../../../data/containers/shared/events\";\nimport type { HeldContainerHead } from \"../../../data/containers/shared/heldContainerHeads\";\nimport { principalPolicyRequestRecord } from \"../../../data/containers/shared/principalPolicies\";\nimport { containerManifestRef } from \"../../../data/containers/shared/projection\";\nimport type { ContainerMutationAuthor } from \"../../../data/containers/shared/types\";\nimport {\n canonicalKeyingJsonString,\n readCanonicalRecord,\n} from \"../../../data/keying/canonicalJson\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../../../data/principals/principalPolicyEvidence\";\n\nexport function referencedRecitationPolicies(\n path: readonly HeldContainerHead[],\n policies: readonly PrincipalPolicyCheckpointEvidence[],\n): readonly PrincipalPolicyCheckpointEvidence[] {\n const referencedIds = new Set(\n path.flatMap((head) =>\n head.state.referencedPrincipalHeads.map(\n (ref) => `${ref.principalType}:${ref.principalId}`,\n ),\n ),\n );\n return policies.filter((policy) =>\n referencedIds.has(`${policy.principalType}:${policy.principalId}`),\n );\n}\n\nexport async function buildContainerRecitePlan(input: {\n readonly author: ContainerMutationAuthor;\n readonly path: readonly HeldContainerHead[];\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n}) {\n const previous = input.path.at(-1);\n if (!previous) throw new Error(\"Recitation requires a held container path\");\n if (previous.state.epoch >= MAX_CONTAINER_RECITATION_EPOCH) {\n throw new Error(\"Container re-citation history budget is exhausted\");\n }\n if (\n input.path.some(\n (head) => head.state.organizationId !== input.author.organizationId,\n )\n ) {\n throw new Error(\"Recitation cannot cross organizations\");\n }\n if (\n resolveContainerStatePathUserAccessLevel({\n states: input.path.map((head) => head.state),\n principalPolicies: input.policies,\n userId: input.author.signerUserId,\n }) !== \"admin\"\n ) {\n throw new KeyingVerificationError(\n \"unauthorized\",\n \"Container re-citation signer lacks admin access on the held path\",\n );\n }\n const body = {\n eventType: \"container.recite\" as const,\n containerKeyEpochId: previous.state.containerKeyEpochId,\n containerKeyPublicKey: previous.state.containerKeyPublicKey,\n };\n const { event, eventHash } = await signContainerMutationEvent({\n author: input.author,\n body,\n containerId: previous.state.containerId,\n dependencyManifestHashes: input.path.map(\n (head) => head.bundle.manifestHash,\n ),\n eventId: crypto.randomUUID(),\n previousManifestHash: previous.bundle.manifestHash,\n signedAt: new Date().toISOString(),\n });\n const state = {\n ...previous.state,\n epoch: previous.state.epoch + 1,\n eventHash,\n previousManifestHash: previous.bundle.manifestHash,\n };\n const manifest = await deriveContainerAccessManifest(state);\n const manifestHash = await computeAccessManifestHash(manifest);\n const request: ContainerReciteRequest = {\n body,\n event: readCanonicalRecord(event, \"Recitation event\"),\n manifest: readCanonicalRecord(manifest, \"Recitation manifest\"),\n expectedManifestHash: manifestHash,\n previousManifestRef: containerManifestRef(previous.bundle),\n previousContainerPathRefs: input.path.map((head) =>\n containerManifestRef(head.bundle),\n ),\n principalPolicies: referencedRecitationPolicies(\n input.path,\n input.policies,\n ).map((policy) => principalPolicyRequestRecord(policy)),\n };\n return { body, event, eventHash, manifest, manifestHash, state, request };\n}\n\nexport function assertContainerReciteAcknowledgement(\n plan: Awaited<ReturnType<typeof buildContainerRecitePlan>>,\n response: ContainerReciteResponse,\n): void {\n const bundle = response.accessManifest;\n const signedFieldsMatch = [\n [bundle.event.event, plan.event],\n [bundle.event.body, plan.body],\n [bundle.manifest, plan.manifest],\n [bundle.state, plan.state],\n ].every(\n ([actual, expected]) =>\n canonicalKeyingJsonString(actual, \"Recitation response\") ===\n canonicalKeyingJsonString(expected, \"Recitation plan\"),\n );\n if (\n response.containerId !== plan.state.containerId ||\n response.organizationId !== plan.state.organizationId ||\n response.parentId !== plan.state.parentContainerId ||\n response.manifestHead.epoch !== plan.state.epoch ||\n response.manifestHead.manifestHash !== plan.manifestHash ||\n bundle.manifestHash !== plan.manifestHash ||\n bundle.event.eventHash !== plan.eventHash ||\n !signedFieldsMatch ||\n canonicalKeyingJsonString(\n response.referencedPrincipalHeads,\n \"Recitation references\",\n ) !==\n canonicalKeyingJsonString(\n plan.manifest.referencedPrincipalHeads,\n \"Recitation planned references\",\n )\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Container recitation response does not match the signed plan\",\n );\n}\n"]}
1
+ {"version":3,"file":"recitePlan.js","sourceRoot":"","sources":["recitePlan.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computeAccessManifestHash,\n deriveContainerAccessManifest,\n KeyingVerificationError,\n MAX_CONTAINER_RECITATION_EPOCH,\n resolveContainerStatePathUserAccessLevel,\n} from \"@tearleads/crypto\";\nimport type { ContainerReciteRequest } from \"@tearleads/validators/request\";\nimport type { ContainerReciteResponse } from \"@tearleads/validators/response\";\nimport { signContainerMutationEvent } from \"../../../data/containers/shared/events\";\nimport type { HeldContainerHead } from \"../../../data/containers/shared/heldContainerHeads\";\nimport { principalPolicyRef } from \"../../../data/containers/shared/principalPolicies\";\nimport { containerManifestRef } from \"../../../data/containers/shared/projection\";\nimport type { ContainerMutationAuthor } from \"../../../data/containers/shared/types\";\nimport {\n canonicalKeyingJsonString,\n readCanonicalRecord,\n} from \"../../../data/keying/canonicalJson\";\nimport type { PrincipalPolicyCheckpointEvidence } from \"../../../data/principals/principalPolicyEvidence\";\n\nexport function referencedRecitationPolicies(\n path: readonly HeldContainerHead[],\n policies: readonly PrincipalPolicyCheckpointEvidence[],\n): readonly PrincipalPolicyCheckpointEvidence[] {\n const referencedIds = new Set(\n path.flatMap((head) =>\n head.state.referencedPrincipalHeads.map(\n (ref) => `${ref.principalType}:${ref.principalId}`,\n ),\n ),\n );\n return policies.filter((policy) =>\n referencedIds.has(`${policy.principalType}:${policy.principalId}`),\n );\n}\n\nexport async function buildContainerRecitePlan(input: {\n readonly author: ContainerMutationAuthor;\n readonly path: readonly HeldContainerHead[];\n readonly policies: readonly PrincipalPolicyCheckpointEvidence[];\n}) {\n const previous = input.path.at(-1);\n if (!previous) throw new Error(\"Recitation requires a held container path\");\n if (previous.state.epoch >= MAX_CONTAINER_RECITATION_EPOCH) {\n throw new Error(\"Container re-citation history budget is exhausted\");\n }\n if (\n input.path.some(\n (head) => head.state.organizationId !== input.author.organizationId,\n )\n ) {\n throw new Error(\"Recitation cannot cross organizations\");\n }\n if (\n resolveContainerStatePathUserAccessLevel({\n states: input.path.map((head) => head.state),\n principalPolicies: input.policies,\n userId: input.author.signerUserId,\n }) !== \"admin\"\n ) {\n throw new KeyingVerificationError(\n \"unauthorized\",\n \"Container re-citation signer lacks admin access on the held path\",\n );\n }\n const body = {\n eventType: \"container.recite\" as const,\n containerKeyEpochId: previous.state.containerKeyEpochId,\n containerKeyPublicKey: previous.state.containerKeyPublicKey,\n };\n const { event, eventHash } = await signContainerMutationEvent({\n author: input.author,\n body,\n containerId: previous.state.containerId,\n dependencyManifestHashes: input.path.map(\n (head) => head.bundle.manifestHash,\n ),\n eventId: crypto.randomUUID(),\n previousManifestHash: previous.bundle.manifestHash,\n signedAt: new Date().toISOString(),\n });\n const state = {\n ...previous.state,\n epoch: previous.state.epoch + 1,\n eventHash,\n previousManifestHash: previous.bundle.manifestHash,\n };\n const manifest = await deriveContainerAccessManifest(state);\n const manifestHash = await computeAccessManifestHash(manifest);\n const request: ContainerReciteRequest = {\n body,\n event: readCanonicalRecord(event, \"Recitation event\"),\n manifest: readCanonicalRecord(manifest, \"Recitation manifest\"),\n expectedManifestHash: manifestHash,\n previousManifestRef: containerManifestRef(previous.bundle),\n previousContainerPathRefs: input.path.map((head) =>\n containerManifestRef(head.bundle),\n ),\n principalPolicyRefs: referencedRecitationPolicies(\n input.path,\n input.policies,\n ).map(principalPolicyRef),\n };\n return { body, event, eventHash, manifest, manifestHash, state, request };\n}\n\nexport function assertContainerReciteAcknowledgement(\n plan: Awaited<ReturnType<typeof buildContainerRecitePlan>>,\n response: ContainerReciteResponse,\n): void {\n const bundle = response.accessManifest;\n const signedFieldsMatch = [\n [bundle.event.event, plan.event],\n [bundle.event.body, plan.body],\n [bundle.manifest, plan.manifest],\n [bundle.state, plan.state],\n ].every(\n ([actual, expected]) =>\n canonicalKeyingJsonString(actual, \"Recitation response\") ===\n canonicalKeyingJsonString(expected, \"Recitation plan\"),\n );\n if (\n response.containerId !== plan.state.containerId ||\n response.organizationId !== plan.state.organizationId ||\n response.parentId !== plan.state.parentContainerId ||\n response.manifestHead.epoch !== plan.state.epoch ||\n response.manifestHead.manifestHash !== plan.manifestHash ||\n bundle.manifestHash !== plan.manifestHash ||\n bundle.event.eventHash !== plan.eventHash ||\n !signedFieldsMatch ||\n canonicalKeyingJsonString(\n response.referencedPrincipalHeads,\n \"Recitation references\",\n ) !==\n canonicalKeyingJsonString(\n plan.manifest.referencedPrincipalHeads,\n \"Recitation planned references\",\n )\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Container recitation response does not match the signed plan\",\n );\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  import { computeContainerKekRecipientTargetHash, computeContainerKeyEpochHash, deriveContainerKekWrappingPublicKey, normalizeContainerAccessEventBody, } from "../../../internal/crypto/index.js";
2
2
  import { buildContainerCreateBody, buildContainerCreateKeyEpoch, deriveContainerCreateManifest, resolveContainerKekEpochId, signContainerCreateEvent, } from "../../../data/containers/shared/events.js";
3
+ import { principalPolicyRef } from "../../../data/containers/shared/principalPolicies.js";
3
4
  import { wrapContainerKeyToManagedPrincipal, wrapContainerKeyToRootUser, } from "../../../data/containers/shared/projection.js";
4
5
  import { readCanonicalJson, readCanonicalRecord, readCanonicalRecords, } from "../../../data/keying/canonicalJson.js";
5
- import { principalHeadFromInitialGroupPolicy, principalPolicyRecordFromInitialGroupPolicy, } from "./initialGroupPolicy.js";
6
+ import { principalHeadFromInitialGroupPolicy } from "./initialGroupPolicy.js";
6
7
  function buildRootContainerCreateBody(input) {
7
8
  const baseBody = buildContainerCreateBody({
8
9
  systemSlot: input.systemSlot,
@@ -56,7 +57,7 @@ function buildRootContainerCreateRequest(input) {
56
57
  manifest: readCanonicalRecord(input.manifest, "Container root create manifest"),
57
58
  previousManifestRef: null,
58
59
  parentContainerPathRefs: [],
59
- principalPolicies: readCanonicalRecords(input.principalPolicies, "Container root create principal policies"),
60
+ principalPolicyRefs: input.principalPolicyRefs,
60
61
  keyEpoch: readCanonicalRecord(input.keyEpoch, "Container root create key epoch"),
61
62
  predecessorBridge: null,
62
63
  keyring: null,
@@ -64,26 +65,13 @@ function buildRootContainerCreateRequest(input) {
64
65
  userRecipientKeys: readCanonicalRecords(input.userRecipientKeys, "Container root create user recipient keys"),
65
66
  };
66
67
  }
67
- async function buildRootManagedPrincipalContext(adminGroup) {
68
- if (!adminGroup) {
69
- return {
70
- managedPrincipalHead: null,
71
- managedPrincipalPolicies: [],
72
- };
73
- }
74
- const managedPrincipalHead = await principalHeadFromInitialGroupPolicy({
75
- principalId: adminGroup.groupId,
76
- policy: adminGroup.initialGroupPolicy,
77
- });
78
- return {
79
- managedPrincipalHead,
80
- managedPrincipalPolicies: [
81
- principalPolicyRecordFromInitialGroupPolicy({
82
- head: managedPrincipalHead,
83
- policy: adminGroup.initialGroupPolicy,
84
- }),
85
- ],
86
- };
68
+ async function rootManagedPrincipalHead(group) {
69
+ return group
70
+ ? principalHeadFromInitialGroupPolicy({
71
+ principalId: group.groupId,
72
+ policy: group.initialGroupPolicy,
73
+ })
74
+ : null;
87
75
  }
88
76
  async function deriveRootCreateArtifacts(input) {
89
77
  if (!input.body.containerKeyPublicKey)
@@ -175,11 +163,10 @@ function normalizedRootCreateBody(input) {
175
163
  export async function buildRootContainerCreatePlan(input) {
176
164
  const containerKey = rootKeyMaterial(input.containerKey);
177
165
  const adminGroup = input.adminGroup ?? null;
178
- const { managedPrincipalHead, managedPrincipalPolicies } = await buildRootManagedPrincipalContext(adminGroup);
179
- const member = await buildRootManagedPrincipalContext(input.memberGroup ?? null);
166
+ const managedPrincipalHead = await rootManagedPrincipalHead(adminGroup);
167
+ const memberHead = await rootManagedPrincipalHead(input.memberGroup ?? null);
180
168
  if (input.memberGroup && !adminGroup)
181
169
  throw new Error("Members root grant requires Admins authority");
182
- managedPrincipalPolicies.push(...member.managedPrincipalPolicies);
183
170
  const containerKeyEpochId = await resolveContainerKekEpochId({
184
171
  containerId: input.containerId,
185
172
  keyEpoch: 1,
@@ -190,7 +177,7 @@ export async function buildRootContainerCreatePlan(input) {
190
177
  containerId: input.containerId,
191
178
  keyMaterial: containerKey,
192
179
  }),
193
- memberHead: member.managedPrincipalHead,
180
+ memberHead,
194
181
  systemSlot: input.systemSlot ?? null,
195
182
  author: input.author,
196
183
  containerKeyEpochId,
@@ -207,7 +194,7 @@ export async function buildRootContainerCreatePlan(input) {
207
194
  });
208
195
  const { recipientTargets, wraps, userRecipientKeys } = await wrapRootContainerRecipients({
209
196
  memberGroup: input.memberGroup ?? null,
210
- memberHead: member.managedPrincipalHead,
197
+ memberHead,
211
198
  adminGroup,
212
199
  containerKey,
213
200
  containerKeyEpochId,
@@ -239,7 +226,9 @@ export async function buildRootContainerCreatePlan(input) {
239
226
  keyEpoch,
240
227
  manifest,
241
228
  manifestHash,
242
- principalPolicies: managedPrincipalPolicies,
229
+ principalPolicyRefs: [managedPrincipalHead, memberHead]
230
+ .filter((head) => head !== null)
231
+ .map(principalPolicyRef),
243
232
  userRecipientKeys,
244
233
  wraps,
245
234
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["create.ts"],"names":[],"mappings":"AASA,OAAO,EACL,sCAAsC,EACtC,4BAA4B,EAC5B,mCAAmC,EACnC,iCAAiC,GAClC,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,6BAA6B,EAC7B,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,4CAA4C,CAAC;AAMpD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,mCAAmC,EACnC,2CAA2C,GAC5C,MAAM,sBAAsB,CAAC;AAE9B,SAAS,4BAA4B,CAAC,KAQrC;IACC,MAAM,QAAQ,GAAG,wBAAwB,CAAC;QACxC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,qBAAqB,EAAE,KAAK,CAAC,qBAAqB;QAClD,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;KACzB,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC/B,OAAO;YACL,GAAG,QAAQ;YACX,YAAY,EAAE;gBACZ;oBACE,WAAW,EAAE,OAAO;oBACpB,SAAS,EAAE,KAAK,CAAC,oBAAoB,CAAC,WAAW;oBACjD,WAAW,EAAE,KAAK,CAAC,oBAAoB,CAAC,aAAa;iBACtD;gBACD,GAAG,CAAC,KAAK,CAAC,UAAU;oBAClB,CAAC,CAAC;wBACE;4BACE,WAAW,EAAE,MAAe;4BAC5B,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;4BACvC,WAAW,EAAE,OAAgB;yBAC9B;qBACF;oBACH,CAAC,CAAC,EAAE,CAAC;aACR;YACD,wBAAwB,EAAE;gBACxB,KAAK,CAAC,oBAAoB;gBAC1B,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aAChD;SACF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,GAAG,QAAQ;QACX,YAAY,EAAE;YACZ;gBACE,WAAW,EAAE,OAAO;gBACpB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY;gBACpC,WAAW,EAAE,MAAM;aACpB;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CAAC,KASxC;IACC,OAAO;QACL,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC,KAAK,EAAE,6BAA6B,CAAC;QACtE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,IAAI,EAAE,4BAA4B,CAAC;QACnE,oBAAoB,EAAE,KAAK,CAAC,YAAY;QACxC,QAAQ,EAAE,mBAAmB,CAC3B,KAAK,CAAC,QAAQ,EACd,gCAAgC,CACjC;QACD,mBAAmB,EAAE,IAAI;QACzB,uBAAuB,EAAE,EAAE;QAC3B,iBAAiB,EAAE,oBAAoB,CACrC,KAAK,CAAC,iBAAiB,EACvB,0CAA0C,CAC3C;QACD,QAAQ,EAAE,mBAAmB,CAC3B,KAAK,CAAC,QAAQ,EACd,iCAAiC,CAClC;QACD,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,6BAA6B,CAAC;QACvE,iBAAiB,EAAE,oBAAoB,CACrC,KAAK,CAAC,iBAAiB,EACvB,2CAA2C,CAC5C;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gCAAgC,CAC7C,UAAiD;IAKjD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;YACL,oBAAoB,EAAE,IAAI;YAC1B,wBAAwB,EAAE,EAAE;SAC7B,CAAC;IACJ,CAAC;IAED,MAAM,oBAAoB,GAAG,MAAM,mCAAmC,CAAC;QACrE,WAAW,EAAE,UAAU,CAAC,OAAO;QAC/B,MAAM,EAAE,UAAU,CAAC,kBAAkB;KACtC,CAAC,CAAC;IAEH,OAAO;QACL,oBAAoB;QACpB,wBAAwB,EAAE;YACxB,2CAA2C,CAAC;gBAC1C,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,UAAU,CAAC,kBAAkB;aACtC,CAAC;SACH;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,KAOxC;IACC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB;QACnC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,wBAAwB,CAAC;QAC1D,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE;QAC5B,8DAA8D;QAC9D,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,cAAc;QAC3C,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrD,CAAC,CAAC;IACH,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,6BAA6B,CAC3E;QACE,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU;QACjC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,qBAAqB,EAAE,KAAK,CAAC,IAAI,CAAC,qBAAqB;QACvD,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY;QACrC,SAAS;QACT,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,8DAA8D;QAC9D,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,cAAc;QAC3C,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,wBAAwB,EAAE,KAAK,CAAC,IAAI,CAAC,wBAAwB;KAC9D,CACF,CAAC;IACF,MAAM,QAAQ,GAAG,4BAA4B,CAAC;QAC5C,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,SAAS;QACT,YAAY;QACZ,yBAAyB,EAAE,IAAI;KAChC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACvE,CAAC;AAED,KAAK,UAAU,2BAA2B,CAAC,KAQ1C;IACC,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,oBAAoB,EAAE,CAAC;QACnD,OAAO;YACL,GAAG,CAAC,MAAM,kCAAkC,CAAC;gBAC3C,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;gBAC9C,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,+BAA+B,EAC7B,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,sBAAsB;gBAClE,aAAa,EAAE,KAAK,CAAC,oBAAoB;aAC1C,CAAC,CAAC;YACH,gBAAgB,EAAE,IAAI;SACvB,CAAC;IACJ,CAAC;IAED,OAAO,0BAA0B,CAAC;QAChC,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;QACtE,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,2BAA2B,CACxC,KAGC;IAED,MAAM,IAAI,GAAG,MAAM,2BAA2B,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU;QACnC,CAAC,CAAC,MAAM,kCAAkC,CAAC;YACvC,GAAG,KAAK;YACR,+BAA+B,EAC7B,KAAK,CAAC,WAAW,CAAC,kBAAkB,CAAC,KAAK,CAAC,sBAAsB;YACnE,aAAa,EAAE,KAAK,CAAC,UAAU;SAChC,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC;IACX,OAAO;QACL,gBAAgB,EAAE;YAChB,IAAI,CAAC,eAAe;YACpB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5C;QACD,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,iBAAiB,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE;KACxE,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAgB;IACvC,MAAM,QAAQ,GAAG,GAAG,IAAI,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACnE,IAAI,QAAQ,CAAC,UAAU,KAAK,EAAE;QAC5B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAyD;IAEzD,MAAM,IAAI,GAAG,iCAAiC,CAC5C,iBAAiB,CAAC,4BAA4B,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC,CAC3E,CAAC;IACF,IAAI,IAAI,CAAC,SAAS,KAAK,kBAAkB;QACvC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,KAUlD;IACC,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC;IAC5C,MAAM,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,GACtD,MAAM,gCAAgC,CAAC,UAAU,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,MAAM,gCAAgC,CACnD,KAAK,CAAC,WAAW,IAAI,IAAI,CAC1B,CAAC;IACF,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,UAAU;QAClC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;IAClE,MAAM,mBAAmB,GAAG,MAAM,0BAA0B,CAAC;QAC3D,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,CAAC;QACX,WAAW,EAAE,YAAY;KAC1B,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,wBAAwB,CAAC;QACpC,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;YAC/D,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,WAAW,EAAE,YAAY;SAC1B,CAAC;QACF,UAAU,EAAE,MAAM,CAAC,oBAAoB;QACvC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;QACpC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,mBAAmB;QACnB,oBAAoB;QACpB,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;KAC7C,CAAC,CAAC;IACH,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,GACjE,MAAM,yBAAyB,CAAC;QAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI;QACJ,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,mBAAmB;QACnB,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC;IACL,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,iBAAiB,EAAE,GAClD,MAAM,2BAA2B,CAAC;QAChC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;QACtC,UAAU,EAAE,MAAM,CAAC,oBAAoB;QACvC,UAAU;QACV,YAAY;QACZ,mBAAmB;QACnB,YAAY;QACZ,oBAAoB;QACpB,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;QACtE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,YAAY;KAClC,CAAC,CAAC;IACL,MAAM,aAAa,GACjB,MAAM,sCAAsC,CAAC,gBAAgB,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,MAAM,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IAClE,MAAM,IAAI,GAAwB;QAChC,IAAI;QACJ,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,mBAAmB;QACnB,KAAK;QACL,SAAS;QACT,QAAQ;QACR,YAAY;QACZ,aAAa;QACb,QAAQ;QACR,YAAY;QACZ,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB;QAChB,OAAO,EAAE,+BAA+B,CAAC;YACvC,IAAI;YACJ,KAAK;YACL,QAAQ;YACR,QAAQ;YACR,YAAY;YACZ,iBAAiB,EAAE,wBAAwB;YAC3C,iBAAiB;YACjB,KAAK;SACN,CAAC;QACF,KAAK;QACL,KAAK;KACN,CAAC;IAEF,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,2CAA2C,CACzD,IAAyB;IAEzB,OAAO;QACL,cAAc,EAAE;YACd,YAAY,EAAE,IAAI;YAClB,oBAAoB,EAAE,EAAE;YACxB,MAAM,EAAE,EAAE;SACX;QACD,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc;QACzC,IAAI,EAAE;YACJ;gBACE,KAAK,EAAE;oBACL,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,sBAAsB,CAAC;oBAC9D,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,qBAAqB,CAAC;oBAC3D,SAAS,EAAE,IAAI,CAAC,SAAS;iBAC1B;gBACD,QAAQ,EAAE,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,yBAAyB,CAAC;gBACvE,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,KAAK,EAAE,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,sBAAsB,CAAC;aAC/D;SACF;QACD,aAAa,EAAE;YACb;gBACE,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,kBAAkB,EAAE,IAAI,CAAC,YAAY;gBACrC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;gBAC7C,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;gBACzC,QAAQ,EAAE,mBAAmB,CAC3B,IAAI,CAAC,QAAQ,EACb,0BAA0B,CAC3B;gBACD,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,wBAAwB,EAAE,EAAE;gBAC5B,yBAAyB,EAAE,IAAI;gBAC/B,OAAO,EAAE,IAAI;gBACb,gBAAgB,EAAE,oBAAoB,CACpC,IAAI,CAAC,gBAAgB,EACrB,kCAAkC,CACnC;gBACD,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,EAAE,sBAAsB,CAAC;aAChE;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n AccessEvent,\n AccessManifest,\n ContainerCreateAccessEventBody,\n ContainerGrantPrincipalHead,\n ContainerKeyEpoch,\n ContainerKeyWrap,\n ContainerUserRecipientKey,\n} from \"@tearleads/crypto\";\nimport {\n computeContainerKekRecipientTargetHash,\n computeContainerKeyEpochHash,\n deriveContainerKekWrappingPublicKey,\n normalizeContainerAccessEventBody,\n} from \"@tearleads/crypto\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type {\n ContainerMutationRequest,\n CreateOrganizationGroupRequest,\n} from \"@tearleads/validators/request\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n buildContainerCreateBody,\n buildContainerCreateKeyEpoch,\n deriveContainerCreateManifest,\n resolveContainerKekEpochId,\n signContainerCreateEvent,\n} from \"../../../data/containers/shared/events\";\nimport {\n wrapContainerKeyToManagedPrincipal,\n wrapContainerKeyToRootUser,\n} from \"../../../data/containers/shared/projection\";\nimport type {\n ContainerCreatePlan,\n ContainerMutationAuthor,\n MaterializedContainerCreatePlan,\n} from \"../../../data/containers/shared/types\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n readCanonicalRecords,\n} from \"../../../data/keying/canonicalJson\";\n\nimport {\n principalHeadFromInitialGroupPolicy,\n principalPolicyRecordFromInitialGroupPolicy,\n} from \"./initialGroupPolicy\";\n\nfunction buildRootContainerCreateBody(input: {\n author: ContainerMutationAuthor;\n managedPrincipalHead: ContainerGrantPrincipalHead | null;\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n metadataDocumentId: string;\n memberHead: ContainerGrantPrincipalHead | null;\n systemSlot: ContainerSystemSlot | null;\n}): ContainerCreateAccessEventBody {\n const baseBody = buildContainerCreateBody({\n systemSlot: input.systemSlot,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n metadataDocumentId: input.metadataDocumentId,\n parentContainerId: null,\n parentManifestHash: null,\n });\n if (input.managedPrincipalHead) {\n return {\n ...baseBody,\n directGrants: [\n {\n accessLevel: \"admin\",\n subjectId: input.managedPrincipalHead.principalId,\n subjectType: input.managedPrincipalHead.principalType,\n },\n ...(input.memberHead\n ? [\n {\n accessLevel: \"read\" as const,\n subjectId: input.memberHead.principalId,\n subjectType: \"group\" as const,\n },\n ]\n : []),\n ],\n referencedPrincipalHeads: [\n input.managedPrincipalHead,\n ...(input.memberHead ? [input.memberHead] : []),\n ],\n };\n }\n\n return {\n ...baseBody,\n directGrants: [\n {\n accessLevel: \"admin\",\n subjectId: input.author.signerUserId,\n subjectType: \"user\",\n },\n ],\n };\n}\n\nfunction buildRootContainerCreateRequest(input: {\n body: ContainerCreateAccessEventBody;\n event: AccessEvent;\n keyEpoch: ContainerKeyEpoch;\n manifest: AccessManifest;\n manifestHash: string;\n principalPolicies: readonly Record<string, unknown>[];\n userRecipientKeys: readonly ContainerUserRecipientKey[];\n wraps: readonly ContainerKeyWrap[];\n}): ContainerMutationRequest {\n return {\n event: readCanonicalRecord(input.event, \"Container root create event\"),\n body: readCanonicalRecord(input.body, \"Container root create body\"),\n expectedManifestHash: input.manifestHash,\n manifest: readCanonicalRecord(\n input.manifest,\n \"Container root create manifest\",\n ),\n previousManifestRef: null,\n parentContainerPathRefs: [],\n principalPolicies: readCanonicalRecords(\n input.principalPolicies,\n \"Container root create principal policies\",\n ),\n keyEpoch: readCanonicalRecord(\n input.keyEpoch,\n \"Container root create key epoch\",\n ),\n predecessorBridge: null,\n keyring: null,\n wraps: readCanonicalRecords(input.wraps, \"Container root create wraps\"),\n userRecipientKeys: readCanonicalRecords(\n input.userRecipientKeys,\n \"Container root create user recipient keys\",\n ),\n };\n}\n\nasync function buildRootManagedPrincipalContext(\n adminGroup: CreateOrganizationGroupRequest | null,\n): Promise<{\n managedPrincipalHead: ContainerGrantPrincipalHead | null;\n managedPrincipalPolicies: Record<string, unknown>[];\n}> {\n if (!adminGroup) {\n return {\n managedPrincipalHead: null,\n managedPrincipalPolicies: [],\n };\n }\n\n const managedPrincipalHead = await principalHeadFromInitialGroupPolicy({\n principalId: adminGroup.groupId,\n policy: adminGroup.initialGroupPolicy,\n });\n\n return {\n managedPrincipalHead,\n managedPrincipalPolicies: [\n principalPolicyRecordFromInitialGroupPolicy({\n head: managedPrincipalHead,\n policy: adminGroup.initialGroupPolicy,\n }),\n ],\n };\n}\n\nasync function deriveRootCreateArtifacts(input: {\n author: ContainerMutationAuthor;\n body: ContainerCreateAccessEventBody;\n containerId: string;\n containerKeyEpochId: string;\n metadataDocumentId: string;\n signedAt: string | undefined;\n}) {\n if (!input.body.containerKeyPublicKey)\n throw new Error(\"Root container public key is missing\");\n const { event, eventHash } = await signContainerCreateEvent({\n author: input.author,\n body: input.body,\n containerId: input.containerId,\n eventId: crypto.randomUUID(),\n // A root container belongs to the creator's own organization.\n organizationId: input.author.organizationId,\n parentPath: [],\n signedAt: input.signedAt ?? new Date().toISOString(),\n });\n const { manifest, manifestHash, state } = await deriveContainerCreateManifest(\n {\n systemSlot: input.body.systemSlot,\n containerId: input.containerId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.body.containerKeyPublicKey,\n directGrants: input.body.directGrants,\n eventHash,\n metadataDocumentId: input.metadataDocumentId,\n // A root container belongs to the creator's own organization.\n organizationId: input.author.organizationId,\n parentContainerId: null,\n parentManifestHash: null,\n referencedPrincipalHeads: input.body.referencedPrincipalHeads,\n },\n );\n const keyEpoch = buildContainerCreateKeyEpoch({\n containerId: input.containerId,\n containerKeyEpochId: input.containerKeyEpochId,\n eventHash,\n manifestHash,\n parentContainerKeyEpochId: null,\n });\n return { event, eventHash, keyEpoch, manifest, manifestHash, state };\n}\n\nasync function wrapRootContainerKeyForPlan(input: {\n adminGroup: CreateOrganizationGroupRequest | null;\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n managedPrincipalHead: ContainerGrantPrincipalHead | null;\n recipientEncapsulationPublicKey: Uint8Array;\n userId: string;\n}) {\n if (input.adminGroup && input.managedPrincipalHead) {\n return {\n ...(await wrapContainerKeyToManagedPrincipal({\n containerKey: input.containerKey,\n containerKeyEpochId: input.containerKeyEpochId,\n manifestHash: input.manifestHash,\n principalEncapsulationPublicKey:\n input.adminGroup.initialGroupPolicy.state.encapsulationPublicKey,\n principalHead: input.managedPrincipalHead,\n })),\n userRecipientKey: null,\n };\n }\n\n return wrapContainerKeyToRootUser({\n containerKey: input.containerKey,\n containerKeyEpochId: input.containerKeyEpochId,\n manifestHash: input.manifestHash,\n recipientEncapsulationPublicKey: input.recipientEncapsulationPublicKey,\n userId: input.userId,\n });\n}\n\nasync function wrapRootContainerRecipients(\n input: Parameters<typeof wrapRootContainerKeyForPlan>[0] & {\n memberGroup: CreateOrganizationGroupRequest | null;\n memberHead: ContainerGrantPrincipalHead | null;\n },\n) {\n const root = await wrapRootContainerKeyForPlan(input);\n const member =\n input.memberGroup && input.memberHead\n ? await wrapContainerKeyToManagedPrincipal({\n ...input,\n principalEncapsulationPublicKey:\n input.memberGroup.initialGroupPolicy.state.encapsulationPublicKey,\n principalHead: input.memberHead,\n })\n : null;\n return {\n recipientTargets: [\n root.recipientTarget,\n ...(member ? [member.recipientTarget] : []),\n ],\n wraps: [root.wrap, ...(member ? [member.wrap] : [])],\n userRecipientKeys: root.userRecipientKey ? [root.userRecipientKey] : [],\n };\n}\n\nfunction rootKeyMaterial(key?: Uint8Array): Uint8Array {\n const material = key ?? crypto.getRandomValues(new Uint8Array(32));\n if (material.byteLength !== 32)\n throw new Error(\"Container KEK material must be 32 bytes\");\n return material;\n}\n\nfunction normalizedRootCreateBody(\n input: Parameters<typeof buildRootContainerCreateBody>[0],\n): ContainerCreateAccessEventBody {\n const body = normalizeContainerAccessEventBody(\n readCanonicalJson(buildRootContainerCreateBody(input), \"Root create body\"),\n );\n if (body.eventType !== \"container.create\")\n throw new Error(\"Expected root creation body\");\n return body;\n}\n\nexport async function buildRootContainerCreatePlan(input: {\n adminGroup?: CreateOrganizationGroupRequest | undefined;\n memberGroup?: CreateOrganizationGroupRequest | undefined;\n systemSlot?: ContainerSystemSlot | undefined;\n author: ContainerMutationAuthor;\n containerId: string;\n containerKey?: Uint8Array | undefined;\n metadataDocumentId: string;\n recipientEncapsulationPublicKey: Uint8Array;\n signedAt?: string | undefined;\n}): Promise<MaterializedContainerCreatePlan> {\n const containerKey = rootKeyMaterial(input.containerKey);\n const adminGroup = input.adminGroup ?? null;\n const { managedPrincipalHead, managedPrincipalPolicies } =\n await buildRootManagedPrincipalContext(adminGroup);\n\n const member = await buildRootManagedPrincipalContext(\n input.memberGroup ?? null,\n );\n if (input.memberGroup && !adminGroup)\n throw new Error(\"Members root grant requires Admins authority\");\n managedPrincipalPolicies.push(...member.managedPrincipalPolicies);\n const containerKeyEpochId = await resolveContainerKekEpochId({\n containerId: input.containerId,\n keyEpoch: 1,\n keyMaterial: containerKey,\n });\n const body = normalizedRootCreateBody({\n containerKeyPublicKey: await deriveContainerKekWrappingPublicKey({\n containerId: input.containerId,\n keyMaterial: containerKey,\n }),\n memberHead: member.managedPrincipalHead,\n systemSlot: input.systemSlot ?? null,\n author: input.author,\n containerKeyEpochId,\n managedPrincipalHead,\n metadataDocumentId: input.metadataDocumentId,\n });\n const { event, eventHash, keyEpoch, manifest, manifestHash, state } =\n await deriveRootCreateArtifacts({\n author: input.author,\n body,\n containerId: input.containerId,\n containerKeyEpochId,\n metadataDocumentId: input.metadataDocumentId,\n signedAt: input.signedAt,\n });\n const { recipientTargets, wraps, userRecipientKeys } =\n await wrapRootContainerRecipients({\n memberGroup: input.memberGroup ?? null,\n memberHead: member.managedPrincipalHead,\n adminGroup,\n containerKey,\n containerKeyEpochId,\n manifestHash,\n managedPrincipalHead,\n recipientEncapsulationPublicKey: input.recipientEncapsulationPublicKey,\n userId: input.author.signerUserId,\n });\n const keyTargetHash =\n await computeContainerKekRecipientTargetHash(recipientTargets);\n const keyEpochHash = await computeContainerKeyEpochHash(keyEpoch);\n const plan: ContainerCreatePlan = {\n body,\n containerId: input.containerId,\n containerKeyEpochId,\n event,\n eventHash,\n keyEpoch,\n keyEpochHash,\n keyTargetHash,\n manifest,\n manifestHash,\n metadataDocumentId: input.metadataDocumentId,\n parentContainerId: null,\n parentManifestHash: null,\n recipientTargets,\n request: buildRootContainerCreateRequest({\n body,\n event,\n keyEpoch,\n manifest,\n manifestHash,\n principalPolicies: managedPrincipalPolicies,\n userRecipientKeys,\n wraps,\n }),\n state,\n wraps,\n };\n\n return { containerKey, plan };\n}\n\nexport function rootContainerWriterProjectionFromCreatePlan(\n plan: ContainerCreatePlan,\n): ContainerWriterProjectionResponse {\n return {\n policyEvidence: {\n organization: null,\n organizationPayloads: [],\n groups: [],\n },\n containerId: plan.containerId,\n organizationId: plan.state.organizationId,\n path: [\n {\n event: {\n event: readCanonicalRecord(plan.event, \"Container root event\"),\n body: readCanonicalRecord(plan.body, \"Container root body\"),\n eventHash: plan.eventHash,\n },\n manifest: readCanonicalRecord(plan.manifest, \"Container root manifest\"),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Container root state\"),\n },\n ],\n containerKeks: [\n {\n containerId: plan.containerId,\n accessManifestHash: plan.manifestHash,\n containerKeyEpochId: plan.containerKeyEpochId,\n containerKeyEpoch: plan.keyEpoch.keyEpoch,\n keyEpoch: readCanonicalRecord(\n plan.keyEpoch,\n \"Container root key epoch\",\n ),\n keyEpochHash: plan.keyEpochHash,\n keyTargetHash: plan.keyTargetHash,\n containerManifestHistory: [],\n parentContainerKeyEpochId: null,\n keyring: null,\n recipientTargets: readCanonicalRecords(\n plan.recipientTargets,\n \"Container root recipient targets\",\n ),\n wraps: readCanonicalRecords(plan.wraps, \"Container root wraps\"),\n },\n ],\n };\n}\n"]}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["create.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccessEvent,\n AccessManifest,\n ContainerCreateAccessEventBody,\n ContainerGrantPrincipalHead,\n ContainerKeyEpoch,\n ContainerKeyWrap,\n ContainerUserRecipientKey,\n} from \"@tearleads/crypto\";\nimport {\n computeContainerKekRecipientTargetHash,\n computeContainerKeyEpochHash,\n deriveContainerKekWrappingPublicKey,\n normalizeContainerAccessEventBody,\n} from \"@tearleads/crypto\";\nimport type { ContainerSystemSlot } from \"@tearleads/validators/containerSystemSlot\";\nimport type {\n ContainerMutationRequest,\n CreateOrganizationGroupRequest,\n} from \"@tearleads/validators/request\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport {\n buildContainerCreateBody,\n buildContainerCreateKeyEpoch,\n deriveContainerCreateManifest,\n resolveContainerKekEpochId,\n signContainerCreateEvent,\n} from \"../../../data/containers/shared/events\";\nimport { principalPolicyRef } from \"../../../data/containers/shared/principalPolicies\";\nimport {\n wrapContainerKeyToManagedPrincipal,\n wrapContainerKeyToRootUser,\n} from \"../../../data/containers/shared/projection\";\nimport type {\n ContainerCreatePlan,\n ContainerMutationAuthor,\n MaterializedContainerCreatePlan,\n} from \"../../../data/containers/shared/types\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n readCanonicalRecords,\n} from \"../../../data/keying/canonicalJson\";\n\nimport { principalHeadFromInitialGroupPolicy } from \"./initialGroupPolicy\";\n\nfunction buildRootContainerCreateBody(input: {\n author: ContainerMutationAuthor;\n managedPrincipalHead: ContainerGrantPrincipalHead | null;\n containerKeyEpochId: string;\n containerKeyPublicKey: string;\n metadataDocumentId: string;\n memberHead: ContainerGrantPrincipalHead | null;\n systemSlot: ContainerSystemSlot | null;\n}): ContainerCreateAccessEventBody {\n const baseBody = buildContainerCreateBody({\n systemSlot: input.systemSlot,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.containerKeyPublicKey,\n metadataDocumentId: input.metadataDocumentId,\n parentContainerId: null,\n parentManifestHash: null,\n });\n if (input.managedPrincipalHead) {\n return {\n ...baseBody,\n directGrants: [\n {\n accessLevel: \"admin\",\n subjectId: input.managedPrincipalHead.principalId,\n subjectType: input.managedPrincipalHead.principalType,\n },\n ...(input.memberHead\n ? [\n {\n accessLevel: \"read\" as const,\n subjectId: input.memberHead.principalId,\n subjectType: \"group\" as const,\n },\n ]\n : []),\n ],\n referencedPrincipalHeads: [\n input.managedPrincipalHead,\n ...(input.memberHead ? [input.memberHead] : []),\n ],\n };\n }\n\n return {\n ...baseBody,\n directGrants: [\n {\n accessLevel: \"admin\",\n subjectId: input.author.signerUserId,\n subjectType: \"user\",\n },\n ],\n };\n}\n\nfunction buildRootContainerCreateRequest(input: {\n body: ContainerCreateAccessEventBody;\n event: AccessEvent;\n keyEpoch: ContainerKeyEpoch;\n manifest: AccessManifest;\n manifestHash: string;\n principalPolicyRefs: ContainerMutationRequest[\"principalPolicyRefs\"];\n userRecipientKeys: readonly ContainerUserRecipientKey[];\n wraps: readonly ContainerKeyWrap[];\n}): ContainerMutationRequest {\n return {\n event: readCanonicalRecord(input.event, \"Container root create event\"),\n body: readCanonicalRecord(input.body, \"Container root create body\"),\n expectedManifestHash: input.manifestHash,\n manifest: readCanonicalRecord(\n input.manifest,\n \"Container root create manifest\",\n ),\n previousManifestRef: null,\n parentContainerPathRefs: [],\n principalPolicyRefs: input.principalPolicyRefs,\n keyEpoch: readCanonicalRecord(\n input.keyEpoch,\n \"Container root create key epoch\",\n ),\n predecessorBridge: null,\n keyring: null,\n wraps: readCanonicalRecords(input.wraps, \"Container root create wraps\"),\n userRecipientKeys: readCanonicalRecords(\n input.userRecipientKeys,\n \"Container root create user recipient keys\",\n ),\n };\n}\n\nasync function rootManagedPrincipalHead(\n group: CreateOrganizationGroupRequest | null,\n): Promise<ContainerGrantPrincipalHead | null> {\n return group\n ? principalHeadFromInitialGroupPolicy({\n principalId: group.groupId,\n policy: group.initialGroupPolicy,\n })\n : null;\n}\n\nasync function deriveRootCreateArtifacts(input: {\n author: ContainerMutationAuthor;\n body: ContainerCreateAccessEventBody;\n containerId: string;\n containerKeyEpochId: string;\n metadataDocumentId: string;\n signedAt: string | undefined;\n}) {\n if (!input.body.containerKeyPublicKey)\n throw new Error(\"Root container public key is missing\");\n const { event, eventHash } = await signContainerCreateEvent({\n author: input.author,\n body: input.body,\n containerId: input.containerId,\n eventId: crypto.randomUUID(),\n // A root container belongs to the creator's own organization.\n organizationId: input.author.organizationId,\n parentPath: [],\n signedAt: input.signedAt ?? new Date().toISOString(),\n });\n const { manifest, manifestHash, state } = await deriveContainerCreateManifest(\n {\n systemSlot: input.body.systemSlot,\n containerId: input.containerId,\n containerKeyEpochId: input.containerKeyEpochId,\n containerKeyPublicKey: input.body.containerKeyPublicKey,\n directGrants: input.body.directGrants,\n eventHash,\n metadataDocumentId: input.metadataDocumentId,\n // A root container belongs to the creator's own organization.\n organizationId: input.author.organizationId,\n parentContainerId: null,\n parentManifestHash: null,\n referencedPrincipalHeads: input.body.referencedPrincipalHeads,\n },\n );\n const keyEpoch = buildContainerCreateKeyEpoch({\n containerId: input.containerId,\n containerKeyEpochId: input.containerKeyEpochId,\n eventHash,\n manifestHash,\n parentContainerKeyEpochId: null,\n });\n return { event, eventHash, keyEpoch, manifest, manifestHash, state };\n}\n\nasync function wrapRootContainerKeyForPlan(input: {\n adminGroup: CreateOrganizationGroupRequest | null;\n containerKey: Uint8Array;\n containerKeyEpochId: string;\n manifestHash: string;\n managedPrincipalHead: ContainerGrantPrincipalHead | null;\n recipientEncapsulationPublicKey: Uint8Array;\n userId: string;\n}) {\n if (input.adminGroup && input.managedPrincipalHead) {\n return {\n ...(await wrapContainerKeyToManagedPrincipal({\n containerKey: input.containerKey,\n containerKeyEpochId: input.containerKeyEpochId,\n manifestHash: input.manifestHash,\n principalEncapsulationPublicKey:\n input.adminGroup.initialGroupPolicy.state.encapsulationPublicKey,\n principalHead: input.managedPrincipalHead,\n })),\n userRecipientKey: null,\n };\n }\n\n return wrapContainerKeyToRootUser({\n containerKey: input.containerKey,\n containerKeyEpochId: input.containerKeyEpochId,\n manifestHash: input.manifestHash,\n recipientEncapsulationPublicKey: input.recipientEncapsulationPublicKey,\n userId: input.userId,\n });\n}\n\nasync function wrapRootContainerRecipients(\n input: Parameters<typeof wrapRootContainerKeyForPlan>[0] & {\n memberGroup: CreateOrganizationGroupRequest | null;\n memberHead: ContainerGrantPrincipalHead | null;\n },\n) {\n const root = await wrapRootContainerKeyForPlan(input);\n const member =\n input.memberGroup && input.memberHead\n ? await wrapContainerKeyToManagedPrincipal({\n ...input,\n principalEncapsulationPublicKey:\n input.memberGroup.initialGroupPolicy.state.encapsulationPublicKey,\n principalHead: input.memberHead,\n })\n : null;\n return {\n recipientTargets: [\n root.recipientTarget,\n ...(member ? [member.recipientTarget] : []),\n ],\n wraps: [root.wrap, ...(member ? [member.wrap] : [])],\n userRecipientKeys: root.userRecipientKey ? [root.userRecipientKey] : [],\n };\n}\n\nfunction rootKeyMaterial(key?: Uint8Array): Uint8Array {\n const material = key ?? crypto.getRandomValues(new Uint8Array(32));\n if (material.byteLength !== 32)\n throw new Error(\"Container KEK material must be 32 bytes\");\n return material;\n}\n\nfunction normalizedRootCreateBody(\n input: Parameters<typeof buildRootContainerCreateBody>[0],\n): ContainerCreateAccessEventBody {\n const body = normalizeContainerAccessEventBody(\n readCanonicalJson(buildRootContainerCreateBody(input), \"Root create body\"),\n );\n if (body.eventType !== \"container.create\")\n throw new Error(\"Expected root creation body\");\n return body;\n}\n\nexport async function buildRootContainerCreatePlan(input: {\n adminGroup?: CreateOrganizationGroupRequest | undefined;\n memberGroup?: CreateOrganizationGroupRequest | undefined;\n systemSlot?: ContainerSystemSlot | undefined;\n author: ContainerMutationAuthor;\n containerId: string;\n containerKey?: Uint8Array | undefined;\n metadataDocumentId: string;\n recipientEncapsulationPublicKey: Uint8Array;\n signedAt?: string | undefined;\n}): Promise<MaterializedContainerCreatePlan> {\n const containerKey = rootKeyMaterial(input.containerKey);\n const adminGroup = input.adminGroup ?? null;\n const managedPrincipalHead = await rootManagedPrincipalHead(adminGroup);\n const memberHead = await rootManagedPrincipalHead(input.memberGroup ?? null);\n if (input.memberGroup && !adminGroup)\n throw new Error(\"Members root grant requires Admins authority\");\n const containerKeyEpochId = await resolveContainerKekEpochId({\n containerId: input.containerId,\n keyEpoch: 1,\n keyMaterial: containerKey,\n });\n const body = normalizedRootCreateBody({\n containerKeyPublicKey: await deriveContainerKekWrappingPublicKey({\n containerId: input.containerId,\n keyMaterial: containerKey,\n }),\n memberHead,\n systemSlot: input.systemSlot ?? null,\n author: input.author,\n containerKeyEpochId,\n managedPrincipalHead,\n metadataDocumentId: input.metadataDocumentId,\n });\n const { event, eventHash, keyEpoch, manifest, manifestHash, state } =\n await deriveRootCreateArtifacts({\n author: input.author,\n body,\n containerId: input.containerId,\n containerKeyEpochId,\n metadataDocumentId: input.metadataDocumentId,\n signedAt: input.signedAt,\n });\n const { recipientTargets, wraps, userRecipientKeys } =\n await wrapRootContainerRecipients({\n memberGroup: input.memberGroup ?? null,\n memberHead,\n adminGroup,\n containerKey,\n containerKeyEpochId,\n manifestHash,\n managedPrincipalHead,\n recipientEncapsulationPublicKey: input.recipientEncapsulationPublicKey,\n userId: input.author.signerUserId,\n });\n const keyTargetHash =\n await computeContainerKekRecipientTargetHash(recipientTargets);\n const keyEpochHash = await computeContainerKeyEpochHash(keyEpoch);\n const plan: ContainerCreatePlan = {\n body,\n containerId: input.containerId,\n containerKeyEpochId,\n event,\n eventHash,\n keyEpoch,\n keyEpochHash,\n keyTargetHash,\n manifest,\n manifestHash,\n metadataDocumentId: input.metadataDocumentId,\n parentContainerId: null,\n parentManifestHash: null,\n recipientTargets,\n request: buildRootContainerCreateRequest({\n body,\n event,\n keyEpoch,\n manifest,\n manifestHash,\n principalPolicyRefs: [managedPrincipalHead, memberHead]\n .filter((head) => head !== null)\n .map(principalPolicyRef),\n userRecipientKeys,\n wraps,\n }),\n state,\n wraps,\n };\n\n return { containerKey, plan };\n}\n\nexport function rootContainerWriterProjectionFromCreatePlan(\n plan: ContainerCreatePlan,\n): ContainerWriterProjectionResponse {\n return {\n policyEvidence: {\n organization: null,\n organizationPayloads: [],\n groups: [],\n },\n containerId: plan.containerId,\n organizationId: plan.state.organizationId,\n path: [\n {\n event: {\n event: readCanonicalRecord(plan.event, \"Container root event\"),\n body: readCanonicalRecord(plan.body, \"Container root body\"),\n eventHash: plan.eventHash,\n },\n manifest: readCanonicalRecord(plan.manifest, \"Container root manifest\"),\n manifestHash: plan.manifestHash,\n state: readCanonicalRecord(plan.state, \"Container root state\"),\n },\n ],\n containerKeks: [\n {\n containerId: plan.containerId,\n accessManifestHash: plan.manifestHash,\n containerKeyEpochId: plan.containerKeyEpochId,\n containerKeyEpoch: plan.keyEpoch.keyEpoch,\n keyEpoch: readCanonicalRecord(\n plan.keyEpoch,\n \"Container root key epoch\",\n ),\n keyEpochHash: plan.keyEpochHash,\n keyTargetHash: plan.keyTargetHash,\n containerManifestHistory: [],\n parentContainerKeyEpochId: null,\n keyring: null,\n recipientTargets: readCanonicalRecords(\n plan.recipientTargets,\n \"Container root recipient targets\",\n ),\n wraps: readCanonicalRecords(plan.wraps, \"Container root wraps\"),\n },\n ],\n };\n}\n"]}
@@ -1,5 +1,4 @@
1
1
  import { computePrincipalStateHash } from "../../../internal/crypto/index.js";
2
- import { readCanonicalRecord } from "../../../data/keying/canonicalJson.js";
3
2
  export async function principalHeadFromInitialGroupPolicy(input) {
4
3
  return {
5
4
  principalType: "group",
@@ -10,26 +9,4 @@ export async function principalHeadFromInitialGroupPolicy(input) {
10
9
  keyFingerprint: input.policy.state.keyFingerprint,
11
10
  };
12
11
  }
13
- export function principalPolicyRecordFromInitialGroupPolicy(input) {
14
- const { head } = input;
15
- return readCanonicalRecord({
16
- principalType: head.principalType,
17
- principalId: head.principalId,
18
- version: head.version,
19
- keyEpoch: head.keyEpoch,
20
- stateHash: head.stateHash,
21
- state: {
22
- ...input.policy.state,
23
- stateHash: head.stateHash,
24
- },
25
- projection: input.policy.projection,
26
- grants: input.policy.grants,
27
- checkpoint: {
28
- principalType: head.principalType,
29
- principalId: head.principalId,
30
- version: head.version,
31
- stateHash: head.stateHash,
32
- },
33
- }, "Initial managed principal policy");
34
- }
35
12
  //# sourceMappingURL=initialGroupPolicy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"initialGroupPolicy.js","sourceRoot":"","sources":["initialGroupPolicy.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAUzE,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,KAAqC;IAErC,OAAO;QACL,aAAa,EAAE,OAAO;QACtB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;QACnC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ;QACrC,SAAS,EAAE,MAAM,yBAAyB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;QAC9D,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc;KAClD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2CAA2C,CAAC,KAG3D;IACC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAEvB,OAAO,mBAAmB,CACxB;QACE,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE;YACL,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B;QACD,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;QACnC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;QAC3B,UAAU,EAAE;YACV,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B;KACF,EACD,kCAAkC,CACnC,CAAC;AACJ,CAAC","sourcesContent":["import type {\n ContainerGrantPrincipalHead,\n ReferencedPrincipalHead,\n} from \"@tearleads/crypto\";\nimport { computePrincipalStateHash } from \"@tearleads/crypto\";\nimport type { CreateOrganizationGroupRequest } from \"@tearleads/validators/request\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\n\ntype InitialManagedPrincipalPolicy =\n CreateOrganizationGroupRequest[\"initialGroupPolicy\"];\n\ninterface RootManagedPrincipalGrantInput {\n readonly principalId: string;\n readonly policy: InitialManagedPrincipalPolicy;\n}\n\nexport async function principalHeadFromInitialGroupPolicy(\n input: RootManagedPrincipalGrantInput,\n): Promise<ContainerGrantPrincipalHead> {\n return {\n principalType: \"group\",\n principalId: input.principalId,\n version: input.policy.state.version,\n keyEpoch: input.policy.state.keyEpoch,\n stateHash: await computePrincipalStateHash(input.policy.state),\n keyFingerprint: input.policy.state.keyFingerprint,\n };\n}\n\nexport function principalPolicyRecordFromInitialGroupPolicy(input: {\n readonly head: ReferencedPrincipalHead;\n readonly policy: InitialManagedPrincipalPolicy;\n}): Record<string, unknown> {\n const { head } = input;\n\n return readCanonicalRecord(\n {\n principalType: head.principalType,\n principalId: head.principalId,\n version: head.version,\n keyEpoch: head.keyEpoch,\n stateHash: head.stateHash,\n state: {\n ...input.policy.state,\n stateHash: head.stateHash,\n },\n projection: input.policy.projection,\n grants: input.policy.grants,\n checkpoint: {\n principalType: head.principalType,\n principalId: head.principalId,\n version: head.version,\n stateHash: head.stateHash,\n },\n },\n \"Initial managed principal policy\",\n );\n}\n"]}
1
+ {"version":3,"file":"initialGroupPolicy.js","sourceRoot":"","sources":["initialGroupPolicy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAW9D,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,KAAqC;IAErC,OAAO;QACL,aAAa,EAAE,OAAO;QACtB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;QACnC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ;QACrC,SAAS,EAAE,MAAM,yBAAyB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;QAC9D,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc;KAClD,CAAC;AACJ,CAAC","sourcesContent":["import type { ContainerGrantPrincipalHead } from \"@tearleads/crypto\";\nimport { computePrincipalStateHash } from \"@tearleads/crypto\";\nimport type { CreateOrganizationGroupRequest } from \"@tearleads/validators/request\";\n\ntype InitialManagedPrincipalPolicy =\n CreateOrganizationGroupRequest[\"initialGroupPolicy\"];\n\ninterface RootManagedPrincipalGrantInput {\n readonly principalId: string;\n readonly policy: InitialManagedPrincipalPolicy;\n}\n\nexport async function principalHeadFromInitialGroupPolicy(\n input: RootManagedPrincipalGrantInput,\n): Promise<ContainerGrantPrincipalHead> {\n return {\n principalType: \"group\",\n principalId: input.principalId,\n version: input.policy.state.version,\n keyEpoch: input.policy.state.keyEpoch,\n stateHash: await computePrincipalStateHash(input.policy.state),\n keyFingerprint: input.policy.state.keyFingerprint,\n };\n}\n"]}
@@ -7,14 +7,8 @@ function principalIdentityKey(principalType, principalId) {
7
7
  function requestedRepairPrincipalIdentities(plan) {
8
8
  const identities = new Set();
9
9
  for (const rekey of plan.request.containerRekeys ?? []) {
10
- for (const policy of rekey.principalPolicies) {
11
- const principalType = Reflect.get(policy, "principalType");
12
- const principalId = Reflect.get(policy, "principalId");
13
- if ((principalType === "group" || principalType === "organization") &&
14
- typeof principalId === "string" &&
15
- principalId.length > 0) {
16
- identities.add(principalIdentityKey(principalType, principalId));
17
- }
10
+ for (const ref of rekey.principalPolicyRefs) {
11
+ identities.add(principalIdentityKey(ref.principalType, ref.principalId));
18
12
  }
19
13
  }
20
14
  return identities;
@@ -1 +1 @@
1
- {"version":3,"file":"syncPolicyRepair.js","sourceRoot":"","sources":["syncPolicyRepair.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAC;AAO3F,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAI7E,SAAS,oBAAoB,CAC3B,aAAmC,EACnC,WAAmB;IAEnB,OAAO,GAAG,aAAa,IAAI,WAAW,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,kCAAkC,CACzC,IAAsB;IAEtB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QACvD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC7C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;YAC3D,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;YACvD,IACE,CAAC,aAAa,KAAK,OAAO,IAAI,aAAa,KAAK,cAAc,CAAC;gBAC/D,OAAO,WAAW,KAAK,QAAQ;gBAC/B,WAAW,CAAC,MAAM,GAAG,CAAC,EACtB,CAAC;gBACD,UAAU,CAAC,GAAG,CAAC,oBAAoB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,4CAA4C,CAAC,KAGrD;IACC,MAAM,SAAS,GAAG,kCAAkC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;QAC5C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,oBAAoB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,8DAA8D,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,KAKrD;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,CAAC,+BAA+B,EAAE,gBAAgB,CAAC;IACxE,IACE,CAAC,+BAA+B,CAAC,KAAK,CAAC,OAAO,CAAC;QAC/C,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC;QACvD,CAAC,KAAK;QACN,KAAK,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,OAAO;QACR,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK,EAChC,CAAC;QACD,OAAO;IACT,CAAC;IAED,4CAA4C,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,4BAA4B,CAAC;QACjC,KAAK;QACL,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;QACtE,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc;QACzC,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport type { ReferencedPrincipalStateResponse } from \"@tearleads/validators/response\";\nimport { isRetryableDocumentSyncConflict } from \"../../../data/documents/shared/responses\";\nimport type {\n DocumentSyncPlan,\n DocumentSyncSubmitFailure,\n} from \"../../../data/documents/shared/types\";\nimport type { ReferencedPrincipalPolicyWarmer } from \"../../../data/keyingProjectionVerification\";\n\nimport { recoverPrincipalPolicyRepair } from \"../../principals/policyRepair\";\n\ntype ManagedPrincipalType = \"group\" | \"organization\";\n\nfunction principalIdentityKey(\n principalType: ManagedPrincipalType,\n principalId: string,\n): string {\n return `${principalType}:${principalId}`;\n}\n\nfunction requestedRepairPrincipalIdentities(\n plan: DocumentSyncPlan,\n): Set<string> {\n const identities = new Set<string>();\n for (const rekey of plan.request.containerRekeys ?? []) {\n for (const policy of rekey.principalPolicies) {\n const principalType = Reflect.get(policy, \"principalType\");\n const principalId = Reflect.get(policy, \"principalId\");\n if (\n (principalType === \"group\" || principalType === \"organization\") &&\n typeof principalId === \"string\" &&\n principalId.length > 0\n ) {\n identities.add(principalIdentityKey(principalType, principalId));\n }\n }\n }\n return identities;\n}\n\nfunction assertDocumentSyncPolicyRepairHeadsRequested(input: {\n readonly heads: readonly ReferencedPrincipalStateResponse[];\n readonly plan: DocumentSyncPlan;\n}): void {\n const requested = requestedRepairPrincipalIdentities(input.plan);\n for (const head of input.heads) {\n const { principalId, principalType } = head;\n if (!requested.has(principalIdentityKey(principalType, principalId))) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Document sync policy repair head principal was not requested\",\n );\n }\n }\n}\n\nexport async function recoverDocumentSyncPolicyRepair(input: {\n failure: DocumentSyncSubmitFailure;\n plan: DocumentSyncPlan;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<void> {\n const heads = input.failure.stalePrincipalHeads;\n const resolve = input.warmReferencedPrincipalPolicies?.resolveReference;\n if (\n !isRetryableDocumentSyncConflict(input.failure) ||\n (input.plan.request.containerRekeys?.length ?? 0) === 0 ||\n !heads ||\n heads.length === 0 ||\n !resolve ||\n input.stillCurrent?.() === false\n ) {\n return;\n }\n\n assertDocumentSyncPolicyRepairHeadsRequested({ heads, plan: input.plan });\n await recoverPrincipalPolicyRepair({\n heads,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n organizationId: input.plan.organizationId,\n stillCurrent: input.stillCurrent,\n });\n}\n"]}
1
+ {"version":3,"file":"syncPolicyRepair.js","sourceRoot":"","sources":["syncPolicyRepair.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAC;AAO3F,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAI7E,SAAS,oBAAoB,CAC3B,aAAmC,EACnC,WAAmB;IAEnB,OAAO,GAAG,aAAa,IAAI,WAAW,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,kCAAkC,CACzC,IAAsB;IAEtB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QACvD,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;YAC5C,UAAU,CAAC,GAAG,CAAC,oBAAoB,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,4CAA4C,CAAC,KAGrD;IACC,MAAM,SAAS,GAAG,kCAAkC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;QAC5C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,oBAAoB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,8DAA8D,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,KAKrD;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,CAAC,+BAA+B,EAAE,gBAAgB,CAAC;IACxE,IACE,CAAC,+BAA+B,CAAC,KAAK,CAAC,OAAO,CAAC;QAC/C,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC;QACvD,CAAC,KAAK;QACN,KAAK,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,OAAO;QACR,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK,EAChC,CAAC;QACD,OAAO;IACT,CAAC;IAED,4CAA4C,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,4BAA4B,CAAC;QACjC,KAAK;QACL,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;QACtE,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc;QACzC,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport type { ReferencedPrincipalStateResponse } from \"@tearleads/validators/response\";\nimport { isRetryableDocumentSyncConflict } from \"../../../data/documents/shared/responses\";\nimport type {\n DocumentSyncPlan,\n DocumentSyncSubmitFailure,\n} from \"../../../data/documents/shared/types\";\nimport type { ReferencedPrincipalPolicyWarmer } from \"../../../data/keyingProjectionVerification\";\n\nimport { recoverPrincipalPolicyRepair } from \"../../principals/policyRepair\";\n\ntype ManagedPrincipalType = \"group\" | \"organization\";\n\nfunction principalIdentityKey(\n principalType: ManagedPrincipalType,\n principalId: string,\n): string {\n return `${principalType}:${principalId}`;\n}\n\nfunction requestedRepairPrincipalIdentities(\n plan: DocumentSyncPlan,\n): Set<string> {\n const identities = new Set<string>();\n for (const rekey of plan.request.containerRekeys ?? []) {\n for (const ref of rekey.principalPolicyRefs) {\n identities.add(principalIdentityKey(ref.principalType, ref.principalId));\n }\n }\n return identities;\n}\n\nfunction assertDocumentSyncPolicyRepairHeadsRequested(input: {\n readonly heads: readonly ReferencedPrincipalStateResponse[];\n readonly plan: DocumentSyncPlan;\n}): void {\n const requested = requestedRepairPrincipalIdentities(input.plan);\n for (const head of input.heads) {\n const { principalId, principalType } = head;\n if (!requested.has(principalIdentityKey(principalType, principalId))) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Document sync policy repair head principal was not requested\",\n );\n }\n }\n}\n\nexport async function recoverDocumentSyncPolicyRepair(input: {\n failure: DocumentSyncSubmitFailure;\n plan: DocumentSyncPlan;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<void> {\n const heads = input.failure.stalePrincipalHeads;\n const resolve = input.warmReferencedPrincipalPolicies?.resolveReference;\n if (\n !isRetryableDocumentSyncConflict(input.failure) ||\n (input.plan.request.containerRekeys?.length ?? 0) === 0 ||\n !heads ||\n heads.length === 0 ||\n !resolve ||\n input.stillCurrent?.() === false\n ) {\n return;\n }\n\n assertDocumentSyncPolicyRepairHeadsRequested({ heads, plan: input.plan });\n await recoverPrincipalPolicyRepair({\n heads,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n organizationId: input.plan.organizationId,\n stillCurrent: input.stillCurrent,\n });\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { assertProjectionVerificationCurrent } from "../../../data/keyingProjectionVerification/types.js";
2
+ import { isPrincipalHistoryStageChangedError } from "../../../data/persistence/principalHistory/principalHistoryStagePersistence.js";
3
+ /**
4
+ * An acknowledged publication may supersede the exact head a queued recovery
5
+ * is staging (`persistAcknowledgedPrincipalCurrents` writes outside the
6
+ * recovery queue), and the recovery then loses its progress CAS. Resume once,
7
+ * in the same queue turn, from the stage the publication left, instead of
8
+ * failing the operation that asked for the policy. A second loss propagates.
9
+ */
10
+ export async function resumeAfterSupersededStage(attempt, stillCurrent) {
11
+ try {
12
+ return await attempt();
13
+ }
14
+ catch (error) {
15
+ if (!isPrincipalHistoryStageChangedError(error))
16
+ throw error;
17
+ assertProjectionVerificationCurrent(stillCurrent);
18
+ return attempt();
19
+ }
20
+ }
21
+ //# sourceMappingURL=supersededStageResume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supersededStageResume.js","sourceRoot":"","sources":["supersededStageResume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,kDAAkD,CAAC;AACvG,OAAO,EAAE,mCAAmC,EAAE,MAAM,6EAA6E,CAAC;AAElI;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAyB,EACzB,YAA2B;IAE3B,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,mCAAmC,CAAC,KAAK,CAAC;YAAE,MAAM,KAAK,CAAC;QAC7D,mCAAmC,CAAC,YAAY,CAAC,CAAC;QAClD,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC","sourcesContent":["import { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { isPrincipalHistoryStageChangedError } from \"../../../data/persistence/principalHistory/principalHistoryStagePersistence\";\n\n/**\n * An acknowledged publication may supersede the exact head a queued recovery\n * is staging (`persistAcknowledgedPrincipalCurrents` writes outside the\n * recovery queue), and the recovery then loses its progress CAS. Resume once,\n * in the same queue turn, from the stage the publication left, instead of\n * failing the operation that asked for the policy. A second loss propagates.\n */\nexport async function resumeAfterSupersededStage<T>(\n attempt: () => Promise<T>,\n stillCurrent: () => boolean,\n): Promise<T> {\n try {\n return await attempt();\n } catch (error) {\n if (!isPrincipalHistoryStageChangedError(error)) throw error;\n assertProjectionVerificationCurrent(stillCurrent);\n return attempt();\n }\n}\n"]}
@@ -8,6 +8,7 @@ import { PrincipalHistoryRecoveryRaceError, PrincipalPolicyHistoryReadError, } f
8
8
  import { apiPrincipalPolicyPageReader, } from "./principalPolicyHistoryReader.js";
9
9
  import { createPrincipalCurrentRecoveryBatch } from "./recoveryOperation/principalCurrentRecoveryBatch.js";
10
10
  import { recoverWithPrincipalLocalPreference } from "./recoveryOperation/principalRecoveryLocalPreference.js";
11
+ import { resumeAfterSupersededStage } from "./recoveryOperation/supersededStageResume.js";
11
12
  /** Keep the private recovery key inside its runtime lease while resolving cited evidence. */
12
13
  export function createRuntimePrincipalPolicyResolver(runtime, options = {}) {
13
14
  const resolve = createRuntimePrincipalPolicyCurrentResolver(runtime);
@@ -15,6 +16,16 @@ export function createRuntimePrincipalPolicyResolver(runtime, options = {}) {
15
16
  ? (input) => resolve({ ...input, preferLocalCurrent: options.preferLocalCurrent })
16
17
  : undefined;
17
18
  }
19
+ /** One recovery attempt for a resolver request through the operation's batch. */
20
+ function recoverPolicyCurrent(batch, options, input) {
21
+ return input.reference
22
+ ? recoverWithPrincipalLocalPreference(batch.recover, {
23
+ ...options,
24
+ reference: input.reference,
25
+ historyPage: input.historyPage,
26
+ }, input.preferLocalCurrent === true || input.preferLocalHistory === true, input.preferLocalHistory === true)
27
+ : batch.discover(options);
28
+ }
18
29
  /** Keep current artifacts with their verified evidence and private runtime lifetime. */
19
30
  export function createRuntimePrincipalPolicyCurrentResolver(runtime) {
20
31
  const lease = readPrincipalHistoryProtection(runtime);
@@ -52,15 +63,7 @@ export function createRuntimePrincipalPolicyCurrentResolver(runtime) {
52
63
  resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,
53
64
  stillCurrent,
54
65
  };
55
- const batch = recoverFor(input.recoveryBatch);
56
- const result = input.reference
57
- ? await recoverWithPrincipalLocalPreference(batch.recover, {
58
- ...options,
59
- reference: input.reference,
60
- historyPage: input.historyPage,
61
- }, input.preferLocalCurrent === true ||
62
- input.preferLocalHistory === true, input.preferLocalHistory === true)
63
- : await batch.discover(options);
66
+ const result = await resumeAfterSupersededStage(() => recoverPolicyCurrent(recoverFor(input.recoveryBatch), options, input), stillCurrent);
64
67
  // Reused evidence stays bound to every producer lifetime.
65
68
  const resultCurrent = () => stillCurrent() && result.stillCurrent();
66
69
  assertProjectionVerificationCurrent(resultCurrent);