@tearleads/client-sdk 0.1.21 → 0.1.23

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 (54) hide show
  1. package/client/organizations/organizationGroupHistory.js +4 -7
  2. package/client/organizations/organizationGroupHistory.js.map +1 -1
  3. package/client/organizations/organizationReadModels.js +2 -86
  4. package/client/organizations/organizationReadModels.js.map +1 -1
  5. package/client/organizations/principalMutations.js +53 -133
  6. package/client/organizations/principalMutations.js.map +1 -1
  7. package/client/principalMutationDispatch.js +2 -2
  8. package/client/principalMutationDispatch.js.map +1 -1
  9. package/data/keyingProjectionVerification/principalPolicyVerification.js +5 -5
  10. package/data/keyingProjectionVerification/principalPolicyVerification.js.map +1 -1
  11. package/data/keyingProjectionVerification/resolvedPrincipalPolicy.js +21 -7
  12. package/data/keyingProjectionVerification/resolvedPrincipalPolicy.js.map +1 -1
  13. package/data/keyingProjectionVerification/types.d.ts +1 -8
  14. package/data/keyingProjectionVerification/types.js +0 -9
  15. package/data/keyingProjectionVerification/types.js.map +1 -1
  16. package/data/keyingProjectionVerification.d.ts +1 -1
  17. package/data/keyingProjectionVerification.js.map +1 -1
  18. package/data/persistence/principalHistoryPrefixPersistence.d.ts +5 -1
  19. package/data/persistence/principalHistoryPrefixPersistence.js +22 -5
  20. package/data/persistence/principalHistoryPrefixPersistence.js.map +1 -1
  21. package/data/principals/principalMutationJournalShape.d.ts +1 -1
  22. package/data/principals/principalMutationJournalShape.js +2 -2
  23. package/data/principals/principalMutationJournalShape.js.map +1 -1
  24. package/index.js.map +1 -1
  25. package/package.json +1 -1
  26. package/workflows/container-contents/container-state/groupGrantVerification.js +23 -74
  27. package/workflows/container-contents/container-state/groupGrantVerification.js.map +1 -1
  28. package/workflows/container-contents/container-state/groupShareEpoch.js +6 -23
  29. package/workflows/container-contents/container-state/groupShareEpoch.js.map +1 -1
  30. package/workflows/container-contents/container-state/remote.js +5 -3
  31. package/workflows/container-contents/container-state/remote.js.map +1 -1
  32. package/workflows/container-contents/container-state/types.js.map +1 -1
  33. package/workflows/container-contents/documentLinks.d.ts +1 -1
  34. package/workflows/container-contents/documentLinks.js.map +1 -1
  35. package/workflows/container-contents/documentPurge.d.ts +1 -1
  36. package/workflows/container-contents/documentPurge.js.map +1 -1
  37. package/workflows/container-contents/metadataRemoteSync.d.ts +1 -1
  38. package/workflows/container-contents/metadataRemoteSync.js.map +1 -1
  39. package/workflows/container-contents/remoteHydration/types.d.ts +2 -2
  40. package/workflows/container-contents/remoteHydration/types.js.map +1 -1
  41. package/workflows/container-contents/remoteHydration/verifiedDestination.js +6 -7
  42. package/workflows/container-contents/remoteHydration/verifiedDestination.js.map +1 -1
  43. package/workflows/containers/child/runtimeCurrentGroupShare.js +1 -1
  44. package/workflows/containers/child/runtimeCurrentGroupShare.js.map +1 -1
  45. package/workflows/organizations/groupMetadataRuntime.js +11 -8
  46. package/workflows/organizations/groupMetadataRuntime.js.map +1 -1
  47. package/workflows/organizations/organizationGroupNames.js +8 -55
  48. package/workflows/organizations/organizationGroupNames.js.map +1 -1
  49. package/workflows/organizations/principalOperationReceipt.js +1 -1
  50. package/workflows/organizations/principalOperationReceipt.js.map +1 -1
  51. package/workflows/organizations/runtimeGroupMetadataAuthority.js +16 -0
  52. package/workflows/organizations/runtimeGroupMetadataAuthority.js.map +1 -0
  53. package/workflows/principals/runtimePolicyWarmer.js +29 -27
  54. package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
@@ -9,7 +9,7 @@ export function dispatchAuthoredPrincipalMutation(api, organizationId, mutation,
9
9
  return api.createOrganizationGroupResult(organizationId, mutation.request, options);
10
10
  case "group-delete":
11
11
  return api.deleteOrganizationGroupResult(organizationId, mutation.groupId, mutation.request, options);
12
- case undefined:
12
+ case "compound":
13
13
  return api.commitOrganizationGroupPolicyResult(organizationId, mutation.groupId, mutation.request, options);
14
14
  default:
15
15
  return unsupportedMutation(mutation);
@@ -33,7 +33,7 @@ export function createJournaledPrincipalMutations(api, context, dispatch) {
33
33
  throw new Error("Unexpected principal receipt operation");
34
34
  return { ok: true, data: result.data };
35
35
  }
36
- const commit = (organizationId, groupId, request, options) => submit(organizationId, { groupId, request }, isCommitOrganizationGroupPolicyResponse, options);
36
+ const commit = (organizationId, groupId, request, options) => submit(organizationId, { kind: "compound", groupId, request }, isCommitOrganizationGroupPolicyResponse, options);
37
37
  const create = (organizationId, request, options) => submit(organizationId, { kind: "group-create", groupId: request.groupId, request }, isCreateOrganizationGroupResponse, options);
38
38
  const remove = (organizationId, groupId, request, options) => submit(organizationId, { kind: "group-delete", groupId, request }, isDeleteOrganizationGroupResponse, options);
39
39
  const put = (_type, organizationId, request, options) => submit(organizationId, { kind: "organization", groupId: null, request }, isPrincipalPolicyMutationResponse, options);
@@ -1 +1 @@
1
- {"version":3,"file":"principalMutationDispatch.js","sourceRoot":"","sources":["principalMutationDispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ApiClient,\n RequestResult,\n RequestResultOptions,\n} from \"@tearleads/api-client\";\nimport {\n isCommitOrganizationGroupPolicyResponse,\n isCreateOrganizationGroupResponse,\n isDeleteOrganizationGroupResponse,\n isPrincipalPolicyMutationResponse,\n} from \"@tearleads/validators/response\";\nimport type { AuthoredPrincipalMutation } from \"../data/principals/principalMutationJournal\";\nimport {\n type PrincipalMutationJournalContext,\n submitJournaledPrincipalMutation,\n} from \"../workflows/organizations/principalMutationJournalSession\";\nimport type { PrincipalMutationResponse } from \"../workflows/organizations/principalOperationReceipt\";\n\nimport type { createPrincipalMutationDispatcher } from \"./principalMutationDeadline\";\n\nexport type JournaledPrincipalMutationMethods = Pick<\n ApiClient,\n | \"commitOrganizationGroupPolicy\"\n | \"commitOrganizationGroupPolicyResult\"\n | \"createOrganizationGroup\"\n | \"createOrganizationGroupResult\"\n | \"deleteOrganizationGroup\"\n | \"deleteOrganizationGroupResult\"\n | \"putPrincipalPolicy\"\n | \"putPrincipalPolicyResult\"\n>;\n\n/** Dispatch the authenticated operation, with no application planning callback. */\nexport function dispatchAuthoredPrincipalMutation(\n api: ApiClient,\n organizationId: string,\n mutation: AuthoredPrincipalMutation,\n options: RequestResultOptions = {},\n): Promise<RequestResult<PrincipalMutationResponse>> {\n switch (mutation.kind) {\n case \"organization\":\n return api.putPrincipalPolicyResult(\n \"organization\",\n organizationId,\n mutation.request,\n options,\n );\n case \"group-create\":\n return api.createOrganizationGroupResult(\n organizationId,\n mutation.request,\n options,\n );\n case \"group-delete\":\n return api.deleteOrganizationGroupResult(\n organizationId,\n mutation.groupId,\n mutation.request,\n options,\n );\n case undefined:\n return api.commitOrganizationGroupPolicyResult(\n organizationId,\n mutation.groupId,\n mutation.request,\n options,\n );\n default:\n return unsupportedMutation(mutation);\n }\n}\n\nfunction unsupportedMutation(_mutation: never): never {\n throw new Error(\"Unsupported principal mutation operation\");\n}\n\nexport function createJournaledPrincipalMutations(\n api: ApiClient,\n context: (\n organizationId: string,\n ) => Omit<PrincipalMutationJournalContext, \"submit\">,\n dispatch: ReturnType<typeof createPrincipalMutationDispatcher>,\n): JournaledPrincipalMutationMethods {\n async function submit<T extends PrincipalMutationResponse>(\n organizationId: string,\n mutation: AuthoredPrincipalMutation,\n validator: (value: unknown) => value is T,\n options: RequestResultOptions = {},\n ): Promise<RequestResult<T>> {\n const result = await submitJournaledPrincipalMutation({\n ...context(organizationId),\n mutation,\n submit: (saved) =>\n dispatch(options, (dispatchOptions) =>\n dispatchAuthoredPrincipalMutation(\n api,\n organizationId,\n saved,\n dispatchOptions,\n ),\n ),\n });\n if (!result.ok) return result;\n // The session already verified this operation before clearing its row.\n // This check narrows the union for each existing public API signature.\n if (!validator(result.data))\n throw new Error(\"Unexpected principal receipt operation\");\n return { ok: true, data: result.data };\n }\n const commit: ApiClient[\"commitOrganizationGroupPolicyResult\"] = (\n organizationId,\n groupId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { groupId, request },\n isCommitOrganizationGroupPolicyResponse,\n options,\n );\n const create: ApiClient[\"createOrganizationGroupResult\"] = (\n organizationId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"group-create\", groupId: request.groupId, request },\n isCreateOrganizationGroupResponse,\n options,\n );\n const remove: ApiClient[\"deleteOrganizationGroupResult\"] = (\n organizationId,\n groupId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"group-delete\", groupId, request },\n isDeleteOrganizationGroupResponse,\n options,\n );\n const put: ApiClient[\"putPrincipalPolicyResult\"] = (\n _type,\n organizationId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"organization\", groupId: null, request },\n isPrincipalPolicyMutationResponse,\n options,\n );\n return {\n commitOrganizationGroupPolicyResult: commit,\n commitOrganizationGroupPolicy: async (...args) =>\n nullable(await commit(...args)),\n createOrganizationGroupResult: create,\n createOrganizationGroup: async (...args) => nullable(await create(...args)),\n deleteOrganizationGroupResult: remove,\n deleteOrganizationGroup: async (...args) => nullable(await remove(...args)),\n putPrincipalPolicyResult: put,\n putPrincipalPolicy: async (...args) => nullable(await put(...args)),\n };\n}\n\nfunction nullable<T>(result: RequestResult<T>): T | null {\n return result.ok ? result.data : null;\n}\n"]}
1
+ {"version":3,"file":"principalMutationDispatch.js","sourceRoot":"","sources":["principalMutationDispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ApiClient,\n RequestResult,\n RequestResultOptions,\n} from \"@tearleads/api-client\";\nimport {\n isCommitOrganizationGroupPolicyResponse,\n isCreateOrganizationGroupResponse,\n isDeleteOrganizationGroupResponse,\n isPrincipalPolicyMutationResponse,\n} from \"@tearleads/validators/response\";\nimport type { AuthoredPrincipalMutation } from \"../data/principals/principalMutationJournal\";\nimport {\n type PrincipalMutationJournalContext,\n submitJournaledPrincipalMutation,\n} from \"../workflows/organizations/principalMutationJournalSession\";\nimport type { PrincipalMutationResponse } from \"../workflows/organizations/principalOperationReceipt\";\n\nimport type { createPrincipalMutationDispatcher } from \"./principalMutationDeadline\";\n\nexport type JournaledPrincipalMutationMethods = Pick<\n ApiClient,\n | \"commitOrganizationGroupPolicy\"\n | \"commitOrganizationGroupPolicyResult\"\n | \"createOrganizationGroup\"\n | \"createOrganizationGroupResult\"\n | \"deleteOrganizationGroup\"\n | \"deleteOrganizationGroupResult\"\n | \"putPrincipalPolicy\"\n | \"putPrincipalPolicyResult\"\n>;\n\n/** Dispatch the authenticated operation, with no application planning callback. */\nexport function dispatchAuthoredPrincipalMutation(\n api: ApiClient,\n organizationId: string,\n mutation: AuthoredPrincipalMutation,\n options: RequestResultOptions = {},\n): Promise<RequestResult<PrincipalMutationResponse>> {\n switch (mutation.kind) {\n case \"organization\":\n return api.putPrincipalPolicyResult(\n \"organization\",\n organizationId,\n mutation.request,\n options,\n );\n case \"group-create\":\n return api.createOrganizationGroupResult(\n organizationId,\n mutation.request,\n options,\n );\n case \"group-delete\":\n return api.deleteOrganizationGroupResult(\n organizationId,\n mutation.groupId,\n mutation.request,\n options,\n );\n case \"compound\":\n return api.commitOrganizationGroupPolicyResult(\n organizationId,\n mutation.groupId,\n mutation.request,\n options,\n );\n default:\n return unsupportedMutation(mutation);\n }\n}\n\nfunction unsupportedMutation(_mutation: never): never {\n throw new Error(\"Unsupported principal mutation operation\");\n}\n\nexport function createJournaledPrincipalMutations(\n api: ApiClient,\n context: (\n organizationId: string,\n ) => Omit<PrincipalMutationJournalContext, \"submit\">,\n dispatch: ReturnType<typeof createPrincipalMutationDispatcher>,\n): JournaledPrincipalMutationMethods {\n async function submit<T extends PrincipalMutationResponse>(\n organizationId: string,\n mutation: AuthoredPrincipalMutation,\n validator: (value: unknown) => value is T,\n options: RequestResultOptions = {},\n ): Promise<RequestResult<T>> {\n const result = await submitJournaledPrincipalMutation({\n ...context(organizationId),\n mutation,\n submit: (saved) =>\n dispatch(options, (dispatchOptions) =>\n dispatchAuthoredPrincipalMutation(\n api,\n organizationId,\n saved,\n dispatchOptions,\n ),\n ),\n });\n if (!result.ok) return result;\n // The session already verified this operation before clearing its row.\n // This check narrows the union for each existing public API signature.\n if (!validator(result.data))\n throw new Error(\"Unexpected principal receipt operation\");\n return { ok: true, data: result.data };\n }\n const commit: ApiClient[\"commitOrganizationGroupPolicyResult\"] = (\n organizationId,\n groupId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"compound\", groupId, request },\n isCommitOrganizationGroupPolicyResponse,\n options,\n );\n const create: ApiClient[\"createOrganizationGroupResult\"] = (\n organizationId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"group-create\", groupId: request.groupId, request },\n isCreateOrganizationGroupResponse,\n options,\n );\n const remove: ApiClient[\"deleteOrganizationGroupResult\"] = (\n organizationId,\n groupId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"group-delete\", groupId, request },\n isDeleteOrganizationGroupResponse,\n options,\n );\n const put: ApiClient[\"putPrincipalPolicyResult\"] = (\n _type,\n organizationId,\n request,\n options,\n ) =>\n submit(\n organizationId,\n { kind: \"organization\", groupId: null, request },\n isPrincipalPolicyMutationResponse,\n options,\n );\n return {\n commitOrganizationGroupPolicyResult: commit,\n commitOrganizationGroupPolicy: async (...args) =>\n nullable(await commit(...args)),\n createOrganizationGroupResult: create,\n createOrganizationGroup: async (...args) => nullable(await create(...args)),\n deleteOrganizationGroupResult: remove,\n deleteOrganizationGroup: async (...args) => nullable(await remove(...args)),\n putPrincipalPolicyResult: put,\n putPrincipalPolicy: async (...args) => nullable(await put(...args)),\n };\n}\n\nfunction nullable<T>(result: RequestResult<T>): T | null {\n return result.ok ? result.data : null;\n}\n"]}
@@ -155,6 +155,11 @@ async function loadOrganizationExternalAuthority(input) {
155
155
  }
156
156
  }
157
157
  async function verifyReferencedPrincipalPolicy(input) {
158
+ // Scoped recovery carries organization, dependency and lifetime bindings.
159
+ // A bare policy cache entry cannot replace those bindings.
160
+ const recovered = await resolveReferencedPrincipalPolicy(input);
161
+ if (recovered)
162
+ return recovered;
158
163
  const cacheKey = referencedPrincipalPolicyKey(input.reference);
159
164
  const cachedPolicy = input.principalPolicyCache.get(cacheKey);
160
165
  const execSql = input.checkpointContext.execSql;
@@ -170,11 +175,6 @@ async function verifyReferencedPrincipalPolicy(input) {
170
175
  }
171
176
  const referenceLabel = principalPolicyReferenceLabel(input.reference);
172
177
  let bundle = await loadPrincipalPolicyBundleForReference(execSql, input.reference, localCheckpoint);
173
- if (!bundle) {
174
- const recovered = await resolveReferencedPrincipalPolicy(input);
175
- if (recovered)
176
- return recovered;
177
- }
178
178
  if (!bundle && input.warmReferencedPrincipalPolicies) {
179
179
  // The reference is not cached locally — the common case for a member who
180
180
  // gained access via another org's group grant and never hydrated that
@@ -1 +1 @@
1
- {"version":3,"file":"principalPolicyVerification.js","sourceRoot":"","sources":["principalPolicyVerification.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicySignerPublicKey,\n type ReferencedPrincipalHead,\n toFingerprint,\n type VerifiedPrincipalPolicy,\n verifyPrincipalPolicyBundle,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { loadPrincipalPolicyCheckpoint } from \"../persistence/keyingCheckpointPersistence\";\nimport {\n principalPolicyHeadMeetsCheckpoint,\n verifiedPrincipalPolicyMeetsCheckpoint,\n} from \"../persistence/principalPolicyCheckpointSelection\";\nimport { loadPrincipalPolicyBundle } from \"../persistence/principalPolicyPersistence\";\nimport { loadPrincipalPolicyBundleForReference } from \"../persistence/principalPolicyReferencePersistence\";\nimport { principalPolicyBundleStates } from \"../principalPolicyStates\";\nimport {\n parseOrganizationAuthorityDescriptor,\n principalHeadMatchesReference,\n requireOrganizationGroupHead,\n} from \"../principals/organizationAuthorityDescriptor\";\nimport {\n organizationAdminExternalAuthority,\n principalPolicyReferenceFromBundle,\n verifyOrganizationAdminPolicy,\n verifyPrincipalPolicyBundleWithExternalOrganizationAdmins,\n} from \"../principals/principalPolicyAdminSigners\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../principals/principalPolicyEvidence\";\nimport {\n observePrincipalPolicy,\n type ProjectionCheckpointContext,\n} from \"./checkpointContext\";\nimport { ProjectionDependencyUnavailableError } from \"./dependencyUnavailable\";\nimport { rethrowProjectionVerificationBoundaryError } from \"./error\";\nimport {\n filterUncachedPrincipalPolicyReferences,\n referencedPrincipalPolicyKey,\n verifiedPrincipalPolicyContainsReference,\n} from \"./principalPolicyCache\";\nimport { resolveReferencedPrincipalPolicy } from \"./resolvedPrincipalPolicy\";\nimport type {\n PrincipalPolicyCache,\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"./types\";\nimport {\n assertProjectionVerificationCurrent,\n generationGuardedPrincipalPolicyWarmer,\n} from \"./types\";\n\nfunction principalPolicyReferenceLabel(\n reference: ReferencedPrincipalHead,\n): string {\n return `${reference.principalType}:${reference.principalId}@${reference.version}`;\n}\n\n/**\n * A referenced principal policy is not in the local store and warming could\n * not fetch it this pass — a transient cold-cache condition, typical for a\n * member whose access arrives via a group policy the device has not hydrated\n * yet. Sync passes discriminate on this type to defer the affected container\n * and retry on a later trigger, rather than failing the whole pass.\n */\nexport class PrincipalPolicyNotCachedError extends Error {\n constructor(referenceLabel: string) {\n super(`Principal policy ${referenceLabel} is not cached`);\n this.name = \"PrincipalPolicyNotCachedError\";\n }\n}\n\nexport function isPrincipalPolicyNotCachedError(error: unknown): boolean {\n return (\n error instanceof PrincipalPolicyNotCachedError ||\n (error instanceof Error && error.name === \"PrincipalPolicyNotCachedError\")\n );\n}\n\nasync function collectPrincipalPolicySignerPublicKeys(input: {\n bundle: PrincipalPolicyBundleResponse;\n label: string;\n resolveUserKey: ProjectionUserKeyResolver;\n}): Promise<PrincipalPolicySignerPublicKey[]> {\n const signerPublicKeysByKey = new Map<\n string,\n PrincipalPolicySignerPublicKey\n >();\n\n for (const state of principalPolicyBundleStates(input.bundle)) {\n const cacheKey = `${state.signerUserId}:${state.signerUserKeyFingerprint}`;\n if (signerPublicKeysByKey.has(cacheKey)) {\n continue;\n }\n\n const signerKey = await input.resolveUserKey(state.signerUserId);\n if (!signerKey) {\n throw new ProjectionDependencyUnavailableError(\n `${input.label} signer key could not be resolved for ${state.signerUserId}`,\n );\n }\n\n const signingKeyFingerprint = await toFingerprint(\n signerKey.signingPublicKey,\n );\n if (signingKeyFingerprint !== state.signerUserKeyFingerprint) {\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n `${input.label} signer key fingerprint mismatch`,\n );\n }\n\n signerPublicKeysByKey.set(cacheKey, {\n userId: state.signerUserId,\n signingKeyFingerprint,\n signingPublicKey: signerKey.signingPublicKey,\n });\n }\n\n return [...signerPublicKeysByKey.values()];\n}\n\ntype OrganizationAdminPolicyInput = {\n checkpointContext: ProjectionCheckpointContext;\n organizationId: string;\n resolveUserKey: ProjectionUserKeyResolver;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n};\n\nasync function loadOrganizationPolicyForVerification(\n input: OrganizationAdminPolicyInput,\n): Promise<\n | {\n bundle: PrincipalPolicyBundleResponse;\n localCheckpoint: Awaited<\n ReturnType<typeof loadPrincipalPolicyCheckpoint>\n >;\n }\n | undefined\n> {\n const execSql = input.checkpointContext.execSql;\n let bundle = await loadPrincipalPolicyBundle(\n execSql,\n \"organization\",\n input.organizationId,\n );\n if (!bundle) {\n return undefined;\n }\n let localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n \"organization\",\n input.organizationId,\n );\n if (\n !principalPolicyHeadMeetsCheckpoint(bundle.currentState, localCheckpoint) &&\n input.warmReferencedPrincipalPolicies\n ) {\n await input.warmReferencedPrincipalPolicies({\n organizationId: input.organizationId,\n references: [principalPolicyReferenceFromBundle(bundle)],\n });\n bundle = await loadPrincipalPolicyBundle(\n execSql,\n \"organization\",\n input.organizationId,\n );\n localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n \"organization\",\n input.organizationId,\n );\n if (!bundle) {\n return undefined;\n }\n }\n\n return { bundle, localCheckpoint };\n}\n\nfunction assertReservedAdminsPolicyShape(\n policy: VerifiedPrincipalPolicy,\n): void {\n const history = policy.history ?? [{ projection: policy.projection }];\n if (\n history.some(\n (entry) =>\n entry.projection.length === 0 ||\n entry.projection.some((member) => member.role !== \"admin\"),\n )\n ) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"reserved Admins policy must contain only direct admin users\",\n );\n }\n}\n\nasync function verifyOrganizationAdminsPolicy(input: {\n adminGroupId: string;\n execSql: ProjectionCheckpointContext[\"execSql\"];\n expectedHead: ReferencedPrincipalHead;\n resolveUserKey: ProjectionUserKeyResolver;\n}): Promise<VerifiedPrincipalPolicy | undefined> {\n const adminBundle = await loadPrincipalPolicyBundle(\n input.execSql,\n \"group\",\n input.adminGroupId,\n );\n if (!adminBundle) {\n return undefined;\n }\n if (\n !principalHeadMatchesReference(\n principalPolicyReferenceFromBundle(adminBundle),\n input.expectedHead,\n )\n ) {\n throw new KeyingVerificationError(\n \"hash_mismatch\",\n \"Admins policy does not match the signed organization directory\",\n );\n }\n const adminCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"group\",\n input.adminGroupId,\n );\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle: adminBundle,\n label: `Admins policy ${input.adminGroupId}`,\n resolveUserKey: input.resolveUserKey,\n });\n const verified = await verifyPrincipalPolicyBundle({\n bundle: adminBundle,\n expectedReference: input.expectedHead,\n localCheckpoint: adminCheckpoint,\n signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n assertReservedAdminsPolicyShape(verified.value);\n return verified.value;\n}\n\nasync function loadOrganizationExternalAuthority(\n input: OrganizationAdminPolicyInput,\n): Promise<ReturnType<typeof organizationAdminExternalAuthority> | null> {\n const organizationPolicy = await loadOrganizationPolicyForVerification(input);\n if (!organizationPolicy) {\n return null;\n }\n\n try {\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle: organizationPolicy.bundle,\n label: `Organization policy ${input.organizationId}`,\n resolveUserKey: input.resolveUserKey,\n });\n const verified = await verifyOrganizationAdminPolicy({\n bundle: organizationPolicy.bundle,\n localCheckpoint: organizationPolicy.localCheckpoint,\n organizationId: input.organizationId,\n signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n const descriptor = parseOrganizationAuthorityDescriptor(\n organizationPolicy.bundle.currentPayload.ciphertext,\n );\n if (descriptor.organizationId !== input.organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"organization authority descriptor scope does not match\",\n );\n }\n const verifiedAdmins = await verifyOrganizationAdminsPolicy({\n adminGroupId: descriptor.adminGroupId,\n execSql: input.checkpointContext.execSql,\n expectedHead: requireOrganizationGroupHead(\n descriptor,\n descriptor.adminGroupId,\n ),\n resolveUserKey: input.resolveUserKey,\n });\n if (!verifiedAdmins) {\n return null;\n }\n observePrincipalPolicy(\n input.checkpointContext,\n verified.value,\n input.organizationId,\n );\n observePrincipalPolicy(\n input.checkpointContext,\n verifiedAdmins,\n input.organizationId,\n );\n return organizationAdminExternalAuthority(verifiedAdmins);\n } catch (error) {\n rethrowProjectionVerificationBoundaryError(error);\n if (error instanceof KeyingVerificationError) {\n throw error;\n }\n return null;\n }\n}\n\nasync function verifyReferencedPrincipalPolicy(input: {\n recoveryBatch: object;\n checkpointContext: ProjectionCheckpointContext;\n organizationId: string;\n principalPolicyCache: PrincipalPolicyCache;\n reference: ReferencedPrincipalHead;\n stillCurrent?: (() => boolean) | undefined;\n resolveUserKey: ProjectionUserKeyResolver;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<PrincipalPolicyCurrentEvidence> {\n const cacheKey = referencedPrincipalPolicyKey(input.reference);\n const cachedPolicy = input.principalPolicyCache.get(cacheKey);\n const execSql = input.checkpointContext.execSql;\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n input.reference.principalType,\n input.reference.principalId,\n );\n if (cachedPolicy && !(\"retainedHistory\" in cachedPolicy)) {\n if (\n !verifiedPrincipalPolicyContainsReference(cachedPolicy, input.reference)\n ) {\n throw new KeyingVerificationError(\n \"hash_mismatch\",\n \"in-memory principal policy cache does not match its exact reference\",\n );\n }\n if (verifiedPrincipalPolicyMeetsCheckpoint(cachedPolicy, localCheckpoint)) {\n observePrincipalPolicy(\n input.checkpointContext,\n cachedPolicy,\n input.organizationId,\n );\n return cachedPolicy;\n }\n }\n\n const referenceLabel = principalPolicyReferenceLabel(input.reference);\n let bundle = await loadPrincipalPolicyBundleForReference(\n execSql,\n input.reference,\n localCheckpoint,\n );\n if (!bundle) {\n const recovered = await resolveReferencedPrincipalPolicy(input);\n if (recovered) return recovered;\n }\n if (!bundle && input.warmReferencedPrincipalPolicies) {\n // The reference is not cached locally — the common case for a member who\n // gained access via another org's group grant and never hydrated that\n // group's policy. Fetch+verify+persist it, then re-read from the cache.\n await input.warmReferencedPrincipalPolicies({\n organizationId: input.organizationId,\n references: [input.reference],\n });\n bundle = await loadPrincipalPolicyBundleForReference(\n execSql,\n input.reference,\n localCheckpoint,\n );\n }\n if (!bundle) {\n throw new PrincipalPolicyNotCachedError(referenceLabel);\n }\n\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n label: `Principal policy ${referenceLabel}`,\n resolveUserKey: input.resolveUserKey,\n });\n const verified =\n await verifyPrincipalPolicyBundleWithExternalOrganizationAdmins({\n bundle,\n expectedReference: input.reference,\n loadExternalAuthority: () =>\n loadOrganizationExternalAuthority({\n checkpointContext: input.checkpointContext,\n organizationId: input.organizationId,\n resolveUserKey: input.resolveUserKey,\n warmReferencedPrincipalPolicies:\n input.warmReferencedPrincipalPolicies,\n }),\n localCheckpoint,\n signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n\n observePrincipalPolicy(\n input.checkpointContext,\n verified.value,\n input.organizationId,\n );\n input.principalPolicyCache.set(cacheKey, verified.value);\n return verified.value;\n}\n\nexport async function collectReferencedPrincipalPolicies(input: {\n checkpointContext: ProjectionCheckpointContext;\n organizationId: string;\n principalPolicyCache: PrincipalPolicyCache;\n references: readonly ReferencedPrincipalHead[];\n resolveUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<PrincipalPolicyCurrentEvidence[]> {\n const warmReferencedPrincipalPolicies =\n generationGuardedPrincipalPolicyWarmer(\n input.warmReferencedPrincipalPolicies,\n input.stillCurrent,\n );\n const uniqueReferences = new Map<string, ReferencedPrincipalHead>();\n for (const reference of input.references) {\n uniqueReferences.set(referencedPrincipalPolicyKey(reference), reference);\n }\n\n const references = [...uniqueReferences.values()];\n // Warm every missing reference in one batched fetch before verifying, so a\n // path that references several uncached policies makes a single round of\n // requests rather than one per reference.\n if (\n warmReferencedPrincipalPolicies &&\n !warmReferencedPrincipalPolicies.resolveReference\n ) {\n const uncached = await filterUncachedPrincipalPolicyReferences({\n execSql: input.checkpointContext.execSql,\n principalPolicyCache: input.principalPolicyCache,\n references,\n });\n if (uncached.length > 0) {\n assertProjectionVerificationCurrent(input.stillCurrent);\n await warmReferencedPrincipalPolicies({\n organizationId: input.organizationId,\n references: uncached,\n });\n assertProjectionVerificationCurrent(input.stillCurrent);\n }\n }\n\n const recoveryBatch = {};\n return Promise.all(\n references.map((reference) =>\n verifyReferencedPrincipalPolicy({\n recoveryBatch,\n checkpointContext: input.checkpointContext,\n organizationId: input.organizationId,\n principalPolicyCache: input.principalPolicyCache,\n reference,\n stillCurrent: input.stillCurrent,\n resolveUserKey: input.resolveUserKey,\n warmReferencedPrincipalPolicies,\n }),\n ),\n );\n}\n"]}
1
+ {"version":3,"file":"principalPolicyVerification.js","sourceRoot":"","sources":["principalPolicyVerification.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicySignerPublicKey,\n type ReferencedPrincipalHead,\n toFingerprint,\n type VerifiedPrincipalPolicy,\n verifyPrincipalPolicyBundle,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { loadPrincipalPolicyCheckpoint } from \"../persistence/keyingCheckpointPersistence\";\nimport {\n principalPolicyHeadMeetsCheckpoint,\n verifiedPrincipalPolicyMeetsCheckpoint,\n} from \"../persistence/principalPolicyCheckpointSelection\";\nimport { loadPrincipalPolicyBundle } from \"../persistence/principalPolicyPersistence\";\nimport { loadPrincipalPolicyBundleForReference } from \"../persistence/principalPolicyReferencePersistence\";\nimport { principalPolicyBundleStates } from \"../principalPolicyStates\";\nimport {\n parseOrganizationAuthorityDescriptor,\n principalHeadMatchesReference,\n requireOrganizationGroupHead,\n} from \"../principals/organizationAuthorityDescriptor\";\nimport {\n organizationAdminExternalAuthority,\n principalPolicyReferenceFromBundle,\n verifyOrganizationAdminPolicy,\n verifyPrincipalPolicyBundleWithExternalOrganizationAdmins,\n} from \"../principals/principalPolicyAdminSigners\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../principals/principalPolicyEvidence\";\nimport {\n observePrincipalPolicy,\n type ProjectionCheckpointContext,\n} from \"./checkpointContext\";\nimport { ProjectionDependencyUnavailableError } from \"./dependencyUnavailable\";\nimport { rethrowProjectionVerificationBoundaryError } from \"./error\";\nimport {\n filterUncachedPrincipalPolicyReferences,\n referencedPrincipalPolicyKey,\n verifiedPrincipalPolicyContainsReference,\n} from \"./principalPolicyCache\";\nimport { resolveReferencedPrincipalPolicy } from \"./resolvedPrincipalPolicy\";\nimport type {\n PrincipalPolicyCache,\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"./types\";\nimport {\n assertProjectionVerificationCurrent,\n generationGuardedPrincipalPolicyWarmer,\n} from \"./types\";\n\nfunction principalPolicyReferenceLabel(\n reference: ReferencedPrincipalHead,\n): string {\n return `${reference.principalType}:${reference.principalId}@${reference.version}`;\n}\n\n/**\n * A referenced principal policy is not in the local store and warming could\n * not fetch it this pass — a transient cold-cache condition, typical for a\n * member whose access arrives via a group policy the device has not hydrated\n * yet. Sync passes discriminate on this type to defer the affected container\n * and retry on a later trigger, rather than failing the whole pass.\n */\nexport class PrincipalPolicyNotCachedError extends Error {\n constructor(referenceLabel: string) {\n super(`Principal policy ${referenceLabel} is not cached`);\n this.name = \"PrincipalPolicyNotCachedError\";\n }\n}\n\nexport function isPrincipalPolicyNotCachedError(error: unknown): boolean {\n return (\n error instanceof PrincipalPolicyNotCachedError ||\n (error instanceof Error && error.name === \"PrincipalPolicyNotCachedError\")\n );\n}\n\nasync function collectPrincipalPolicySignerPublicKeys(input: {\n bundle: PrincipalPolicyBundleResponse;\n label: string;\n resolveUserKey: ProjectionUserKeyResolver;\n}): Promise<PrincipalPolicySignerPublicKey[]> {\n const signerPublicKeysByKey = new Map<\n string,\n PrincipalPolicySignerPublicKey\n >();\n\n for (const state of principalPolicyBundleStates(input.bundle)) {\n const cacheKey = `${state.signerUserId}:${state.signerUserKeyFingerprint}`;\n if (signerPublicKeysByKey.has(cacheKey)) {\n continue;\n }\n\n const signerKey = await input.resolveUserKey(state.signerUserId);\n if (!signerKey) {\n throw new ProjectionDependencyUnavailableError(\n `${input.label} signer key could not be resolved for ${state.signerUserId}`,\n );\n }\n\n const signingKeyFingerprint = await toFingerprint(\n signerKey.signingPublicKey,\n );\n if (signingKeyFingerprint !== state.signerUserKeyFingerprint) {\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n `${input.label} signer key fingerprint mismatch`,\n );\n }\n\n signerPublicKeysByKey.set(cacheKey, {\n userId: state.signerUserId,\n signingKeyFingerprint,\n signingPublicKey: signerKey.signingPublicKey,\n });\n }\n\n return [...signerPublicKeysByKey.values()];\n}\n\ntype OrganizationAdminPolicyInput = {\n checkpointContext: ProjectionCheckpointContext;\n organizationId: string;\n resolveUserKey: ProjectionUserKeyResolver;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n};\n\nasync function loadOrganizationPolicyForVerification(\n input: OrganizationAdminPolicyInput,\n): Promise<\n | {\n bundle: PrincipalPolicyBundleResponse;\n localCheckpoint: Awaited<\n ReturnType<typeof loadPrincipalPolicyCheckpoint>\n >;\n }\n | undefined\n> {\n const execSql = input.checkpointContext.execSql;\n let bundle = await loadPrincipalPolicyBundle(\n execSql,\n \"organization\",\n input.organizationId,\n );\n if (!bundle) {\n return undefined;\n }\n let localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n \"organization\",\n input.organizationId,\n );\n if (\n !principalPolicyHeadMeetsCheckpoint(bundle.currentState, localCheckpoint) &&\n input.warmReferencedPrincipalPolicies\n ) {\n await input.warmReferencedPrincipalPolicies({\n organizationId: input.organizationId,\n references: [principalPolicyReferenceFromBundle(bundle)],\n });\n bundle = await loadPrincipalPolicyBundle(\n execSql,\n \"organization\",\n input.organizationId,\n );\n localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n \"organization\",\n input.organizationId,\n );\n if (!bundle) {\n return undefined;\n }\n }\n\n return { bundle, localCheckpoint };\n}\n\nfunction assertReservedAdminsPolicyShape(\n policy: VerifiedPrincipalPolicy,\n): void {\n const history = policy.history ?? [{ projection: policy.projection }];\n if (\n history.some(\n (entry) =>\n entry.projection.length === 0 ||\n entry.projection.some((member) => member.role !== \"admin\"),\n )\n ) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"reserved Admins policy must contain only direct admin users\",\n );\n }\n}\n\nasync function verifyOrganizationAdminsPolicy(input: {\n adminGroupId: string;\n execSql: ProjectionCheckpointContext[\"execSql\"];\n expectedHead: ReferencedPrincipalHead;\n resolveUserKey: ProjectionUserKeyResolver;\n}): Promise<VerifiedPrincipalPolicy | undefined> {\n const adminBundle = await loadPrincipalPolicyBundle(\n input.execSql,\n \"group\",\n input.adminGroupId,\n );\n if (!adminBundle) {\n return undefined;\n }\n if (\n !principalHeadMatchesReference(\n principalPolicyReferenceFromBundle(adminBundle),\n input.expectedHead,\n )\n ) {\n throw new KeyingVerificationError(\n \"hash_mismatch\",\n \"Admins policy does not match the signed organization directory\",\n );\n }\n const adminCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"group\",\n input.adminGroupId,\n );\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle: adminBundle,\n label: `Admins policy ${input.adminGroupId}`,\n resolveUserKey: input.resolveUserKey,\n });\n const verified = await verifyPrincipalPolicyBundle({\n bundle: adminBundle,\n expectedReference: input.expectedHead,\n localCheckpoint: adminCheckpoint,\n signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n assertReservedAdminsPolicyShape(verified.value);\n return verified.value;\n}\n\nasync function loadOrganizationExternalAuthority(\n input: OrganizationAdminPolicyInput,\n): Promise<ReturnType<typeof organizationAdminExternalAuthority> | null> {\n const organizationPolicy = await loadOrganizationPolicyForVerification(input);\n if (!organizationPolicy) {\n return null;\n }\n\n try {\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle: organizationPolicy.bundle,\n label: `Organization policy ${input.organizationId}`,\n resolveUserKey: input.resolveUserKey,\n });\n const verified = await verifyOrganizationAdminPolicy({\n bundle: organizationPolicy.bundle,\n localCheckpoint: organizationPolicy.localCheckpoint,\n organizationId: input.organizationId,\n signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n const descriptor = parseOrganizationAuthorityDescriptor(\n organizationPolicy.bundle.currentPayload.ciphertext,\n );\n if (descriptor.organizationId !== input.organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"organization authority descriptor scope does not match\",\n );\n }\n const verifiedAdmins = await verifyOrganizationAdminsPolicy({\n adminGroupId: descriptor.adminGroupId,\n execSql: input.checkpointContext.execSql,\n expectedHead: requireOrganizationGroupHead(\n descriptor,\n descriptor.adminGroupId,\n ),\n resolveUserKey: input.resolveUserKey,\n });\n if (!verifiedAdmins) {\n return null;\n }\n observePrincipalPolicy(\n input.checkpointContext,\n verified.value,\n input.organizationId,\n );\n observePrincipalPolicy(\n input.checkpointContext,\n verifiedAdmins,\n input.organizationId,\n );\n return organizationAdminExternalAuthority(verifiedAdmins);\n } catch (error) {\n rethrowProjectionVerificationBoundaryError(error);\n if (error instanceof KeyingVerificationError) {\n throw error;\n }\n return null;\n }\n}\n\nasync function verifyReferencedPrincipalPolicy(input: {\n recoveryBatch: object;\n checkpointContext: ProjectionCheckpointContext;\n organizationId: string;\n principalPolicyCache: PrincipalPolicyCache;\n reference: ReferencedPrincipalHead;\n stillCurrent?: (() => boolean) | undefined;\n resolveUserKey: ProjectionUserKeyResolver;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<PrincipalPolicyCurrentEvidence> {\n // Scoped recovery carries organization, dependency and lifetime bindings.\n // A bare policy cache entry cannot replace those bindings.\n const recovered = await resolveReferencedPrincipalPolicy(input);\n if (recovered) return recovered;\n const cacheKey = referencedPrincipalPolicyKey(input.reference);\n const cachedPolicy = input.principalPolicyCache.get(cacheKey);\n const execSql = input.checkpointContext.execSql;\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n input.reference.principalType,\n input.reference.principalId,\n );\n if (cachedPolicy && !(\"retainedHistory\" in cachedPolicy)) {\n if (\n !verifiedPrincipalPolicyContainsReference(cachedPolicy, input.reference)\n ) {\n throw new KeyingVerificationError(\n \"hash_mismatch\",\n \"in-memory principal policy cache does not match its exact reference\",\n );\n }\n if (verifiedPrincipalPolicyMeetsCheckpoint(cachedPolicy, localCheckpoint)) {\n observePrincipalPolicy(\n input.checkpointContext,\n cachedPolicy,\n input.organizationId,\n );\n return cachedPolicy;\n }\n }\n\n const referenceLabel = principalPolicyReferenceLabel(input.reference);\n let bundle = await loadPrincipalPolicyBundleForReference(\n execSql,\n input.reference,\n localCheckpoint,\n );\n if (!bundle && input.warmReferencedPrincipalPolicies) {\n // The reference is not cached locally — the common case for a member who\n // gained access via another org's group grant and never hydrated that\n // group's policy. Fetch+verify+persist it, then re-read from the cache.\n await input.warmReferencedPrincipalPolicies({\n organizationId: input.organizationId,\n references: [input.reference],\n });\n bundle = await loadPrincipalPolicyBundleForReference(\n execSql,\n input.reference,\n localCheckpoint,\n );\n }\n if (!bundle) {\n throw new PrincipalPolicyNotCachedError(referenceLabel);\n }\n\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n label: `Principal policy ${referenceLabel}`,\n resolveUserKey: input.resolveUserKey,\n });\n const verified =\n await verifyPrincipalPolicyBundleWithExternalOrganizationAdmins({\n bundle,\n expectedReference: input.reference,\n loadExternalAuthority: () =>\n loadOrganizationExternalAuthority({\n checkpointContext: input.checkpointContext,\n organizationId: input.organizationId,\n resolveUserKey: input.resolveUserKey,\n warmReferencedPrincipalPolicies:\n input.warmReferencedPrincipalPolicies,\n }),\n localCheckpoint,\n signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n\n observePrincipalPolicy(\n input.checkpointContext,\n verified.value,\n input.organizationId,\n );\n input.principalPolicyCache.set(cacheKey, verified.value);\n return verified.value;\n}\n\nexport async function collectReferencedPrincipalPolicies(input: {\n checkpointContext: ProjectionCheckpointContext;\n organizationId: string;\n principalPolicyCache: PrincipalPolicyCache;\n references: readonly ReferencedPrincipalHead[];\n resolveUserKey: ProjectionUserKeyResolver;\n stillCurrent?: (() => boolean) | undefined;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n}): Promise<PrincipalPolicyCurrentEvidence[]> {\n const warmReferencedPrincipalPolicies =\n generationGuardedPrincipalPolicyWarmer(\n input.warmReferencedPrincipalPolicies,\n input.stillCurrent,\n );\n const uniqueReferences = new Map<string, ReferencedPrincipalHead>();\n for (const reference of input.references) {\n uniqueReferences.set(referencedPrincipalPolicyKey(reference), reference);\n }\n\n const references = [...uniqueReferences.values()];\n // Warm every missing reference in one batched fetch before verifying, so a\n // path that references several uncached policies makes a single round of\n // requests rather than one per reference.\n if (\n warmReferencedPrincipalPolicies &&\n !warmReferencedPrincipalPolicies.resolveReference\n ) {\n const uncached = await filterUncachedPrincipalPolicyReferences({\n execSql: input.checkpointContext.execSql,\n principalPolicyCache: input.principalPolicyCache,\n references,\n });\n if (uncached.length > 0) {\n assertProjectionVerificationCurrent(input.stillCurrent);\n await warmReferencedPrincipalPolicies({\n organizationId: input.organizationId,\n references: uncached,\n });\n assertProjectionVerificationCurrent(input.stillCurrent);\n }\n }\n\n const recoveryBatch = {};\n return Promise.all(\n references.map((reference) =>\n verifyReferencedPrincipalPolicy({\n recoveryBatch,\n checkpointContext: input.checkpointContext,\n organizationId: input.organizationId,\n principalPolicyCache: input.principalPolicyCache,\n reference,\n stillCurrent: input.stillCurrent,\n resolveUserKey: input.resolveUserKey,\n warmReferencedPrincipalPolicies,\n }),\n ),\n );\n}\n"]}
@@ -39,13 +39,27 @@ export async function resolveReferencedPrincipalPolicy(input) {
39
39
  const resolve = input.warmReferencedPrincipalPolicies?.resolveReference;
40
40
  if (!resolve)
41
41
  return null;
42
- result = await resolve({
43
- recoveryBatch: input.recoveryBatch,
44
- organizationId: input.organizationId,
45
- reference: input.reference,
46
- stillCurrent: input.stillCurrent,
47
- });
48
- await meetsCheckpoints(input.checkpointContext, result, false);
42
+ const read = async (recoveryBatch) => {
43
+ assertProjectionVerificationCurrent(input.stillCurrent);
44
+ const recovered = await resolve({
45
+ recoveryBatch,
46
+ organizationId: input.organizationId,
47
+ reference: input.reference,
48
+ stillCurrent: input.stillCurrent,
49
+ });
50
+ assertProjectionVerificationCurrent(input.stillCurrent);
51
+ assertProjectionVerificationCurrent(recovered.stillCurrent);
52
+ return recovered;
53
+ };
54
+ result = await read(input.recoveryBatch);
55
+ // A concurrent admission may advance a pin after recovery verified it.
56
+ // Refresh once outside the old batch's pinned directory view; the fresh
57
+ // recovery and final checkpoint check still reject rollback/equivocation.
58
+ if (!(await meetsCheckpoints(input.checkpointContext, result, true))) {
59
+ assertProjectionVerificationCurrent(result.stillCurrent);
60
+ result = await read({});
61
+ await meetsCheckpoints(input.checkpointContext, result, false);
62
+ }
49
63
  }
50
64
  assertProjectionVerificationCurrent(input.stillCurrent);
51
65
  assertProjectionVerificationCurrent(result.stillCurrent);
@@ -1 +1 @@
1
- {"version":3,"file":"resolvedPrincipalPolicy.js","sourceRoot":"","sources":["resolvedPrincipalPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n type VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { loadPrincipalPolicyCheckpoint } from \"../persistence/keyingCheckpointPersistence\";\nimport { verifiedPrincipalPolicyMeetsCheckpoint } from \"../persistence/principalPolicyCheckpointSelection\";\nimport {\n observePrincipalPolicy,\n type ProjectionCheckpointContext,\n} from \"./checkpointContext\";\nimport {\n referencedPrincipalPolicyKey,\n verifiedPrincipalPolicyContainsReference,\n} from \"./principalPolicyCache\";\nimport {\n assertProjectionVerificationCurrent,\n type PrincipalPolicyCache,\n type ReferencedPrincipalPolicyWarmer,\n type ResolvedPrincipalPolicyEvidence,\n} from \"./types\";\n\n// Sparse cache hits must carry the organization binding and every dependency\n// into each new admission batch; a bare current-policy capability is insufficient.\n// The caller owns this cache. Cross-generation reuse is deliberately disabled by\n// the saved guard; a new lifetime restores authenticated persistent evidence.\nconst recoveredByCache = new WeakMap<\n PrincipalPolicyCache,\n Map<string, ResolvedPrincipalPolicyEvidence>\n>();\n\nasync function meetsCheckpoints(\n context: ProjectionCheckpointContext,\n result: ResolvedPrincipalPolicyEvidence,\n refreshMissing: boolean,\n): Promise<boolean> {\n for (const policy of [...result.dependencies, result.policy]) {\n const checkpoint = await loadPrincipalPolicyCheckpoint(\n context.execSql,\n policy.principalType,\n policy.principalId,\n );\n if (\n refreshMissing &&\n checkpoint &&\n (policy.version < checkpoint.version ||\n (policy.version > checkpoint.version &&\n !policy.retainedHistory.some(\n (entry) => entry.state.version === checkpoint.version,\n )))\n )\n return false;\n if (!verifiedPrincipalPolicyMeetsCheckpoint(policy, checkpoint))\n throw new KeyingVerificationError(\n \"rollback\",\n \"Recovered principal evidence predates the durable checkpoint\",\n );\n }\n return true;\n}\n\nexport async function resolveReferencedPrincipalPolicy(input: {\n readonly recoveryBatch?: object | undefined;\n readonly checkpointContext: ProjectionCheckpointContext;\n readonly organizationId: string;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly principalPolicyCache: PrincipalPolicyCache;\n readonly reference: ReferencedPrincipalHead;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): Promise<VerifiedPrincipalPolicyCurrent | null> {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const key = referencedPrincipalPolicyKey(input.reference);\n const remembered = recoveredByCache.get(input.principalPolicyCache)?.get(key);\n let result =\n remembered?.organizationId === input.organizationId &&\n remembered.policy === input.principalPolicyCache.get(key) &&\n remembered.stillCurrent()\n ? remembered\n : undefined;\n if (\n result &&\n !(await meetsCheckpoints(input.checkpointContext, result, true))\n )\n result = undefined;\n if (!result) {\n const resolve = input.warmReferencedPrincipalPolicies?.resolveReference;\n if (!resolve) return null;\n result = await resolve({\n recoveryBatch: input.recoveryBatch,\n organizationId: input.organizationId,\n reference: input.reference,\n stillCurrent: input.stillCurrent,\n });\n await meetsCheckpoints(input.checkpointContext, result, false);\n }\n assertProjectionVerificationCurrent(input.stillCurrent);\n assertProjectionVerificationCurrent(result.stillCurrent);\n if (result.organizationId !== input.organizationId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Recovered principal evidence belongs to another organization\",\n );\n if (!verifiedPrincipalPolicyContainsReference(result.policy, input.reference))\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Recovered principal evidence does not contain the exact citation\",\n );\n for (const policy of [...result.dependencies, result.policy])\n observePrincipalPolicy(\n input.checkpointContext,\n policy,\n input.organizationId,\n );\n let rememberedPolicies = recoveredByCache.get(input.principalPolicyCache);\n if (!rememberedPolicies) {\n rememberedPolicies = new Map();\n recoveredByCache.set(input.principalPolicyCache, rememberedPolicies);\n }\n rememberedPolicies.set(key, {\n ...result,\n dependencies: [...result.dependencies],\n });\n input.principalPolicyCache.set(key, result.policy);\n return result.policy;\n}\n"]}
1
+ {"version":3,"file":"resolvedPrincipalPolicy.js","sourceRoot":"","sources":["resolvedPrincipalPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n type VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { loadPrincipalPolicyCheckpoint } from \"../persistence/keyingCheckpointPersistence\";\nimport { verifiedPrincipalPolicyMeetsCheckpoint } from \"../persistence/principalPolicyCheckpointSelection\";\nimport {\n observePrincipalPolicy,\n type ProjectionCheckpointContext,\n} from \"./checkpointContext\";\nimport {\n referencedPrincipalPolicyKey,\n verifiedPrincipalPolicyContainsReference,\n} from \"./principalPolicyCache\";\nimport {\n assertProjectionVerificationCurrent,\n type PrincipalPolicyCache,\n type ReferencedPrincipalPolicyWarmer,\n type ResolvedPrincipalPolicyEvidence,\n} from \"./types\";\n\n// Sparse cache hits must carry the organization binding and every dependency\n// into each new admission batch; a bare current-policy capability is insufficient.\n// The caller owns this cache. Cross-generation reuse is deliberately disabled by\n// the saved guard; a new lifetime restores authenticated persistent evidence.\nconst recoveredByCache = new WeakMap<\n PrincipalPolicyCache,\n Map<string, ResolvedPrincipalPolicyEvidence>\n>();\n\nasync function meetsCheckpoints(\n context: ProjectionCheckpointContext,\n result: ResolvedPrincipalPolicyEvidence,\n refreshMissing: boolean,\n): Promise<boolean> {\n for (const policy of [...result.dependencies, result.policy]) {\n const checkpoint = await loadPrincipalPolicyCheckpoint(\n context.execSql,\n policy.principalType,\n policy.principalId,\n );\n if (\n refreshMissing &&\n checkpoint &&\n (policy.version < checkpoint.version ||\n (policy.version > checkpoint.version &&\n !policy.retainedHistory.some(\n (entry) => entry.state.version === checkpoint.version,\n )))\n )\n return false;\n if (!verifiedPrincipalPolicyMeetsCheckpoint(policy, checkpoint))\n throw new KeyingVerificationError(\n \"rollback\",\n \"Recovered principal evidence predates the durable checkpoint\",\n );\n }\n return true;\n}\n\nexport async function resolveReferencedPrincipalPolicy(input: {\n readonly recoveryBatch?: object | undefined;\n readonly checkpointContext: ProjectionCheckpointContext;\n readonly organizationId: string;\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly principalPolicyCache: PrincipalPolicyCache;\n readonly reference: ReferencedPrincipalHead;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n}): Promise<VerifiedPrincipalPolicyCurrent | null> {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const key = referencedPrincipalPolicyKey(input.reference);\n const remembered = recoveredByCache.get(input.principalPolicyCache)?.get(key);\n let result =\n remembered?.organizationId === input.organizationId &&\n remembered.policy === input.principalPolicyCache.get(key) &&\n remembered.stillCurrent()\n ? remembered\n : undefined;\n if (\n result &&\n !(await meetsCheckpoints(input.checkpointContext, result, true))\n )\n result = undefined;\n if (!result) {\n const resolve = input.warmReferencedPrincipalPolicies?.resolveReference;\n if (!resolve) return null;\n const read = async (recoveryBatch: object | undefined) => {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const recovered = await resolve({\n recoveryBatch,\n organizationId: input.organizationId,\n reference: input.reference,\n stillCurrent: input.stillCurrent,\n });\n assertProjectionVerificationCurrent(input.stillCurrent);\n assertProjectionVerificationCurrent(recovered.stillCurrent);\n return recovered;\n };\n result = await read(input.recoveryBatch);\n // A concurrent admission may advance a pin after recovery verified it.\n // Refresh once outside the old batch's pinned directory view; the fresh\n // recovery and final checkpoint check still reject rollback/equivocation.\n if (!(await meetsCheckpoints(input.checkpointContext, result, true))) {\n assertProjectionVerificationCurrent(result.stillCurrent);\n result = await read({});\n await meetsCheckpoints(input.checkpointContext, result, false);\n }\n }\n assertProjectionVerificationCurrent(input.stillCurrent);\n assertProjectionVerificationCurrent(result.stillCurrent);\n if (result.organizationId !== input.organizationId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Recovered principal evidence belongs to another organization\",\n );\n if (!verifiedPrincipalPolicyContainsReference(result.policy, input.reference))\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Recovered principal evidence does not contain the exact citation\",\n );\n for (const policy of [...result.dependencies, result.policy])\n observePrincipalPolicy(\n input.checkpointContext,\n policy,\n input.organizationId,\n );\n let rememberedPolicies = recoveredByCache.get(input.principalPolicyCache);\n if (!rememberedPolicies) {\n rememberedPolicies = new Map();\n recoveredByCache.set(input.principalPolicyCache, rememberedPolicies);\n }\n rememberedPolicies.set(key, {\n ...result,\n dependencies: [...result.dependencies],\n });\n input.principalPolicyCache.set(key, result.policy);\n return result.policy;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { ReferencedPrincipalHead, VerifiedPrincipalPolicyCurrent, VerifiedPrincipalPolicySelection } from "../../internal/crypto/index.js";
2
- import type { PrincipalPolicyBundleResponse, ProjectionPolicyEvidenceResponse } from "../../internal/validators/response/index.js";
2
+ import type { ProjectionPolicyEvidenceResponse } from "../../internal/validators/response/index.js";
3
3
  import type { PrincipalPolicyCurrentEvidence } from "../principals/principalPolicyEvidence.js";
4
4
  import type { TrustedUserIdentity } from "../trustedUserIdentity/index.js";
5
5
  export type ProjectionUserKey = TrustedUserIdentity;
@@ -25,11 +25,6 @@ export interface ReferencedPrincipalPolicyWarmRequest {
25
25
  readonly references: readonly ReferencedPrincipalHead[];
26
26
  readonly stillCurrent?: (() => boolean) | undefined;
27
27
  }
28
- export interface PrincipalPolicyBundleCacheRequest {
29
- readonly bundles: readonly PrincipalPolicyBundleResponse[];
30
- readonly organizationId: string;
31
- readonly stillCurrent?: (() => boolean) | undefined;
32
- }
33
28
  export interface ProjectionPolicyHistoryResolveRequest {
34
29
  /** Authenticate terminal evidence first; its consumer must validate durable currency. */
35
30
  readonly historicalProof?: boolean | undefined;
@@ -42,9 +37,7 @@ export interface ResolvedProjectionPolicyHistory {
42
37
  readonly policies: readonly VerifiedPrincipalPolicySelection[];
43
38
  readonly stillCurrent: () => boolean;
44
39
  }
45
- export type PrincipalPolicyBundleCacher = (input: PrincipalPolicyBundleCacheRequest) => Promise<void>;
46
40
  export type ReferencedPrincipalPolicyWarmer = ((input: ReferencedPrincipalPolicyWarmRequest) => Promise<void>) & {
47
- readonly cacheBundles?: PrincipalPolicyBundleCacher | undefined;
48
41
  readonly resolveProjectionHistory?: ((input: ProjectionPolicyHistoryResolveRequest) => Promise<ResolvedProjectionPolicyHistory>) | undefined;
49
42
  readonly resolveReference?: ((input: PrincipalPolicyResolveRequest) => Promise<ResolvedPrincipalPolicyEvidence>) | undefined;
50
43
  };
@@ -65,15 +65,6 @@ export function generationGuardedPrincipalPolicyWarmer(warmer, stillCurrent) {
65
65
  },
66
66
  }
67
67
  : {}),
68
- ...(operation.cacheBundles
69
- ? {
70
- cacheBundles: async (input) => {
71
- assertProjectionVerificationCurrent(stillCurrent);
72
- await operation.cacheBundles?.({ ...input, stillCurrent });
73
- assertProjectionVerificationCurrent(stillCurrent);
74
- },
75
- }
76
- : {}),
77
68
  });
78
69
  };
79
70
  return guardWithCapabilities(warmer);
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ReferencedPrincipalHead,\n VerifiedPrincipalPolicyCurrent,\n VerifiedPrincipalPolicySelection,\n} from \"@tearleads/crypto\";\nimport type {\n PrincipalPolicyBundleResponse,\n ProjectionPolicyEvidenceResponse,\n} from \"@tearleads/validators/response\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../principals/principalPolicyEvidence\";\nimport type { TrustedUserIdentity } from \"../trustedUserIdentity\";\n\nexport type ProjectionUserKey = TrustedUserIdentity;\n\nexport type ProjectionUserKeyResolver = (\n userId: string,\n) => Promise<ProjectionUserKey | null>;\n\nexport type PrincipalPolicyCache = Map<string, PrincipalPolicyCurrentEvidence>;\n\nexport interface PrincipalPolicyResolveRequest {\n /** Reuse authenticated local ancestry before an authorized online recovery. */\n readonly preferLocalHistory?: boolean | undefined;\n /** Identity of one projection collection, never caller-supplied evidence. */\n readonly recoveryBatch?: object | undefined;\n readonly organizationId: string;\n readonly reference: ReferencedPrincipalHead;\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface ResolvedPrincipalPolicyEvidence {\n readonly stillCurrent: () => boolean;\n readonly organizationId: string;\n readonly policy: VerifiedPrincipalPolicyCurrent;\n readonly dependencies: readonly VerifiedPrincipalPolicyCurrent[];\n}\n\nexport interface ReferencedPrincipalPolicyWarmRequest {\n readonly organizationId: string;\n readonly references: readonly ReferencedPrincipalHead[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface PrincipalPolicyBundleCacheRequest {\n readonly bundles: readonly PrincipalPolicyBundleResponse[];\n readonly organizationId: string;\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface ProjectionPolicyHistoryResolveRequest {\n /** Authenticate terminal evidence first; its consumer must validate durable currency. */\n readonly historicalProof?: boolean | undefined;\n readonly organizationId: string;\n readonly evidence: ProjectionPolicyEvidenceResponse;\n readonly references: readonly ReferencedPrincipalHead[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface ResolvedProjectionPolicyHistory {\n readonly policies: readonly VerifiedPrincipalPolicySelection[];\n readonly stillCurrent: () => boolean;\n}\n\nexport type PrincipalPolicyBundleCacher = (\n input: PrincipalPolicyBundleCacheRequest,\n) => Promise<void>;\n\nexport type ReferencedPrincipalPolicyWarmer = ((\n input: ReferencedPrincipalPolicyWarmRequest,\n) => Promise<void>) & {\n readonly cacheBundles?: PrincipalPolicyBundleCacher | undefined;\n readonly resolveProjectionHistory?:\n | ((\n input: ProjectionPolicyHistoryResolveRequest,\n ) => Promise<ResolvedProjectionPolicyHistory>)\n | undefined;\n readonly resolveReference?:\n | ((\n input: PrincipalPolicyResolveRequest,\n ) => Promise<ResolvedPrincipalPolicyEvidence>)\n | undefined;\n};\n\nexport class ProjectionVerificationCancelledError extends Error {\n constructor() {\n super(\"Projection verification generation expired\");\n this.name = \"ProjectionVerificationCancelledError\";\n }\n}\n\nconst projectionVerificationCancellation =\n new ProjectionVerificationCancelledError();\n\nexport function isProjectionVerificationCancelledError(\n error: unknown,\n): error is ProjectionVerificationCancelledError {\n return error === projectionVerificationCancellation;\n}\n\nexport function rethrowProjectionVerificationCancelled(error: unknown): void {\n if (isProjectionVerificationCancelledError(error)) throw error;\n}\n\nexport async function nullOnProjectionVerificationCancellation<T>(\n operation: () => Promise<T>,\n): Promise<T | null> {\n try {\n return await operation();\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return null;\n throw error;\n }\n}\n\nexport function assertProjectionVerificationCurrent(\n stillCurrent: (() => boolean) | undefined,\n): void {\n if (stillCurrent?.() === false) {\n throw projectionVerificationCancellation;\n }\n}\n\nexport function generationGuardedPrincipalPolicyWarmer(\n warmer: ReferencedPrincipalPolicyWarmer | undefined,\n stillCurrent: (() => boolean) | undefined,\n): ReferencedPrincipalPolicyWarmer | undefined {\n if (!warmer || !stillCurrent) return warmer;\n const guard =\n (operation: ReferencedPrincipalPolicyWarmer) =>\n async (input: ReferencedPrincipalPolicyWarmRequest) => {\n assertProjectionVerificationCurrent(stillCurrent);\n await operation({ ...input, stillCurrent });\n assertProjectionVerificationCurrent(stillCurrent);\n };\n const guardWithCapabilities = (\n operation: ReferencedPrincipalPolicyWarmer,\n ): ReferencedPrincipalPolicyWarmer => {\n const guarded = guard(operation);\n const resolve = operation.resolveReference;\n const resolveProjectionHistory = operation.resolveProjectionHistory;\n return Object.assign(guarded, {\n ...(resolveProjectionHistory\n ? {\n resolveProjectionHistory: async (\n input: ProjectionPolicyHistoryResolveRequest,\n ) => {\n const current = () =>\n stillCurrent() && input.stillCurrent?.() !== false;\n assertProjectionVerificationCurrent(current);\n const result = await resolveProjectionHistory({\n ...input,\n stillCurrent: current,\n });\n assertProjectionVerificationCurrent(current);\n return result;\n },\n }\n : {}),\n ...(resolve\n ? {\n resolveReference: async (input: PrincipalPolicyResolveRequest) => {\n const current = () =>\n stillCurrent() && input.stillCurrent?.() !== false;\n assertProjectionVerificationCurrent(current);\n const result = await resolve({ ...input, stillCurrent: current });\n assertProjectionVerificationCurrent(current);\n return result;\n },\n }\n : {}),\n ...(operation.cacheBundles\n ? {\n cacheBundles: async (input: PrincipalPolicyBundleCacheRequest) => {\n assertProjectionVerificationCurrent(stillCurrent);\n await operation.cacheBundles?.({ ...input, stillCurrent });\n assertProjectionVerificationCurrent(stillCurrent);\n },\n }\n : {}),\n });\n };\n return guardWithCapabilities(warmer);\n}\n\nexport function withGenerationGuardedPolicyWarmer<\n Input extends {\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n },\n>(input: Input): Input {\n return {\n ...input,\n warmReferencedPrincipalPolicies: generationGuardedPrincipalPolicyWarmer(\n input.warmReferencedPrincipalPolicies,\n input.stillCurrent,\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ReferencedPrincipalHead,\n VerifiedPrincipalPolicyCurrent,\n VerifiedPrincipalPolicySelection,\n} from \"@tearleads/crypto\";\nimport type { ProjectionPolicyEvidenceResponse } from \"@tearleads/validators/response\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../principals/principalPolicyEvidence\";\nimport type { TrustedUserIdentity } from \"../trustedUserIdentity\";\n\nexport type ProjectionUserKey = TrustedUserIdentity;\n\nexport type ProjectionUserKeyResolver = (\n userId: string,\n) => Promise<ProjectionUserKey | null>;\n\nexport type PrincipalPolicyCache = Map<string, PrincipalPolicyCurrentEvidence>;\n\nexport interface PrincipalPolicyResolveRequest {\n /** Reuse authenticated local ancestry before an authorized online recovery. */\n readonly preferLocalHistory?: boolean | undefined;\n /** Identity of one projection collection, never caller-supplied evidence. */\n readonly recoveryBatch?: object | undefined;\n readonly organizationId: string;\n readonly reference: ReferencedPrincipalHead;\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface ResolvedPrincipalPolicyEvidence {\n readonly stillCurrent: () => boolean;\n readonly organizationId: string;\n readonly policy: VerifiedPrincipalPolicyCurrent;\n readonly dependencies: readonly VerifiedPrincipalPolicyCurrent[];\n}\n\nexport interface ReferencedPrincipalPolicyWarmRequest {\n readonly organizationId: string;\n readonly references: readonly ReferencedPrincipalHead[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface ProjectionPolicyHistoryResolveRequest {\n /** Authenticate terminal evidence first; its consumer must validate durable currency. */\n readonly historicalProof?: boolean | undefined;\n readonly organizationId: string;\n readonly evidence: ProjectionPolicyEvidenceResponse;\n readonly references: readonly ReferencedPrincipalHead[];\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface ResolvedProjectionPolicyHistory {\n readonly policies: readonly VerifiedPrincipalPolicySelection[];\n readonly stillCurrent: () => boolean;\n}\n\nexport type ReferencedPrincipalPolicyWarmer = ((\n input: ReferencedPrincipalPolicyWarmRequest,\n) => Promise<void>) & {\n readonly resolveProjectionHistory?:\n | ((\n input: ProjectionPolicyHistoryResolveRequest,\n ) => Promise<ResolvedProjectionPolicyHistory>)\n | undefined;\n readonly resolveReference?:\n | ((\n input: PrincipalPolicyResolveRequest,\n ) => Promise<ResolvedPrincipalPolicyEvidence>)\n | undefined;\n};\n\nexport class ProjectionVerificationCancelledError extends Error {\n constructor() {\n super(\"Projection verification generation expired\");\n this.name = \"ProjectionVerificationCancelledError\";\n }\n}\n\nconst projectionVerificationCancellation =\n new ProjectionVerificationCancelledError();\n\nexport function isProjectionVerificationCancelledError(\n error: unknown,\n): error is ProjectionVerificationCancelledError {\n return error === projectionVerificationCancellation;\n}\n\nexport function rethrowProjectionVerificationCancelled(error: unknown): void {\n if (isProjectionVerificationCancelledError(error)) throw error;\n}\n\nexport async function nullOnProjectionVerificationCancellation<T>(\n operation: () => Promise<T>,\n): Promise<T | null> {\n try {\n return await operation();\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return null;\n throw error;\n }\n}\n\nexport function assertProjectionVerificationCurrent(\n stillCurrent: (() => boolean) | undefined,\n): void {\n if (stillCurrent?.() === false) {\n throw projectionVerificationCancellation;\n }\n}\n\nexport function generationGuardedPrincipalPolicyWarmer(\n warmer: ReferencedPrincipalPolicyWarmer | undefined,\n stillCurrent: (() => boolean) | undefined,\n): ReferencedPrincipalPolicyWarmer | undefined {\n if (!warmer || !stillCurrent) return warmer;\n const guard =\n (operation: ReferencedPrincipalPolicyWarmer) =>\n async (input: ReferencedPrincipalPolicyWarmRequest) => {\n assertProjectionVerificationCurrent(stillCurrent);\n await operation({ ...input, stillCurrent });\n assertProjectionVerificationCurrent(stillCurrent);\n };\n const guardWithCapabilities = (\n operation: ReferencedPrincipalPolicyWarmer,\n ): ReferencedPrincipalPolicyWarmer => {\n const guarded = guard(operation);\n const resolve = operation.resolveReference;\n const resolveProjectionHistory = operation.resolveProjectionHistory;\n return Object.assign(guarded, {\n ...(resolveProjectionHistory\n ? {\n resolveProjectionHistory: async (\n input: ProjectionPolicyHistoryResolveRequest,\n ) => {\n const current = () =>\n stillCurrent() && input.stillCurrent?.() !== false;\n assertProjectionVerificationCurrent(current);\n const result = await resolveProjectionHistory({\n ...input,\n stillCurrent: current,\n });\n assertProjectionVerificationCurrent(current);\n return result;\n },\n }\n : {}),\n ...(resolve\n ? {\n resolveReference: async (input: PrincipalPolicyResolveRequest) => {\n const current = () =>\n stillCurrent() && input.stillCurrent?.() !== false;\n assertProjectionVerificationCurrent(current);\n const result = await resolve({ ...input, stillCurrent: current });\n assertProjectionVerificationCurrent(current);\n return result;\n },\n }\n : {}),\n });\n };\n return guardWithCapabilities(warmer);\n}\n\nexport function withGenerationGuardedPolicyWarmer<\n Input extends {\n readonly stillCurrent?: (() => boolean) | undefined;\n readonly warmReferencedPrincipalPolicies?:\n | ReferencedPrincipalPolicyWarmer\n | undefined;\n },\n>(input: Input): Input {\n return {\n ...input,\n warmReferencedPrincipalPolicies: generationGuardedPrincipalPolicyWarmer(\n input.warmReferencedPrincipalPolicies,\n input.stillCurrent,\n ),\n };\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import type { ProjectionUserKeyResolver } from "./keyingProjectionVerification/types.js";
2
2
  export { resolveEventContainerPaths } from "./keyingProjectionVerification/documentDependencyPaths.js";
3
3
  export { readAccessEvent, readRecordString, readRequiredRecordValue, } from "./keyingProjectionVerification/readers.js";
4
- export type { PrincipalPolicyBundleCacheRequest, PrincipalPolicyCache, ProjectionUserKey, ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer, } from "./keyingProjectionVerification/types.js";
4
+ export type { PrincipalPolicyCache, ProjectionUserKey, ProjectionUserKeyResolver, ReferencedPrincipalPolicyWarmer, } from "./keyingProjectionVerification/types.js";
5
5
  export { isProjectionVerificationCancelledError, nullOnProjectionVerificationCancellation, } from "./keyingProjectionVerification/types.js";
6
6
  export declare function requireProjectionUserKeyResolver(resolveProjectionUserKey: ProjectionUserKeyResolver | null | undefined, label: string): ProjectionUserKeyResolver;
7
7
  export { collectContainerWriterProjectionPrincipalPolicies, verifyContainerWriterProjection, } from "./keyingProjectionVerification/containerProjectionVerification.js";
@@ -1 +1 @@
1
- {"version":3,"file":"keyingProjectionVerification.js","sourceRoot":"","sources":["keyingProjectionVerification.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kCAAkC,EAAE,MAAM,wCAAwC,CAAC;AAE5F,OAAO,EAAE,0BAA0B,EAAE,MAAM,wDAAwD,CAAC;AACpG,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,wCAAwC,CAAC;AAShD,OAAO,EACL,sCAAsC,EACtC,wCAAwC,GACzC,MAAM,sCAAsC,CAAC;AAE9C,MAAM,UAAU,gCAAgC,CAC9C,wBAAsE,EACtE,KAAa;IAEb,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAC;IACnE,CAAC;IAED,sEAAsE;IACtE,8EAA8E;IAC9E,OAAO,kCAAkC,CAAC,wBAAwB,CAAC,CAAC;AACtE,CAAC;AAED,OAAO,EACL,iDAAiD,EACjD,+BAA+B,GAChC,MAAM,gEAAgE,CAAC;AACxE,OAAO,EAEL,8BAA8B,EAC9B,2CAA2C,GAC5C,MAAM,+DAA+D,CAAC;AACvE,OAAO,EACL,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,+DAA+D,CAAC","sourcesContent":["import type { ProjectionUserKeyResolver } from \"./keyingProjectionVerification/types\";\nimport { requireTrustedUserIdentityResolver } from \"./trustedUserIdentity/requiredResolver\";\n\nexport { resolveEventContainerPaths } from \"./keyingProjectionVerification/documentDependencyPaths\";\nexport {\n readAccessEvent,\n readRecordString,\n readRequiredRecordValue,\n} from \"./keyingProjectionVerification/readers\";\n\nexport type {\n PrincipalPolicyBundleCacheRequest,\n PrincipalPolicyCache,\n ProjectionUserKey,\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"./keyingProjectionVerification/types\";\nexport {\n isProjectionVerificationCancelledError,\n nullOnProjectionVerificationCancellation,\n} from \"./keyingProjectionVerification/types\";\n\nexport function requireProjectionUserKeyResolver(\n resolveProjectionUserKey: ProjectionUserKeyResolver | null | undefined,\n label: string,\n): ProjectionUserKeyResolver {\n if (!resolveProjectionUserKey) {\n throw new Error(`${label} requires projection key verification`);\n }\n\n // A ProjectionUserKey is a TrustedUserIdentity, so the shared adapter\n // provides the untrusted-shape and wrong-user guards (with identity caching).\n return requireTrustedUserIdentityResolver(resolveProjectionUserKey);\n}\n\nexport {\n collectContainerWriterProjectionPrincipalPolicies,\n verifyContainerWriterProjection,\n} from \"./keyingProjectionVerification/containerProjectionVerification\";\nexport {\n type DocumentWriterProjectionAuthorization,\n verifyDocumentWriterProjection,\n verifyDocumentWriterProjectionAuthorization,\n} from \"./keyingProjectionVerification/documentProjectionVerification\";\nexport {\n verifyDocumentPurgeProof,\n verifyDocumentPurgeProofBaseline,\n} from \"./keyingProjectionVerification/documentPurgeProofVerification\";\n"]}
1
+ {"version":3,"file":"keyingProjectionVerification.js","sourceRoot":"","sources":["keyingProjectionVerification.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kCAAkC,EAAE,MAAM,wCAAwC,CAAC;AAE5F,OAAO,EAAE,0BAA0B,EAAE,MAAM,wDAAwD,CAAC;AACpG,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,wCAAwC,CAAC;AAQhD,OAAO,EACL,sCAAsC,EACtC,wCAAwC,GACzC,MAAM,sCAAsC,CAAC;AAE9C,MAAM,UAAU,gCAAgC,CAC9C,wBAAsE,EACtE,KAAa;IAEb,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAC;IACnE,CAAC;IAED,sEAAsE;IACtE,8EAA8E;IAC9E,OAAO,kCAAkC,CAAC,wBAAwB,CAAC,CAAC;AACtE,CAAC;AAED,OAAO,EACL,iDAAiD,EACjD,+BAA+B,GAChC,MAAM,gEAAgE,CAAC;AACxE,OAAO,EAEL,8BAA8B,EAC9B,2CAA2C,GAC5C,MAAM,+DAA+D,CAAC;AACvE,OAAO,EACL,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,+DAA+D,CAAC","sourcesContent":["import type { ProjectionUserKeyResolver } from \"./keyingProjectionVerification/types\";\nimport { requireTrustedUserIdentityResolver } from \"./trustedUserIdentity/requiredResolver\";\n\nexport { resolveEventContainerPaths } from \"./keyingProjectionVerification/documentDependencyPaths\";\nexport {\n readAccessEvent,\n readRecordString,\n readRequiredRecordValue,\n} from \"./keyingProjectionVerification/readers\";\n\nexport type {\n PrincipalPolicyCache,\n ProjectionUserKey,\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"./keyingProjectionVerification/types\";\nexport {\n isProjectionVerificationCancelledError,\n nullOnProjectionVerificationCancellation,\n} from \"./keyingProjectionVerification/types\";\n\nexport function requireProjectionUserKeyResolver(\n resolveProjectionUserKey: ProjectionUserKeyResolver | null | undefined,\n label: string,\n): ProjectionUserKeyResolver {\n if (!resolveProjectionUserKey) {\n throw new Error(`${label} requires projection key verification`);\n }\n\n // A ProjectionUserKey is a TrustedUserIdentity, so the shared adapter\n // provides the untrusted-shape and wrong-user guards (with identity caching).\n return requireTrustedUserIdentityResolver(resolveProjectionUserKey);\n}\n\nexport {\n collectContainerWriterProjectionPrincipalPolicies,\n verifyContainerWriterProjection,\n} from \"./keyingProjectionVerification/containerProjectionVerification\";\nexport {\n type DocumentWriterProjectionAuthorization,\n verifyDocumentWriterProjection,\n verifyDocumentWriterProjectionAuthorization,\n} from \"./keyingProjectionVerification/documentProjectionVerification\";\nexport {\n verifyDocumentPurgeProof,\n verifyDocumentPurgeProofBaseline,\n} from \"./keyingProjectionVerification/documentPurgeProofVerification\";\n"]}
@@ -9,7 +9,11 @@ export declare function loadPrincipalHistoryPrefix(execSql: ExecSql, scopeId: st
9
9
  currentJson: string;
10
10
  progress: string;
11
11
  } | null>;
12
- /** Keep the newest prefix unless replay replaces the exact rejected candidate. */
12
+ /**
13
+ * Preserve identical completed progress; this sink does not authenticate hints.
14
+ * Callers must discard an unreadable prefix or identify it with rejectedPrefix
15
+ * before publishing a repair of the same head and current artifacts.
16
+ */
13
17
  export declare function savePrincipalHistoryPrefix(input: {
14
18
  readonly execSql: ExecSql;
15
19
  readonly prefix: PrincipalHistoryPrefix;
@@ -18,7 +18,11 @@ export async function loadPrincipalHistoryPrefix(execSql, scopeId) {
18
18
  .limit(1);
19
19
  return prefix ?? null;
20
20
  }
21
- /** Keep the newest prefix unless replay replaces the exact rejected candidate. */
21
+ /**
22
+ * Preserve identical completed progress; this sink does not authenticate hints.
23
+ * Callers must discard an unreadable prefix or identify it with rejectedPrefix
24
+ * before publishing a repair of the same head and current artifacts.
25
+ */
22
26
  export async function savePrincipalHistoryPrefix(input) {
23
27
  const prefix = { ...input.prefix };
24
28
  const indexRootHash = input.indexRootHash;
@@ -34,11 +38,24 @@ export async function savePrincipalHistoryPrefix(input) {
34
38
  .from(principalHistoryPrefixes)
35
39
  .where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))
36
40
  .limit(1);
37
- if (previous &&
38
- previous.version > prefix.version &&
39
- !(rejected?.scopeId === previous.scopeId &&
40
- rejected.progress === previous.progress))
41
+ const replacesRejected = previous &&
42
+ rejected?.scopeId === previous.scopeId &&
43
+ rejected.progress === previous.progress;
44
+ if (previous && previous.version > prefix.version && !replacesRejected)
41
45
  return;
46
+ if (previous &&
47
+ previous.version === prefix.version &&
48
+ previous.organizationId === prefix.organizationId &&
49
+ previous.headJson === prefix.headJson &&
50
+ previous.currentJson === prefix.currentJson &&
51
+ !replacesRejected) {
52
+ // Resealing an unchanged prefix would invalidate an acknowledgement's
53
+ // progress CAS even though its authenticated predecessor is unchanged.
54
+ // Still refresh authenticated root ownership and retention below.
55
+ // Reuse authenticates this opaque progress; rejected hints are removed
56
+ // or explicitly replaced before repair can rely on the new prefix.
57
+ prefix.progress = previous.progress;
58
+ }
42
59
  if (previous)
43
60
  await archivePrincipalHistoryKeyEnvelopes(tx, previous);
44
61
  await archivePrincipalHistoryKeyEnvelopes(tx, prefix);
@@ -1 +1 @@
1
- {"version":3,"file":"principalHistoryPrefixPersistence.js","sourceRoot":"","sources":["principalHistoryPrefixPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport { assertProjectionVerificationCurrent } from \"../keyingProjectionVerification/types\";\nimport {\n principalHistoryEvidenceTables,\n principalHistoryPrefixes,\n} from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { principalHistoryStageTables } from \"../sqlite/principalHistoryStageSchema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport { reclaimPrincipalHistoryNodes } from \"./principalHistoryNodeRetention\";\nimport {\n releasePrincipalHistoryRoot,\n retainPrincipalHistoryRoot,\n} from \"./principalHistoryRootOwnership\";\nimport { reclaimCompletedPrincipalHistoryStages } from \"./principalHistoryStageRetention\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\nexport type PrincipalHistoryPrefix =\n typeof principalHistoryPrefixes.$inferSelect;\n\nexport async function loadPrincipalHistoryPrefix(\n execSql: ExecSql,\n scopeId: string,\n) {\n await ensureSqlTables(execSql, principalHistoryEvidenceTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [prefix] = await db\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, scopeId))\n .limit(1);\n return prefix ?? null;\n}\n\n/** Keep the newest prefix unless replay replaces the exact rejected candidate. */\nexport async function savePrincipalHistoryPrefix(input: {\n readonly execSql: ExecSql;\n readonly prefix: PrincipalHistoryPrefix;\n readonly indexRootHash: string;\n readonly stillCurrent: () => boolean;\n readonly rejectedPrefix?: PrincipalHistoryPrefix | null;\n}): Promise<void> {\n const prefix = { ...input.prefix };\n const indexRootHash = input.indexRootHash;\n const rejected = input.rejectedPrefix ? { ...input.rejectedPrefix } : null;\n await ensureSqlTables(input.execSql, [\n ...principalHistoryEvidenceTables,\n ...principalHistoryStageTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const result = await runtime.guardedTransaction(\n async (tx) => {\n const [previous] = await tx\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))\n .limit(1);\n if (\n previous &&\n previous.version > prefix.version &&\n !(\n rejected?.scopeId === previous.scopeId &&\n rejected.progress === previous.progress\n )\n )\n return;\n if (previous) await archivePrincipalHistoryKeyEnvelopes(tx, previous);\n await archivePrincipalHistoryKeyEnvelopes(tx, prefix);\n await tx\n .insert(principalHistoryPrefixes)\n .values(prefix)\n .onConflictDoUpdate({\n target: principalHistoryPrefixes.scopeId,\n set: prefix,\n })\n .run();\n await reclaimCompletedPrincipalHistoryStages(tx, prefix);\n await retainPrincipalHistoryRoot(tx, {\n id: `prefix:${prefix.scopeId}`,\n scopeId: prefix.scopeId,\n organizationId: prefix.organizationId,\n rootHash: indexRootHash,\n });\n await reclaimPrincipalHistoryNodes(tx, prefix);\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => result.committed);\n}\n\n/** Invalid hints are disposable, but a losing reader must preserve a newer hint. */\nexport async function discardPrincipalHistoryPrefix(input: {\n readonly execSql: ExecSql;\n readonly prefix: PrincipalHistoryPrefix;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const prefix = { ...input.prefix };\n await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const result = await runtime.guardedTransaction(\n async (tx) => {\n const [current] = await tx\n .select({ progress: principalHistoryPrefixes.progress })\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))\n .limit(1);\n if (current?.progress !== prefix.progress) return;\n await releasePrincipalHistoryRoot(tx, `prefix:${prefix.scopeId}`);\n await tx\n .delete(principalHistoryPrefixes)\n .where(\n and(\n eq(principalHistoryPrefixes.scopeId, prefix.scopeId),\n eq(principalHistoryPrefixes.progress, prefix.progress),\n ),\n )\n .run();\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => result.committed);\n}\n"]}
1
+ {"version":3,"file":"principalHistoryPrefixPersistence.js","sourceRoot":"","sources":["principalHistoryPrefixPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport { assertProjectionVerificationCurrent } from \"../keyingProjectionVerification/types\";\nimport {\n principalHistoryEvidenceTables,\n principalHistoryPrefixes,\n} from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { principalHistoryStageTables } from \"../sqlite/principalHistoryStageSchema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport { reclaimPrincipalHistoryNodes } from \"./principalHistoryNodeRetention\";\nimport {\n releasePrincipalHistoryRoot,\n retainPrincipalHistoryRoot,\n} from \"./principalHistoryRootOwnership\";\nimport { reclaimCompletedPrincipalHistoryStages } from \"./principalHistoryStageRetention\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\nexport type PrincipalHistoryPrefix =\n typeof principalHistoryPrefixes.$inferSelect;\n\nexport async function loadPrincipalHistoryPrefix(\n execSql: ExecSql,\n scopeId: string,\n) {\n await ensureSqlTables(execSql, principalHistoryEvidenceTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [prefix] = await db\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, scopeId))\n .limit(1);\n return prefix ?? null;\n}\n\n/**\n * Preserve identical completed progress; this sink does not authenticate hints.\n * Callers must discard an unreadable prefix or identify it with rejectedPrefix\n * before publishing a repair of the same head and current artifacts.\n */\nexport async function savePrincipalHistoryPrefix(input: {\n readonly execSql: ExecSql;\n readonly prefix: PrincipalHistoryPrefix;\n readonly indexRootHash: string;\n readonly stillCurrent: () => boolean;\n readonly rejectedPrefix?: PrincipalHistoryPrefix | null;\n}): Promise<void> {\n const prefix = { ...input.prefix };\n const indexRootHash = input.indexRootHash;\n const rejected = input.rejectedPrefix ? { ...input.rejectedPrefix } : null;\n await ensureSqlTables(input.execSql, [\n ...principalHistoryEvidenceTables,\n ...principalHistoryStageTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const result = await runtime.guardedTransaction(\n async (tx) => {\n const [previous] = await tx\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))\n .limit(1);\n const replacesRejected =\n previous &&\n rejected?.scopeId === previous.scopeId &&\n rejected.progress === previous.progress;\n if (previous && previous.version > prefix.version && !replacesRejected)\n return;\n if (\n previous &&\n previous.version === prefix.version &&\n previous.organizationId === prefix.organizationId &&\n previous.headJson === prefix.headJson &&\n previous.currentJson === prefix.currentJson &&\n !replacesRejected\n ) {\n // Resealing an unchanged prefix would invalidate an acknowledgement's\n // progress CAS even though its authenticated predecessor is unchanged.\n // Still refresh authenticated root ownership and retention below.\n // Reuse authenticates this opaque progress; rejected hints are removed\n // or explicitly replaced before repair can rely on the new prefix.\n prefix.progress = previous.progress;\n }\n if (previous) await archivePrincipalHistoryKeyEnvelopes(tx, previous);\n await archivePrincipalHistoryKeyEnvelopes(tx, prefix);\n await tx\n .insert(principalHistoryPrefixes)\n .values(prefix)\n .onConflictDoUpdate({\n target: principalHistoryPrefixes.scopeId,\n set: prefix,\n })\n .run();\n await reclaimCompletedPrincipalHistoryStages(tx, prefix);\n await retainPrincipalHistoryRoot(tx, {\n id: `prefix:${prefix.scopeId}`,\n scopeId: prefix.scopeId,\n organizationId: prefix.organizationId,\n rootHash: indexRootHash,\n });\n await reclaimPrincipalHistoryNodes(tx, prefix);\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => result.committed);\n}\n\n/** Invalid hints are disposable, but a losing reader must preserve a newer hint. */\nexport async function discardPrincipalHistoryPrefix(input: {\n readonly execSql: ExecSql;\n readonly prefix: PrincipalHistoryPrefix;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const prefix = { ...input.prefix };\n await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const result = await runtime.guardedTransaction(\n async (tx) => {\n const [current] = await tx\n .select({ progress: principalHistoryPrefixes.progress })\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))\n .limit(1);\n if (current?.progress !== prefix.progress) return;\n await releasePrincipalHistoryRoot(tx, `prefix:${prefix.scopeId}`);\n await tx\n .delete(principalHistoryPrefixes)\n .where(\n and(\n eq(principalHistoryPrefixes.scopeId, prefix.scopeId),\n eq(principalHistoryPrefixes.progress, prefix.progress),\n ),\n )\n .run();\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => result.committed);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { type CommitOrganizationGroupPolicyRequest, type CreateOrganizationGroupWithPolicyRequest, type DeleteOrganizationGroupRequest, type OrganizationPrincipalPolicyRequest } from "../../internal/validators/request/index.js";
2
2
  export type AuthoredPrincipalMutation = {
3
- readonly kind?: undefined;
3
+ readonly kind: "compound";
4
4
  readonly groupId: string;
5
5
  readonly request: CommitOrganizationGroupPolicyRequest;
6
6
  } | {
@@ -29,12 +29,12 @@ export function readPrincipalMutation(value, scope) {
29
29
  assertStateScope(request.organizationPolicy.state, "organization", scope.organizationId, scope);
30
30
  return { kind, groupId, request };
31
31
  }
32
- if (kind !== undefined)
32
+ if (kind !== "compound")
33
33
  throw new Error("Principal mutation journal operation is unsupported");
34
34
  const request = CommitOrganizationGroupPolicyRequestSchema.parse(body);
35
35
  assertStateScope(request.groupPolicy.state, "group", groupId, scope);
36
36
  assertStateScope(request.organizationPolicy.state, "organization", scope.organizationId, scope);
37
- return { groupId, request };
37
+ return { kind, groupId, request };
38
38
  }
39
39
  function assertStateScope(state, principalType, principalId, scope) {
40
40
  if (state.principalType !== principalType ||
@@ -1 +1 @@
1
- {"version":3,"file":"principalMutationJournalShape.js","sourceRoot":"","sources":["principalMutationJournalShape.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CommitOrganizationGroupPolicyRequest,\n CommitOrganizationGroupPolicyRequestSchema,\n type CreateOrganizationGroupWithPolicyRequest,\n CreateOrganizationGroupWithPolicyRequestSchema,\n type DeleteOrganizationGroupRequest,\n DeleteOrganizationGroupRequestSchema,\n type OrganizationPrincipalPolicyRequest,\n OrganizationPrincipalPolicyRequestSchema,\n} from \"@tearleads/validators/request\";\nimport { isUuidV4String } from \"@tearleads/validators/util\";\n\nexport type AuthoredPrincipalMutation =\n | {\n // Existing signed pending requests have no kind. Keep them in the same\n // scope and recovery lane so an upgrade cannot hide uncertain work.\n readonly kind?: undefined;\n readonly groupId: string;\n readonly request: CommitOrganizationGroupPolicyRequest;\n }\n | {\n readonly kind: \"group-create\";\n readonly groupId: string;\n readonly request: CreateOrganizationGroupWithPolicyRequest;\n }\n | {\n readonly kind: \"group-delete\";\n readonly groupId: string;\n readonly request: DeleteOrganizationGroupRequest;\n }\n | {\n readonly kind: \"organization\";\n readonly groupId: null;\n readonly request: OrganizationPrincipalPolicyRequest;\n };\n\ninterface SignerScope {\n readonly organizationId: string;\n readonly userId: string;\n readonly signingFingerprint: string;\n}\n\n/** Validate authored inputs; opening an existing row authenticates it first. */\nexport function readPrincipalMutation(\n value: unknown,\n scope: SignerScope,\n): AuthoredPrincipalMutation {\n if (typeof value !== \"object\" || value === null)\n throw new Error(\"Principal mutation journal payload is invalid\");\n const groupId: unknown = Reflect.get(value, \"groupId\");\n const kind: unknown = Reflect.get(value, \"kind\");\n const body: unknown = Reflect.get(value, \"request\");\n if (kind === \"organization\") {\n if (groupId !== null)\n throw new Error(\"Organization journal target differs\");\n const request = OrganizationPrincipalPolicyRequestSchema.parse(body);\n assertStateScope(\n request.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n }\n if (typeof groupId !== \"string\" || !isUuidV4String(groupId))\n throw new Error(\"Principal mutation journal group target is invalid\");\n if (kind === \"group-create\") {\n const request = CreateOrganizationGroupWithPolicyRequestSchema.parse(body);\n if (request.groupId !== groupId)\n throw new Error(\"Group creation journal target differs\");\n assertStateScope(request.initialGroupPolicy.state, \"group\", groupId, scope);\n assertStateScope(\n request.organizationPolicy.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n }\n if (kind === \"group-delete\") {\n const request = DeleteOrganizationGroupRequestSchema.parse(body);\n assertStateScope(\n request.organizationPolicy.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n }\n if (kind !== undefined)\n throw new Error(\"Principal mutation journal operation is unsupported\");\n const request = CommitOrganizationGroupPolicyRequestSchema.parse(body);\n assertStateScope(request.groupPolicy.state, \"group\", groupId, scope);\n assertStateScope(\n request.organizationPolicy.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { groupId, request };\n}\n\nfunction assertStateScope(\n state: OrganizationPrincipalPolicyRequest[\"state\"],\n principalType: \"organization\" | \"group\",\n principalId: string,\n scope: SignerScope,\n) {\n if (\n state.principalType !== principalType ||\n state.principalId !== principalId ||\n state.signerUserId !== scope.userId ||\n state.signerUserKeyFingerprint !== scope.signingFingerprint\n )\n throw new Error(\"Principal mutation journal target or signer differs\");\n}\n"]}
1
+ {"version":3,"file":"principalMutationJournalShape.js","sourceRoot":"","sources":["principalMutationJournalShape.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CommitOrganizationGroupPolicyRequest,\n CommitOrganizationGroupPolicyRequestSchema,\n type CreateOrganizationGroupWithPolicyRequest,\n CreateOrganizationGroupWithPolicyRequestSchema,\n type DeleteOrganizationGroupRequest,\n DeleteOrganizationGroupRequestSchema,\n type OrganizationPrincipalPolicyRequest,\n OrganizationPrincipalPolicyRequestSchema,\n} from \"@tearleads/validators/request\";\nimport { isUuidV4String } from \"@tearleads/validators/util\";\n\nexport type AuthoredPrincipalMutation =\n | {\n readonly kind: \"compound\";\n readonly groupId: string;\n readonly request: CommitOrganizationGroupPolicyRequest;\n }\n | {\n readonly kind: \"group-create\";\n readonly groupId: string;\n readonly request: CreateOrganizationGroupWithPolicyRequest;\n }\n | {\n readonly kind: \"group-delete\";\n readonly groupId: string;\n readonly request: DeleteOrganizationGroupRequest;\n }\n | {\n readonly kind: \"organization\";\n readonly groupId: null;\n readonly request: OrganizationPrincipalPolicyRequest;\n };\n\ninterface SignerScope {\n readonly organizationId: string;\n readonly userId: string;\n readonly signingFingerprint: string;\n}\n\n/** Validate authored inputs; opening an existing row authenticates it first. */\nexport function readPrincipalMutation(\n value: unknown,\n scope: SignerScope,\n): AuthoredPrincipalMutation {\n if (typeof value !== \"object\" || value === null)\n throw new Error(\"Principal mutation journal payload is invalid\");\n const groupId: unknown = Reflect.get(value, \"groupId\");\n const kind: unknown = Reflect.get(value, \"kind\");\n const body: unknown = Reflect.get(value, \"request\");\n if (kind === \"organization\") {\n if (groupId !== null)\n throw new Error(\"Organization journal target differs\");\n const request = OrganizationPrincipalPolicyRequestSchema.parse(body);\n assertStateScope(\n request.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n }\n if (typeof groupId !== \"string\" || !isUuidV4String(groupId))\n throw new Error(\"Principal mutation journal group target is invalid\");\n if (kind === \"group-create\") {\n const request = CreateOrganizationGroupWithPolicyRequestSchema.parse(body);\n if (request.groupId !== groupId)\n throw new Error(\"Group creation journal target differs\");\n assertStateScope(request.initialGroupPolicy.state, \"group\", groupId, scope);\n assertStateScope(\n request.organizationPolicy.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n }\n if (kind === \"group-delete\") {\n const request = DeleteOrganizationGroupRequestSchema.parse(body);\n assertStateScope(\n request.organizationPolicy.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n }\n if (kind !== \"compound\")\n throw new Error(\"Principal mutation journal operation is unsupported\");\n const request = CommitOrganizationGroupPolicyRequestSchema.parse(body);\n assertStateScope(request.groupPolicy.state, \"group\", groupId, scope);\n assertStateScope(\n request.organizationPolicy.state,\n \"organization\",\n scope.organizationId,\n scope,\n );\n return { kind, groupId, request };\n}\n\nfunction assertStateScope(\n state: OrganizationPrincipalPolicyRequest[\"state\"],\n principalType: \"organization\" | \"group\",\n principalId: string,\n scope: SignerScope,\n) {\n if (\n state.principalType !== principalType ||\n state.principalId !== principalId ||\n state.signerUserId !== scope.userId ||\n state.signerUserKeyFingerprint !== scope.signingFingerprint\n )\n throw new Error(\"Principal mutation journal target or signer differs\");\n}\n"]}