@tearleads/client-sdk 0.1.48 → 0.1.50

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 (46) hide show
  1. package/client/organizations/currentPrincipalMutations.js +36 -17
  2. package/client/organizations/currentPrincipalMutations.js.map +1 -1
  3. package/client/organizations/principalContainerMutations.js +1 -0
  4. package/client/organizations/principalContainerMutations.js.map +1 -1
  5. package/client/organizations/principalMutations.js +2 -2
  6. package/client/organizations/principalMutations.js.map +1 -1
  7. package/data/principals/principalMutationJournalShape.js +6 -0
  8. package/data/principals/principalMutationJournalShape.js.map +1 -1
  9. package/internal/api-client/ApiClient.d.ts +122 -0
  10. package/internal/api-client/principalPolicyRequests.d.ts +122 -0
  11. package/internal/validators/operation/principals.d.ts +1026 -206
  12. package/internal/validators/request/principal.d.ts +332 -0
  13. package/internal/validators/request/principal.js +1 -0
  14. package/internal/validators/request/principal.js.map +1 -1
  15. package/internal/validators/response/principal.d.ts +488 -0
  16. package/internal/validators/response/principal.js +1 -0
  17. package/internal/validators/response/principal.js.map +1 -1
  18. package/package.json +1 -1
  19. package/workflows/containers/child/rekeyProjection.d.ts +6 -1
  20. package/workflows/containers/child/rekeyProjection.js +41 -0
  21. package/workflows/containers/child/rekeyProjection.js.map +1 -1
  22. package/workflows/organizations/authoredPrincipalPolicyWarmer.js +25 -0
  23. package/workflows/organizations/authoredPrincipalPolicyWarmer.js.map +1 -0
  24. package/workflows/organizations/commitCurrentGroupPolicyMutation.js +101 -34
  25. package/workflows/organizations/commitCurrentGroupPolicyMutation.js.map +1 -1
  26. package/workflows/organizations/groupPolicyMutationContext.d.ts +5 -52
  27. package/workflows/organizations/groupPolicyMutationContext.js +2 -65
  28. package/workflows/organizations/groupPolicyMutationContext.js.map +1 -1
  29. package/workflows/organizations/precedingPrincipalRematerialization.js +31 -0
  30. package/workflows/organizations/precedingPrincipalRematerialization.js.map +1 -0
  31. package/workflows/organizations/principalContainerRematerialization.js +39 -7
  32. package/workflows/organizations/principalContainerRematerialization.js.map +1 -1
  33. package/workflows/organizations/principalContainerRematerializationPlanning.js +6 -1
  34. package/workflows/organizations/principalContainerRematerializationPlanning.js.map +1 -1
  35. package/workflows/organizations/principalContainerRematerializationTargets.js +0 -11
  36. package/workflows/organizations/principalContainerRematerializationTargets.js.map +1 -1
  37. package/workflows/organizations/principalMutationReceipt.js +6 -0
  38. package/workflows/organizations/principalMutationReceipt.js.map +1 -1
  39. package/workflows/organizations/principalPolicyApi.d.ts +33 -0
  40. package/workflows/organizations/principalPolicyApi.js +2 -0
  41. package/workflows/organizations/principalPolicyApi.js.map +1 -0
  42. package/workflows/organizations/runtimeCurrentGroupMutation.js +36 -19
  43. package/workflows/organizations/runtimeCurrentGroupMutation.js.map +1 -1
  44. package/workflows/organizations/submitGroupPolicyCommit.d.ts +22 -0
  45. package/workflows/organizations/submitGroupPolicyCommit.js +71 -0
  46. package/workflows/organizations/submitGroupPolicyCommit.js.map +1 -0
@@ -7,12 +7,13 @@ import { createProjectionUserKeyResolver } from "../../data/keyingProjectionVeri
7
7
  import { rebaseOnDeepestAncestor } from "../containers/child/carriedDescendantRekeys.js";
8
8
  import { scheduleHeldDescendantRecitations } from "../containers/child/recite.js";
9
9
  import { buildMaterializedContainerRekeyPlan } from "../containers/child/rekey.js";
10
- import { isSpeculativeContainerWriterProjection } from "../containers/child/rekeyProjection.js";
10
+ import { containerWriterProjectionFromRotationPlan, containerWriterProjectionFromSharePlan, isSpeculativeContainerWriterProjection, } from "../containers/child/rekeyProjection.js";
11
11
  import { selectReplacementPrincipalPolicyReferences } from "../containers/child/replacementPrincipalPolicyReferences.js";
12
12
  import { buildMaterializedContainerRevokePlan } from "../containers/child/revoke.js";
13
13
  import { buildMaterializedContainerSharePlan } from "../containers/child/shareMaterialization.js";
14
+ import { withPrecedingRematerialization } from "./precedingPrincipalRematerialization.js";
14
15
  import { addPlan, carryLevel, staleLevelsAbove, } from "./principalContainerRematerializationPlanning.js";
15
- import { loadRematerializationTargets, loadServedProjection, rotatedPath, seededPrincipalPolicyCache, } from "./principalContainerRematerializationTargets.js";
16
+ import { loadRematerializationTargets, loadServedProjection, seededPrincipalPolicyCache, } from "./principalContainerRematerializationTargets.js";
16
17
  function matchingGroupGrant(input) {
17
18
  return (input.directGrants.find((grant) => grant.subjectType === "group" && grant.subjectId === input.groupId) ?? null);
18
19
  }
@@ -166,10 +167,20 @@ async function planRematerializationTarget(batch, target) {
166
167
  rematerialization,
167
168
  resolveProjectionUserKey: batch.resolveProjectionUserKey,
168
169
  });
170
+ const nextProjection = "keyring" in planned.plan
171
+ ? await containerWriterProjectionFromRotationPlan({
172
+ plan: planned.plan,
173
+ previousProjection,
174
+ })
175
+ : await containerWriterProjectionFromSharePlan({
176
+ plan: planned.plan,
177
+ previousProjection,
178
+ });
169
179
  addPlan(batch, {
170
180
  carried: false,
171
181
  planned,
172
- rotated: await rotatedPath({ planned, previousProjection }),
182
+ rotated: "keyring" in planned.plan ? nextProjection : null,
183
+ nextProjection,
173
184
  });
174
185
  }
175
186
  /**
@@ -179,6 +190,7 @@ async function planRematerializationTarget(batch, target) {
179
190
  * re-planned there rather than rotated twice.
180
191
  */
181
192
  async function buildPrincipalContainerRematerializationPlans(input, carriedContainerIds = []) {
193
+ input = withPrecedingRematerialization(input);
182
194
  if (input.revokedContainerId &&
183
195
  !input.grants.some((grant) => grant.containerId === input.revokedContainerId)) {
184
196
  throw new Error("Revoked container is not granted to the group");
@@ -189,11 +201,16 @@ async function buildPrincipalContainerRematerializationPlans(input, carriedConta
189
201
  grants: input.grants,
190
202
  });
191
203
  const batch = {
192
- knownContainerKeks: new Map(),
204
+ knownContainerKeks: new Map(input.preceding?.knownContainerKeks),
193
205
  plans: [],
194
206
  // A rotation planned above cites the group at the head this batch commits,
195
207
  // which no store holds yet; the cache is what lets a rebased path verify.
196
- principalPolicyCache: seededPrincipalPolicyCache(input.nextPolicy),
208
+ principalPolicyCache: new Map([
209
+ ...(input.preceding?.policies ?? []).flatMap((policy) => [
210
+ ...seededPrincipalPolicyCache(policy),
211
+ ]),
212
+ ...seededPrincipalPolicyCache(input.nextPolicy),
213
+ ]),
197
214
  rematerialization: input,
198
215
  resolveProjectionUserKey: createProjectionUserKeyResolver({
199
216
  resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,
@@ -203,7 +220,18 @@ async function buildPrincipalContainerRematerializationPlans(input, carriedConta
203
220
  for (const target of targets) {
204
221
  await planRematerializationTarget(batch, target);
205
222
  }
206
- return { entries: batch.plans, retiredContainerIds };
223
+ return {
224
+ entries: batch.plans,
225
+ retiredContainerIds,
226
+ preceding: {
227
+ policies: [...(input.preceding?.policies ?? []), input.nextPolicy],
228
+ projections: [
229
+ ...(input.preceding?.projections ?? []),
230
+ ...batch.plans.flatMap((entry) => entry.nextProjection ? [entry.nextProjection] : []),
231
+ ],
232
+ knownContainerKeks: batch.knownContainerKeks,
233
+ },
234
+ };
207
235
  }
208
236
  /**
209
237
  * The server names a level it found pinned to a retired epoch. A batch answers
@@ -222,9 +250,12 @@ function assertNamedContainersRotated(plans, requiredContainerIds) {
222
250
  }
223
251
  }
224
252
  export async function preparePrincipalContainerRematerializationBatch(input) {
225
- let { entries, retiredContainerIds } = await buildPrincipalContainerRematerializationPlans(input);
253
+ let { entries, retiredContainerIds, preceding } = await buildPrincipalContainerRematerializationPlans(input);
226
254
  const requests = () => entries.map((entry) => entry.planned.plan.request);
227
255
  return {
256
+ get preceding() {
257
+ return preceding;
258
+ },
228
259
  get retiredContainerIds() {
229
260
  return retiredContainerIds;
230
261
  },
@@ -241,6 +272,7 @@ export async function preparePrincipalContainerRematerializationBatch(input) {
241
272
  assertNamedContainersRotated(replanned.entries, requiredContainerIds);
242
273
  entries = replanned.entries;
243
274
  retiredContainerIds = replanned.retiredContainerIds;
275
+ preceding = replanned.preceding;
244
276
  return requests();
245
277
  },
246
278
  acknowledge: async (responses, stillCurrent) => {
@@ -1 +1 @@
1
- {"version":3,"file":"principalContainerRematerialization.js","sourceRoot":"","sources":["principalContainerRematerialization.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,iDAAiD,CAAC;AAEjG,OAAO,EAAE,iCAAiC,EAAE,MAAM,sDAAsD,CAAC;AACzG,OAAO,EACL,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAEL,+BAA+B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,+BAA+B,EAAE,MAAM,yDAAyD,CAAC;AAC1G,OAAO,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAC;AACtF,OAAO,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,mCAAmC,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,sCAAsC,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,EAAE,0CAA0C,EAAE,MAAM,0DAA0D,CAAC;AACtH,OAAO,EAAE,oCAAoC,EAAE,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAAE,mCAAmC,EAAE,MAAM,0CAA0C,CAAC;AAC/F,OAAO,EACL,OAAO,EAEP,UAAU,EAEV,gBAAgB,GACjB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EAIpB,WAAW,EACX,0BAA0B,GAC3B,MAAM,8CAA8C,CAAC;AAEtD,SAAS,kBAAkB,CAAC,KAG3B;IACC,OAAO,CACL,KAAK,CAAC,YAAY,CAAC,IAAI,CACrB,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,WAAW,KAAK,OAAO,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,OAAO,CACrE,IAAI,IAAI,CACV,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,KAKhC;IACC,OAAO,CACL,KAAK,CAAC,wBAAwB,CAAC,IAAI,CACjC,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,aAAa,KAAK,OAAO,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,CAAC,OAAO,CACvE,EAAE,QAAQ,IAAI,IAAI,CACpB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,2BAA2B,CACxC,KAA+C,EAC/C,QAAiC,EACjC,UAA6C,EAC7C,oBAA0C;IAE1C,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,+BAA+B,CAAC;QACpC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,8BAA8B,EAC5B,CAAC,sCAAsC,CAAC,UAAU,CAAC;QACrD,oBAAoB;QACpB,UAAU;QACV,cAAc,EAAE,+BAA+B,CAAC;YAC9C,0BAA0B,EAAE,KAAK,CAAC,0BAA0B;SAC7D,CAAC;QACF,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;KACvE,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,kBAAkB,CAC9B,yBAAyB,CAAC,UAAU,CAAC,CAAC,QAAQ,CAC/C,CAAC;IACF,MAAM,KAAK,GAAG,kBAAkB,CAAC;QAC/B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC,CAAC;IACH,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;QACxD,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAC5C,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,CAC9D,CAAC;QACF,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,CAAC,WAAW,4CAA4C,CAC9E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,kBAAkB,GAAG,uBAAuB,CAAC;QACjD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;KACzD,CAAC,CAAC;IACH,IAAI,KAAK,IAAI,kBAAkB,KAAK,IAAI,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,CAAC,WAAW,iCAAiC,CACnE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,6CAA6C,CACjE,KAA+C;IAE/C,OAAO,CACL,MAAM,6CAA6C,CAAC,KAAK,CAAC,CAC3D,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACvD,CAAC;AAuBD,SAAS,oBAAoB,CAC3B,OAAmD;IAEnD,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,4CAA4C,CAAC,KAY3D;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC3B,MAAM,iBAAiB,GAAG;QACxB,GAAG,KAAK,CAAC,iBAAiB;QAC1B,UAAU,EAAE,MAAM,0CAA0C,CAAC;YAC3D,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAC,UAAU;YAC1C,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;YAChD,+BAA+B,EAC7B,KAAK,CAAC,iBAAiB,CAAC,+BAA+B;SAC1D,CAAC;KACH,CAAC;IACF,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAC7C,MAAM,2BAA2B,CAC/B,iBAAiB,EACjB,QAAQ,EACR,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,oBAAoB,CAC3B,CAAC;IACJ,MAAM,SAAS,GAAG,iBAAiB,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CACxD,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,CAC9D,CAAC;IACF,MAAM,MAAM,GAAG;QACb,GAAG,iBAAiB,CAAC,MAAM;QAC3B,cAAc,EAAE,UAAU,CAAC,cAAc;KAC1C,CAAC;IACF,MAAM,WAAW,GAAG;QAClB,MAAM;QACN,OAAO,EAAE,iBAAiB,CAAC,OAAO;QAClC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,yEAAyE;QACzE,yEAAyE;QACzE,iEAAiE;QACjE,8BAA8B,EAC5B,CAAC,sCAAsC,CAAC,UAAU,CAAC;QACrD,kBAAkB,EAAE,UAAU;QAC9B,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;QAChD,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;QACxD,YAAY,EAAE,iBAAiB,CAAC,YAAY;QAC5C,eAAe,EAAE,iBAAiB,CAAC,eAAe;QAClD,+BAA+B,EAC7B,iBAAiB,CAAC,+BAA+B;KACpD,CAAC;IACF,IAAI,QAAQ,CAAC,WAAW,KAAK,iBAAiB,CAAC,kBAAkB,EAAE,CAAC;QAClE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,CAAC,WAAW,2CAA2C,CAC7E,CAAC;QACJ,CAAC;QACD,OAAO,oCAAoC,CAAC;YAC1C,GAAG,WAAW;YACd,0BAA0B,EAAE,iBAAiB,CAAC,UAAU;YACxD,cAAc,EAAE;gBACd,SAAS,EAAE,iBAAiB,CAAC,OAAO;gBACpC,WAAW,EAAE,OAAO;aACrB;SACF,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,WAAW,EAAE,CAAC;QAC3D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,CAAC,WAAW,0CAA0C,CAC5E,CAAC;QACJ,CAAC;QACD,OAAO,mCAAmC,CAAC;YACzC,GAAG,WAAW;YACd,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,SAAS,EAAE;gBACT,eAAe,EAAE,iBAAiB,CAAC,UAAU;gBAC7C,SAAS,EAAE,iBAAiB,CAAC,OAAO;gBACpC,WAAW,EAAE,OAAO;aACrB;SACF,CAAC,CAAC;IACL,CAAC;IACD,IAAI,kBAAkB,KAAK,iBAAiB,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QACjE,OAAO,mCAAmC,CAAC;YACzC,GAAG,WAAW;YACd,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,SAAS,EAAE;gBACT,eAAe,EAAE,iBAAiB,CAAC,UAAU;gBAC7C,SAAS,EAAE,iBAAiB,CAAC,OAAO;gBACpC,WAAW,EAAE,OAAO;aACrB;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,mCAAmC,CAAC;QACzC,GAAG,WAAW;QACd,0BAA0B,EAAE,iBAAiB,CAAC,UAAU;KACzD,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,2BAA2B,CACxC,KAAoB,EACpB,MAA+B;IAE/B,MAAM,EAAE,iBAAiB,EAAE,GAAG,KAAK,CAAC;IACpC,IAAI,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,OAAO;QACnB,CAAC,CAAC,gBAAgB,CACd,OAAO,CAAC,UAAU,EAClB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,EAAE,CACzD;QACH,CAAC,CAAC,EAAE,CAAC;IACP,KAAK,MAAM,WAAW,IAAI,KAAK,EAAE,CAAC;QAChC,MAAM,UAAU,CACd,KAAK,EACL,MAAM,oBAAoB,CAAC,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,CACrE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,gEAAgE;IAChE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,kBAAkB,GAAG,OAAO,EAAE,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC;IACpE,MAAM,OAAO,GAAG,MAAM,4CAA4C,CAAC;QACjE,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;QAChD,UAAU,EAAE,kBAAkB;QAC9B,iBAAiB;QACjB,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;KACzD,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,KAAK;QACd,OAAO;QACP,OAAO,EAAE,MAAM,WAAW,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;KAC5D,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,6CAA6C,CAC1D,KAA+C,EAC/C,sBAAyC,EAAE;IAK3C,IACE,KAAK,CAAC,kBAAkB;QACxB,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAChB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,kBAAkB,CAC1D,EACD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,4BAA4B,CAAC;QAC1E,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,mBAAmB;QACnB,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,GAAkB;QAC3B,kBAAkB,EAAE,IAAI,GAAG,EAAE;QAC7B,KAAK,EAAE,EAAE;QACT,2EAA2E;QAC3E,0EAA0E;QAC1E,oBAAoB,EAAE,0BAA0B,CAAC,KAAK,CAAC,UAAU,CAAC;QAClE,iBAAiB,EAAE,KAAK;QACxB,wBAAwB,EAAE,+BAA+B,CAAC;YACxD,0BAA0B,EAAE,KAAK,CAAC,0BAA0B;SAC7D,CAAC;QACF,YAAY,EAAE,EAAE;KACjB,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,2BAA2B,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE,mBAAmB,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,4BAA4B,CACnC,KAA0C,EAC1C,oBAAuC;IAEvC,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CACtB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CACtD,CACF,CAAC;IACF,MAAM,SAAS,GAAG,oBAAoB;SACnC,KAAK,CAAC,CAAC,EAAE,6BAA6B,CAAC;SACvC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IACvD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,aAAa,SAAS,+CAA+C,CACtE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+CAA+C,CACnE,KAA+C;IAE/C,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAClC,MAAM,6CAA6C,CAAC,KAAK,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1E,OAAO;QACL,IAAI,mBAAmB;YACrB,OAAO,mBAAmB,CAAC;QAC7B,CAAC;QACD,IAAI,KAAK;YACP,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,QAAQ;YACV,OAAO,QAAQ,EAAE,CAAC;QACpB,CAAC;QACD,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE;YACpC,oEAAoE;YACpE,wEAAwE;YACxE,MAAM,SAAS,GAAG,MAAM,6CAA6C,CACnE,KAAK,EACL,oBAAoB,CACrB,CAAC;YACF,4BAA4B,CAAC,SAAS,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;YACtE,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;YAC5B,mBAAmB,GAAG,SAAS,CAAC,mBAAmB,CAAC;YACpD,OAAO,QAAQ,EAAE,CAAC;QACpB,CAAC;QACD,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE;YAC7C,MAAM,SAAS,GAAG,GAAG,EAAE,CACrB,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,KAAK,IAAI,YAAY,EAAE,EAAE,KAAK,KAAK,CAAC;YACjE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAC1E,MAAM,YAAY,GAAG,MAAM,iCAAiC,CAAC;gBAC3D,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,KAAK;gBACZ,SAAS;gBACT,YAAY,EAAE,SAAS;aACxB,CAAC,CAAC;YACH,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE;gBAAE,OAAO;YAC1C,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAGhC,CAAC;YACJ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC;gBACjD,MAAM,KAAK,GAAG,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;gBAC5D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjB,mBAAmB,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;YACjD,CAAC;YACD,KAAK,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,IAAI,mBAAmB,EAAE,CAAC;gBACtE,IAAI,CAAC;oBACH,8BAA8B,CAAC;wBAC7B,cAAc;wBACd,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,KAAK,EAAE,EAAE;wBACT,QAAQ,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;qBAC7B,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,oEAAoE;oBACpE,SAAS;gBACX,CAAC;gBACD,iCAAiC,CAAC;oBAChC,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,MAAM,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE;oBAC3C,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,KAAK,EAAE,iBAAiB;oBACxB,YAAY,EAAE,KAAK,CAAC,sBAAsB,IAAI,SAAS;oBACvD,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;iBACrD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n ContainerDirectGrant,\n PrincipalContainerGrant,\n} from \"@tearleads/crypto\";\nimport type { ContainerMutationRequest } from \"@tearleads/validators/request\";\nimport type {\n ContainerMutationResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { MAX_ROTATION_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport { rememberVerifiedContainerHeads } from \"../../data/containers/shared/heldContainerHeads\";\nimport type { AuthoredContainerMutationHead } from \"../../data/containers/shared/mutationAcknowledgement\";\nimport { acknowledgeContainerMutationBatch } from \"../../data/containers/shared/mutationAcknowledgement\";\nimport {\n getTargetContainerContext,\n readContainerState,\n} from \"../../data/containers/shared/projection\";\nimport {\n type PrincipalPolicyCache,\n verifyContainerWriterProjection,\n} from \"../../data/keyingProjectionVerification\";\nimport { createProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification/userKeyResolver\";\nimport { rebaseOnDeepestAncestor } from \"../containers/child/carriedDescendantRekeys\";\nimport { scheduleHeldDescendantRecitations } from \"../containers/child/recite\";\nimport { buildMaterializedContainerRekeyPlan } from \"../containers/child/rekey\";\nimport { isSpeculativeContainerWriterProjection } from \"../containers/child/rekeyProjection\";\nimport { selectReplacementPrincipalPolicyReferences } from \"../containers/child/replacementPrincipalPolicyReferences\";\nimport { buildMaterializedContainerRevokePlan } from \"../containers/child/revoke\";\nimport { buildMaterializedContainerSharePlan } from \"../containers/child/shareMaterialization\";\nimport {\n addPlan,\n type BatchPlanning,\n carryLevel,\n type PrincipalContainerRematerializationInput,\n staleLevelsAbove,\n} from \"./principalContainerRematerializationPlanning\";\nimport {\n loadRematerializationTargets,\n loadServedProjection,\n type MaterializedPrincipalContainerMutationPlan,\n type PlannedRematerialization,\n type RematerializationTarget,\n rotatedPath,\n seededPrincipalPolicyCache,\n} from \"./principalContainerRematerializationTargets\";\n\nfunction matchingGroupGrant(input: {\n readonly directGrants: readonly ContainerDirectGrant[];\n readonly groupId: string;\n}): ContainerDirectGrant | null {\n return (\n input.directGrants.find(\n (grant) =>\n grant.subjectType === \"group\" && grant.subjectId === input.groupId,\n ) ?? null\n );\n}\n\nfunction referencedGroupKeyEpoch(input: {\n readonly groupId: string;\n readonly referencedPrincipalHeads: ReturnType<\n typeof readContainerState\n >[\"referencedPrincipalHeads\"];\n}): number | null {\n return (\n input.referencedPrincipalHeads.find(\n (head) =>\n head.principalType === \"group\" && head.principalId === input.groupId,\n )?.keyEpoch ?? null\n );\n}\n\nasync function loadGrantedContainerContext(\n input: PrincipalContainerRematerializationInput,\n grantRow: PrincipalContainerGrant,\n projection: ContainerWriterProjectionResponse,\n principalPolicyCache: PrincipalPolicyCache,\n) {\n // A projection re-rooted on a rotation this batch has yet to commit must\n // not pin anything: its heads are speculative until acknowledged, and a\n // pin past the group's served head would refuse the other served paths.\n await verifyContainerWriterProjection({\n execSql: input.execSql,\n persistVerificationCheckpoints:\n !isSpeculativeContainerWriterProjection(projection),\n principalPolicyCache,\n projection,\n resolveUserKey: createProjectionUserKeyResolver({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n }),\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n const state = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n const grant = matchingGroupGrant({\n directGrants: state.directGrants,\n groupId: input.groupId,\n });\n if (grant && grant.accessLevel !== grantRow.accessLevel) {\n const nextGrant = input.nextPolicy.grants.find(\n (candidate) => candidate.containerId === grantRow.containerId,\n );\n if (!nextGrant || nextGrant.accessLevel !== grantRow.accessLevel) {\n throw new Error(\n `Container ${grantRow.containerId} does not contain the expected group grant`,\n );\n }\n }\n const referencedKeyEpoch = referencedGroupKeyEpoch({\n groupId: input.groupId,\n referencedPrincipalHeads: state.referencedPrincipalHeads,\n });\n if (grant && referencedKeyEpoch === null) {\n throw new Error(\n `Container ${grantRow.containerId} is missing its group reference`,\n );\n }\n return { grant, projection, referencedKeyEpoch };\n}\n\nexport async function buildPrincipalContainerRematerializationBatch(\n input: PrincipalContainerRematerializationInput,\n): Promise<ContainerMutationRequest[]> {\n return (\n await buildPrincipalContainerRematerializationPlans(input)\n ).entries.map((entry) => entry.planned.plan.request);\n}\n\nexport interface PreparedPrincipalContainerRematerializationBatch {\n readonly retiredContainerIds: readonly string[];\n readonly acknowledge: (\n responses: readonly ContainerMutationResponse[],\n stillCurrent?: (() => boolean) | undefined,\n ) => Promise<void>;\n /**\n * Re-sign the batch with the descendant rekeys the server named for its\n * rotations woven in, parent-first, each against the path the batch will\n * leave behind. A named container the batch already rotates is re-planned\n * under what is carried above it, so no container rotates twice. Returns the\n * whole request list, which replaces `requests`; `acknowledge` then expects\n * the responses in that order.\n */\n readonly carry: (\n requiredContainerIds: readonly string[],\n ) => Promise<readonly ContainerMutationRequest[]>;\n readonly plans: readonly MaterializedPrincipalContainerMutationPlan[];\n readonly requests: readonly ContainerMutationRequest[];\n}\n\nfunction authoredMutationHead(\n planned: MaterializedPrincipalContainerMutationPlan,\n): AuthoredContainerMutationHead {\n return planned.plan;\n}\n\nasync function buildPrincipalContainerRematerializationPlan(input: {\n readonly grantRow: PrincipalContainerGrant;\n /** Keys the batch minted above this container; see `BatchPlanning`. */\n readonly knownContainerKeks: ReadonlyMap<string, Uint8Array>;\n /** Holds the policy this batch commits, which rebased paths already cite. */\n readonly principalPolicyCache: PrincipalPolicyCache;\n /** The served projection, re-rooted on any rotation planned above it. */\n readonly projection: ContainerWriterProjectionResponse;\n readonly rematerialization: PrincipalContainerRematerializationInput;\n readonly resolveProjectionUserKey: ReturnType<\n typeof createProjectionUserKeyResolver\n >;\n}): Promise<MaterializedPrincipalContainerMutationPlan> {\n const { grantRow } = input;\n const rematerialization = {\n ...input.rematerialization,\n nextPolicy: await selectReplacementPrincipalPolicyReferences({\n policy: input.rematerialization.nextPolicy,\n projection: input.projection,\n principalPolicyCache: input.principalPolicyCache,\n resolveAuthoredPolicyReferences:\n input.rematerialization.resolveAuthoredPolicyReferences,\n }),\n };\n const { grant, projection, referencedKeyEpoch } =\n await loadGrantedContainerContext(\n rematerialization,\n grantRow,\n input.projection,\n input.principalPolicyCache,\n );\n const nextGrant = rematerialization.nextPolicy.grants.find(\n (candidate) => candidate.containerId === grantRow.containerId,\n );\n const author = {\n ...rematerialization.author,\n organizationId: projection.organizationId,\n };\n const sharedInput = {\n author,\n execSql: rematerialization.execSql,\n knownContainerKeks: input.knownContainerKeks,\n // Planning against a path this batch has yet to commit pins nothing; the\n // acknowledgement advances every head at once. The rekey planner applies\n // this rule itself; revoke and grant planning take it from here.\n persistVerificationCheckpoints:\n !isSpeculativeContainerWriterProjection(projection),\n previousProjection: projection,\n principalPolicyCache: input.principalPolicyCache,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: rematerialization.stillCurrent,\n targetSecretKey: rematerialization.targetSecretKey,\n warmReferencedPrincipalPolicies:\n rematerialization.warmReferencedPrincipalPolicies,\n };\n if (grantRow.containerId === rematerialization.revokedContainerId) {\n if (!grant) {\n throw new Error(\n `Container ${grantRow.containerId} does not contain the revoked group grant`,\n );\n }\n return buildMaterializedContainerRevokePlan({\n ...sharedInput,\n replacementPrincipalPolicy: rematerialization.nextPolicy,\n revokedSubject: {\n subjectId: rematerialization.groupId,\n subjectType: \"group\",\n },\n });\n }\n if (!grant || grant.accessLevel !== nextGrant?.accessLevel) {\n if (!nextGrant) {\n throw new Error(\n `Container ${grantRow.containerId} is absent from the next group grant set`,\n );\n }\n return buildMaterializedContainerSharePlan({\n ...sharedInput,\n accessLevel: nextGrant.accessLevel,\n recipient: {\n principalPolicy: rematerialization.nextPolicy,\n subjectId: rematerialization.groupId,\n subjectType: \"group\",\n },\n });\n }\n if (referencedKeyEpoch === rematerialization.nextPolicy.keyEpoch) {\n return buildMaterializedContainerSharePlan({\n ...sharedInput,\n accessLevel: grant.accessLevel,\n recipient: {\n principalPolicy: rematerialization.nextPolicy,\n subjectId: rematerialization.groupId,\n subjectType: \"group\",\n },\n });\n }\n return buildMaterializedContainerRekeyPlan({\n ...sharedInput,\n replacementPrincipalPolicy: rematerialization.nextPolicy,\n });\n}\n\n/**\n * Plan one target against the paths already planned above it. A grant's\n * rematerialization extends the served head; a rotation's, and every carried\n * rekey, extends the epoch the batch mints above it.\n */\nasync function planRematerializationTarget(\n batch: BatchPlanning,\n target: RematerializationTarget,\n): Promise<void> {\n const { rematerialization } = batch;\n let rebased = rebaseOnDeepestAncestor(target.projection, batch.rotatedAbove);\n const stale = rebased\n ? staleLevelsAbove(\n rebased.projection,\n rebased.ancestor.containerKeks.at(-1)?.containerId ?? \"\",\n )\n : [];\n for (const containerId of stale) {\n await carryLevel(\n batch,\n await loadServedProjection(rematerialization.apiClient, containerId),\n );\n }\n if (!target.grantRow) {\n await carryLevel(batch, target.projection);\n return;\n }\n // Each level carried above re-roots the target one step deeper.\n if (stale.length > 0) {\n rebased = rebaseOnDeepestAncestor(target.projection, batch.rotatedAbove);\n }\n const previousProjection = rebased?.projection ?? target.projection;\n const planned = await buildPrincipalContainerRematerializationPlan({\n grantRow: target.grantRow,\n knownContainerKeks: batch.knownContainerKeks,\n principalPolicyCache: batch.principalPolicyCache,\n projection: previousProjection,\n rematerialization,\n resolveProjectionUserKey: batch.resolveProjectionUserKey,\n });\n addPlan(batch, {\n carried: false,\n planned,\n rotated: await rotatedPath({ planned, previousProjection }),\n });\n}\n\n/**\n * Sign the batch parent-first. `carriedContainerIds` are the descendant rekeys\n * a refused attempt was told to carry; woven in by depth, each sits under the\n * rotation it rides, and a named container the batch rematerializes anyway is\n * re-planned there rather than rotated twice.\n */\nasync function buildPrincipalContainerRematerializationPlans(\n input: PrincipalContainerRematerializationInput,\n carriedContainerIds: readonly string[] = [],\n): Promise<{\n entries: PlannedRematerialization[];\n retiredContainerIds: readonly string[];\n}> {\n if (\n input.revokedContainerId &&\n !input.grants.some(\n (grant) => grant.containerId === input.revokedContainerId,\n )\n ) {\n throw new Error(\"Revoked container is not granted to the group\");\n }\n const { targets, retiredContainerIds } = await loadRematerializationTargets({\n apiClient: input.apiClient,\n carriedContainerIds,\n grants: input.grants,\n });\n const batch: BatchPlanning = {\n knownContainerKeks: new Map(),\n plans: [],\n // A rotation planned above cites the group at the head this batch commits,\n // which no store holds yet; the cache is what lets a rebased path verify.\n principalPolicyCache: seededPrincipalPolicyCache(input.nextPolicy),\n rematerialization: input,\n resolveProjectionUserKey: createProjectionUserKeyResolver({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n }),\n rotatedAbove: [],\n };\n for (const target of targets) {\n await planRematerializationTarget(batch, target);\n }\n return { entries: batch.plans, retiredContainerIds };\n}\n\n/**\n * The server names a level it found pinned to a retired epoch. A batch answers\n * with a rotation of it: a carried rekey, or its own rematerialization when\n * that is a rekey or revoke. A rematerialized grant rotates nothing, so a\n * batch that both grants a container and must re-key it cannot be signed;\n * no policy change the SDK builds combines the two.\n */\nfunction assertNamedContainersRotated(\n plans: readonly PlannedRematerialization[],\n requiredContainerIds: readonly string[],\n): void {\n const rotatedIds = new Set(\n plans.flatMap((entry) =>\n entry.rotated ? [entry.planned.plan.containerId] : [],\n ),\n );\n const unrotated = requiredContainerIds\n .slice(0, MAX_ROTATION_CONTAINER_REKEYS)\n .find((containerId) => !rotatedIds.has(containerId));\n if (unrotated !== undefined) {\n throw new Error(\n `Container ${unrotated} needs a rekey this policy change only grants`,\n );\n }\n}\n\nexport async function preparePrincipalContainerRematerializationBatch(\n input: PrincipalContainerRematerializationInput,\n): Promise<PreparedPrincipalContainerRematerializationBatch> {\n let { entries, retiredContainerIds } =\n await buildPrincipalContainerRematerializationPlans(input);\n const requests = () => entries.map((entry) => entry.planned.plan.request);\n return {\n get retiredContainerIds() {\n return retiredContainerIds;\n },\n get plans() {\n return entries.map((entry) => entry.planned);\n },\n get requests() {\n return requests();\n },\n carry: async (requiredContainerIds) => {\n // The refused attempt rolled back whole, so every served head still\n // stands; the batch is signed again from them with the named levels in.\n const replanned = await buildPrincipalContainerRematerializationPlans(\n input,\n requiredContainerIds,\n );\n assertNamedContainersRotated(replanned.entries, requiredContainerIds);\n entries = replanned.entries;\n retiredContainerIds = replanned.retiredContainerIds;\n return requests();\n },\n acknowledge: async (responses, stillCurrent) => {\n const isCurrent = () =>\n input.stillCurrent?.() !== false && stillCurrent?.() !== false;\n const heads = entries.map((entry) => authoredMutationHead(entry.planned));\n const acknowledged = await acknowledgeContainerMutationBatch({\n execSql: input.execSql,\n plans: heads,\n responses,\n stillCurrent: isCurrent,\n });\n if (!acknowledged || !isCurrent()) return;\n const plansByOrganization = new Map<\n string,\n AuthoredContainerMutationHead[]\n >();\n for (const head of heads) {\n const organizationId = head.state.organizationId;\n const group = plansByOrganization.get(organizationId) ?? [];\n group.push(head);\n plansByOrganization.set(organizationId, group);\n }\n for (const [organizationId, organizationPlans] of plansByOrganization) {\n try {\n rememberVerifiedContainerHeads({\n organizationId,\n execSql: input.execSql,\n heads: [],\n policies: [input.nextPolicy],\n });\n } catch {\n // Cache failure must not invalidate the durably acknowledged batch.\n continue;\n }\n scheduleHeldDescendantRecitations({\n apiClient: input.apiClient,\n author: { ...input.author, organizationId },\n execSql: input.execSql,\n plans: organizationPlans,\n stillCurrent: input.recitationStillCurrent ?? isCurrent,\n reportSecurityIncident: input.reportSecurityIncident,\n });\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"principalContainerRematerialization.js","sourceRoot":"","sources":["principalContainerRematerialization.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContainerDirectGrant,\n PrincipalContainerGrant,\n} from \"@tearleads/crypto\";\nimport type { ContainerMutationRequest } from \"@tearleads/validators/request\";\nimport type {\n ContainerMutationResponse,\n ContainerWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport { MAX_ROTATION_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport { rememberVerifiedContainerHeads } from \"../../data/containers/shared/heldContainerHeads\";\nimport type { AuthoredContainerMutationHead } from \"../../data/containers/shared/mutationAcknowledgement\";\nimport { acknowledgeContainerMutationBatch } from \"../../data/containers/shared/mutationAcknowledgement\";\nimport {\n getTargetContainerContext,\n readContainerState,\n} from \"../../data/containers/shared/projection\";\nimport {\n type PrincipalPolicyCache,\n verifyContainerWriterProjection,\n} from \"../../data/keyingProjectionVerification\";\nimport { createProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification/userKeyResolver\";\nimport { rebaseOnDeepestAncestor } from \"../containers/child/carriedDescendantRekeys\";\nimport { scheduleHeldDescendantRecitations } from \"../containers/child/recite\";\nimport { buildMaterializedContainerRekeyPlan } from \"../containers/child/rekey\";\nimport {\n containerWriterProjectionFromRotationPlan,\n containerWriterProjectionFromSharePlan,\n isSpeculativeContainerWriterProjection,\n} from \"../containers/child/rekeyProjection\";\nimport { selectReplacementPrincipalPolicyReferences } from \"../containers/child/replacementPrincipalPolicyReferences\";\nimport { buildMaterializedContainerRevokePlan } from \"../containers/child/revoke\";\nimport { buildMaterializedContainerSharePlan } from \"../containers/child/shareMaterialization\";\nimport { withPrecedingRematerialization } from \"./precedingPrincipalRematerialization\";\nimport {\n addPlan,\n type BatchPlanning,\n carryLevel,\n type PrincipalContainerRematerializationInput,\n type PrincipalRematerializationPredecessor,\n staleLevelsAbove,\n} from \"./principalContainerRematerializationPlanning\";\nimport {\n loadRematerializationTargets,\n loadServedProjection,\n type MaterializedPrincipalContainerMutationPlan,\n type PlannedRematerialization,\n type RematerializationTarget,\n seededPrincipalPolicyCache,\n} from \"./principalContainerRematerializationTargets\";\n\nfunction matchingGroupGrant(input: {\n readonly directGrants: readonly ContainerDirectGrant[];\n readonly groupId: string;\n}): ContainerDirectGrant | null {\n return (\n input.directGrants.find(\n (grant) =>\n grant.subjectType === \"group\" && grant.subjectId === input.groupId,\n ) ?? null\n );\n}\n\nfunction referencedGroupKeyEpoch(input: {\n readonly groupId: string;\n readonly referencedPrincipalHeads: ReturnType<\n typeof readContainerState\n >[\"referencedPrincipalHeads\"];\n}): number | null {\n return (\n input.referencedPrincipalHeads.find(\n (head) =>\n head.principalType === \"group\" && head.principalId === input.groupId,\n )?.keyEpoch ?? null\n );\n}\n\nasync function loadGrantedContainerContext(\n input: PrincipalContainerRematerializationInput,\n grantRow: PrincipalContainerGrant,\n projection: ContainerWriterProjectionResponse,\n principalPolicyCache: PrincipalPolicyCache,\n) {\n // A projection re-rooted on a rotation this batch has yet to commit must\n // not pin anything: its heads are speculative until acknowledged, and a\n // pin past the group's served head would refuse the other served paths.\n await verifyContainerWriterProjection({\n execSql: input.execSql,\n persistVerificationCheckpoints:\n !isSpeculativeContainerWriterProjection(projection),\n principalPolicyCache,\n projection,\n resolveUserKey: createProjectionUserKeyResolver({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n }),\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n });\n const state = readContainerState(\n getTargetContainerContext(projection).manifest,\n );\n const grant = matchingGroupGrant({\n directGrants: state.directGrants,\n groupId: input.groupId,\n });\n if (grant && grant.accessLevel !== grantRow.accessLevel) {\n const nextGrant = input.nextPolicy.grants.find(\n (candidate) => candidate.containerId === grantRow.containerId,\n );\n if (!nextGrant || nextGrant.accessLevel !== grantRow.accessLevel) {\n throw new Error(\n `Container ${grantRow.containerId} does not contain the expected group grant`,\n );\n }\n }\n const referencedKeyEpoch = referencedGroupKeyEpoch({\n groupId: input.groupId,\n referencedPrincipalHeads: state.referencedPrincipalHeads,\n });\n if (grant && referencedKeyEpoch === null) {\n throw new Error(\n `Container ${grantRow.containerId} is missing its group reference`,\n );\n }\n return { grant, projection, referencedKeyEpoch };\n}\n\nexport async function buildPrincipalContainerRematerializationBatch(\n input: PrincipalContainerRematerializationInput,\n): Promise<ContainerMutationRequest[]> {\n return (\n await buildPrincipalContainerRematerializationPlans(input)\n ).entries.map((entry) => entry.planned.plan.request);\n}\n\nexport interface PreparedPrincipalContainerRematerializationBatch {\n readonly preceding?: PrincipalRematerializationPredecessor | undefined;\n readonly retiredContainerIds: readonly string[];\n readonly acknowledge: (\n responses: readonly ContainerMutationResponse[],\n stillCurrent?: (() => boolean) | undefined,\n ) => Promise<void>;\n /**\n * Re-sign the batch with the descendant rekeys the server named for its\n * rotations woven in, parent-first, each against the path the batch will\n * leave behind. A named container the batch already rotates is re-planned\n * under what is carried above it, so no container rotates twice. Returns the\n * whole request list, which replaces `requests`; `acknowledge` then expects\n * the responses in that order.\n */\n readonly carry: (\n requiredContainerIds: readonly string[],\n ) => Promise<readonly ContainerMutationRequest[]>;\n readonly plans: readonly MaterializedPrincipalContainerMutationPlan[];\n readonly requests: readonly ContainerMutationRequest[];\n}\n\nfunction authoredMutationHead(\n planned: MaterializedPrincipalContainerMutationPlan,\n): AuthoredContainerMutationHead {\n return planned.plan;\n}\n\nasync function buildPrincipalContainerRematerializationPlan(input: {\n readonly grantRow: PrincipalContainerGrant;\n /** Keys the batch minted above this container; see `BatchPlanning`. */\n readonly knownContainerKeks: ReadonlyMap<string, Uint8Array>;\n /** Holds the policy this batch commits, which rebased paths already cite. */\n readonly principalPolicyCache: PrincipalPolicyCache;\n /** The served projection, re-rooted on any rotation planned above it. */\n readonly projection: ContainerWriterProjectionResponse;\n readonly rematerialization: PrincipalContainerRematerializationInput;\n readonly resolveProjectionUserKey: ReturnType<\n typeof createProjectionUserKeyResolver\n >;\n}): Promise<MaterializedPrincipalContainerMutationPlan> {\n const { grantRow } = input;\n const rematerialization = {\n ...input.rematerialization,\n nextPolicy: await selectReplacementPrincipalPolicyReferences({\n policy: input.rematerialization.nextPolicy,\n projection: input.projection,\n principalPolicyCache: input.principalPolicyCache,\n resolveAuthoredPolicyReferences:\n input.rematerialization.resolveAuthoredPolicyReferences,\n }),\n };\n const { grant, projection, referencedKeyEpoch } =\n await loadGrantedContainerContext(\n rematerialization,\n grantRow,\n input.projection,\n input.principalPolicyCache,\n );\n const nextGrant = rematerialization.nextPolicy.grants.find(\n (candidate) => candidate.containerId === grantRow.containerId,\n );\n const author = {\n ...rematerialization.author,\n organizationId: projection.organizationId,\n };\n const sharedInput = {\n author,\n execSql: rematerialization.execSql,\n knownContainerKeks: input.knownContainerKeks,\n // Planning against a path this batch has yet to commit pins nothing; the\n // acknowledgement advances every head at once. The rekey planner applies\n // this rule itself; revoke and grant planning take it from here.\n persistVerificationCheckpoints:\n !isSpeculativeContainerWriterProjection(projection),\n previousProjection: projection,\n principalPolicyCache: input.principalPolicyCache,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n stillCurrent: rematerialization.stillCurrent,\n targetSecretKey: rematerialization.targetSecretKey,\n warmReferencedPrincipalPolicies:\n rematerialization.warmReferencedPrincipalPolicies,\n };\n if (grantRow.containerId === rematerialization.revokedContainerId) {\n if (!grant) {\n throw new Error(\n `Container ${grantRow.containerId} does not contain the revoked group grant`,\n );\n }\n return buildMaterializedContainerRevokePlan({\n ...sharedInput,\n replacementPrincipalPolicy: rematerialization.nextPolicy,\n revokedSubject: {\n subjectId: rematerialization.groupId,\n subjectType: \"group\",\n },\n });\n }\n if (!grant || grant.accessLevel !== nextGrant?.accessLevel) {\n if (!nextGrant) {\n throw new Error(\n `Container ${grantRow.containerId} is absent from the next group grant set`,\n );\n }\n return buildMaterializedContainerSharePlan({\n ...sharedInput,\n accessLevel: nextGrant.accessLevel,\n recipient: {\n principalPolicy: rematerialization.nextPolicy,\n subjectId: rematerialization.groupId,\n subjectType: \"group\",\n },\n });\n }\n if (referencedKeyEpoch === rematerialization.nextPolicy.keyEpoch) {\n return buildMaterializedContainerSharePlan({\n ...sharedInput,\n accessLevel: grant.accessLevel,\n recipient: {\n principalPolicy: rematerialization.nextPolicy,\n subjectId: rematerialization.groupId,\n subjectType: \"group\",\n },\n });\n }\n return buildMaterializedContainerRekeyPlan({\n ...sharedInput,\n replacementPrincipalPolicy: rematerialization.nextPolicy,\n });\n}\n\n/**\n * Plan one target against the paths already planned above it. A grant's\n * rematerialization extends the served head; a rotation's, and every carried\n * rekey, extends the epoch the batch mints above it.\n */\nasync function planRematerializationTarget(\n batch: BatchPlanning,\n target: RematerializationTarget,\n): Promise<void> {\n const { rematerialization } = batch;\n let rebased = rebaseOnDeepestAncestor(target.projection, batch.rotatedAbove);\n const stale = rebased\n ? staleLevelsAbove(\n rebased.projection,\n rebased.ancestor.containerKeks.at(-1)?.containerId ?? \"\",\n )\n : [];\n for (const containerId of stale) {\n await carryLevel(\n batch,\n await loadServedProjection(rematerialization.apiClient, containerId),\n );\n }\n if (!target.grantRow) {\n await carryLevel(batch, target.projection);\n return;\n }\n // Each level carried above re-roots the target one step deeper.\n if (stale.length > 0) {\n rebased = rebaseOnDeepestAncestor(target.projection, batch.rotatedAbove);\n }\n const previousProjection = rebased?.projection ?? target.projection;\n const planned = await buildPrincipalContainerRematerializationPlan({\n grantRow: target.grantRow,\n knownContainerKeks: batch.knownContainerKeks,\n principalPolicyCache: batch.principalPolicyCache,\n projection: previousProjection,\n rematerialization,\n resolveProjectionUserKey: batch.resolveProjectionUserKey,\n });\n const nextProjection =\n \"keyring\" in planned.plan\n ? await containerWriterProjectionFromRotationPlan({\n plan: planned.plan,\n previousProjection,\n })\n : await containerWriterProjectionFromSharePlan({\n plan: planned.plan,\n previousProjection,\n });\n addPlan(batch, {\n carried: false,\n planned,\n rotated: \"keyring\" in planned.plan ? nextProjection : null,\n nextProjection,\n });\n}\n\n/**\n * Sign the batch parent-first. `carriedContainerIds` are the descendant rekeys\n * a refused attempt was told to carry; woven in by depth, each sits under the\n * rotation it rides, and a named container the batch rematerializes anyway is\n * re-planned there rather than rotated twice.\n */\nasync function buildPrincipalContainerRematerializationPlans(\n input: PrincipalContainerRematerializationInput,\n carriedContainerIds: readonly string[] = [],\n): Promise<{\n entries: PlannedRematerialization[];\n retiredContainerIds: readonly string[];\n preceding: PrincipalRematerializationPredecessor;\n}> {\n input = withPrecedingRematerialization(input);\n if (\n input.revokedContainerId &&\n !input.grants.some(\n (grant) => grant.containerId === input.revokedContainerId,\n )\n ) {\n throw new Error(\"Revoked container is not granted to the group\");\n }\n const { targets, retiredContainerIds } = await loadRematerializationTargets({\n apiClient: input.apiClient,\n carriedContainerIds,\n grants: input.grants,\n });\n const batch: BatchPlanning = {\n knownContainerKeks: new Map(input.preceding?.knownContainerKeks),\n plans: [],\n // A rotation planned above cites the group at the head this batch commits,\n // which no store holds yet; the cache is what lets a rebased path verify.\n principalPolicyCache: new Map([\n ...(input.preceding?.policies ?? []).flatMap((policy) => [\n ...seededPrincipalPolicyCache(policy),\n ]),\n ...seededPrincipalPolicyCache(input.nextPolicy),\n ]),\n rematerialization: input,\n resolveProjectionUserKey: createProjectionUserKeyResolver({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n }),\n rotatedAbove: [],\n };\n for (const target of targets) {\n await planRematerializationTarget(batch, target);\n }\n return {\n entries: batch.plans,\n retiredContainerIds,\n preceding: {\n policies: [...(input.preceding?.policies ?? []), input.nextPolicy],\n projections: [\n ...(input.preceding?.projections ?? []),\n ...batch.plans.flatMap((entry) =>\n entry.nextProjection ? [entry.nextProjection] : [],\n ),\n ],\n knownContainerKeks: batch.knownContainerKeks,\n },\n };\n}\n\n/**\n * The server names a level it found pinned to a retired epoch. A batch answers\n * with a rotation of it: a carried rekey, or its own rematerialization when\n * that is a rekey or revoke. A rematerialized grant rotates nothing, so a\n * batch that both grants a container and must re-key it cannot be signed;\n * no policy change the SDK builds combines the two.\n */\nfunction assertNamedContainersRotated(\n plans: readonly PlannedRematerialization[],\n requiredContainerIds: readonly string[],\n): void {\n const rotatedIds = new Set(\n plans.flatMap((entry) =>\n entry.rotated ? [entry.planned.plan.containerId] : [],\n ),\n );\n const unrotated = requiredContainerIds\n .slice(0, MAX_ROTATION_CONTAINER_REKEYS)\n .find((containerId) => !rotatedIds.has(containerId));\n if (unrotated !== undefined) {\n throw new Error(\n `Container ${unrotated} needs a rekey this policy change only grants`,\n );\n }\n}\n\nexport async function preparePrincipalContainerRematerializationBatch(\n input: PrincipalContainerRematerializationInput,\n): Promise<PreparedPrincipalContainerRematerializationBatch> {\n let { entries, retiredContainerIds, preceding } =\n await buildPrincipalContainerRematerializationPlans(input);\n const requests = () => entries.map((entry) => entry.planned.plan.request);\n return {\n get preceding() {\n return preceding;\n },\n get retiredContainerIds() {\n return retiredContainerIds;\n },\n get plans() {\n return entries.map((entry) => entry.planned);\n },\n get requests() {\n return requests();\n },\n carry: async (requiredContainerIds) => {\n // The refused attempt rolled back whole, so every served head still\n // stands; the batch is signed again from them with the named levels in.\n const replanned = await buildPrincipalContainerRematerializationPlans(\n input,\n requiredContainerIds,\n );\n assertNamedContainersRotated(replanned.entries, requiredContainerIds);\n entries = replanned.entries;\n retiredContainerIds = replanned.retiredContainerIds;\n preceding = replanned.preceding;\n return requests();\n },\n acknowledge: async (responses, stillCurrent) => {\n const isCurrent = () =>\n input.stillCurrent?.() !== false && stillCurrent?.() !== false;\n const heads = entries.map((entry) => authoredMutationHead(entry.planned));\n const acknowledged = await acknowledgeContainerMutationBatch({\n execSql: input.execSql,\n plans: heads,\n responses,\n stillCurrent: isCurrent,\n });\n if (!acknowledged || !isCurrent()) return;\n const plansByOrganization = new Map<\n string,\n AuthoredContainerMutationHead[]\n >();\n for (const head of heads) {\n const organizationId = head.state.organizationId;\n const group = plansByOrganization.get(organizationId) ?? [];\n group.push(head);\n plansByOrganization.set(organizationId, group);\n }\n for (const [organizationId, organizationPlans] of plansByOrganization) {\n try {\n rememberVerifiedContainerHeads({\n organizationId,\n execSql: input.execSql,\n heads: [],\n policies: [input.nextPolicy],\n });\n } catch {\n // Cache failure must not invalidate the durably acknowledged batch.\n continue;\n }\n scheduleHeldDescendantRecitations({\n apiClient: input.apiClient,\n author: { ...input.author, organizationId },\n execSql: input.execSql,\n plans: organizationPlans,\n stillCurrent: input.recitationStillCurrent ?? isCurrent,\n reportSecurityIncident: input.reportSecurityIncident,\n });\n }\n },\n };\n}\n"]}
@@ -35,7 +35,12 @@ export async function carryLevel(batch, served) {
35
35
  targetSecretKey: rematerialization.targetSecretKey,
36
36
  warmReferencedPrincipalPolicies: rematerialization.warmReferencedPrincipalPolicies,
37
37
  });
38
- addPlan(batch, { carried: true, planned, rotated: planned.writerProjection });
38
+ addPlan(batch, {
39
+ carried: true,
40
+ planned,
41
+ rotated: planned.writerProjection,
42
+ nextProjection: planned.writerProjection,
43
+ });
39
44
  }
40
45
  export function addPlan(batch, entry) {
41
46
  batch.plans.push(entry);
@@ -1 +1 @@
1
- {"version":3,"file":"principalContainerRematerializationPlanning.js","sourceRoot":"","sources":["principalContainerRematerializationPlanning.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAa3E,OAAO,EACL,0BAA0B,GAE3B,MAAM,6CAA6C,CAAC;AAmDrD,uEAAuE;AACvE,SAAS,YAAY,CAAC,KAAoB;IACxC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAC7D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAoB,EACpB,MAAyC;IAEzC,MAAM,EAAE,iBAAiB,EAAE,GAAG,KAAK,CAAC;IACpC,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,6BAA6B,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,uCAAuC,6BAA6B,oBAAoB,CACzF,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC;QAC/C,SAAS,EAAE,iBAAiB,CAAC,SAAS;QACtC,MAAM,EAAE,iBAAiB,CAAC,MAAM;QAChC,OAAO,EAAE,iBAAiB,CAAC,OAAO;QAClC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;QAChD,8DAA8D;QAC9D,sDAAsD;QACtD,0BAA0B,EAAE,iBAAiB,CAAC,UAAU;QACxD,+BAA+B,EAC7B,iBAAiB,CAAC,+BAA+B;QACnD,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;QACxD,OAAO,EAAE,KAAK,CAAC,YAAY;QAC3B,MAAM;QACN,YAAY,EAAE,iBAAiB,CAAC,YAAY;QAC5C,eAAe,EAAE,iBAAiB,CAAC,eAAe;QAClD,+BAA+B,EAC7B,iBAAiB,CAAC,+BAA+B;KACpD,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,KAAoB,EACpB,KAA+B;IAE/B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO;IAC3B,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,mBAAmB,CAAC;IACvE,IAAI,MAAM;QAAE,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAA6C,EAC7C,iBAAyB;IAEzB,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAC7B,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,KAAK,iBAAiB,CAC/C,CAAC;IACF,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAClC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACb,KAAK,GAAG,CAAC;QACT,GAAG,CAAC,yBAAyB,KAAK,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAC5E,CAAC;IACF,OAAO,UAAU,GAAG,CAAC;QACnB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalContainerGrant } from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { MAX_ROTATION_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport type { ContainerReciteApi } from \"../../data/containers/shared/reciteApi\";\nimport type { ContainerMutationAuthor } from \"../../data/containers/shared/types\";\nimport type {\n PrincipalPolicyCache,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification\";\nimport type { createProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification/userKeyResolver\";\nimport type { CurrentPolicyReferenceResolver } from \"../../data/principals/currentPolicyReferenceResolver\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../data/principals/principalPolicyEvidence\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport {\n planCarriedDescendantRekey,\n type SpeculativePath,\n} from \"../containers/child/carriedDescendantRekeys\";\nimport type { PlannedRematerialization } from \"./principalContainerRematerializationTargets\";\n\nexport interface RematerializationApi\n extends ContainerReciteApi,\n Pick<ApiClient, \"getContainerWriterProjectionResult\"> {\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n}\n\nexport interface PrincipalContainerRematerializationInput {\n readonly reportSecurityIncident: SecurityIncidentReporter;\n readonly apiClient: RematerializationApi;\n readonly author: ContainerMutationAuthor;\n readonly execSql: ExecSql;\n readonly grants: readonly PrincipalContainerGrant[];\n readonly groupId: string;\n readonly nextPolicy: PrincipalPolicyCurrentEvidence;\n readonly resolveAuthoredPolicyReferences?:\n | CurrentPolicyReferenceResolver\n | undefined;\n readonly revokedContainerId?: string | undefined;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n /** Session lifetime for best-effort work after durable acknowledgement. */\n readonly recitationStillCurrent?: (() => boolean) | undefined;\n readonly targetSecretKey: Uint8Array;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}\n\n/** What the batch has signed so far, in the order it will be submitted. */\nexport interface BatchPlanning {\n /**\n * Keys the batch minted, by epoch id. A rotation wraps its successor to the\n * group at the head this batch commits, which no store can open yet; a\n * level planned beneath it opens that epoch with the key minted here, and\n * its keyring then opens the retired epoch the level below is pinned to.\n */\n readonly knownContainerKeks: Map<string, Uint8Array>;\n readonly plans: PlannedRematerialization[];\n readonly principalPolicyCache: PrincipalPolicyCache;\n readonly rematerialization: PrincipalContainerRematerializationInput;\n readonly resolveProjectionUserKey: ReturnType<\n typeof createProjectionUserKeyResolver\n >;\n readonly rotatedAbove: SpeculativePath[];\n}\n\n/** How many rekeys the batch carries beyond its rematerializations. */\nfunction carriedCount(batch: BatchPlanning): number {\n return batch.plans.filter((entry) => entry.carried).length;\n}\n\n/**\n * Sign a rekey of `served` under the batch's rotations above it, and add it.\n * The server accepts at most `MAX_ROTATION_CONTAINER_REKEYS` carried entries;\n * past that a rematerialization below them could not be signed on a current\n * path, so the batch is refused here, before signing what the server would\n * refuse anyway, and the policy change has to wait for a lazy repair of the\n * tree. Groups granted that far apart on one chain are not a shape the SDK\n * creates.\n */\nexport async function carryLevel(\n batch: BatchPlanning,\n served: ContainerWriterProjectionResponse,\n): Promise<void> {\n const { rematerialization } = batch;\n if (carriedCount(batch) >= MAX_ROTATION_CONTAINER_REKEYS) {\n throw new Error(\n `Policy change would carry more than ${MAX_ROTATION_CONTAINER_REKEYS} descendant rekeys`,\n );\n }\n const planned = await planCarriedDescendantRekey({\n apiClient: rematerialization.apiClient,\n author: rematerialization.author,\n execSql: rematerialization.execSql,\n knownContainerKeks: batch.knownContainerKeks,\n principalPolicyCache: batch.principalPolicyCache,\n // Its path cites the policy this batch commits, so like every\n // rematerialized rotation it must cite the successor.\n replacementPrincipalPolicy: rematerialization.nextPolicy,\n resolveAuthoredPolicyReferences:\n rematerialization.resolveAuthoredPolicyReferences,\n resolveProjectionUserKey: batch.resolveProjectionUserKey,\n rotated: batch.rotatedAbove,\n served,\n stillCurrent: rematerialization.stillCurrent,\n targetSecretKey: rematerialization.targetSecretKey,\n warmReferencedPrincipalPolicies:\n rematerialization.warmReferencedPrincipalPolicies,\n });\n addPlan(batch, { carried: true, planned, rotated: planned.writerProjection });\n}\n\nexport function addPlan(\n batch: BatchPlanning,\n entry: PlannedRematerialization,\n): void {\n batch.plans.push(entry);\n if (!entry.rotated) return;\n batch.rotatedAbove.push(entry.rotated);\n const minted = entry.rotated.containerKeks.at(-1)?.containerKeyEpochId;\n if (minted) batch.knownContainerKeks.set(minted, entry.planned.containerKey);\n}\n\n/**\n * Levels of a re-rooted path pinned to an epoch the batch retires above them:\n * those strictly between the rotated ancestor the path was re-rooted on and\n * the target, parent-first, from the first stale one down. A rotation planned\n * above a target strands every level between the two, and each must be\n * re-keyed under the one above before the target can be signed. The batch\n * carries them without waiting to be told: they are proper ancestors of a\n * granted container, so the server would name them, and a refusal per level\n * is a round trip each. Anything stale above the rotated ancestor is not this\n * batch's doing and is left alone. `carryLevel` holds the count to the cap.\n */\nexport function staleLevelsAbove(\n projection: ContainerWriterProjectionResponse,\n rotatedAncestorId: string,\n): string[] {\n const keks = projection.containerKeks;\n const ancestor = keks.findIndex(\n (kek) => kek.containerId === rotatedAncestorId,\n );\n if (ancestor < 0) return [];\n const between = keks.slice(ancestor, -1);\n const firstStale = between.findIndex(\n (kek, index) =>\n index > 0 &&\n kek.parentContainerKeyEpochId !== between[index - 1]?.containerKeyEpochId,\n );\n return firstStale < 0\n ? []\n : between.slice(firstStale).map((kek) => kek.containerId);\n}\n"]}
1
+ {"version":3,"file":"principalContainerRematerializationPlanning.js","sourceRoot":"","sources":["principalContainerRematerializationPlanning.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalContainerGrant } from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { MAX_ROTATION_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport type { ContainerReciteApi } from \"../../data/containers/shared/reciteApi\";\nimport type { ContainerMutationAuthor } from \"../../data/containers/shared/types\";\nimport type {\n PrincipalPolicyCache,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification\";\nimport type { ResolvedPrincipalPolicyEvidence } from \"../../data/keyingProjectionVerification/types\";\nimport type { createProjectionUserKeyResolver } from \"../../data/keyingProjectionVerification/userKeyResolver\";\nimport type { CurrentPolicyReferenceResolver } from \"../../data/principals/currentPolicyReferenceResolver\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../data/principals/principalPolicyEvidence\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport {\n planCarriedDescendantRekey,\n type SpeculativePath,\n} from \"../containers/child/carriedDescendantRekeys\";\nimport type { PlannedRematerialization } from \"./principalContainerRematerializationTargets\";\n\nexport interface RematerializationApi\n extends ContainerReciteApi,\n Pick<ApiClient, \"getContainerWriterProjectionResult\"> {\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n}\n\nexport interface PrincipalRematerializationPredecessor {\n readonly authored?: readonly ResolvedPrincipalPolicyEvidence[] | undefined;\n readonly policies: readonly PrincipalPolicyCurrentEvidence[];\n readonly projections: readonly ContainerWriterProjectionResponse[];\n readonly knownContainerKeks: ReadonlyMap<string, Uint8Array>;\n}\n\nexport interface PrincipalContainerRematerializationInput {\n readonly preceding?: PrincipalRematerializationPredecessor | undefined;\n readonly reportSecurityIncident: SecurityIncidentReporter;\n readonly apiClient: RematerializationApi;\n readonly author: ContainerMutationAuthor;\n readonly execSql: ExecSql;\n readonly grants: readonly PrincipalContainerGrant[];\n readonly groupId: string;\n readonly nextPolicy: PrincipalPolicyCurrentEvidence;\n readonly resolveAuthoredPolicyReferences?:\n | CurrentPolicyReferenceResolver\n | undefined;\n readonly revokedContainerId?: string | undefined;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n /** Session lifetime for best-effort work after durable acknowledgement. */\n readonly recitationStillCurrent?: (() => boolean) | undefined;\n readonly targetSecretKey: Uint8Array;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}\n\n/** What the batch has signed so far, in the order it will be submitted. */\nexport interface BatchPlanning {\n /**\n * Keys the batch minted, by epoch id. A rotation wraps its successor to the\n * group at the head this batch commits, which no store can open yet; a\n * level planned beneath it opens that epoch with the key minted here, and\n * its keyring then opens the retired epoch the level below is pinned to.\n */\n readonly knownContainerKeks: Map<string, Uint8Array>;\n readonly plans: PlannedRematerialization[];\n readonly principalPolicyCache: PrincipalPolicyCache;\n readonly rematerialization: PrincipalContainerRematerializationInput;\n readonly resolveProjectionUserKey: ReturnType<\n typeof createProjectionUserKeyResolver\n >;\n readonly rotatedAbove: SpeculativePath[];\n}\n\n/** How many rekeys the batch carries beyond its rematerializations. */\nfunction carriedCount(batch: BatchPlanning): number {\n return batch.plans.filter((entry) => entry.carried).length;\n}\n\n/**\n * Sign a rekey of `served` under the batch's rotations above it, and add it.\n * The server accepts at most `MAX_ROTATION_CONTAINER_REKEYS` carried entries;\n * past that a rematerialization below them could not be signed on a current\n * path, so the batch is refused here, before signing what the server would\n * refuse anyway, and the policy change has to wait for a lazy repair of the\n * tree. Groups granted that far apart on one chain are not a shape the SDK\n * creates.\n */\nexport async function carryLevel(\n batch: BatchPlanning,\n served: ContainerWriterProjectionResponse,\n): Promise<void> {\n const { rematerialization } = batch;\n if (carriedCount(batch) >= MAX_ROTATION_CONTAINER_REKEYS) {\n throw new Error(\n `Policy change would carry more than ${MAX_ROTATION_CONTAINER_REKEYS} descendant rekeys`,\n );\n }\n const planned = await planCarriedDescendantRekey({\n apiClient: rematerialization.apiClient,\n author: rematerialization.author,\n execSql: rematerialization.execSql,\n knownContainerKeks: batch.knownContainerKeks,\n principalPolicyCache: batch.principalPolicyCache,\n // Its path cites the policy this batch commits, so like every\n // rematerialized rotation it must cite the successor.\n replacementPrincipalPolicy: rematerialization.nextPolicy,\n resolveAuthoredPolicyReferences:\n rematerialization.resolveAuthoredPolicyReferences,\n resolveProjectionUserKey: batch.resolveProjectionUserKey,\n rotated: batch.rotatedAbove,\n served,\n stillCurrent: rematerialization.stillCurrent,\n targetSecretKey: rematerialization.targetSecretKey,\n warmReferencedPrincipalPolicies:\n rematerialization.warmReferencedPrincipalPolicies,\n });\n addPlan(batch, {\n carried: true,\n planned,\n rotated: planned.writerProjection,\n nextProjection: planned.writerProjection,\n });\n}\n\nexport function addPlan(\n batch: BatchPlanning,\n entry: PlannedRematerialization,\n): void {\n batch.plans.push(entry);\n if (!entry.rotated) return;\n batch.rotatedAbove.push(entry.rotated);\n const minted = entry.rotated.containerKeks.at(-1)?.containerKeyEpochId;\n if (minted) batch.knownContainerKeks.set(minted, entry.planned.containerKey);\n}\n\n/**\n * Levels of a re-rooted path pinned to an epoch the batch retires above them:\n * those strictly between the rotated ancestor the path was re-rooted on and\n * the target, parent-first, from the first stale one down. A rotation planned\n * above a target strands every level between the two, and each must be\n * re-keyed under the one above before the target can be signed. The batch\n * carries them without waiting to be told: they are proper ancestors of a\n * granted container, so the server would name them, and a refusal per level\n * is a round trip each. Anything stale above the rotated ancestor is not this\n * batch's doing and is left alone. `carryLevel` holds the count to the cap.\n */\nexport function staleLevelsAbove(\n projection: ContainerWriterProjectionResponse,\n rotatedAncestorId: string,\n): string[] {\n const keks = projection.containerKeks;\n const ancestor = keks.findIndex(\n (kek) => kek.containerId === rotatedAncestorId,\n );\n if (ancestor < 0) return [];\n const between = keks.slice(ancestor, -1);\n const firstStale = between.findIndex(\n (kek, index) =>\n index > 0 &&\n kek.parentContainerKeyEpochId !== between[index - 1]?.containerKeyEpochId,\n );\n return firstStale < 0\n ? []\n : between.slice(firstStale).map((kek) => kek.containerId);\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  import { MAX_ROTATION_CONTAINER_REKEYS } from "../../internal/validators/util/index.js";
2
2
  import { isContainerNotFoundFailure } from "../../data/containers/shared/mutationFailures.js";
3
3
  import { referencedPrincipalPolicyKey } from "../../data/keyingProjectionVerification/principalPolicyCache.js";
4
- import { containerWriterProjectionFromRotationPlan } from "../containers/child/rekeyProjection.js";
5
4
  /**
6
5
  * Order a batch parent-first, by served depth. A group granted on a container
7
6
  * and on one of its descendants rotates both, and the lower rotation must be
@@ -77,14 +76,4 @@ export function seededPrincipalPolicyCache(nextPolicy) {
77
76
  ],
78
77
  ]);
79
78
  }
80
- /** A rematerialization's path once accepted; null for a grant. */
81
- export async function rotatedPath(input) {
82
- const { plan } = input.planned;
83
- if (!("keyring" in plan))
84
- return null;
85
- return containerWriterProjectionFromRotationPlan({
86
- plan,
87
- previousProjection: input.previousProjection,
88
- });
89
- }
90
79
  //# sourceMappingURL=principalContainerRematerializationTargets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"principalContainerRematerializationTargets.js","sourceRoot":"","sources":["principalContainerRematerializationTargets.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalContainerGrant } from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { MAX_ROTATION_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport { isContainerNotFoundFailure } from \"../../data/containers/shared/mutationFailures\";\nimport type {\n MaterializedContainerRekeyPlan,\n MaterializedContainerRevokePlan,\n MaterializedContainerSharePlan,\n} from \"../../data/containers/shared/types\";\nimport type { PrincipalPolicyCache } from \"../../data/keyingProjectionVerification\";\nimport { referencedPrincipalPolicyKey } from \"../../data/keyingProjectionVerification/principalPolicyCache\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../data/principals/principalPolicyEvidence\";\nimport type { SpeculativePath } from \"../containers/child/carriedDescendantRekeys\";\nimport { containerWriterProjectionFromRotationPlan } from \"../containers/child/rekeyProjection\";\n\nexport type MaterializedPrincipalContainerMutationPlan =\n | MaterializedContainerRekeyPlan\n | MaterializedContainerRevokePlan\n | MaterializedContainerSharePlan;\n\n/** A plan with its container's path once accepted; null for a grant, which rotates nothing. */\nexport interface PlannedRematerialization {\n /** A descendant rekey carried for a rotation above, not a rematerialization. */\n readonly carried: boolean;\n readonly planned: MaterializedPrincipalContainerMutationPlan;\n readonly rotated: SpeculativePath | null;\n}\n\n/**\n * One container a batch signs for: a group grant it rematerializes, or a\n * descendant rekey it carries for a rotation above (`grantRow` null).\n */\nexport interface RematerializationTarget {\n readonly grantRow: PrincipalContainerGrant | null;\n readonly projection: ContainerWriterProjectionResponse;\n}\n\n/**\n * Order a batch parent-first, by served depth. A group granted on a container\n * and on one of its descendants rotates both, and the lower rotation must be\n * signed against the epoch the upper one mints in this same batch, or it\n * extends a head the batch itself retires. A carried rekey sits below the\n * rotation it rides for the same reason. Ties keep id order for stability.\n */\nexport function orderRematerializationsParentFirst<\n T extends {\n readonly projection: {\n readonly containerId: string;\n readonly path: readonly unknown[];\n };\n },\n>(batch: readonly T[]): T[] {\n return [...batch].sort(\n (left, right) =>\n left.projection.path.length - right.projection.path.length ||\n left.projection.containerId.localeCompare(right.projection.containerId),\n );\n}\n\ninterface ProjectionApi {\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n}\n\n/** The served projection of a container the batch will sign for. */\nexport async function loadServedProjection(\n apiClient: ProjectionApi,\n containerId: string,\n): Promise<ContainerWriterProjectionResponse> {\n const projection = await apiClient.getContainerWriterProjection(containerId);\n if (!projection) {\n throw new Error(\n `Container ${containerId} could not be prepared for principal rotation`,\n );\n }\n if (projection.containerId !== containerId) {\n throw new Error(\"Served projection describes another container\");\n }\n return projection;\n}\n\n/**\n * Fetch what the batch signs for, parent-first. A named descendant the batch\n * already rematerializes is not fetched twice: its own rotation is re-planned\n * under whatever the batch carries above it. Names are a hint from the server,\n * never an authority; each is verified where it is planned.\n */\nexport async function loadRematerializationTargets(input: {\n readonly apiClient: Pick<ApiClient, \"getContainerWriterProjectionResult\">;\n readonly carriedContainerIds: readonly string[];\n readonly grants: readonly PrincipalContainerGrant[];\n}): Promise<{\n targets: RematerializationTarget[];\n retiredContainerIds: string[];\n}> {\n const grantByContainerId = new Map(\n input.grants.map((grant) => [grant.containerId, grant] as const),\n );\n const carried = [...new Set(input.carriedContainerIds)]\n .filter((containerId) => !grantByContainerId.has(containerId))\n .slice(0, MAX_ROTATION_CONTAINER_REKEYS);\n const targets: RematerializationTarget[] = [];\n const retiredContainerIds: string[] = [];\n for (const containerId of [...grantByContainerId.keys(), ...carried].sort(\n (left, right) => left.localeCompare(right),\n )) {\n const grantRow = grantByContainerId.get(containerId) ?? null;\n const result = await input.apiClient.getContainerWriterProjectionResult(\n containerId,\n { reportErrors: false },\n );\n if (!result.ok) {\n // This is only a planning hint. Keep the signed grant intact; the API\n // independently requires every live grant under the organization lock.\n if (\n grantRow &&\n result.kind === \"http\" &&\n isContainerNotFoundFailure(result)\n ) {\n retiredContainerIds.push(containerId);\n continue;\n }\n result.report();\n throw new Error(\n `Container ${containerId} could not be prepared for principal rotation: ${result.message}`,\n );\n }\n if (result.data.containerId !== containerId)\n throw new Error(\"Served projection describes another container\");\n targets.push({ grantRow, projection: result.data });\n }\n return {\n targets: orderRematerializationsParentFirst(targets),\n retiredContainerIds,\n };\n}\n\n/** An in-memory cache holding only the policy this batch is about to commit. */\nexport function seededPrincipalPolicyCache(\n nextPolicy: PrincipalPolicyCurrentEvidence,\n): PrincipalPolicyCache {\n return new Map([\n [\n referencedPrincipalPolicyKey({\n keyEpoch: nextPolicy.keyEpoch,\n keyFingerprint: nextPolicy.state.keyFingerprint,\n principalId: nextPolicy.principalId,\n principalType: nextPolicy.principalType,\n stateHash: nextPolicy.stateHash,\n version: nextPolicy.version,\n }),\n nextPolicy,\n ],\n ]);\n}\n\n/** A rematerialization's path once accepted; null for a grant. */\nexport async function rotatedPath(input: {\n readonly planned: MaterializedPrincipalContainerMutationPlan;\n readonly previousProjection: ContainerWriterProjectionResponse;\n}): Promise<SpeculativePath | null> {\n const { plan } = input.planned;\n if (!(\"keyring\" in plan)) return null;\n return containerWriterProjectionFromRotationPlan({\n plan,\n previousProjection: input.previousProjection,\n });\n}\n"]}
1
+ {"version":3,"file":"principalContainerRematerializationTargets.js","sourceRoot":"","sources":["principalContainerRematerializationTargets.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalContainerGrant } from \"@tearleads/crypto\";\nimport type { ContainerWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { MAX_ROTATION_CONTAINER_REKEYS } from \"@tearleads/validators/util\";\nimport { isContainerNotFoundFailure } from \"../../data/containers/shared/mutationFailures\";\nimport type {\n MaterializedContainerRekeyPlan,\n MaterializedContainerRevokePlan,\n MaterializedContainerSharePlan,\n} from \"../../data/containers/shared/types\";\nimport type { PrincipalPolicyCache } from \"../../data/keyingProjectionVerification\";\nimport { referencedPrincipalPolicyKey } from \"../../data/keyingProjectionVerification/principalPolicyCache\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../data/principals/principalPolicyEvidence\";\nimport type { SpeculativePath } from \"../containers/child/carriedDescendantRekeys\";\n\nexport type MaterializedPrincipalContainerMutationPlan =\n | MaterializedContainerRekeyPlan\n | MaterializedContainerRevokePlan\n | MaterializedContainerSharePlan;\n\n/** Authored paths for chaining plans; only rotated is null for a grant. */\nexport interface PlannedRematerialization {\n /** The authored successor for either a grant or a rotation. */\n readonly nextProjection?: ContainerWriterProjectionResponse | undefined;\n /** A descendant rekey carried for a rotation above, not a rematerialization. */\n readonly carried: boolean;\n readonly planned: MaterializedPrincipalContainerMutationPlan;\n readonly rotated: SpeculativePath | null;\n}\n\n/**\n * One container a batch signs for: a group grant it rematerializes, or a\n * descendant rekey it carries for a rotation above (`grantRow` null).\n */\nexport interface RematerializationTarget {\n readonly grantRow: PrincipalContainerGrant | null;\n readonly projection: ContainerWriterProjectionResponse;\n}\n\n/**\n * Order a batch parent-first, by served depth. A group granted on a container\n * and on one of its descendants rotates both, and the lower rotation must be\n * signed against the epoch the upper one mints in this same batch, or it\n * extends a head the batch itself retires. A carried rekey sits below the\n * rotation it rides for the same reason. Ties keep id order for stability.\n */\nexport function orderRematerializationsParentFirst<\n T extends {\n readonly projection: {\n readonly containerId: string;\n readonly path: readonly unknown[];\n };\n },\n>(batch: readonly T[]): T[] {\n return [...batch].sort(\n (left, right) =>\n left.projection.path.length - right.projection.path.length ||\n left.projection.containerId.localeCompare(right.projection.containerId),\n );\n}\n\ninterface ProjectionApi {\n getContainerWriterProjection(\n containerId: string,\n ): Promise<ContainerWriterProjectionResponse | null>;\n}\n\n/** The served projection of a container the batch will sign for. */\nexport async function loadServedProjection(\n apiClient: ProjectionApi,\n containerId: string,\n): Promise<ContainerWriterProjectionResponse> {\n const projection = await apiClient.getContainerWriterProjection(containerId);\n if (!projection) {\n throw new Error(\n `Container ${containerId} could not be prepared for principal rotation`,\n );\n }\n if (projection.containerId !== containerId) {\n throw new Error(\"Served projection describes another container\");\n }\n return projection;\n}\n\n/**\n * Fetch what the batch signs for, parent-first. A named descendant the batch\n * already rematerializes is not fetched twice: its own rotation is re-planned\n * under whatever the batch carries above it. Names are a hint from the server,\n * never an authority; each is verified where it is planned.\n */\nexport async function loadRematerializationTargets(input: {\n readonly apiClient: Pick<ApiClient, \"getContainerWriterProjectionResult\">;\n readonly carriedContainerIds: readonly string[];\n readonly grants: readonly PrincipalContainerGrant[];\n}): Promise<{\n targets: RematerializationTarget[];\n retiredContainerIds: string[];\n}> {\n const grantByContainerId = new Map(\n input.grants.map((grant) => [grant.containerId, grant] as const),\n );\n const carried = [...new Set(input.carriedContainerIds)]\n .filter((containerId) => !grantByContainerId.has(containerId))\n .slice(0, MAX_ROTATION_CONTAINER_REKEYS);\n const targets: RematerializationTarget[] = [];\n const retiredContainerIds: string[] = [];\n for (const containerId of [...grantByContainerId.keys(), ...carried].sort(\n (left, right) => left.localeCompare(right),\n )) {\n const grantRow = grantByContainerId.get(containerId) ?? null;\n const result = await input.apiClient.getContainerWriterProjectionResult(\n containerId,\n { reportErrors: false },\n );\n if (!result.ok) {\n // This is only a planning hint. Keep the signed grant intact; the API\n // independently requires every live grant under the organization lock.\n if (\n grantRow &&\n result.kind === \"http\" &&\n isContainerNotFoundFailure(result)\n ) {\n retiredContainerIds.push(containerId);\n continue;\n }\n result.report();\n throw new Error(\n `Container ${containerId} could not be prepared for principal rotation: ${result.message}`,\n );\n }\n if (result.data.containerId !== containerId)\n throw new Error(\"Served projection describes another container\");\n targets.push({ grantRow, projection: result.data });\n }\n return {\n targets: orderRematerializationsParentFirst(targets),\n retiredContainerIds,\n };\n}\n\n/** An in-memory cache holding only the policy this batch is about to commit. */\nexport function seededPrincipalPolicyCache(\n nextPolicy: PrincipalPolicyCurrentEvidence,\n): PrincipalPolicyCache {\n return new Map([\n [\n referencedPrincipalPolicyKey({\n keyEpoch: nextPolicy.keyEpoch,\n keyFingerprint: nextPolicy.state.keyFingerprint,\n principalId: nextPolicy.principalId,\n principalType: nextPolicy.principalType,\n stateHash: nextPolicy.stateHash,\n version: nextPolicy.version,\n }),\n nextPolicy,\n ],\n ]);\n}\n"]}
@@ -6,6 +6,12 @@ export async function assertAuthoredPrincipalMutationReceipt(request, response)
6
6
  for (const part of ["groupPolicy", "organizationPolicy"]) {
7
7
  await assertAuthoredPrincipalPolicyReceipt(request[part], response[part]);
8
8
  }
9
+ if (Boolean(request.memberPolicy) !== Boolean(response.memberPolicy)) {
10
+ throw new Error("Principal mutation receipt Members policy differs");
11
+ }
12
+ if (request.memberPolicy && response.memberPolicy) {
13
+ await assertAuthoredPrincipalPolicyReceipt(request.memberPolicy, response.memberPolicy);
14
+ }
9
15
  }
10
16
  export async function assertAuthoredPrincipalPolicyReceipt(expected, observed) {
11
17
  const { stateHash, createdAt: _createdAt, ...state } = observed.currentState;
@@ -1 +1 @@
1
- {"version":3,"file":"principalMutationReceipt.js","sourceRoot":"","sources":["principalMutationReceipt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,qCAAqC,EAAE,MAAM,mCAAmC,CAAC;AAE1F,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,sCAAsC,CAC1D,OAA6C,EAC7C,QAA+C;IAE/C,KAAK,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,oBAAoB,CAAU,EAAE,CAAC;QAClE,MAAM,oCAAoC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oCAAoC,CACxD,QAA6D,EAC7D,QAA8D;IAE9D,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC;IAC7E,IACE,SAAS,KAAK,CAAC,MAAM,yBAAyB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/D,yBAAyB,CAAC,KAAK,EAAE,kCAAkC,CAAC;YAClE,yBAAyB,CAAC,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC;QAEvE,MAAM,IAAI,KAAK,CACb,oEAAoE,CACrE,CAAC;IACJ,qCAAqC,CAAC;QACpC,OAAO,EAAE,QAAQ;QACjB,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,EAAE,GAAG,QAAQ,CAAC,YAAY,EAAE,SAAS,EAAE;KACtD,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { computePrincipalStateHash } from \"@tearleads/crypto\";\nimport type { CommitOrganizationGroupPolicyRequest } from \"@tearleads/validators/request\";\nimport type { CommitOrganizationGroupPolicyResponse } from \"@tearleads/validators/response\";\nimport { canonicalKeyingJsonString } from \"../../data/keyingCanonicalJson\";\nimport { assertPrincipalPolicyReceiptArtifacts } from \"./principalPolicyReceiptArtifacts\";\n\n/** A past commit acknowledgement is not evidence for advancing current pins. */\nexport async function assertAuthoredPrincipalMutationReceipt(\n request: CommitOrganizationGroupPolicyRequest,\n response: CommitOrganizationGroupPolicyResponse,\n): Promise<void> {\n for (const part of [\"groupPolicy\", \"organizationPolicy\"] as const) {\n await assertAuthoredPrincipalPolicyReceipt(request[part], response[part]);\n }\n}\n\nexport async function assertAuthoredPrincipalPolicyReceipt(\n expected: CommitOrganizationGroupPolicyRequest[\"groupPolicy\"],\n observed: CommitOrganizationGroupPolicyResponse[\"groupPolicy\"],\n): Promise<void> {\n const { stateHash, createdAt: _createdAt, ...state } = observed.currentState;\n if (\n stateHash !== (await computePrincipalStateHash(expected.state)) ||\n canonicalKeyingJsonString(state, \"principal mutation receipt state\") !==\n canonicalKeyingJsonString(expected.state, \"authored principal state\")\n )\n throw new Error(\n \"Principal mutation receipt state differs from the authored request\",\n );\n assertPrincipalPolicyReceiptArtifacts({\n request: expected,\n response: observed,\n expectedHead: { ...observed.currentState, stateHash },\n });\n}\n"]}
1
+ {"version":3,"file":"principalMutationReceipt.js","sourceRoot":"","sources":["principalMutationReceipt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,qCAAqC,EAAE,MAAM,mCAAmC,CAAC;AAE1F,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,sCAAsC,CAC1D,OAA6C,EAC7C,QAA+C;IAE/C,KAAK,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,oBAAoB,CAAU,EAAE,CAAC;QAClE,MAAM,oCAAoC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAClD,MAAM,oCAAoC,CACxC,OAAO,CAAC,YAAY,EACpB,QAAQ,CAAC,YAAY,CACtB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oCAAoC,CACxD,QAA6D,EAC7D,QAA8D;IAE9D,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC;IAC7E,IACE,SAAS,KAAK,CAAC,MAAM,yBAAyB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/D,yBAAyB,CAAC,KAAK,EAAE,kCAAkC,CAAC;YAClE,yBAAyB,CAAC,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC;QAEvE,MAAM,IAAI,KAAK,CACb,oEAAoE,CACrE,CAAC;IACJ,qCAAqC,CAAC;QACpC,OAAO,EAAE,QAAQ;QACjB,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,EAAE,GAAG,QAAQ,CAAC,YAAY,EAAE,SAAS,EAAE;KACtD,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { computePrincipalStateHash } from \"@tearleads/crypto\";\nimport type { CommitOrganizationGroupPolicyRequest } from \"@tearleads/validators/request\";\nimport type { CommitOrganizationGroupPolicyResponse } from \"@tearleads/validators/response\";\nimport { canonicalKeyingJsonString } from \"../../data/keyingCanonicalJson\";\nimport { assertPrincipalPolicyReceiptArtifacts } from \"./principalPolicyReceiptArtifacts\";\n\n/** A past commit acknowledgement is not evidence for advancing current pins. */\nexport async function assertAuthoredPrincipalMutationReceipt(\n request: CommitOrganizationGroupPolicyRequest,\n response: CommitOrganizationGroupPolicyResponse,\n): Promise<void> {\n for (const part of [\"groupPolicy\", \"organizationPolicy\"] as const) {\n await assertAuthoredPrincipalPolicyReceipt(request[part], response[part]);\n }\n if (Boolean(request.memberPolicy) !== Boolean(response.memberPolicy)) {\n throw new Error(\"Principal mutation receipt Members policy differs\");\n }\n if (request.memberPolicy && response.memberPolicy) {\n await assertAuthoredPrincipalPolicyReceipt(\n request.memberPolicy,\n response.memberPolicy,\n );\n }\n}\n\nexport async function assertAuthoredPrincipalPolicyReceipt(\n expected: CommitOrganizationGroupPolicyRequest[\"groupPolicy\"],\n observed: CommitOrganizationGroupPolicyResponse[\"groupPolicy\"],\n): Promise<void> {\n const { stateHash, createdAt: _createdAt, ...state } = observed.currentState;\n if (\n stateHash !== (await computePrincipalStateHash(expected.state)) ||\n canonicalKeyingJsonString(state, \"principal mutation receipt state\") !==\n canonicalKeyingJsonString(expected.state, \"authored principal state\")\n )\n throw new Error(\n \"Principal mutation receipt state differs from the authored request\",\n );\n assertPrincipalPolicyReceiptArtifacts({\n request: expected,\n response: observed,\n expectedHead: { ...observed.currentState, stateHash },\n });\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import type { RequestFailureKind } from "../../internal/api-client/index.js";
2
+ import type { CommitOrganizationGroupPolicyRequest, CreateOrganizationGroupWithPolicyRequest } from "../../internal/validators/request/index.js";
3
+ import type { CommitOrganizationGroupPolicyResponse, CreateOrganizationGroupResponse, PrincipalPolicyBundleResponse } from "../../internal/validators/response/index.js";
4
+ export interface PrincipalPolicyReadApi {
5
+ /** Resolve authored work before reading the state for a new mutation. */
6
+ readonly recoverPendingPrincipalMutation?: ((organizationId: string) => Promise<void>) | undefined;
7
+ getCurrentPrincipalPolicy: (principalType: "group" | "organization", principalId: string) => Promise<PrincipalPolicyBundleResponse | null>;
8
+ }
9
+ export interface PrincipalPolicyReadWriteApi extends PrincipalPolicyReadApi {
10
+ commitOrganizationGroupPolicy: (organizationId: string, groupId: string, input: CommitOrganizationGroupPolicyRequest) => Promise<CommitOrganizationGroupPolicyResponse | null>;
11
+ /**
12
+ * Optional status-bearing variant. A rematerialized rotation the server
13
+ * refuses for stranding a granted path names the descendant rekeys the batch
14
+ * must carry; without this the refusal is a plain failure.
15
+ */
16
+ commitOrganizationGroupPolicyResult?: (organizationId: string, groupId: string, input: CommitOrganizationGroupPolicyRequest, options?: {
17
+ readonly reportErrors?: boolean | undefined;
18
+ }) => Promise<{
19
+ readonly ok: true;
20
+ readonly data: CommitOrganizationGroupPolicyResponse;
21
+ } | {
22
+ readonly ok: false;
23
+ readonly kind?: RequestFailureKind | undefined;
24
+ readonly message?: string | undefined;
25
+ readonly code?: string | undefined;
26
+ readonly report?: (() => void) | undefined;
27
+ readonly requiredContainerIds?: readonly string[] | undefined;
28
+ readonly status: number | null;
29
+ }>;
30
+ }
31
+ export interface OrganizationPrincipalPolicyApi extends PrincipalPolicyReadApi {
32
+ createOrganizationGroup: (organizationId: string, input: CreateOrganizationGroupWithPolicyRequest) => Promise<CreateOrganizationGroupResponse | null>;
33
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=principalPolicyApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"principalPolicyApi.js","sourceRoot":"","sources":["principalPolicyApi.ts"],"names":[],"mappings":"","sourcesContent":["import type { RequestFailureKind } from \"@tearleads/api-client\";\nimport type {\n CommitOrganizationGroupPolicyRequest,\n CreateOrganizationGroupWithPolicyRequest,\n} from \"@tearleads/validators/request\";\nimport type {\n CommitOrganizationGroupPolicyResponse,\n CreateOrganizationGroupResponse,\n PrincipalPolicyBundleResponse,\n} from \"@tearleads/validators/response\";\n\nexport interface PrincipalPolicyReadApi {\n /** Resolve authored work before reading the state for a new mutation. */\n readonly recoverPendingPrincipalMutation?:\n | ((organizationId: string) => Promise<void>)\n | undefined;\n getCurrentPrincipalPolicy: (\n principalType: \"group\" | \"organization\",\n principalId: string,\n ) => Promise<PrincipalPolicyBundleResponse | null>;\n}\n\nexport interface PrincipalPolicyReadWriteApi extends PrincipalPolicyReadApi {\n commitOrganizationGroupPolicy: (\n organizationId: string,\n groupId: string,\n input: CommitOrganizationGroupPolicyRequest,\n ) => Promise<CommitOrganizationGroupPolicyResponse | null>;\n /**\n * Optional status-bearing variant. A rematerialized rotation the server\n * refuses for stranding a granted path names the descendant rekeys the batch\n * must carry; without this the refusal is a plain failure.\n */\n commitOrganizationGroupPolicyResult?: (\n organizationId: string,\n groupId: string,\n input: CommitOrganizationGroupPolicyRequest,\n options?: { readonly reportErrors?: boolean | undefined },\n ) => Promise<\n | {\n readonly ok: true;\n readonly data: CommitOrganizationGroupPolicyResponse;\n }\n | {\n readonly ok: false;\n readonly kind?: RequestFailureKind | undefined;\n readonly message?: string | undefined;\n readonly code?: string | undefined;\n readonly report?: (() => void) | undefined;\n readonly requiredContainerIds?: readonly string[] | undefined;\n readonly status: number | null;\n }\n >;\n}\n\nexport interface OrganizationPrincipalPolicyApi extends PrincipalPolicyReadApi {\n createOrganizationGroup: (\n organizationId: string,\n input: CreateOrganizationGroupWithPolicyRequest,\n ) => Promise<CreateOrganizationGroupResponse | null>;\n}\n"]}
@@ -14,24 +14,31 @@ export function createRuntimeCurrentGroupMutation(runtime) {
14
14
  return async (input, work) => {
15
15
  input = { ...input };
16
16
  return lease(input.stillCurrent, async ({ protection, stillCurrent, resolveCurrentPolicy, readPages, directoryRecovery, }) => {
17
- const context = await loadCurrentGroupPolicyMutationContext({
18
- ...input,
19
- execSql: runtime.infra.execSql,
20
- resolveCurrentPolicy,
21
- recoverPendingPrincipalMutation: (organizationId) => runtime.apiClient.recoverPendingPrincipalMutation(organizationId),
22
- stillCurrent,
23
- });
24
- const result = await work({
25
- ...context,
26
- resolveAuthoredPolicyReferences: (current, references) => resolveCurrentGroupMutationReferences({
27
- current,
28
- predecessor: context.verifiedCurrentPolicy,
29
- references,
30
- readPredecessorReference: context.readPredecessorReference,
31
- stillCurrent: context.stillCurrent,
32
- }),
33
- retainAcknowledged: await createCurrentMutationRetention(runtime, input, context, protection, readPages, directoryRecovery(context.organizationCurrent.current)),
34
- });
17
+ const loadGroup = async (groupId) => {
18
+ const context = await loadCurrentGroupPolicyMutationContext({
19
+ ...input,
20
+ groupId,
21
+ execSql: runtime.infra.execSql,
22
+ resolveCurrentPolicy,
23
+ recoverPendingPrincipalMutation: (organizationId) => runtime.apiClient.recoverPendingPrincipalMutation(organizationId),
24
+ stillCurrent,
25
+ });
26
+ const retention = await createCurrentMutationRetention(runtime, { ...input, groupId }, context, protection, readPages, directoryRecovery(context.organizationCurrent.current));
27
+ return {
28
+ ...context,
29
+ ...retention,
30
+ loadGroup,
31
+ resolveAuthoredPolicyReferences: (current, references) => resolveCurrentGroupMutationReferences({
32
+ current,
33
+ predecessor: context.verifiedCurrentPolicy,
34
+ references,
35
+ readPredecessorReference: context.readPredecessorReference,
36
+ stillCurrent: context.stillCurrent,
37
+ }),
38
+ };
39
+ };
40
+ const context = await loadGroup(input.groupId);
41
+ const result = await work(context);
35
42
  assertProjectionVerificationCurrent(context.stillCurrent);
36
43
  return result;
37
44
  });
@@ -63,12 +70,13 @@ async function createCurrentMutationRetention(runtime, input, context, protectio
63
70
  });
64
71
  const groupPredecessor = await capture(groupRecovery);
65
72
  const directoryPredecessor = await capture(directoryRecovery);
66
- return async (receipt) => {
73
+ const retainAcknowledged = async (receipt) => {
67
74
  assertProjectionVerificationCurrent(context.stillCurrent);
68
75
  await retainAcknowledgedPrincipalCurrents({
69
76
  execSql: runtime.infra.execSql,
70
77
  organizationId: input.organizationId,
71
78
  entries: [
79
+ ...(receipt.additionalGroups ?? []),
72
80
  {
73
81
  recovery: groupRecovery,
74
82
  predecessor: groupPredecessor,
@@ -83,6 +91,11 @@ async function createCurrentMutationRetention(runtime, input, context, protectio
83
91
  },
84
92
  ],
85
93
  retirements: [
94
+ ...(receipt.additionalGroups ?? []).map((entry) => ({
95
+ principalId: entry.request.state.principalId,
96
+ principalType: "group",
97
+ containerIds: entry.retiredContainerIds ?? [],
98
+ })),
86
99
  {
87
100
  principalId: input.groupId,
88
101
  principalType: "group",
@@ -92,5 +105,9 @@ async function createCurrentMutationRetention(runtime, input, context, protectio
92
105
  stillCurrent: context.stillCurrent,
93
106
  });
94
107
  };
108
+ return {
109
+ groupRetention: { recovery: groupRecovery, predecessor: groupPredecessor },
110
+ retainAcknowledged,
111
+ };
95
112
  }
96
113
  //# sourceMappingURL=runtimeCurrentGroupMutation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeCurrentGroupMutation.js","sourceRoot":"","sources":["runtimeCurrentGroupMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalPolicyHistoryProgressOptions } from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport type { CommitOrganizationGroupPolicyResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport type { CurrentPolicyReferenceResolver } from \"../../data/principals/currentPolicyReferenceResolver\";\nimport { scopedGroupHistoryProtection } from \"../../data/principals/principalHistoryScopeProtection\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { PrincipalPolicyRecoveryRuntime } from \"../principals/runtimePolicyRecovery\";\nimport { captureAcknowledgedPrincipalPredecessor } from \"./acknowledgedPrincipalPredecessor\";\nimport { resolveCurrentGroupMutationReferences } from \"./currentGroupMutationReferences\";\nimport { loadCurrentGroupPolicyMutationContext } from \"./currentGroupPolicyMutationContext\";\nimport { createCurrentPrincipalMutationLease } from \"./currentPrincipalMutationLease\";\nimport type { PrincipalMutationRecoveryApi } from \"./principalMutationJournalManagement\";\nimport {\n type AcknowledgedPrincipalCurrentInput,\n retainAcknowledgedPrincipalCurrents,\n} from \"./retainAcknowledgedPrincipalCurrents\";\n\ntype MutationRuntime = PrincipalPolicyRecoveryRuntime & {\n readonly apiClient: PrincipalPolicyRecoveryRuntime[\"apiClient\"] &\n Pick<PrincipalMutationRecoveryApi, \"recoverPendingPrincipalMutation\">;\n};\n\ntype CurrentMutationContext = Awaited<\n ReturnType<typeof loadCurrentGroupPolicyMutationContext>\n>;\n\nexport type RuntimeCurrentGroupMutationContext = CurrentMutationContext & {\n readonly resolveAuthoredPolicyReferences: CurrentPolicyReferenceResolver;\n readonly retainAcknowledged: (\n receipt: CurrentMutationReceipt,\n ) => Promise<void>;\n};\n\ninterface CurrentMutationReceipt {\n readonly request: PutPrincipalPolicyRequest;\n readonly organizationRequest: PutPrincipalPolicyRequest;\n readonly response: CommitOrganizationGroupPolicyResponse;\n readonly retiredContainerIds?: readonly string[] | undefined;\n}\n\ninterface MutationInput {\n readonly groupId: string;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly stillCurrent: () => boolean;\n}\n\n/** Keep private prefix custody inside the entire mutation and its acknowledgement. */\nexport function createRuntimeCurrentGroupMutation(runtime: MutationRuntime) {\n const lease = createCurrentPrincipalMutationLease(runtime);\n if (!lease) return undefined;\n return async <T>(\n input: MutationInput,\n work: (context: RuntimeCurrentGroupMutationContext) => Promise<T>,\n ): Promise<T> => {\n input = { ...input };\n return lease(\n input.stillCurrent,\n async ({\n protection,\n stillCurrent,\n resolveCurrentPolicy,\n readPages,\n directoryRecovery,\n }) => {\n const context = await loadCurrentGroupPolicyMutationContext({\n ...input,\n execSql: runtime.infra.execSql,\n resolveCurrentPolicy,\n recoverPendingPrincipalMutation: (organizationId) =>\n runtime.apiClient.recoverPendingPrincipalMutation(organizationId),\n stillCurrent,\n });\n const result = await work({\n ...context,\n resolveAuthoredPolicyReferences: (current, references) =>\n resolveCurrentGroupMutationReferences({\n current,\n predecessor: context.verifiedCurrentPolicy,\n references,\n readPredecessorReference: context.readPredecessorReference,\n stillCurrent: context.stillCurrent,\n }),\n retainAcknowledged: await createCurrentMutationRetention(\n runtime,\n input,\n context,\n protection,\n readPages,\n directoryRecovery(context.organizationCurrent.current),\n ),\n });\n assertProjectionVerificationCurrent(context.stillCurrent);\n return result;\n },\n );\n };\n}\n\nasync function createCurrentMutationRetention(\n runtime: MutationRuntime,\n input: MutationInput,\n context: CurrentMutationContext,\n protection: PrincipalPolicyHistoryProgressOptions,\n readPages: ApiClient[\"getPrincipalPolicyPages\"],\n directoryRecovery: AcknowledgedPrincipalCurrentInput[\"recovery\"],\n) {\n const common = {\n apiClient: { getPrincipalPolicyPages: readPages },\n resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,\n };\n const groupRecovery: AcknowledgedPrincipalCurrentInput[\"recovery\"] = {\n ...common,\n expectedHead: principalPolicyReferenceFromBundle(context.currentPolicy),\n protection: context.isOrganizationAdminsGroup\n ? protection\n : scopedGroupHistoryProtection(\n protection,\n input.organizationId,\n context.adminGroupId,\n ),\n historyVerification: context.isOrganizationAdminsGroup\n ? \"direct-admins\"\n : \"standard\",\n ...(context.isOrganizationAdminsGroup\n ? {}\n : { loadExternalAuthority: async () => context.externalAuthority }),\n };\n const capture = (recovery: AcknowledgedPrincipalCurrentInput[\"recovery\"]) =>\n captureAcknowledgedPrincipalPredecessor({\n ...recovery,\n execSql: runtime.infra.execSql,\n organizationId: input.organizationId,\n stillCurrent: context.stillCurrent,\n });\n const groupPredecessor = await capture(groupRecovery);\n const directoryPredecessor = await capture(directoryRecovery);\n return async (receipt: CurrentMutationReceipt): Promise<void> => {\n assertProjectionVerificationCurrent(context.stillCurrent);\n await retainAcknowledgedPrincipalCurrents({\n execSql: runtime.infra.execSql,\n organizationId: input.organizationId,\n entries: [\n {\n recovery: groupRecovery,\n predecessor: groupPredecessor,\n request: receipt.request,\n response: receipt.response.groupPolicy,\n },\n {\n recovery: directoryRecovery,\n predecessor: directoryPredecessor,\n request: receipt.organizationRequest,\n response: receipt.response.organizationPolicy,\n },\n ],\n retirements: [\n {\n principalId: input.groupId,\n principalType: \"group\",\n containerIds: receipt.retiredContainerIds ?? [],\n },\n ],\n stillCurrent: context.stillCurrent,\n });\n };\n}\n"]}
1
+ {"version":3,"file":"runtimeCurrentGroupMutation.js","sourceRoot":"","sources":["runtimeCurrentGroupMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalPolicyHistoryProgressOptions } from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport type { CommitOrganizationGroupPolicyResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport type { CurrentPolicyReferenceResolver } from \"../../data/principals/currentPolicyReferenceResolver\";\nimport { scopedGroupHistoryProtection } from \"../../data/principals/principalHistoryScopeProtection\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { PrincipalPolicyRecoveryRuntime } from \"../principals/runtimePolicyRecovery\";\nimport { captureAcknowledgedPrincipalPredecessor } from \"./acknowledgedPrincipalPredecessor\";\nimport { resolveCurrentGroupMutationReferences } from \"./currentGroupMutationReferences\";\nimport { loadCurrentGroupPolicyMutationContext } from \"./currentGroupPolicyMutationContext\";\nimport { createCurrentPrincipalMutationLease } from \"./currentPrincipalMutationLease\";\nimport type { PrincipalMutationRecoveryApi } from \"./principalMutationJournalManagement\";\nimport {\n type AcknowledgedPrincipalCurrentInput,\n retainAcknowledgedPrincipalCurrents,\n} from \"./retainAcknowledgedPrincipalCurrents\";\n\ntype MutationRuntime = PrincipalPolicyRecoveryRuntime & {\n readonly apiClient: PrincipalPolicyRecoveryRuntime[\"apiClient\"] &\n Pick<PrincipalMutationRecoveryApi, \"recoverPendingPrincipalMutation\">;\n};\n\ntype CurrentMutationContext = Awaited<\n ReturnType<typeof loadCurrentGroupPolicyMutationContext>\n>;\n\nexport type RuntimeCurrentGroupMutationContext = CurrentMutationContext & {\n readonly resolveAuthoredPolicyReferences: CurrentPolicyReferenceResolver;\n readonly loadGroup: (\n groupId: string,\n ) => Promise<RuntimeCurrentGroupMutationContext>;\n readonly groupRetention: Pick<\n AcknowledgedPrincipalCurrentInput,\n \"recovery\" | \"predecessor\"\n >;\n readonly retainAcknowledged: (\n receipt: CurrentMutationReceipt,\n ) => Promise<void>;\n};\n\ninterface CurrentMutationReceipt {\n readonly additionalGroups?:\n | readonly (AcknowledgedPrincipalCurrentInput & {\n readonly retiredContainerIds?: readonly string[] | undefined;\n })[]\n | undefined;\n readonly request: PutPrincipalPolicyRequest;\n readonly organizationRequest: PutPrincipalPolicyRequest;\n readonly response: CommitOrganizationGroupPolicyResponse;\n readonly retiredContainerIds?: readonly string[] | undefined;\n}\n\ninterface MutationInput {\n readonly groupId: string;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly stillCurrent: () => boolean;\n}\n\n/** Keep private prefix custody inside the entire mutation and its acknowledgement. */\nexport function createRuntimeCurrentGroupMutation(runtime: MutationRuntime) {\n const lease = createCurrentPrincipalMutationLease(runtime);\n if (!lease) return undefined;\n return async <T>(\n input: MutationInput,\n work: (context: RuntimeCurrentGroupMutationContext) => Promise<T>,\n ): Promise<T> => {\n input = { ...input };\n return lease(\n input.stillCurrent,\n async ({\n protection,\n stillCurrent,\n resolveCurrentPolicy,\n readPages,\n directoryRecovery,\n }) => {\n const loadGroup = async (\n groupId: string,\n ): Promise<RuntimeCurrentGroupMutationContext> => {\n const context = await loadCurrentGroupPolicyMutationContext({\n ...input,\n groupId,\n execSql: runtime.infra.execSql,\n resolveCurrentPolicy,\n recoverPendingPrincipalMutation: (organizationId) =>\n runtime.apiClient.recoverPendingPrincipalMutation(organizationId),\n stillCurrent,\n });\n const retention = await createCurrentMutationRetention(\n runtime,\n { ...input, groupId },\n context,\n protection,\n readPages,\n directoryRecovery(context.organizationCurrent.current),\n );\n return {\n ...context,\n ...retention,\n loadGroup,\n resolveAuthoredPolicyReferences: (current, references) =>\n resolveCurrentGroupMutationReferences({\n current,\n predecessor: context.verifiedCurrentPolicy,\n references,\n readPredecessorReference: context.readPredecessorReference,\n stillCurrent: context.stillCurrent,\n }),\n };\n };\n const context = await loadGroup(input.groupId);\n const result = await work(context);\n assertProjectionVerificationCurrent(context.stillCurrent);\n return result;\n },\n );\n };\n}\n\nasync function createCurrentMutationRetention(\n runtime: MutationRuntime,\n input: MutationInput,\n context: CurrentMutationContext,\n protection: PrincipalPolicyHistoryProgressOptions,\n readPages: ApiClient[\"getPrincipalPolicyPages\"],\n directoryRecovery: AcknowledgedPrincipalCurrentInput[\"recovery\"],\n) {\n const common = {\n apiClient: { getPrincipalPolicyPages: readPages },\n resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,\n };\n const groupRecovery: AcknowledgedPrincipalCurrentInput[\"recovery\"] = {\n ...common,\n expectedHead: principalPolicyReferenceFromBundle(context.currentPolicy),\n protection: context.isOrganizationAdminsGroup\n ? protection\n : scopedGroupHistoryProtection(\n protection,\n input.organizationId,\n context.adminGroupId,\n ),\n historyVerification: context.isOrganizationAdminsGroup\n ? \"direct-admins\"\n : \"standard\",\n ...(context.isOrganizationAdminsGroup\n ? {}\n : { loadExternalAuthority: async () => context.externalAuthority }),\n };\n const capture = (recovery: AcknowledgedPrincipalCurrentInput[\"recovery\"]) =>\n captureAcknowledgedPrincipalPredecessor({\n ...recovery,\n execSql: runtime.infra.execSql,\n organizationId: input.organizationId,\n stillCurrent: context.stillCurrent,\n });\n const groupPredecessor = await capture(groupRecovery);\n const directoryPredecessor = await capture(directoryRecovery);\n const retainAcknowledged = async (\n receipt: CurrentMutationReceipt,\n ): Promise<void> => {\n assertProjectionVerificationCurrent(context.stillCurrent);\n await retainAcknowledgedPrincipalCurrents({\n execSql: runtime.infra.execSql,\n organizationId: input.organizationId,\n entries: [\n ...(receipt.additionalGroups ?? []),\n {\n recovery: groupRecovery,\n predecessor: groupPredecessor,\n request: receipt.request,\n response: receipt.response.groupPolicy,\n },\n {\n recovery: directoryRecovery,\n predecessor: directoryPredecessor,\n request: receipt.organizationRequest,\n response: receipt.response.organizationPolicy,\n },\n ],\n retirements: [\n ...(receipt.additionalGroups ?? []).map((entry) => ({\n principalId: entry.request.state.principalId,\n principalType: \"group\" as const,\n containerIds: entry.retiredContainerIds ?? [],\n })),\n {\n principalId: input.groupId,\n principalType: \"group\",\n containerIds: receipt.retiredContainerIds ?? [],\n },\n ],\n stillCurrent: context.stillCurrent,\n });\n };\n return {\n groupRetention: { recovery: groupRecovery, predecessor: groupPredecessor },\n retainAcknowledged,\n };\n}\n"]}