@tearleads/client-sdk 0.1.19 → 0.1.21

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 (238) hide show
  1. package/client/organizations/index.js +2 -2
  2. package/client/organizations/index.js.map +1 -1
  3. package/client/organizations/organizationHistory.js +66 -0
  4. package/client/organizations/organizationHistory.js.map +1 -0
  5. package/client/organizations/organizationReadModels.d.ts +1 -1
  6. package/client/organizations/organizationReadModels.js +7 -27
  7. package/client/organizations/organizationReadModels.js.map +1 -1
  8. package/client/organizations/organizationsTypes.d.ts +1 -1
  9. package/client/organizations/organizationsTypes.js.map +1 -1
  10. package/data/containers/shared/types.d.ts +2 -2
  11. package/data/containers/shared/types.js.map +1 -1
  12. package/data/documents/shared/syncSubmitFailure.d.ts +2 -2
  13. package/data/documents/shared/syncSubmitFailure.js.map +1 -1
  14. package/data/keyingProjectionVerification/documentPurgeCheckpointCurrency.js +34 -8
  15. package/data/keyingProjectionVerification/documentPurgeCheckpointCurrency.js.map +1 -1
  16. package/data/keyingProjectionVerification/documentPurgeDocumentChainVerification.js.map +1 -1
  17. package/data/keyingProjectionVerification/documentPurgePolicyCheckpoints.js +17 -0
  18. package/data/keyingProjectionVerification/documentPurgePolicyCheckpoints.js.map +1 -0
  19. package/data/keyingProjectionVerification/documentPurgePolicyCurrency.js +55 -0
  20. package/data/keyingProjectionVerification/documentPurgePolicyCurrency.js.map +1 -0
  21. package/data/keyingProjectionVerification/documentPurgePrincipalEvidence.js +25 -13
  22. package/data/keyingProjectionVerification/documentPurgePrincipalEvidence.js.map +1 -1
  23. package/data/keyingProjectionVerification/documentPurgeProofVerification.d.ts +5 -3
  24. package/data/keyingProjectionVerification/documentPurgeProofVerification.js +52 -8
  25. package/data/keyingProjectionVerification/documentPurgeProofVerification.js.map +1 -1
  26. package/data/keyingProjectionVerification/projectionPolicyEvidence.js.map +1 -1
  27. package/data/keyingProjectionVerification/types.d.ts +4 -0
  28. package/data/keyingProjectionVerification/types.js.map +1 -1
  29. package/data/persistence/organizations/organizationReadModelProjection.js +2 -2
  30. package/data/persistence/organizations/organizationReadModelProjection.js.map +1 -1
  31. package/data/persistence/principalAuthorizationCheckpoints.js +1 -1
  32. package/data/persistence/principalAuthorizationCheckpoints.js.map +1 -1
  33. package/data/persistence/principalCurrentAcknowledgementPersistence.d.ts +1 -0
  34. package/data/persistence/principalCurrentAcknowledgementPersistence.js +58 -12
  35. package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
  36. package/data/persistence/principalHistoryEvidencePersistence.d.ts +2 -0
  37. package/data/persistence/principalHistoryEvidencePersistence.js +2 -0
  38. package/data/persistence/principalHistoryEvidencePersistence.js.map +1 -1
  39. package/data/persistence/principalHistoryIncompleteRetention.js +32 -0
  40. package/data/persistence/principalHistoryIncompleteRetention.js.map +1 -0
  41. package/data/persistence/principalHistoryNodeRetention.js +76 -0
  42. package/data/persistence/principalHistoryNodeRetention.js.map +1 -0
  43. package/data/persistence/principalHistoryPrefixPersistence.d.ts +1 -0
  44. package/data/persistence/principalHistoryPrefixPersistence.js +30 -1
  45. package/data/persistence/principalHistoryPrefixPersistence.js.map +1 -1
  46. package/data/persistence/principalHistoryRootOwnership.js +71 -0
  47. package/data/persistence/principalHistoryRootOwnership.js.map +1 -0
  48. package/data/persistence/principalHistoryStagePersistence.js +45 -0
  49. package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
  50. package/data/persistence/principalHistoryStageRetention.js +44 -0
  51. package/data/persistence/principalHistoryStageRetention.js.map +1 -0
  52. package/data/persistence/principalHistoryUnpublishedRetention.js +71 -0
  53. package/data/persistence/principalHistoryUnpublishedRetention.js.map +1 -0
  54. package/data/persistence/principalKeyEnvelopeArchivePersistence.js +63 -0
  55. package/data/persistence/principalKeyEnvelopeArchivePersistence.js.map +1 -0
  56. package/data/persistence/principalKeyEnvelopeCandidates.js +10 -1
  57. package/data/persistence/principalKeyEnvelopeCandidates.js.map +1 -1
  58. package/data/persistence/principalPolicyReferencePersistence.js +2 -2
  59. package/data/persistence/principalPolicyReferencePersistence.js.map +1 -1
  60. package/data/sqlite/principalHistoryEvidenceSchema.js +2 -0
  61. package/data/sqlite/principalHistoryEvidenceSchema.js.map +1 -1
  62. package/data/sqlite/principalHistoryNodeRetentionSchema.js +30 -0
  63. package/data/sqlite/principalHistoryNodeRetentionSchema.js.map +1 -0
  64. package/data/sqlite/principalHistoryRetentionSchema.js +40 -0
  65. package/data/sqlite/principalHistoryRetentionSchema.js.map +1 -0
  66. package/data/sqlite/principalHistoryStageSchema.js +2 -0
  67. package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
  68. package/data/sqlite/schema.d.ts +453 -0
  69. package/data/sqlite/schema.js +6 -0
  70. package/data/sqlite/schema.js.map +1 -1
  71. package/data/sqlite/sqliteCommitGuards.js +49 -0
  72. package/data/sqlite/sqliteCommitGuards.js.map +1 -0
  73. package/data/sqlite/sqlitePersistenceRuntime.js +14 -2
  74. package/data/sqlite/sqlitePersistenceRuntime.js.map +1 -1
  75. package/index.d.ts +3 -1
  76. package/index.js.map +1 -1
  77. package/internal/api-client/ApiClient.d.ts +60 -137
  78. package/internal/api-client/ApiClient.js +7 -5
  79. package/internal/api-client/ApiClient.js.map +1 -1
  80. package/internal/api-client/apiRequestRuntime.js +7 -7
  81. package/internal/api-client/apiRequestRuntime.js.map +1 -1
  82. package/internal/api-client/documentPurge.js +25 -0
  83. package/internal/api-client/documentPurge.js.map +1 -0
  84. package/internal/api-client/organizationPolicyHistory.d.ts +53 -0
  85. package/internal/api-client/organizationPolicyHistory.js +15 -0
  86. package/internal/api-client/organizationPolicyHistory.js.map +1 -0
  87. package/internal/api-client/requestInternals.js +4 -4
  88. package/internal/api-client/requestInternals.js.map +1 -1
  89. package/internal/api-client/types.d.ts +2 -2
  90. package/internal/api-client/types.js.map +1 -1
  91. package/internal/crypto/keying/accessEvent.js +11 -9
  92. package/internal/crypto/keying/accessEvent.js.map +1 -1
  93. package/internal/crypto/keying/principalPolicyChainEntry.js +3 -0
  94. package/internal/crypto/keying/principalPolicyChainEntry.js.map +1 -1
  95. package/internal/crypto/keying/principalPolicyHistory.js +4 -0
  96. package/internal/crypto/keying/principalPolicyHistory.js.map +1 -1
  97. package/internal/crypto/keying/principalPolicyHistoryTypes.d.ts +2 -0
  98. package/internal/crypto/keying/principalPolicyHistoryTypes.js.map +1 -1
  99. package/internal/crypto/keying/principalPolicyTransition.d.ts +2 -1
  100. package/internal/crypto/keying/principalPolicyTransition.js +5 -0
  101. package/internal/crypto/keying/principalPolicyTransition.js.map +1 -1
  102. package/internal/crypto/principalState.js +2 -2
  103. package/internal/crypto/principalState.js.map +1 -1
  104. package/internal/validators/operation/containerMutations.d.ts +448 -6528
  105. package/internal/validators/operation/documentMutations.d.ts +323 -579
  106. package/internal/validators/operation/documentMutations.js +22 -4
  107. package/internal/validators/operation/documentMutations.js.map +1 -1
  108. package/internal/validators/operation/documentSync.d.ts +26 -406
  109. package/internal/validators/operation/organizationPolicyHistory.d.ts +188 -310
  110. package/internal/validators/operation/organizationPolicyHistory.js +17 -3
  111. package/internal/validators/operation/organizationPolicyHistory.js.map +1 -1
  112. package/internal/validators/operation/organizations.d.ts +2 -2
  113. package/internal/validators/request/principal.js +2 -2
  114. package/internal/validators/request/principal.js.map +1 -1
  115. package/internal/validators/response/containerMutationError.d.ts +28 -408
  116. package/internal/validators/response/documentMutation.d.ts +232 -544
  117. package/internal/validators/response/documentMutation.js +1 -2
  118. package/internal/validators/response/documentMutation.js.map +1 -1
  119. package/internal/validators/response/documentSyncError.d.ts +26 -406
  120. package/internal/validators/response/documentSyncError.js +4 -3
  121. package/internal/validators/response/documentSyncError.js.map +1 -1
  122. package/internal/validators/response/index.d.ts +1 -1
  123. package/internal/validators/response/index.js +1 -1
  124. package/internal/validators/response/index.js.map +1 -1
  125. package/internal/validators/response/organization.d.ts +1 -1
  126. package/internal/validators/response/organization.js +1 -1
  127. package/internal/validators/response/organization.js.map +1 -1
  128. package/internal/validators/response/organizationPolicyHistory.d.ts +127 -309
  129. package/internal/validators/response/organizationPolicyHistory.js +10 -4
  130. package/internal/validators/response/organizationPolicyHistory.js.map +1 -1
  131. package/internal/validators/response/organizationReadModel.d.ts +5 -5
  132. package/internal/validators/response/principal.d.ts +28 -408
  133. package/internal/validators/response/principal.js +3 -1
  134. package/internal/validators/response/principal.js.map +1 -1
  135. package/internal/validators/response/principalReference.d.ts +1 -1
  136. package/internal/validators/response/principalReference.js +1 -1
  137. package/internal/validators/response/principalReference.js.map +1 -1
  138. package/internal/validators/response/principalSnapshot.js +4 -4
  139. package/internal/validators/response/principalSnapshot.js.map +1 -1
  140. package/internal/validators/util/index.d.ts +1 -1
  141. package/internal/validators/util/index.js +1 -1
  142. package/internal/validators/util/index.js.map +1 -1
  143. package/internal/validators/util/principalHistoryWire.d.ts +2 -0
  144. package/internal/validators/util/principalHistoryWire.js +2 -0
  145. package/internal/validators/util/principalHistoryWire.js.map +1 -1
  146. package/package.json +1 -1
  147. package/workflows/container-contents/container-state/createWithMetadata.js +19 -49
  148. package/workflows/container-contents/container-state/createWithMetadata.js.map +1 -1
  149. package/workflows/container-contents/container-state/groupGrantVerification.js +29 -0
  150. package/workflows/container-contents/container-state/groupGrantVerification.js.map +1 -1
  151. package/workflows/container-contents/container-state/groupShareEpoch.js +33 -0
  152. package/workflows/container-contents/container-state/groupShareEpoch.js.map +1 -0
  153. package/workflows/container-contents/container-state/remote.js +4 -1
  154. package/workflows/container-contents/container-state/remote.js.map +1 -1
  155. package/workflows/container-contents/container-state/share.js +2 -24
  156. package/workflows/container-contents/container-state/share.js.map +1 -1
  157. package/workflows/container-contents/documentTombstoneEvidence.js +23 -12
  158. package/workflows/container-contents/documentTombstoneEvidence.js.map +1 -1
  159. package/workflows/containers/child/create.js +1 -3
  160. package/workflows/containers/child/create.js.map +1 -1
  161. package/workflows/containers/child/createSubmission.d.ts +1 -3
  162. package/workflows/containers/child/createSubmission.js +13 -15
  163. package/workflows/containers/child/createSubmission.js.map +1 -1
  164. package/workflows/containers/child/currentShareGrantMutation.js +82 -0
  165. package/workflows/containers/child/currentShareGrantMutation.js.map +1 -0
  166. package/workflows/containers/child/currentSharePrincipalPolicy.js +83 -0
  167. package/workflows/containers/child/currentSharePrincipalPolicy.js.map +1 -0
  168. package/workflows/containers/child/mutationSubmit.js +1 -1
  169. package/workflows/containers/child/mutationSubmit.js.map +1 -1
  170. package/workflows/containers/child/runtimeCurrentGroupShare.js +82 -0
  171. package/workflows/containers/child/runtimeCurrentGroupShare.js.map +1 -0
  172. package/workflows/containers/child/share.js +1 -14
  173. package/workflows/containers/child/share.js.map +1 -1
  174. package/workflows/containers/child/shareProjection.js +15 -0
  175. package/workflows/containers/child/shareProjection.js.map +1 -0
  176. package/workflows/containers/mutationResponse.js +1 -1
  177. package/workflows/containers/mutationResponse.js.map +1 -1
  178. package/workflows/documents/purge.d.ts +3 -0
  179. package/workflows/documents/purge.js +13 -0
  180. package/workflows/documents/purge.js.map +1 -1
  181. package/workflows/documents/sync.js +2 -0
  182. package/workflows/documents/sync.js.map +1 -1
  183. package/workflows/documents/syncFailures.js +2 -2
  184. package/workflows/documents/syncFailures.js.map +1 -1
  185. package/workflows/documents/syncPolicyRepair.js +15 -13
  186. package/workflows/documents/syncPolicyRepair.js.map +1 -1
  187. package/workflows/organizations/initialPrincipalCurrentPublication.js +2 -0
  188. package/workflows/organizations/initialPrincipalCurrentPublication.js.map +1 -1
  189. package/workflows/organizations/loadPolicyHistoryDetails.js +31 -32
  190. package/workflows/organizations/loadPolicyHistoryDetails.js.map +1 -1
  191. package/workflows/organizations/organizationPolicyHistoryDetails.js +37 -15
  192. package/workflows/organizations/organizationPolicyHistoryDetails.js.map +1 -1
  193. package/workflows/organizations/organizationPolicyHistoryVerification.js +56 -69
  194. package/workflows/organizations/organizationPolicyHistoryVerification.js.map +1 -1
  195. package/workflows/organizations/policyHistoryCache.js +5 -2
  196. package/workflows/organizations/policyHistoryCache.js.map +1 -1
  197. package/workflows/organizations/policyHistoryTypes.d.ts +1 -0
  198. package/workflows/organizations/policyHistoryTypes.js.map +1 -1
  199. package/workflows/organizations/retainAcknowledgedPrincipalCurrents.js +4 -1
  200. package/workflows/organizations/retainAcknowledgedPrincipalCurrents.js.map +1 -1
  201. package/workflows/principals/loadRecoveredPrincipalHistoryPage.d.ts +0 -1
  202. package/workflows/principals/loadRecoveredPrincipalHistoryPage.js +1 -2
  203. package/workflows/principals/loadRecoveredPrincipalHistoryPage.js.map +1 -1
  204. package/workflows/principals/policyRepair.js +38 -0
  205. package/workflows/principals/policyRepair.js.map +1 -0
  206. package/workflows/principals/policyRepairBudget.d.ts +2 -2
  207. package/workflows/principals/policyRepairBudget.js +3 -3
  208. package/workflows/principals/policyRepairBudget.js.map +1 -1
  209. package/workflows/principals/principalHistoryRecoveryPrefix.js +4 -0
  210. package/workflows/principals/principalHistoryRecoveryPrefix.js.map +1 -1
  211. package/workflows/principals/principalRecoveryLocalPreference.js +3 -2
  212. package/workflows/principals/principalRecoveryLocalPreference.js.map +1 -1
  213. package/workflows/principals/publicPrincipalHistoryPage.js +1 -0
  214. package/workflows/principals/publicPrincipalHistoryPage.js.map +1 -1
  215. package/workflows/principals/publicPrincipalHistoryProgress.js +1 -0
  216. package/workflows/principals/publicPrincipalHistoryProgress.js.map +1 -1
  217. package/workflows/principals/publicPrincipalHistoryTypes.d.ts +2 -0
  218. package/workflows/principals/publicPrincipalHistoryTypes.js.map +1 -1
  219. package/workflows/principals/publicProjectionPrincipal.js +1 -0
  220. package/workflows/principals/publicProjectionPrincipal.js.map +1 -1
  221. package/workflows/principals/recoverPrincipalHistoryPage.js +2 -1
  222. package/workflows/principals/recoverPrincipalHistoryPage.js.map +1 -1
  223. package/workflows/principals/recoverPrincipalPolicyHistory.js +1 -0
  224. package/workflows/principals/recoverPrincipalPolicyHistory.js.map +1 -1
  225. package/workflows/principals/recoverPublicPrincipalHistory.js +2 -0
  226. package/workflows/principals/recoverPublicPrincipalHistory.js.map +1 -1
  227. package/workflows/principals/runtimePolicyRecovery.js +2 -1
  228. package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
  229. package/workflows/principals/selectPublicPrincipalHistory.js +21 -15
  230. package/workflows/principals/selectPublicPrincipalHistory.js.map +1 -1
  231. package/workflows/sync/remoteResetPrincipalScope.js +6 -0
  232. package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
  233. package/data/keyingProjectionVerification/principalPolicySnapshotVerification.js +0 -208
  234. package/data/keyingProjectionVerification/principalPolicySnapshotVerification.js.map +0 -1
  235. package/data/keyingProjectionVerification/snapshotVerificationCache.js +0 -39
  236. package/data/keyingProjectionVerification/snapshotVerificationCache.js.map +0 -1
  237. package/workflows/containers/child/policyRepair.js +0 -23
  238. package/workflows/containers/child/policyRepair.js.map +0 -1
@@ -6,6 +6,8 @@ export type ProjectionUserKey = TrustedUserIdentity;
6
6
  export type ProjectionUserKeyResolver = (userId: string) => Promise<ProjectionUserKey | null>;
7
7
  export type PrincipalPolicyCache = Map<string, PrincipalPolicyCurrentEvidence>;
8
8
  export interface PrincipalPolicyResolveRequest {
9
+ /** Reuse authenticated local ancestry before an authorized online recovery. */
10
+ readonly preferLocalHistory?: boolean | undefined;
9
11
  /** Identity of one projection collection, never caller-supplied evidence. */
10
12
  readonly recoveryBatch?: object | undefined;
11
13
  readonly organizationId: string;
@@ -29,6 +31,8 @@ export interface PrincipalPolicyBundleCacheRequest {
29
31
  readonly stillCurrent?: (() => boolean) | undefined;
30
32
  }
31
33
  export interface ProjectionPolicyHistoryResolveRequest {
34
+ /** Authenticate terminal evidence first; its consumer must validate durable currency. */
35
+ readonly historicalProof?: boolean | undefined;
32
36
  readonly organizationId: string;
33
37
  readonly evidence: ProjectionPolicyEvidenceResponse;
34
38
  readonly references: readonly ReferencedPrincipalHead[];
@@ -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 /** 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 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 {\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"]}
@@ -46,7 +46,7 @@ function toGroupCurrentState(row, policyHead) {
46
46
  row.stateHash.length === 0 ||
47
47
  !Number.isInteger(row.stateVersion) ||
48
48
  row.stateVersion <= 0 ||
49
- !Number.isInteger(row.keyEpoch) ||
49
+ !Number.isSafeInteger(row.keyEpoch) ||
50
50
  row.keyEpoch <= 0 ||
51
51
  !Number.isInteger(row.memberCount) ||
52
52
  row.memberCount < 0 ||
@@ -71,7 +71,7 @@ function toPolicyHead(row) {
71
71
  row.stateHash.length === 0 ||
72
72
  !Number.isInteger(row.stateVersion) ||
73
73
  row.stateVersion <= 0 ||
74
- !Number.isInteger(row.keyEpoch) ||
74
+ !Number.isSafeInteger(row.keyEpoch) ||
75
75
  row.keyEpoch <= 0 ||
76
76
  row.keyFingerprint.length === 0 ||
77
77
  !Number.isInteger(row.memberCount) ||
@@ -1 +1 @@
1
- {"version":3,"file":"organizationReadModelProjection.js","sourceRoot":"","sources":["organizationReadModelProjection.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ListOrganizationGroupsResponse,\n OrganizationContainerGrantsResponse,\n OrganizationDirectoryResponse,\n OrganizationDirectoryUserResponse,\n OrganizationGroupCurrentStateResponse,\n OrganizationRosterStatus,\n} from \"@tearleads/validators/response\";\nimport { and, asc, eq } from \"drizzle-orm\";\nimport {\n organizationReadModelDirectoryUsers,\n organizationReadModelGroupMembers,\n organizationReadModelGroups,\n organizationReadModelPolicyHeads,\n organizationReadModelRequesters,\n organizationReadModelState,\n} from \"../../sqlite/organizationReadModelSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { loadOrganizationReadModelGrantsInTransaction } from \"./organizationReadModelGrantPersistence\";\nimport {\n ORGANIZATION_READ_MODEL_PROTOCOL_VERSION,\n OrganizationReadModelIntegrityError,\n} from \"./organizationReadModelProtocol\";\n\nexport type OrganizationDirectoryProjection = Omit<\n OrganizationDirectoryResponse,\n \"currentUser\"\n>;\n\nexport interface OrganizationReadModelProjection {\n readonly cursor: string;\n readonly directory: OrganizationDirectoryProjection;\n readonly grants: OrganizationContainerGrantsResponse;\n readonly groups: Omit<ListOrganizationGroupsResponse, \"groups\"> & {\n groups: Array<\n ListOrganizationGroupsResponse[\"groups\"][number] & { name: string }\n >;\n };\n readonly membershipEdges: OrganizationReadModelMembershipEdge[];\n readonly organizationId: string;\n readonly policyHeads: readonly OrganizationReadModelPolicyHead[];\n readonly protocolVersion: typeof ORGANIZATION_READ_MODEL_PROTOCOL_VERSION;\n readonly requester: OrganizationDirectoryResponse[\"currentUser\"] | null;\n readonly updatedAt: string;\n}\n\nexport interface OrganizationReadModelPolicyHead {\n readonly keyEpoch: number;\n readonly keyFingerprint: string;\n readonly memberCount: number;\n readonly organizationId: string;\n readonly principalId: string;\n readonly principalType: \"group\" | \"organization\";\n readonly stateHash: string;\n readonly version: number;\n}\n\nexport interface OrganizationReadModelMembershipEdge {\n readonly groupId: string;\n readonly userId: string;\n}\n\ninterface SelectedDirectoryUser {\n readonly createdAt: string;\n readonly disabledAt: string | null;\n readonly disabledByUserId: string | null;\n readonly encapsulationKeyFingerprint: string;\n readonly encapsulationPublicKey: string;\n readonly isPersonalOrganizationOwner: boolean;\n readonly joinedAt: string;\n readonly profileDocumentId: string | null;\n readonly signingKeyFingerprint: string;\n readonly signingPublicKey: string;\n readonly status: string;\n readonly updatedAt: string;\n readonly userId: string;\n}\n\ninterface SelectedGroup {\n readonly createdAt: string;\n readonly groupId: string;\n readonly isBuiltin: boolean;\n readonly keyEpoch: number | null;\n readonly memberCount: number | null;\n readonly name: string;\n readonly stateHash: string | null;\n readonly stateVersion: number | null;\n}\n\ninterface SelectedPolicyHead {\n readonly keyEpoch: number;\n readonly keyFingerprint: string;\n readonly memberCount: number;\n readonly organizationId: string;\n readonly principalId: string;\n readonly principalType: string;\n readonly stateHash: string;\n readonly stateVersion: number;\n}\n\nfunction isOrganizationRosterStatus(\n value: string,\n): value is OrganizationRosterStatus {\n return value === \"active\" || value === \"disabled\";\n}\n\nfunction toDirectoryUser(\n row: SelectedDirectoryUser,\n currentUserId: string,\n): OrganizationDirectoryUserResponse {\n if (!isOrganizationRosterStatus(row.status)) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization directory status is invalid\",\n );\n }\n\n return {\n userId: row.userId,\n signingKeyFingerprint: row.signingKeyFingerprint,\n signingPublicKey: row.signingPublicKey,\n encapsulationPublicKey: row.encapsulationPublicKey,\n encapsulationKeyFingerprint: row.encapsulationKeyFingerprint,\n createdAt: row.createdAt,\n isPersonalOrganizationOwner: row.isPersonalOrganizationOwner,\n isSelf: row.userId === currentUserId,\n status: row.status,\n profileDocumentId: row.profileDocumentId,\n joinedAt: row.joinedAt,\n updatedAt: row.updatedAt,\n disabledAt: row.disabledAt,\n disabledByUserId: row.disabledByUserId,\n };\n}\n\nfunction toGroupCurrentState(\n row: SelectedGroup,\n policyHead: OrganizationReadModelPolicyHead | undefined,\n): OrganizationGroupCurrentStateResponse | null {\n const values = [\n row.stateHash,\n row.stateVersion,\n row.keyEpoch,\n row.memberCount,\n ];\n if (values.every((value) => value === null)) {\n if (policyHead) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization group policy head is orphaned\",\n );\n }\n return null;\n }\n if (\n row.stateHash === null ||\n row.stateVersion === null ||\n row.keyEpoch === null ||\n row.memberCount === null ||\n row.stateHash.length === 0 ||\n !Number.isInteger(row.stateVersion) ||\n row.stateVersion <= 0 ||\n !Number.isInteger(row.keyEpoch) ||\n row.keyEpoch <= 0 ||\n !Number.isInteger(row.memberCount) ||\n row.memberCount < 0 ||\n !policyHead ||\n policyHead.stateHash !== row.stateHash ||\n policyHead.version !== row.stateVersion ||\n policyHead.keyEpoch !== row.keyEpoch ||\n policyHead.memberCount !== row.memberCount\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization group state is invalid\",\n );\n }\n\n return {\n stateHash: row.stateHash,\n version: row.stateVersion,\n keyEpoch: row.keyEpoch,\n keyFingerprint: policyHead.keyFingerprint,\n memberCount: row.memberCount,\n };\n}\n\nfunction toPolicyHead(\n row: SelectedPolicyHead,\n): OrganizationReadModelPolicyHead {\n if (\n (row.principalType !== \"group\" && row.principalType !== \"organization\") ||\n row.principalId.length === 0 ||\n row.stateHash.length === 0 ||\n !Number.isInteger(row.stateVersion) ||\n row.stateVersion <= 0 ||\n !Number.isInteger(row.keyEpoch) ||\n row.keyEpoch <= 0 ||\n row.keyFingerprint.length === 0 ||\n !Number.isInteger(row.memberCount) ||\n row.memberCount < 0\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization policy head is invalid\",\n );\n }\n\n return {\n organizationId: row.organizationId,\n principalType: row.principalType,\n principalId: row.principalId,\n stateHash: row.stateHash,\n version: row.stateVersion,\n keyEpoch: row.keyEpoch,\n keyFingerprint: row.keyFingerprint,\n memberCount: row.memberCount,\n };\n}\n\nasync function loadDirectoryRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<SelectedDirectoryUser[]> {\n return tx\n .select({\n createdAt: organizationReadModelDirectoryUsers.createdAt,\n disabledAt: organizationReadModelDirectoryUsers.disabledAt,\n disabledByUserId: organizationReadModelDirectoryUsers.disabledByUserId,\n encapsulationKeyFingerprint:\n organizationReadModelDirectoryUsers.encapsulationKeyFingerprint,\n encapsulationPublicKey:\n organizationReadModelDirectoryUsers.encapsulationPublicKey,\n joinedAt: organizationReadModelDirectoryUsers.joinedAt,\n isPersonalOrganizationOwner:\n organizationReadModelDirectoryUsers.isPersonalOrganizationOwner,\n profileDocumentId: organizationReadModelDirectoryUsers.profileDocumentId,\n signingKeyFingerprint:\n organizationReadModelDirectoryUsers.signingKeyFingerprint,\n signingPublicKey: organizationReadModelDirectoryUsers.signingPublicKey,\n status: organizationReadModelDirectoryUsers.status,\n updatedAt: organizationReadModelDirectoryUsers.updatedAt,\n userId: organizationReadModelDirectoryUsers.userId,\n })\n .from(organizationReadModelDirectoryUsers)\n .where(\n eq(organizationReadModelDirectoryUsers.organizationId, organizationId),\n )\n .orderBy(\n asc(organizationReadModelDirectoryUsers.sortOrder),\n asc(organizationReadModelDirectoryUsers.userId),\n );\n}\n\nasync function loadGroupRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<SelectedGroup[]> {\n return tx\n .select({\n createdAt: organizationReadModelGroups.createdAt,\n groupId: organizationReadModelGroups.groupId,\n isBuiltin: organizationReadModelGroups.isBuiltin,\n keyEpoch: organizationReadModelGroups.keyEpoch,\n memberCount: organizationReadModelGroups.memberCount,\n name: organizationReadModelGroups.name,\n stateHash: organizationReadModelGroups.stateHash,\n stateVersion: organizationReadModelGroups.stateVersion,\n })\n .from(organizationReadModelGroups)\n .where(eq(organizationReadModelGroups.organizationId, organizationId))\n .orderBy(\n asc(organizationReadModelGroups.sortOrder),\n asc(organizationReadModelGroups.groupId),\n );\n}\n\nasync function loadPolicyHeadRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<SelectedPolicyHead[]> {\n return tx\n .select({\n keyEpoch: organizationReadModelPolicyHeads.keyEpoch,\n keyFingerprint: organizationReadModelPolicyHeads.keyFingerprint,\n memberCount: organizationReadModelPolicyHeads.memberCount,\n organizationId: organizationReadModelPolicyHeads.organizationId,\n principalId: organizationReadModelPolicyHeads.principalId,\n principalType: organizationReadModelPolicyHeads.principalType,\n stateHash: organizationReadModelPolicyHeads.stateHash,\n stateVersion: organizationReadModelPolicyHeads.stateVersion,\n })\n .from(organizationReadModelPolicyHeads)\n .where(eq(organizationReadModelPolicyHeads.organizationId, organizationId))\n .orderBy(\n asc(organizationReadModelPolicyHeads.principalType),\n asc(organizationReadModelPolicyHeads.principalId),\n );\n}\n\nasync function loadMembershipEdges(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<OrganizationReadModelMembershipEdge[]> {\n return tx\n .select({\n groupId: organizationReadModelGroupMembers.groupId,\n userId: organizationReadModelGroupMembers.userId,\n })\n .from(organizationReadModelGroupMembers)\n .where(eq(organizationReadModelGroupMembers.organizationId, organizationId))\n .orderBy(\n asc(organizationReadModelGroupMembers.groupId),\n asc(organizationReadModelGroupMembers.sortOrder),\n asc(organizationReadModelGroupMembers.userId),\n );\n}\n\nfunction validatePolicyHeads(input: {\n readonly groupRows: readonly SelectedGroup[];\n readonly organizationId: string;\n readonly policyHeadRows: readonly SelectedPolicyHead[];\n}): {\n readonly groupPolicyHeads: ReadonlyMap<\n string,\n OrganizationReadModelPolicyHead\n >;\n readonly policyHeads: readonly OrganizationReadModelPolicyHead[];\n} {\n const policyHeads = input.policyHeadRows.map(toPolicyHead);\n const organizationPolicyHeads = policyHeads.filter(\n (head) => head.principalType === \"organization\",\n );\n if (\n organizationPolicyHeads.length !== 1 ||\n organizationPolicyHeads[0]?.principalId !== input.organizationId\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization policy head is missing or ambiguous\",\n );\n }\n const groupPolicyHeads = new Map(\n policyHeads\n .filter((head) => head.principalType === \"group\")\n .map((head) => [head.principalId, head]),\n );\n const visibleGroupIds = new Set(input.groupRows.map((row) => row.groupId));\n if (\n [...groupPolicyHeads.keys()].some(\n (principalId) => !visibleGroupIds.has(principalId),\n )\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization group policy head is not visible\",\n );\n }\n return { groupPolicyHeads, policyHeads };\n}\n\nexport async function loadOrganizationReadModelProjectionInTransaction(input: {\n readonly currentUserId: string;\n readonly organizationId: string;\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<OrganizationReadModelProjection | null> {\n const [state] = await input.tx\n .select({\n cursor: organizationReadModelState.cursor,\n memberGroupId: organizationReadModelState.memberGroupId,\n profileDocumentId: organizationReadModelState.profileDocumentId,\n updatedAt: organizationReadModelState.updatedAt,\n })\n .from(organizationReadModelState)\n .where(eq(organizationReadModelState.organizationId, input.organizationId))\n .limit(1);\n if (!state) {\n return null;\n }\n const [requester] = await input.tx\n .select({ isOrgAdmin: organizationReadModelRequesters.isOrgAdmin })\n .from(organizationReadModelRequesters)\n .where(\n and(\n eq(\n organizationReadModelRequesters.organizationId,\n input.organizationId,\n ),\n eq(organizationReadModelRequesters.userId, input.currentUserId),\n ),\n )\n .limit(1);\n const directoryRows = await loadDirectoryRows(input.tx, input.organizationId);\n const groupRows = await loadGroupRows(input.tx, input.organizationId);\n const grants = await loadOrganizationReadModelGrantsInTransaction(input);\n const membershipEdges = await loadMembershipEdges(\n input.tx,\n input.organizationId,\n );\n const policyHeadRows = await loadPolicyHeadRows(\n input.tx,\n input.organizationId,\n );\n const { groupPolicyHeads, policyHeads } = validatePolicyHeads({\n groupRows,\n organizationId: input.organizationId,\n policyHeadRows,\n });\n\n return {\n cursor: state.cursor,\n directory: {\n organizationId: input.organizationId,\n profileDocumentId: state.profileDocumentId,\n users: directoryRows.map((row) =>\n toDirectoryUser(row, input.currentUserId),\n ),\n },\n grants,\n groups: {\n organizationId: input.organizationId,\n memberGroupId: state.memberGroupId,\n groups: groupRows.map((row) => ({\n groupId: row.groupId,\n organizationId: input.organizationId,\n name: row.name,\n createdAt: row.createdAt,\n isBuiltin: row.isBuiltin,\n currentState: toGroupCurrentState(\n row,\n groupPolicyHeads.get(row.groupId),\n ),\n })),\n },\n membershipEdges,\n organizationId: input.organizationId,\n policyHeads,\n protocolVersion: ORGANIZATION_READ_MODEL_PROTOCOL_VERSION,\n requester: requester ? { isOrgAdmin: requester.isOrgAdmin } : null,\n updatedAt: state.updatedAt,\n };\n}\n"]}
1
+ {"version":3,"file":"organizationReadModelProjection.js","sourceRoot":"","sources":["organizationReadModelProjection.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,mCAAmC,EACnC,iCAAiC,EACjC,2BAA2B,EAC3B,gCAAgC,EAChC,+BAA+B,EAC/B,0BAA0B,GAC3B,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAAE,4CAA4C,EAAE,MAAM,yCAAyC,CAAC;AACvG,OAAO,EACL,wCAAwC,EACxC,mCAAmC,GACpC,MAAM,iCAAiC,CAAC;AA8EzC,SAAS,0BAA0B,CACjC,KAAa;IAEb,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,UAAU,CAAC;AACpD,CAAC;AAED,SAAS,eAAe,CACtB,GAA0B,EAC1B,aAAqB;IAErB,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,mCAAmC,CAC3C,iDAAiD,CAClD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,qBAAqB,EAAE,GAAG,CAAC,qBAAqB;QAChD,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;QACtC,sBAAsB,EAAE,GAAG,CAAC,sBAAsB;QAClD,2BAA2B,EAAE,GAAG,CAAC,2BAA2B;QAC5D,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,2BAA2B,EAAE,GAAG,CAAC,2BAA2B;QAC5D,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,aAAa;QACpC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;QACxC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;KACvC,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,GAAkB,EAClB,UAAuD;IAEvD,MAAM,MAAM,GAAG;QACb,GAAG,CAAC,SAAS;QACb,GAAG,CAAC,YAAY;QAChB,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,WAAW;KAChB,CAAC;IACF,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,EAAE,CAAC;QAC5C,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,mCAAmC,CAC3C,mDAAmD,CACpD,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IACE,GAAG,CAAC,SAAS,KAAK,IAAI;QACtB,GAAG,CAAC,YAAY,KAAK,IAAI;QACzB,GAAG,CAAC,QAAQ,KAAK,IAAI;QACrB,GAAG,CAAC,WAAW,KAAK,IAAI;QACxB,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAC1B,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC;QACnC,GAAG,CAAC,YAAY,IAAI,CAAC;QACrB,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnC,GAAG,CAAC,QAAQ,IAAI,CAAC;QACjB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QAClC,GAAG,CAAC,WAAW,GAAG,CAAC;QACnB,CAAC,UAAU;QACX,UAAU,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS;QACtC,UAAU,CAAC,OAAO,KAAK,GAAG,CAAC,YAAY;QACvC,UAAU,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ;QACpC,UAAU,CAAC,WAAW,KAAK,GAAG,CAAC,WAAW,EAC1C,CAAC;QACD,MAAM,IAAI,mCAAmC,CAC3C,4CAA4C,CAC7C,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,OAAO,EAAE,GAAG,CAAC,YAAY;QACzB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,cAAc,EAAE,UAAU,CAAC,cAAc;QACzC,WAAW,EAAE,GAAG,CAAC,WAAW;KAC7B,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,GAAuB;IAEvB,IACE,CAAC,GAAG,CAAC,aAAa,KAAK,OAAO,IAAI,GAAG,CAAC,aAAa,KAAK,cAAc,CAAC;QACvE,GAAG,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;QAC5B,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAC1B,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC;QACnC,GAAG,CAAC,YAAY,IAAI,CAAC;QACrB,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC;QACnC,GAAG,CAAC,QAAQ,IAAI,CAAC;QACjB,GAAG,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC;QAC/B,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QAClC,GAAG,CAAC,WAAW,GAAG,CAAC,EACnB,CAAC;QACD,MAAM,IAAI,mCAAmC,CAC3C,4CAA4C,CAC7C,CAAC;IACJ,CAAC;IAED,OAAO;QACL,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,OAAO,EAAE,GAAG,CAAC,YAAY;QACzB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,WAAW,EAAE,GAAG,CAAC,WAAW;KAC7B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,EAAgC,EAChC,cAAsB;IAEtB,OAAO,EAAE;SACN,MAAM,CAAC;QACN,SAAS,EAAE,mCAAmC,CAAC,SAAS;QACxD,UAAU,EAAE,mCAAmC,CAAC,UAAU;QAC1D,gBAAgB,EAAE,mCAAmC,CAAC,gBAAgB;QACtE,2BAA2B,EACzB,mCAAmC,CAAC,2BAA2B;QACjE,sBAAsB,EACpB,mCAAmC,CAAC,sBAAsB;QAC5D,QAAQ,EAAE,mCAAmC,CAAC,QAAQ;QACtD,2BAA2B,EACzB,mCAAmC,CAAC,2BAA2B;QACjE,iBAAiB,EAAE,mCAAmC,CAAC,iBAAiB;QACxE,qBAAqB,EACnB,mCAAmC,CAAC,qBAAqB;QAC3D,gBAAgB,EAAE,mCAAmC,CAAC,gBAAgB;QACtE,MAAM,EAAE,mCAAmC,CAAC,MAAM;QAClD,SAAS,EAAE,mCAAmC,CAAC,SAAS;QACxD,MAAM,EAAE,mCAAmC,CAAC,MAAM;KACnD,CAAC;SACD,IAAI,CAAC,mCAAmC,CAAC;SACzC,KAAK,CACJ,EAAE,CAAC,mCAAmC,CAAC,cAAc,EAAE,cAAc,CAAC,CACvE;SACA,OAAO,CACN,GAAG,CAAC,mCAAmC,CAAC,SAAS,CAAC,EAClD,GAAG,CAAC,mCAAmC,CAAC,MAAM,CAAC,CAChD,CAAC;AACN,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,EAAgC,EAChC,cAAsB;IAEtB,OAAO,EAAE;SACN,MAAM,CAAC;QACN,SAAS,EAAE,2BAA2B,CAAC,SAAS;QAChD,OAAO,EAAE,2BAA2B,CAAC,OAAO;QAC5C,SAAS,EAAE,2BAA2B,CAAC,SAAS;QAChD,QAAQ,EAAE,2BAA2B,CAAC,QAAQ;QAC9C,WAAW,EAAE,2BAA2B,CAAC,WAAW;QACpD,IAAI,EAAE,2BAA2B,CAAC,IAAI;QACtC,SAAS,EAAE,2BAA2B,CAAC,SAAS;QAChD,YAAY,EAAE,2BAA2B,CAAC,YAAY;KACvD,CAAC;SACD,IAAI,CAAC,2BAA2B,CAAC;SACjC,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;SACrE,OAAO,CACN,GAAG,CAAC,2BAA2B,CAAC,SAAS,CAAC,EAC1C,GAAG,CAAC,2BAA2B,CAAC,OAAO,CAAC,CACzC,CAAC;AACN,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,EAAgC,EAChC,cAAsB;IAEtB,OAAO,EAAE;SACN,MAAM,CAAC;QACN,QAAQ,EAAE,gCAAgC,CAAC,QAAQ;QACnD,cAAc,EAAE,gCAAgC,CAAC,cAAc;QAC/D,WAAW,EAAE,gCAAgC,CAAC,WAAW;QACzD,cAAc,EAAE,gCAAgC,CAAC,cAAc;QAC/D,WAAW,EAAE,gCAAgC,CAAC,WAAW;QACzD,aAAa,EAAE,gCAAgC,CAAC,aAAa;QAC7D,SAAS,EAAE,gCAAgC,CAAC,SAAS;QACrD,YAAY,EAAE,gCAAgC,CAAC,YAAY;KAC5D,CAAC;SACD,IAAI,CAAC,gCAAgC,CAAC;SACtC,KAAK,CAAC,EAAE,CAAC,gCAAgC,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;SAC1E,OAAO,CACN,GAAG,CAAC,gCAAgC,CAAC,aAAa,CAAC,EACnD,GAAG,CAAC,gCAAgC,CAAC,WAAW,CAAC,CAClD,CAAC;AACN,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,EAAgC,EAChC,cAAsB;IAEtB,OAAO,EAAE;SACN,MAAM,CAAC;QACN,OAAO,EAAE,iCAAiC,CAAC,OAAO;QAClD,MAAM,EAAE,iCAAiC,CAAC,MAAM;KACjD,CAAC;SACD,IAAI,CAAC,iCAAiC,CAAC;SACvC,KAAK,CAAC,EAAE,CAAC,iCAAiC,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;SAC3E,OAAO,CACN,GAAG,CAAC,iCAAiC,CAAC,OAAO,CAAC,EAC9C,GAAG,CAAC,iCAAiC,CAAC,SAAS,CAAC,EAChD,GAAG,CAAC,iCAAiC,CAAC,MAAM,CAAC,CAC9C,CAAC;AACN,CAAC;AAED,SAAS,mBAAmB,CAAC,KAI5B;IAOC,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC3D,MAAM,uBAAuB,GAAG,WAAW,CAAC,MAAM,CAChD,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,KAAK,cAAc,CAChD,CAAC;IACF,IACE,uBAAuB,CAAC,MAAM,KAAK,CAAC;QACpC,uBAAuB,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,KAAK,CAAC,cAAc,EAChE,CAAC;QACD,MAAM,IAAI,mCAAmC,CAC3C,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IACD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAC9B,WAAW;SACR,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,KAAK,OAAO,CAAC;SAChD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAC3C,CAAC;IACF,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,IACE,CAAC,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAC/B,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,CAAC,CACnD,EACD,CAAC;QACD,MAAM,IAAI,mCAAmC,CAC3C,sDAAsD,CACvD,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gDAAgD,CAAC,KAItE;IACC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,EAAE;SAC3B,MAAM,CAAC;QACN,MAAM,EAAE,0BAA0B,CAAC,MAAM;QACzC,aAAa,EAAE,0BAA0B,CAAC,aAAa;QACvD,iBAAiB,EAAE,0BAA0B,CAAC,iBAAiB;QAC/D,SAAS,EAAE,0BAA0B,CAAC,SAAS;KAChD,CAAC;SACD,IAAI,CAAC,0BAA0B,CAAC;SAChC,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAAC,cAAc,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;SAC1E,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,KAAK,CAAC,EAAE;SAC/B,MAAM,CAAC,EAAE,UAAU,EAAE,+BAA+B,CAAC,UAAU,EAAE,CAAC;SAClE,IAAI,CAAC,+BAA+B,CAAC;SACrC,KAAK,CACJ,GAAG,CACD,EAAE,CACA,+BAA+B,CAAC,cAAc,EAC9C,KAAK,CAAC,cAAc,CACrB,EACD,EAAE,CAAC,+BAA+B,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAChE,CACF;SACA,KAAK,CAAC,CAAC,CAAC,CAAC;IACZ,MAAM,aAAa,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,MAAM,4CAA4C,CAAC,KAAK,CAAC,CAAC;IACzE,MAAM,eAAe,GAAG,MAAM,mBAAmB,CAC/C,KAAK,CAAC,EAAE,EACR,KAAK,CAAC,cAAc,CACrB,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,kBAAkB,CAC7C,KAAK,CAAC,EAAE,EACR,KAAK,CAAC,cAAc,CACrB,CAAC;IACF,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,GAAG,mBAAmB,CAAC;QAC5D,SAAS;QACT,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,cAAc;KACf,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE;YACT,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/B,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,aAAa,CAAC,CAC1C;SACF;QACD,MAAM;QACN,MAAM,EAAE;YACN,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC9B,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,YAAY,EAAE,mBAAmB,CAC/B,GAAG,EACH,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAClC;aACF,CAAC,CAAC;SACJ;QACD,eAAe;QACf,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,WAAW;QACX,eAAe,EAAE,wCAAwC;QACzD,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI;QAClE,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC;AACJ,CAAC","sourcesContent":["import type {\n ListOrganizationGroupsResponse,\n OrganizationContainerGrantsResponse,\n OrganizationDirectoryResponse,\n OrganizationDirectoryUserResponse,\n OrganizationGroupCurrentStateResponse,\n OrganizationRosterStatus,\n} from \"@tearleads/validators/response\";\nimport { and, asc, eq } from \"drizzle-orm\";\nimport {\n organizationReadModelDirectoryUsers,\n organizationReadModelGroupMembers,\n organizationReadModelGroups,\n organizationReadModelPolicyHeads,\n organizationReadModelRequesters,\n organizationReadModelState,\n} from \"../../sqlite/organizationReadModelSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../../sqlite/sqlitePersistenceRuntime\";\nimport { loadOrganizationReadModelGrantsInTransaction } from \"./organizationReadModelGrantPersistence\";\nimport {\n ORGANIZATION_READ_MODEL_PROTOCOL_VERSION,\n OrganizationReadModelIntegrityError,\n} from \"./organizationReadModelProtocol\";\n\nexport type OrganizationDirectoryProjection = Omit<\n OrganizationDirectoryResponse,\n \"currentUser\"\n>;\n\nexport interface OrganizationReadModelProjection {\n readonly cursor: string;\n readonly directory: OrganizationDirectoryProjection;\n readonly grants: OrganizationContainerGrantsResponse;\n readonly groups: Omit<ListOrganizationGroupsResponse, \"groups\"> & {\n groups: Array<\n ListOrganizationGroupsResponse[\"groups\"][number] & { name: string }\n >;\n };\n readonly membershipEdges: OrganizationReadModelMembershipEdge[];\n readonly organizationId: string;\n readonly policyHeads: readonly OrganizationReadModelPolicyHead[];\n readonly protocolVersion: typeof ORGANIZATION_READ_MODEL_PROTOCOL_VERSION;\n readonly requester: OrganizationDirectoryResponse[\"currentUser\"] | null;\n readonly updatedAt: string;\n}\n\nexport interface OrganizationReadModelPolicyHead {\n readonly keyEpoch: number;\n readonly keyFingerprint: string;\n readonly memberCount: number;\n readonly organizationId: string;\n readonly principalId: string;\n readonly principalType: \"group\" | \"organization\";\n readonly stateHash: string;\n readonly version: number;\n}\n\nexport interface OrganizationReadModelMembershipEdge {\n readonly groupId: string;\n readonly userId: string;\n}\n\ninterface SelectedDirectoryUser {\n readonly createdAt: string;\n readonly disabledAt: string | null;\n readonly disabledByUserId: string | null;\n readonly encapsulationKeyFingerprint: string;\n readonly encapsulationPublicKey: string;\n readonly isPersonalOrganizationOwner: boolean;\n readonly joinedAt: string;\n readonly profileDocumentId: string | null;\n readonly signingKeyFingerprint: string;\n readonly signingPublicKey: string;\n readonly status: string;\n readonly updatedAt: string;\n readonly userId: string;\n}\n\ninterface SelectedGroup {\n readonly createdAt: string;\n readonly groupId: string;\n readonly isBuiltin: boolean;\n readonly keyEpoch: number | null;\n readonly memberCount: number | null;\n readonly name: string;\n readonly stateHash: string | null;\n readonly stateVersion: number | null;\n}\n\ninterface SelectedPolicyHead {\n readonly keyEpoch: number;\n readonly keyFingerprint: string;\n readonly memberCount: number;\n readonly organizationId: string;\n readonly principalId: string;\n readonly principalType: string;\n readonly stateHash: string;\n readonly stateVersion: number;\n}\n\nfunction isOrganizationRosterStatus(\n value: string,\n): value is OrganizationRosterStatus {\n return value === \"active\" || value === \"disabled\";\n}\n\nfunction toDirectoryUser(\n row: SelectedDirectoryUser,\n currentUserId: string,\n): OrganizationDirectoryUserResponse {\n if (!isOrganizationRosterStatus(row.status)) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization directory status is invalid\",\n );\n }\n\n return {\n userId: row.userId,\n signingKeyFingerprint: row.signingKeyFingerprint,\n signingPublicKey: row.signingPublicKey,\n encapsulationPublicKey: row.encapsulationPublicKey,\n encapsulationKeyFingerprint: row.encapsulationKeyFingerprint,\n createdAt: row.createdAt,\n isPersonalOrganizationOwner: row.isPersonalOrganizationOwner,\n isSelf: row.userId === currentUserId,\n status: row.status,\n profileDocumentId: row.profileDocumentId,\n joinedAt: row.joinedAt,\n updatedAt: row.updatedAt,\n disabledAt: row.disabledAt,\n disabledByUserId: row.disabledByUserId,\n };\n}\n\nfunction toGroupCurrentState(\n row: SelectedGroup,\n policyHead: OrganizationReadModelPolicyHead | undefined,\n): OrganizationGroupCurrentStateResponse | null {\n const values = [\n row.stateHash,\n row.stateVersion,\n row.keyEpoch,\n row.memberCount,\n ];\n if (values.every((value) => value === null)) {\n if (policyHead) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization group policy head is orphaned\",\n );\n }\n return null;\n }\n if (\n row.stateHash === null ||\n row.stateVersion === null ||\n row.keyEpoch === null ||\n row.memberCount === null ||\n row.stateHash.length === 0 ||\n !Number.isInteger(row.stateVersion) ||\n row.stateVersion <= 0 ||\n !Number.isSafeInteger(row.keyEpoch) ||\n row.keyEpoch <= 0 ||\n !Number.isInteger(row.memberCount) ||\n row.memberCount < 0 ||\n !policyHead ||\n policyHead.stateHash !== row.stateHash ||\n policyHead.version !== row.stateVersion ||\n policyHead.keyEpoch !== row.keyEpoch ||\n policyHead.memberCount !== row.memberCount\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization group state is invalid\",\n );\n }\n\n return {\n stateHash: row.stateHash,\n version: row.stateVersion,\n keyEpoch: row.keyEpoch,\n keyFingerprint: policyHead.keyFingerprint,\n memberCount: row.memberCount,\n };\n}\n\nfunction toPolicyHead(\n row: SelectedPolicyHead,\n): OrganizationReadModelPolicyHead {\n if (\n (row.principalType !== \"group\" && row.principalType !== \"organization\") ||\n row.principalId.length === 0 ||\n row.stateHash.length === 0 ||\n !Number.isInteger(row.stateVersion) ||\n row.stateVersion <= 0 ||\n !Number.isSafeInteger(row.keyEpoch) ||\n row.keyEpoch <= 0 ||\n row.keyFingerprint.length === 0 ||\n !Number.isInteger(row.memberCount) ||\n row.memberCount < 0\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization policy head is invalid\",\n );\n }\n\n return {\n organizationId: row.organizationId,\n principalType: row.principalType,\n principalId: row.principalId,\n stateHash: row.stateHash,\n version: row.stateVersion,\n keyEpoch: row.keyEpoch,\n keyFingerprint: row.keyFingerprint,\n memberCount: row.memberCount,\n };\n}\n\nasync function loadDirectoryRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<SelectedDirectoryUser[]> {\n return tx\n .select({\n createdAt: organizationReadModelDirectoryUsers.createdAt,\n disabledAt: organizationReadModelDirectoryUsers.disabledAt,\n disabledByUserId: organizationReadModelDirectoryUsers.disabledByUserId,\n encapsulationKeyFingerprint:\n organizationReadModelDirectoryUsers.encapsulationKeyFingerprint,\n encapsulationPublicKey:\n organizationReadModelDirectoryUsers.encapsulationPublicKey,\n joinedAt: organizationReadModelDirectoryUsers.joinedAt,\n isPersonalOrganizationOwner:\n organizationReadModelDirectoryUsers.isPersonalOrganizationOwner,\n profileDocumentId: organizationReadModelDirectoryUsers.profileDocumentId,\n signingKeyFingerprint:\n organizationReadModelDirectoryUsers.signingKeyFingerprint,\n signingPublicKey: organizationReadModelDirectoryUsers.signingPublicKey,\n status: organizationReadModelDirectoryUsers.status,\n updatedAt: organizationReadModelDirectoryUsers.updatedAt,\n userId: organizationReadModelDirectoryUsers.userId,\n })\n .from(organizationReadModelDirectoryUsers)\n .where(\n eq(organizationReadModelDirectoryUsers.organizationId, organizationId),\n )\n .orderBy(\n asc(organizationReadModelDirectoryUsers.sortOrder),\n asc(organizationReadModelDirectoryUsers.userId),\n );\n}\n\nasync function loadGroupRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<SelectedGroup[]> {\n return tx\n .select({\n createdAt: organizationReadModelGroups.createdAt,\n groupId: organizationReadModelGroups.groupId,\n isBuiltin: organizationReadModelGroups.isBuiltin,\n keyEpoch: organizationReadModelGroups.keyEpoch,\n memberCount: organizationReadModelGroups.memberCount,\n name: organizationReadModelGroups.name,\n stateHash: organizationReadModelGroups.stateHash,\n stateVersion: organizationReadModelGroups.stateVersion,\n })\n .from(organizationReadModelGroups)\n .where(eq(organizationReadModelGroups.organizationId, organizationId))\n .orderBy(\n asc(organizationReadModelGroups.sortOrder),\n asc(organizationReadModelGroups.groupId),\n );\n}\n\nasync function loadPolicyHeadRows(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<SelectedPolicyHead[]> {\n return tx\n .select({\n keyEpoch: organizationReadModelPolicyHeads.keyEpoch,\n keyFingerprint: organizationReadModelPolicyHeads.keyFingerprint,\n memberCount: organizationReadModelPolicyHeads.memberCount,\n organizationId: organizationReadModelPolicyHeads.organizationId,\n principalId: organizationReadModelPolicyHeads.principalId,\n principalType: organizationReadModelPolicyHeads.principalType,\n stateHash: organizationReadModelPolicyHeads.stateHash,\n stateVersion: organizationReadModelPolicyHeads.stateVersion,\n })\n .from(organizationReadModelPolicyHeads)\n .where(eq(organizationReadModelPolicyHeads.organizationId, organizationId))\n .orderBy(\n asc(organizationReadModelPolicyHeads.principalType),\n asc(organizationReadModelPolicyHeads.principalId),\n );\n}\n\nasync function loadMembershipEdges(\n tx: ClientSQLiteTransactionScope,\n organizationId: string,\n): Promise<OrganizationReadModelMembershipEdge[]> {\n return tx\n .select({\n groupId: organizationReadModelGroupMembers.groupId,\n userId: organizationReadModelGroupMembers.userId,\n })\n .from(organizationReadModelGroupMembers)\n .where(eq(organizationReadModelGroupMembers.organizationId, organizationId))\n .orderBy(\n asc(organizationReadModelGroupMembers.groupId),\n asc(organizationReadModelGroupMembers.sortOrder),\n asc(organizationReadModelGroupMembers.userId),\n );\n}\n\nfunction validatePolicyHeads(input: {\n readonly groupRows: readonly SelectedGroup[];\n readonly organizationId: string;\n readonly policyHeadRows: readonly SelectedPolicyHead[];\n}): {\n readonly groupPolicyHeads: ReadonlyMap<\n string,\n OrganizationReadModelPolicyHead\n >;\n readonly policyHeads: readonly OrganizationReadModelPolicyHead[];\n} {\n const policyHeads = input.policyHeadRows.map(toPolicyHead);\n const organizationPolicyHeads = policyHeads.filter(\n (head) => head.principalType === \"organization\",\n );\n if (\n organizationPolicyHeads.length !== 1 ||\n organizationPolicyHeads[0]?.principalId !== input.organizationId\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization policy head is missing or ambiguous\",\n );\n }\n const groupPolicyHeads = new Map(\n policyHeads\n .filter((head) => head.principalType === \"group\")\n .map((head) => [head.principalId, head]),\n );\n const visibleGroupIds = new Set(input.groupRows.map((row) => row.groupId));\n if (\n [...groupPolicyHeads.keys()].some(\n (principalId) => !visibleGroupIds.has(principalId),\n )\n ) {\n throw new OrganizationReadModelIntegrityError(\n \"Stored organization group policy head is not visible\",\n );\n }\n return { groupPolicyHeads, policyHeads };\n}\n\nexport async function loadOrganizationReadModelProjectionInTransaction(input: {\n readonly currentUserId: string;\n readonly organizationId: string;\n readonly tx: ClientSQLiteTransactionScope;\n}): Promise<OrganizationReadModelProjection | null> {\n const [state] = await input.tx\n .select({\n cursor: organizationReadModelState.cursor,\n memberGroupId: organizationReadModelState.memberGroupId,\n profileDocumentId: organizationReadModelState.profileDocumentId,\n updatedAt: organizationReadModelState.updatedAt,\n })\n .from(organizationReadModelState)\n .where(eq(organizationReadModelState.organizationId, input.organizationId))\n .limit(1);\n if (!state) {\n return null;\n }\n const [requester] = await input.tx\n .select({ isOrgAdmin: organizationReadModelRequesters.isOrgAdmin })\n .from(organizationReadModelRequesters)\n .where(\n and(\n eq(\n organizationReadModelRequesters.organizationId,\n input.organizationId,\n ),\n eq(organizationReadModelRequesters.userId, input.currentUserId),\n ),\n )\n .limit(1);\n const directoryRows = await loadDirectoryRows(input.tx, input.organizationId);\n const groupRows = await loadGroupRows(input.tx, input.organizationId);\n const grants = await loadOrganizationReadModelGrantsInTransaction(input);\n const membershipEdges = await loadMembershipEdges(\n input.tx,\n input.organizationId,\n );\n const policyHeadRows = await loadPolicyHeadRows(\n input.tx,\n input.organizationId,\n );\n const { groupPolicyHeads, policyHeads } = validatePolicyHeads({\n groupRows,\n organizationId: input.organizationId,\n policyHeadRows,\n });\n\n return {\n cursor: state.cursor,\n directory: {\n organizationId: input.organizationId,\n profileDocumentId: state.profileDocumentId,\n users: directoryRows.map((row) =>\n toDirectoryUser(row, input.currentUserId),\n ),\n },\n grants,\n groups: {\n organizationId: input.organizationId,\n memberGroupId: state.memberGroupId,\n groups: groupRows.map((row) => ({\n groupId: row.groupId,\n organizationId: input.organizationId,\n name: row.name,\n createdAt: row.createdAt,\n isBuiltin: row.isBuiltin,\n currentState: toGroupCurrentState(\n row,\n groupPolicyHeads.get(row.groupId),\n ),\n })),\n },\n membershipEdges,\n organizationId: input.organizationId,\n policyHeads,\n protocolVersion: ORGANIZATION_READ_MODEL_PROTOCOL_VERSION,\n requester: requester ? { isOrgAdmin: requester.isOrgAdmin } : null,\n updatedAt: state.updatedAt,\n };\n}\n"]}
@@ -5,7 +5,7 @@ export class PrincipalAuthorizationCheckpointUnavailableError extends KeyingVeri
5
5
  super("missing_dependency", "Public authorization cannot connect to the latest durable checkpoint");
6
6
  }
7
7
  }
8
- /** Historical capabilities validate trust but never advance current-policy pins. */
8
+ /** Validate public evidence or a verified private ancestry bridge without admitting pins. */
9
9
  export async function validatePrincipalAuthorizationCheckpoints(tx, policies) {
10
10
  for (const policy of policies) {
11
11
  const checkpoint = await loadStoredPrincipalPolicyCheckpoint(tx, policy);
@@ -1 +1 @@
1
- {"version":3,"file":"principalAuthorizationCheckpoints.js","sourceRoot":"","sources":["principalAuthorizationCheckpoints.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAEvB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mCAAmC,EAAE,MAAM,+BAA+B,CAAC;AAEpF,MAAM,OAAO,gDAAiD,SAAQ,uBAAuB;IAC3F;QACE,KAAK,CACH,oBAAoB,EACpB,sEAAsE,CACvE,CAAC;IACJ,CAAC;CACF;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,yCAAyC,CAC7D,EAAgC,EAChC,QAAqD;IAErD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,MAAM,mCAAmC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAClC,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,aAAa,KAAK,MAAM,CAAC,aAAa;YAC5C,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW;YACxC,KAAK,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,CACvC,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACrE,IACE,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO;YACnC,CAAC,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO;gBAClC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,CAAC,CAAC;YAEnE,MAAM,IAAI,gDAAgD,EAAE,CAAC;QAC/D,+BAA+B,CAAC;YAC9B,KAAK;YACL,YAAY,EAAE,MAAM,CAAC,KAAK;YAC1B,eAAe,EAAE,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;AACH,CAAC","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedPrincipalPolicySelection,\n verifyPrincipalPolicyCheckpoint,\n} from \"@tearleads/crypto\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { loadStoredPrincipalPolicyCheckpoint } from \"./keyingCheckpointPersistence\";\n\nexport class PrincipalAuthorizationCheckpointUnavailableError extends KeyingVerificationError {\n constructor() {\n super(\n \"missing_dependency\",\n \"Public authorization cannot connect to the latest durable checkpoint\",\n );\n }\n}\n\n/** Historical capabilities validate trust but never advance current-policy pins. */\nexport async function validatePrincipalAuthorizationCheckpoints(\n tx: ClientSQLiteTransactionScope,\n policies: readonly VerifiedPrincipalPolicySelection[],\n): Promise<void> {\n for (const policy of policies) {\n const checkpoint = await loadStoredPrincipalPolicyCheckpoint(tx, policy);\n if (!checkpoint) continue;\n const matchingHead = policies.filter(\n (other) =>\n other.principalType === policy.principalType &&\n other.principalId === policy.principalId &&\n other.stateHash === policy.stateHash,\n );\n const chain = matchingHead.flatMap((other) => other.retainedHistory);\n if (\n checkpoint.version > policy.version ||\n (checkpoint.version < policy.version &&\n !chain.some(({ state }) => state.version === checkpoint.version))\n )\n throw new PrincipalAuthorizationCheckpointUnavailableError();\n verifyPrincipalPolicyCheckpoint({\n chain,\n currentState: policy.state,\n localCheckpoint: checkpoint,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"principalAuthorizationCheckpoints.js","sourceRoot":"","sources":["principalAuthorizationCheckpoints.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAGvB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,mCAAmC,EAAE,MAAM,+BAA+B,CAAC;AAEpF,MAAM,OAAO,gDAAiD,SAAQ,uBAAuB;IAC3F;QACE,KAAK,CACH,oBAAoB,EACpB,sEAAsE,CACvE,CAAC;IACJ,CAAC;CACF;AAED,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,yCAAyC,CAC7D,EAAgC,EAChC,QAGG;IAEH,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,MAAM,mCAAmC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAClC,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,aAAa,KAAK,MAAM,CAAC,aAAa;YAC5C,KAAK,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW;YACxC,KAAK,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,CACvC,CAAC;QACF,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACrE,IACE,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO;YACnC,CAAC,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO;gBAClC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,CAAC,CAAC;YAEnE,MAAM,IAAI,gDAAgD,EAAE,CAAC;QAC/D,+BAA+B,CAAC;YAC9B,KAAK;YACL,YAAY,EAAE,MAAM,CAAC,KAAK;YAC1B,eAAe,EAAE,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;AACH,CAAC","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedPrincipalPolicyCurrent,\n type VerifiedPrincipalPolicySelection,\n verifyPrincipalPolicyCheckpoint,\n} from \"@tearleads/crypto\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { loadStoredPrincipalPolicyCheckpoint } from \"./keyingCheckpointPersistence\";\n\nexport class PrincipalAuthorizationCheckpointUnavailableError extends KeyingVerificationError {\n constructor() {\n super(\n \"missing_dependency\",\n \"Public authorization cannot connect to the latest durable checkpoint\",\n );\n }\n}\n\n/** Validate public evidence or a verified private ancestry bridge without admitting pins. */\nexport async function validatePrincipalAuthorizationCheckpoints(\n tx: ClientSQLiteTransactionScope,\n policies: readonly (\n | VerifiedPrincipalPolicySelection\n | VerifiedPrincipalPolicyCurrent\n )[],\n): Promise<void> {\n for (const policy of policies) {\n const checkpoint = await loadStoredPrincipalPolicyCheckpoint(tx, policy);\n if (!checkpoint) continue;\n const matchingHead = policies.filter(\n (other) =>\n other.principalType === policy.principalType &&\n other.principalId === policy.principalId &&\n other.stateHash === policy.stateHash,\n );\n const chain = matchingHead.flatMap((other) => other.retainedHistory);\n if (\n checkpoint.version > policy.version ||\n (checkpoint.version < policy.version &&\n !chain.some(({ state }) => state.version === checkpoint.version))\n )\n throw new PrincipalAuthorizationCheckpointUnavailableError();\n verifyPrincipalPolicyCheckpoint({\n chain,\n currentState: policy.state,\n localCheckpoint: checkpoint,\n });\n }\n}\n"]}
@@ -10,6 +10,7 @@ export interface AcknowledgedPrincipalCurrentPublication {
10
10
  readonly previousPrefixProgress: string | null;
11
11
  readonly stage: PrincipalHistoryStage;
12
12
  readonly predecessorStage: PrincipalHistoryStage | null;
13
+ readonly predecessorIndexRootHash: string | null;
13
14
  readonly evidence: PrincipalHistoryEvidencePage;
14
15
  }
15
16
  export interface AcknowledgedPrincipalCurrentRetirement {
@@ -9,6 +9,10 @@ import { ensureSqlTables } from "../sqlite/sqlSchema.js";
9
9
  import { loadStoredPrincipalPolicyCheckpoint, principalPolicyKey, upsertPrincipalPolicyCheckpointInTransaction, } from "./keyingCheckpointPersistence.js";
10
10
  import { storePrincipalGrantRetirements } from "./principalGrantRetirementPersistence.js";
11
11
  import { writePrincipalHistoryEvidencePage, } from "./principalHistoryEvidencePersistence.js";
12
+ import { reclaimPrincipalHistoryNodes } from "./principalHistoryNodeRetention.js";
13
+ import { retainPrincipalHistoryRoot } from "./principalHistoryRootOwnership.js";
14
+ import { reclaimCompletedPrincipalHistoryStages, recordPrincipalHistoryStageScope, } from "./principalHistoryStageRetention.js";
15
+ import { archivePrincipalHistoryKeyEnvelopes } from "./principalKeyEnvelopeArchivePersistence.js";
12
16
  function assertPublicationScope(entries, organizationId) {
13
17
  const seen = new Set();
14
18
  for (const entry of entries) {
@@ -17,6 +21,8 @@ function assertPublicationScope(entries, organizationId) {
17
21
  throw new KeyingVerificationError("duplicate_entry", "Acknowledged current batch repeats a principal");
18
22
  seen.add(key);
19
23
  if (entry.prefix.organizationId !== organizationId ||
24
+ (entry.predecessorStage === null) !==
25
+ (entry.predecessorIndexRootHash === null) ||
20
26
  entry.stage.organizationId !== organizationId ||
21
27
  (entry.predecessorStage
22
28
  ? entry.predecessorStage.organizationId !== organizationId ||
@@ -53,6 +59,44 @@ async function validatePublication(tx, entry) {
53
59
  if ((prefix?.progress ?? null) !== entry.previousPrefixProgress)
54
60
  throw new KeyingVerificationError("stale_predecessor", "Authenticated principal prefix changed before acknowledgement");
55
61
  }
62
+ async function archiveAcknowledgedStageKeys(tx, entry) {
63
+ for (const stage of [entry.predecessorStage, entry.stage]) {
64
+ if (!stage)
65
+ continue;
66
+ await recordPrincipalHistoryStageScope(tx, {
67
+ id: stage.id,
68
+ afterVersion: stage.afterVersion,
69
+ complete: stage.complete,
70
+ organizationId: entry.prefix.organizationId,
71
+ scopeId: entry.prefix.scopeId,
72
+ });
73
+ await archivePrincipalHistoryKeyEnvelopes(tx, {
74
+ ...stage,
75
+ version: stage.afterVersion + 1,
76
+ });
77
+ }
78
+ }
79
+ async function retainPredecessorStage(tx, entry) {
80
+ // Preserve a prefix-only predecessor without replacing an existing completion.
81
+ if (!entry.predecessorStage || !entry.predecessorIndexRootHash)
82
+ return;
83
+ const inserted = await tx
84
+ .insert(principalHistoryStages)
85
+ .values(entry.predecessorStage)
86
+ .onConflictDoUpdate({
87
+ target: principalHistoryStages.id,
88
+ set: entry.predecessorStage,
89
+ setWhere: eq(principalHistoryStages.complete, false),
90
+ })
91
+ .returning({ id: principalHistoryStages.id });
92
+ if (inserted.length > 0)
93
+ await retainPrincipalHistoryRoot(tx, {
94
+ id: `stage:${entry.predecessorStage.id}`,
95
+ scopeId: entry.prefix.scopeId,
96
+ organizationId: entry.prefix.organizationId,
97
+ rootHash: entry.predecessorIndexRootHash,
98
+ });
99
+ }
56
100
  /** Store current artifacts and resumable progress in the same transaction as their pins. */
57
101
  export async function persistAcknowledgedPrincipalCurrents(input) {
58
102
  const entries = structuredClone(input.entries);
@@ -78,18 +122,7 @@ export async function persistAcknowledgedPrincipalCurrents(input) {
78
122
  }
79
123
  for (const entry of entries) {
80
124
  await writePrincipalHistoryEvidencePage(tx, entry.evidence);
81
- // A prefix-only predecessor must keep its encrypted key envelopes
82
- // before its reusable slot is replaced by the acknowledged successor.
83
- if (entry.predecessorStage)
84
- await tx
85
- .insert(principalHistoryStages)
86
- .values(entry.predecessorStage)
87
- .onConflictDoUpdate({
88
- target: principalHistoryStages.id,
89
- set: entry.predecessorStage,
90
- setWhere: eq(principalHistoryStages.complete, false),
91
- })
92
- .run();
125
+ await retainPredecessorStage(tx, entry);
93
126
  // A fully authenticated publication supersedes an in-flight stage for
94
127
  // this exact head. Its other writer fails its progress CAS and resumes.
95
128
  await tx
@@ -100,6 +133,7 @@ export async function persistAcknowledgedPrincipalCurrents(input) {
100
133
  set: entry.stage,
101
134
  })
102
135
  .run();
136
+ await archiveAcknowledgedStageKeys(tx, entry);
103
137
  await tx
104
138
  .insert(principalHistoryPrefixes)
105
139
  .values(entry.prefix)
@@ -108,6 +142,18 @@ export async function persistAcknowledgedPrincipalCurrents(input) {
108
142
  set: entry.prefix,
109
143
  })
110
144
  .run();
145
+ await reclaimCompletedPrincipalHistoryStages(tx, entry.prefix);
146
+ for (const id of [
147
+ `stage:${entry.stage.id}`,
148
+ `prefix:${entry.prefix.scopeId}`,
149
+ ])
150
+ await retainPrincipalHistoryRoot(tx, {
151
+ id,
152
+ scopeId: entry.prefix.scopeId,
153
+ organizationId,
154
+ rootHash: entry.evidence.indexRootHash,
155
+ });
156
+ await reclaimPrincipalHistoryNodes(tx, entry.prefix);
111
157
  await upsertPrincipalPolicyCheckpointInTransaction(tx, entry.policy.checkpoint, new Date().toISOString(), organizationId);
112
158
  }
113
159
  }, stillCurrent, { behavior: "immediate" });
@@ -1 +1 @@
1
- {"version":3,"file":"principalCurrentAcknowledgementPersistence.js","sourceRoot":"","sources":["principalCurrentAcknowledgementPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedPrincipalPolicyCurrent,\n verifyPrincipalPolicyCheckpoint,\n} from \"@tearleads/crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { assertProjectionVerificationCurrent } from \"../keyingProjectionVerification/types\";\nimport { principalHistoryPrefixes } from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport {\n keyingCheckpointTables,\n principalPolicyTables,\n} from \"../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport {\n loadStoredPrincipalPolicyCheckpoint,\n principalPolicyKey,\n upsertPrincipalPolicyCheckpointInTransaction,\n} from \"./keyingCheckpointPersistence\";\nimport { storePrincipalGrantRetirements } from \"./principalGrantRetirementPersistence\";\nimport {\n type PrincipalHistoryEvidencePage,\n writePrincipalHistoryEvidencePage,\n} from \"./principalHistoryEvidencePersistence\";\nimport type { PrincipalHistoryPrefix } from \"./principalHistoryPrefixPersistence\";\nimport type { PrincipalHistoryStage } from \"./principalHistoryStagePersistence\";\n\n/** Owned output of authenticated prefix extension and exact receipt verification. */\nexport interface AcknowledgedPrincipalCurrentPublication {\n readonly policy: VerifiedPrincipalPolicyCurrent;\n readonly prefix: PrincipalHistoryPrefix;\n readonly previousPrefixProgress: string | null;\n readonly stage: PrincipalHistoryStage;\n readonly predecessorStage: PrincipalHistoryStage | null;\n readonly evidence: PrincipalHistoryEvidencePage;\n}\n\nexport interface AcknowledgedPrincipalCurrentRetirement {\n readonly principalId: string;\n readonly principalType: VerifiedPrincipalPolicyCurrent[\"principalType\"];\n readonly containerIds: readonly string[];\n}\n\nfunction assertPublicationScope(\n entries: readonly AcknowledgedPrincipalCurrentPublication[],\n organizationId: string,\n) {\n const seen = new Set<string>();\n for (const entry of entries) {\n const key = principalPolicyKey(entry.policy);\n if (seen.has(key))\n throw new KeyingVerificationError(\n \"duplicate_entry\",\n \"Acknowledged current batch repeats a principal\",\n );\n seen.add(key);\n if (\n entry.prefix.organizationId !== organizationId ||\n entry.stage.organizationId !== organizationId ||\n (entry.predecessorStage\n ? entry.predecessorStage.organizationId !== organizationId ||\n !entry.predecessorStage.complete ||\n entry.predecessorStage.afterVersion !== entry.policy.version - 2\n : entry.policy.principalType !== \"group\" ||\n entry.policy.version !== 1 ||\n entry.policy.state.prevStateHash !== null ||\n entry.previousPrefixProgress !== null) ||\n entry.evidence.organizationId !== organizationId ||\n entry.prefix.scopeId !== entry.evidence.scopeId ||\n entry.prefix.version !== entry.policy.version ||\n entry.stage.afterVersion !== entry.policy.version - 1 ||\n !entry.stage.complete ||\n entry.stage.currentJson !== entry.prefix.currentJson\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Acknowledged current publication is outside its scope\",\n );\n }\n}\n\nasync function validatePublication(\n tx: ClientSQLiteTransactionScope,\n entry: AcknowledgedPrincipalCurrentPublication,\n) {\n const checkpoint = await loadStoredPrincipalPolicyCheckpoint(\n tx,\n entry.policy,\n );\n verifyPrincipalPolicyCheckpoint({\n chain: entry.policy.retainedHistory,\n currentState: entry.policy.state,\n localCheckpoint: checkpoint,\n });\n if (\n (!checkpoint && entry.policy.version !== 1) ||\n (checkpoint && entry.policy.version > checkpoint.version + 1)\n )\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"Acknowledged current policy must directly extend its durable checkpoint\",\n );\n const [prefix] = await tx\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, entry.prefix.scopeId))\n .limit(1);\n if ((prefix?.progress ?? null) !== entry.previousPrefixProgress)\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"Authenticated principal prefix changed before acknowledgement\",\n );\n}\n\n/** Store current artifacts and resumable progress in the same transaction as their pins. */\nexport async function persistAcknowledgedPrincipalCurrents(input: {\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly entries: readonly AcknowledgedPrincipalCurrentPublication[];\n readonly retirements?:\n | readonly AcknowledgedPrincipalCurrentRetirement[]\n | undefined;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const entries = structuredClone(input.entries);\n const retirements = structuredClone(input.retirements ?? []);\n const organizationId = input.organizationId;\n const stillCurrent = input.stillCurrent;\n assertPublicationScope(entries, organizationId);\n assertProjectionVerificationCurrent(stillCurrent);\n await ensureSqlTables(input.execSql, [\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const stored = await runtime.guardedTransaction(\n async (tx) => {\n for (const entry of entries) await validatePublication(tx, entry);\n for (const retirement of retirements) {\n const policy = entries.find(\n (entry) =>\n entry.policy.principalId === retirement.principalId &&\n entry.policy.principalType === retirement.principalType,\n )?.policy;\n if (!policy)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Retirement must accompany its acknowledged principal\",\n );\n await storePrincipalGrantRetirements(\n tx,\n { ...retirement, policy, organizationId },\n entries.map((entry) => entry.policy),\n organizationId,\n );\n }\n for (const entry of entries) {\n await writePrincipalHistoryEvidencePage(tx, entry.evidence);\n // A prefix-only predecessor must keep its encrypted key envelopes\n // before its reusable slot is replaced by the acknowledged successor.\n if (entry.predecessorStage)\n await tx\n .insert(principalHistoryStages)\n .values(entry.predecessorStage)\n .onConflictDoUpdate({\n target: principalHistoryStages.id,\n set: entry.predecessorStage,\n setWhere: eq(principalHistoryStages.complete, false),\n })\n .run();\n // A fully authenticated publication supersedes an in-flight stage for\n // this exact head. Its other writer fails its progress CAS and resumes.\n await tx\n .insert(principalHistoryStages)\n .values(entry.stage)\n .onConflictDoUpdate({\n target: principalHistoryStages.id,\n set: entry.stage,\n })\n .run();\n await tx\n .insert(principalHistoryPrefixes)\n .values(entry.prefix)\n .onConflictDoUpdate({\n target: principalHistoryPrefixes.scopeId,\n set: entry.prefix,\n })\n .run();\n await upsertPrincipalPolicyCheckpointInTransaction(\n tx,\n entry.policy.checkpoint,\n new Date().toISOString(),\n organizationId,\n );\n }\n },\n stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => stored.committed);\n}\n"]}
1
+ {"version":3,"file":"principalCurrentAcknowledgementPersistence.js","sourceRoot":"","sources":["principalCurrentAcknowledgementPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type VerifiedPrincipalPolicyCurrent,\n verifyPrincipalPolicyCheckpoint,\n} from \"@tearleads/crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { assertProjectionVerificationCurrent } from \"../keyingProjectionVerification/types\";\nimport { principalHistoryPrefixes } from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport {\n keyingCheckpointTables,\n principalPolicyTables,\n} from \"../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport {\n loadStoredPrincipalPolicyCheckpoint,\n principalPolicyKey,\n upsertPrincipalPolicyCheckpointInTransaction,\n} from \"./keyingCheckpointPersistence\";\nimport { storePrincipalGrantRetirements } from \"./principalGrantRetirementPersistence\";\nimport {\n type PrincipalHistoryEvidencePage,\n writePrincipalHistoryEvidencePage,\n} from \"./principalHistoryEvidencePersistence\";\nimport { reclaimPrincipalHistoryNodes } from \"./principalHistoryNodeRetention\";\nimport type { PrincipalHistoryPrefix } from \"./principalHistoryPrefixPersistence\";\nimport { retainPrincipalHistoryRoot } from \"./principalHistoryRootOwnership\";\nimport type { PrincipalHistoryStage } from \"./principalHistoryStagePersistence\";\nimport {\n reclaimCompletedPrincipalHistoryStages,\n recordPrincipalHistoryStageScope,\n} from \"./principalHistoryStageRetention\";\nimport { archivePrincipalHistoryKeyEnvelopes } from \"./principalKeyEnvelopeArchivePersistence\";\n\n/** Owned output of authenticated prefix extension and exact receipt verification. */\nexport interface AcknowledgedPrincipalCurrentPublication {\n readonly policy: VerifiedPrincipalPolicyCurrent;\n readonly prefix: PrincipalHistoryPrefix;\n readonly previousPrefixProgress: string | null;\n readonly stage: PrincipalHistoryStage;\n readonly predecessorStage: PrincipalHistoryStage | null;\n readonly predecessorIndexRootHash: string | null;\n readonly evidence: PrincipalHistoryEvidencePage;\n}\n\nexport interface AcknowledgedPrincipalCurrentRetirement {\n readonly principalId: string;\n readonly principalType: VerifiedPrincipalPolicyCurrent[\"principalType\"];\n readonly containerIds: readonly string[];\n}\n\nfunction assertPublicationScope(\n entries: readonly AcknowledgedPrincipalCurrentPublication[],\n organizationId: string,\n) {\n const seen = new Set<string>();\n for (const entry of entries) {\n const key = principalPolicyKey(entry.policy);\n if (seen.has(key))\n throw new KeyingVerificationError(\n \"duplicate_entry\",\n \"Acknowledged current batch repeats a principal\",\n );\n seen.add(key);\n if (\n entry.prefix.organizationId !== organizationId ||\n (entry.predecessorStage === null) !==\n (entry.predecessorIndexRootHash === null) ||\n entry.stage.organizationId !== organizationId ||\n (entry.predecessorStage\n ? entry.predecessorStage.organizationId !== organizationId ||\n !entry.predecessorStage.complete ||\n entry.predecessorStage.afterVersion !== entry.policy.version - 2\n : entry.policy.principalType !== \"group\" ||\n entry.policy.version !== 1 ||\n entry.policy.state.prevStateHash !== null ||\n entry.previousPrefixProgress !== null) ||\n entry.evidence.organizationId !== organizationId ||\n entry.prefix.scopeId !== entry.evidence.scopeId ||\n entry.prefix.version !== entry.policy.version ||\n entry.stage.afterVersion !== entry.policy.version - 1 ||\n !entry.stage.complete ||\n entry.stage.currentJson !== entry.prefix.currentJson\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Acknowledged current publication is outside its scope\",\n );\n }\n}\n\nasync function validatePublication(\n tx: ClientSQLiteTransactionScope,\n entry: AcknowledgedPrincipalCurrentPublication,\n) {\n const checkpoint = await loadStoredPrincipalPolicyCheckpoint(\n tx,\n entry.policy,\n );\n verifyPrincipalPolicyCheckpoint({\n chain: entry.policy.retainedHistory,\n currentState: entry.policy.state,\n localCheckpoint: checkpoint,\n });\n if (\n (!checkpoint && entry.policy.version !== 1) ||\n (checkpoint && entry.policy.version > checkpoint.version + 1)\n )\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"Acknowledged current policy must directly extend its durable checkpoint\",\n );\n const [prefix] = await tx\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, entry.prefix.scopeId))\n .limit(1);\n if ((prefix?.progress ?? null) !== entry.previousPrefixProgress)\n throw new KeyingVerificationError(\n \"stale_predecessor\",\n \"Authenticated principal prefix changed before acknowledgement\",\n );\n}\n\nasync function archiveAcknowledgedStageKeys(\n tx: ClientSQLiteTransactionScope,\n entry: AcknowledgedPrincipalCurrentPublication,\n) {\n for (const stage of [entry.predecessorStage, entry.stage]) {\n if (!stage) continue;\n await recordPrincipalHistoryStageScope(tx, {\n id: stage.id,\n afterVersion: stage.afterVersion,\n complete: stage.complete,\n organizationId: entry.prefix.organizationId,\n scopeId: entry.prefix.scopeId,\n });\n await archivePrincipalHistoryKeyEnvelopes(tx, {\n ...stage,\n version: stage.afterVersion + 1,\n });\n }\n}\n\nasync function retainPredecessorStage(\n tx: ClientSQLiteTransactionScope,\n entry: AcknowledgedPrincipalCurrentPublication,\n) {\n // Preserve a prefix-only predecessor without replacing an existing completion.\n if (!entry.predecessorStage || !entry.predecessorIndexRootHash) return;\n const inserted = await tx\n .insert(principalHistoryStages)\n .values(entry.predecessorStage)\n .onConflictDoUpdate({\n target: principalHistoryStages.id,\n set: entry.predecessorStage,\n setWhere: eq(principalHistoryStages.complete, false),\n })\n .returning({ id: principalHistoryStages.id });\n if (inserted.length > 0)\n await retainPrincipalHistoryRoot(tx, {\n id: `stage:${entry.predecessorStage.id}`,\n scopeId: entry.prefix.scopeId,\n organizationId: entry.prefix.organizationId,\n rootHash: entry.predecessorIndexRootHash,\n });\n}\n\n/** Store current artifacts and resumable progress in the same transaction as their pins. */\nexport async function persistAcknowledgedPrincipalCurrents(input: {\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly entries: readonly AcknowledgedPrincipalCurrentPublication[];\n readonly retirements?:\n | readonly AcknowledgedPrincipalCurrentRetirement[]\n | undefined;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const entries = structuredClone(input.entries);\n const retirements = structuredClone(input.retirements ?? []);\n const organizationId = input.organizationId;\n const stillCurrent = input.stillCurrent;\n assertPublicationScope(entries, organizationId);\n assertProjectionVerificationCurrent(stillCurrent);\n await ensureSqlTables(input.execSql, [\n ...principalPolicyTables,\n ...keyingCheckpointTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const stored = await runtime.guardedTransaction(\n async (tx) => {\n for (const entry of entries) await validatePublication(tx, entry);\n for (const retirement of retirements) {\n const policy = entries.find(\n (entry) =>\n entry.policy.principalId === retirement.principalId &&\n entry.policy.principalType === retirement.principalType,\n )?.policy;\n if (!policy)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Retirement must accompany its acknowledged principal\",\n );\n await storePrincipalGrantRetirements(\n tx,\n { ...retirement, policy, organizationId },\n entries.map((entry) => entry.policy),\n organizationId,\n );\n }\n for (const entry of entries) {\n await writePrincipalHistoryEvidencePage(tx, entry.evidence);\n await retainPredecessorStage(tx, entry);\n // A fully authenticated publication supersedes an in-flight stage for\n // this exact head. Its other writer fails its progress CAS and resumes.\n await tx\n .insert(principalHistoryStages)\n .values(entry.stage)\n .onConflictDoUpdate({\n target: principalHistoryStages.id,\n set: entry.stage,\n })\n .run();\n await archiveAcknowledgedStageKeys(tx, entry);\n await tx\n .insert(principalHistoryPrefixes)\n .values(entry.prefix)\n .onConflictDoUpdate({\n target: principalHistoryPrefixes.scopeId,\n set: entry.prefix,\n })\n .run();\n await reclaimCompletedPrincipalHistoryStages(tx, entry.prefix);\n for (const id of [\n `stage:${entry.stage.id}`,\n `prefix:${entry.prefix.scopeId}`,\n ])\n await retainPrincipalHistoryRoot(tx, {\n id,\n scopeId: entry.prefix.scopeId,\n organizationId,\n rootHash: entry.evidence.indexRootHash,\n });\n await reclaimPrincipalHistoryNodes(tx, entry.prefix);\n await upsertPrincipalPolicyCheckpointInTransaction(\n tx,\n entry.policy.checkpoint,\n new Date().toISOString(),\n organizationId,\n );\n }\n },\n stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => stored.committed);\n}\n"]}
@@ -3,6 +3,7 @@ import { type PrincipalPolicyStateChainEntryResponse } from "../../internal/vali
3
3
  import { type ClientSQLiteTransactionScope } from "../sqlite/sqlitePersistenceRuntime.js";
4
4
  import { type ExecSql } from "../sqlite/sqlSchema.js";
5
5
  export interface PrincipalHistoryEvidencePage {
6
+ readonly indexRootHash: string;
6
7
  readonly scopeId: string;
7
8
  readonly organizationId: string;
8
9
  readonly entries: readonly {
@@ -13,6 +14,7 @@ export interface PrincipalHistoryEvidencePage {
13
14
  }
14
15
  /** Prepare only a page accepted by the signature/authorization verifier. */
15
16
  export declare function preparePrincipalHistoryEvidencePage(input: {
17
+ readonly indexRootHash: string;
16
18
  readonly scopeId: string;
17
19
  readonly organizationId: string;
18
20
  readonly entries: readonly PrincipalPolicyStateChainEntryResponse[];
@@ -4,6 +4,7 @@ import { and, eq } from "drizzle-orm";
4
4
  import { principalHistoryEntries, principalHistoryEvidenceTables, principalHistoryNodes, } from "../sqlite/principalHistoryEvidenceSchema.js";
5
5
  import { getClientSQLitePersistenceRuntime, } from "../sqlite/sqlitePersistenceRuntime.js";
6
6
  import { ensureSqlTables } from "../sqlite/sqlSchema.js";
7
+ import { recordPrincipalHistoryNodeEdges } from "./principalHistoryNodeRetention.js";
7
8
  /** Prepare only a page accepted by the signature/authorization verifier. */
8
9
  export async function preparePrincipalHistoryEvidencePage(input) {
9
10
  if (input.entries.length > PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT ||
@@ -36,6 +37,7 @@ export async function writePrincipalHistoryEvidencePage(tx, page) {
36
37
  .run();
37
38
  }
38
39
  for (const node of [...page.nodes].sort((a, b) => compareCanonicalStrings(a.hash, b.hash))) {
40
+ await recordPrincipalHistoryNodeEdges(tx, scope, node);
39
41
  const row = { ...scope, ...node };
40
42
  await tx
41
43
  .insert(principalHistoryNodes)
@@ -1 +1 @@
1
- {"version":3,"file":"principalHistoryEvidencePersistence.js","sourceRoot":"","sources":["principalHistoryEvidencePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n compareCanonicalStrings,\n KeyingVerificationError,\n PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT,\n type PrincipalHistoryIndexNode,\n type PrincipalPolicyHistoryReferenceProof,\n principalHistoryIndexLeaf,\n type ReferencedPrincipalHead,\n resolvePrincipalHistoryIndexProof,\n type VerifiedPrincipalPolicyHistory,\n} from \"@tearleads/crypto\";\nimport {\n isPrincipalPolicyStateChainEntryResponse,\n type PrincipalPolicyStateChainEntryResponse,\n} from \"@tearleads/validators/response\";\nimport { and, eq } from \"drizzle-orm\";\nimport {\n principalHistoryEntries,\n principalHistoryEvidenceTables,\n principalHistoryNodes,\n} from \"../sqlite/principalHistoryEvidenceSchema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\n\nexport interface PrincipalHistoryEvidencePage {\n readonly scopeId: string;\n readonly organizationId: string;\n readonly entries: readonly {\n readonly leafHash: string;\n readonly entryJson: string;\n }[];\n readonly nodes: readonly PrincipalHistoryIndexNode[];\n}\n\n/** Prepare only a page accepted by the signature/authorization verifier. */\nexport async function preparePrincipalHistoryEvidencePage(input: {\n readonly scopeId: string;\n readonly organizationId: string;\n readonly entries: readonly PrincipalPolicyStateChainEntryResponse[];\n readonly nodes: readonly PrincipalHistoryIndexNode[];\n}): Promise<PrincipalHistoryEvidencePage> {\n if (\n input.entries.length > PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT ||\n input.nodes.length > 2 * PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT\n )\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Principal evidence page exceeds its batch budget\",\n );\n const owned = structuredClone(input);\n return {\n ...owned,\n entries: await Promise.all(\n owned.entries.map(async (entry) => ({\n leafHash: await principalHistoryIndexLeaf(entry.state),\n entryJson: JSON.stringify(entry),\n })),\n ),\n };\n}\n\n/** Publish in the same guarded transaction as the accepted page's progress. */\nexport async function writePrincipalHistoryEvidencePage(\n tx: ClientSQLiteTransactionScope,\n page: PrincipalHistoryEvidencePage,\n): Promise<void> {\n const scope = { scopeId: page.scopeId, organizationId: page.organizationId };\n for (const entry of [...page.entries].sort((a, b) =>\n compareCanonicalStrings(a.leafHash, b.leafHash),\n )) {\n const row = { ...scope, ...entry };\n await tx\n .insert(principalHistoryEntries)\n .values(row)\n .onConflictDoUpdate({\n target: [\n principalHistoryEntries.scopeId,\n principalHistoryEntries.leafHash,\n ],\n set: row,\n })\n .run();\n }\n for (const node of [...page.nodes].sort((a, b) =>\n compareCanonicalStrings(a.hash, b.hash),\n )) {\n const row = { ...scope, ...node };\n await tx\n .insert(principalHistoryNodes)\n .values(row)\n .onConflictDoUpdate({\n target: [principalHistoryNodes.scopeId, principalHistoryNodes.hash],\n set: row,\n })\n .run();\n }\n}\n\n/** Returns untrusted material. The caller must verify it against the issued root. */\nexport async function loadPrincipalHistoryReference(input: {\n readonly execSql: ExecSql;\n readonly scopeId: string;\n readonly history: VerifiedPrincipalPolicyHistory;\n readonly version: number;\n readonly expectedReference?: ReferencedPrincipalHead | undefined;\n}): Promise<PrincipalPolicyHistoryReferenceProof> {\n await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);\n const { db } = getClientSQLitePersistenceRuntime(input.execSql);\n const resolved = await resolvePrincipalHistoryIndexProof({\n rootHash: input.history.indexRootHash,\n treeSize: input.history.currentEntry.state.version,\n version: input.version,\n readNode: async (hash) => {\n const [row] = await db\n .select()\n .from(principalHistoryNodes)\n .where(\n and(\n eq(principalHistoryNodes.scopeId, input.scopeId),\n eq(principalHistoryNodes.hash, hash),\n ),\n )\n .limit(1);\n return row ?? null;\n },\n });\n const [row] = await db\n .select()\n .from(principalHistoryEntries)\n .where(\n and(\n eq(principalHistoryEntries.scopeId, input.scopeId),\n eq(principalHistoryEntries.leafHash, resolved.leafHash),\n ),\n )\n .limit(1);\n let entry: unknown;\n try {\n entry = row ? JSON.parse(row.entryJson) : null;\n } catch {\n entry = null;\n }\n if (!isPrincipalPolicyStateChainEntryResponse(entry))\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Principal history entry is missing or corrupt\",\n );\n const reference = input.expectedReference ?? {\n principalType: entry.state.principalType,\n principalId: entry.state.principalId,\n version: entry.state.version,\n keyEpoch: entry.state.keyEpoch,\n stateHash: entry.state.stateHash,\n keyFingerprint: entry.state.keyFingerprint,\n };\n return { reference, entry, proof: resolved.proof };\n}\n"]}
1
+ {"version":3,"file":"principalHistoryEvidencePersistence.js","sourceRoot":"","sources":["principalHistoryEvidencePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n compareCanonicalStrings,\n KeyingVerificationError,\n PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT,\n type PrincipalHistoryIndexNode,\n type PrincipalPolicyHistoryReferenceProof,\n principalHistoryIndexLeaf,\n type ReferencedPrincipalHead,\n resolvePrincipalHistoryIndexProof,\n type VerifiedPrincipalPolicyHistory,\n} from \"@tearleads/crypto\";\nimport {\n isPrincipalPolicyStateChainEntryResponse,\n type PrincipalPolicyStateChainEntryResponse,\n} from \"@tearleads/validators/response\";\nimport { and, eq } from \"drizzle-orm\";\nimport {\n principalHistoryEntries,\n principalHistoryEvidenceTables,\n principalHistoryNodes,\n} from \"../sqlite/principalHistoryEvidenceSchema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport { recordPrincipalHistoryNodeEdges } from \"./principalHistoryNodeRetention\";\n\nexport interface PrincipalHistoryEvidencePage {\n readonly indexRootHash: string;\n readonly scopeId: string;\n readonly organizationId: string;\n readonly entries: readonly {\n readonly leafHash: string;\n readonly entryJson: string;\n }[];\n readonly nodes: readonly PrincipalHistoryIndexNode[];\n}\n\n/** Prepare only a page accepted by the signature/authorization verifier. */\nexport async function preparePrincipalHistoryEvidencePage(input: {\n readonly indexRootHash: string;\n readonly scopeId: string;\n readonly organizationId: string;\n readonly entries: readonly PrincipalPolicyStateChainEntryResponse[];\n readonly nodes: readonly PrincipalHistoryIndexNode[];\n}): Promise<PrincipalHistoryEvidencePage> {\n if (\n input.entries.length > PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT ||\n input.nodes.length > 2 * PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT\n )\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Principal evidence page exceeds its batch budget\",\n );\n const owned = structuredClone(input);\n return {\n ...owned,\n entries: await Promise.all(\n owned.entries.map(async (entry) => ({\n leafHash: await principalHistoryIndexLeaf(entry.state),\n entryJson: JSON.stringify(entry),\n })),\n ),\n };\n}\n\n/** Publish in the same guarded transaction as the accepted page's progress. */\nexport async function writePrincipalHistoryEvidencePage(\n tx: ClientSQLiteTransactionScope,\n page: PrincipalHistoryEvidencePage,\n): Promise<void> {\n const scope = { scopeId: page.scopeId, organizationId: page.organizationId };\n for (const entry of [...page.entries].sort((a, b) =>\n compareCanonicalStrings(a.leafHash, b.leafHash),\n )) {\n const row = { ...scope, ...entry };\n await tx\n .insert(principalHistoryEntries)\n .values(row)\n .onConflictDoUpdate({\n target: [\n principalHistoryEntries.scopeId,\n principalHistoryEntries.leafHash,\n ],\n set: row,\n })\n .run();\n }\n for (const node of [...page.nodes].sort((a, b) =>\n compareCanonicalStrings(a.hash, b.hash),\n )) {\n await recordPrincipalHistoryNodeEdges(tx, scope, node);\n const row = { ...scope, ...node };\n await tx\n .insert(principalHistoryNodes)\n .values(row)\n .onConflictDoUpdate({\n target: [principalHistoryNodes.scopeId, principalHistoryNodes.hash],\n set: row,\n })\n .run();\n }\n}\n\n/** Returns untrusted material. The caller must verify it against the issued root. */\nexport async function loadPrincipalHistoryReference(input: {\n readonly execSql: ExecSql;\n readonly scopeId: string;\n readonly history: VerifiedPrincipalPolicyHistory;\n readonly version: number;\n readonly expectedReference?: ReferencedPrincipalHead | undefined;\n}): Promise<PrincipalPolicyHistoryReferenceProof> {\n await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);\n const { db } = getClientSQLitePersistenceRuntime(input.execSql);\n const resolved = await resolvePrincipalHistoryIndexProof({\n rootHash: input.history.indexRootHash,\n treeSize: input.history.currentEntry.state.version,\n version: input.version,\n readNode: async (hash) => {\n const [row] = await db\n .select()\n .from(principalHistoryNodes)\n .where(\n and(\n eq(principalHistoryNodes.scopeId, input.scopeId),\n eq(principalHistoryNodes.hash, hash),\n ),\n )\n .limit(1);\n return row ?? null;\n },\n });\n const [row] = await db\n .select()\n .from(principalHistoryEntries)\n .where(\n and(\n eq(principalHistoryEntries.scopeId, input.scopeId),\n eq(principalHistoryEntries.leafHash, resolved.leafHash),\n ),\n )\n .limit(1);\n let entry: unknown;\n try {\n entry = row ? JSON.parse(row.entryJson) : null;\n } catch {\n entry = null;\n }\n if (!isPrincipalPolicyStateChainEntryResponse(entry))\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Principal history entry is missing or corrupt\",\n );\n const reference = input.expectedReference ?? {\n principalType: entry.state.principalType,\n principalId: entry.state.principalId,\n version: entry.state.version,\n keyEpoch: entry.state.keyEpoch,\n stateHash: entry.state.stateHash,\n keyFingerprint: entry.state.keyFingerprint,\n };\n return { reference, entry, proof: resolved.proof };\n}\n"]}
@@ -0,0 +1,32 @@
1
+ import { and, asc, desc, eq, inArray, ne } from "drizzle-orm";
2
+ import { principalHistoryStageScopes } from "../sqlite/principalHistoryRetentionSchema.js";
3
+ import { principalHistoryStages } from "../sqlite/principalHistoryStageSchema.js";
4
+ import { releasePrincipalHistoryRoot } from "./principalHistoryRootOwnership.js";
5
+ const INCOMPLETE_STAGE_LIMIT = 8;
6
+ const RECLAIM_BATCH_LIMIT = 16;
7
+ /** Disposable work only: completed artifacts and trust pins are unaffected. */
8
+ export async function reclaimIncompletePrincipalHistoryStages(tx, current) {
9
+ const obsolete = await tx
10
+ .select({ id: principalHistoryStages.id })
11
+ .from(principalHistoryStageScopes)
12
+ .innerJoin(principalHistoryStages, eq(principalHistoryStageScopes.id, principalHistoryStages.id))
13
+ .where(and(eq(principalHistoryStageScopes.scopeId, current.scopeId), eq(principalHistoryStageScopes.organizationId, current.organizationId), eq(principalHistoryStageScopes.complete, false), eq(principalHistoryStages.organizationId, current.organizationId), eq(principalHistoryStages.complete, false), ne(principalHistoryStageScopes.id, current.id)))
14
+ .orderBy(desc(principalHistoryStageScopes.touchedAt), asc(principalHistoryStageScopes.id))
15
+ // The writer always keeps its own stage, even when recency hints tie.
16
+ .offset(INCOMPLETE_STAGE_LIMIT - (current.complete ? 0 : 1))
17
+ .limit(RECLAIM_BATCH_LIMIT);
18
+ const ids = obsolete.map(({ id }) => id);
19
+ for (const id of ids)
20
+ await releasePrincipalHistoryRoot(tx, `stage:${id}`);
21
+ if (ids.length === 0)
22
+ return;
23
+ await tx
24
+ .delete(principalHistoryStages)
25
+ .where(inArray(principalHistoryStages.id, ids))
26
+ .run();
27
+ await tx
28
+ .delete(principalHistoryStageScopes)
29
+ .where(inArray(principalHistoryStageScopes.id, ids))
30
+ .run();
31
+ }
32
+ //# sourceMappingURL=principalHistoryIncompleteRetention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"principalHistoryIncompleteRetention.js","sourceRoot":"","sources":["principalHistoryIncompleteRetention.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAE/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAE9E,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,uCAAuC,CAC3D,EAAgC,EAChC,OAKC;IAED,MAAM,QAAQ,GAAG,MAAM,EAAE;SACtB,MAAM,CAAC,EAAE,EAAE,EAAE,sBAAsB,CAAC,EAAE,EAAE,CAAC;SACzC,IAAI,CAAC,2BAA2B,CAAC;SACjC,SAAS,CACR,sBAAsB,EACtB,EAAE,CAAC,2BAA2B,CAAC,EAAE,EAAE,sBAAsB,CAAC,EAAE,CAAC,CAC9D;SACA,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,2BAA2B,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EACxD,EAAE,CAAC,2BAA2B,CAAC,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,EACtE,EAAE,CAAC,2BAA2B,CAAC,QAAQ,EAAE,KAAK,CAAC,EAC/C,EAAE,CAAC,sBAAsB,CAAC,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,EACjE,EAAE,CAAC,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,EAC1C,EAAE,CAAC,2BAA2B,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAC/C,CACF;SACA,OAAO,CACN,IAAI,CAAC,2BAA2B,CAAC,SAAS,CAAC,EAC3C,GAAG,CAAC,2BAA2B,CAAC,EAAE,CAAC,CACpC;QACD,sEAAsE;SACrE,MAAM,CAAC,sBAAsB,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3D,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACzC,KAAK,MAAM,EAAE,IAAI,GAAG;QAAE,MAAM,2BAA2B,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;IAC3E,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC7B,MAAM,EAAE;SACL,MAAM,CAAC,sBAAsB,CAAC;SAC9B,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;SAC9C,GAAG,EAAE,CAAC;IACT,MAAM,EAAE;SACL,MAAM,CAAC,2BAA2B,CAAC;SACnC,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;SACnD,GAAG,EAAE,CAAC;AACX,CAAC","sourcesContent":["import { and, asc, desc, eq, inArray, ne } from \"drizzle-orm\";\nimport { principalHistoryStageScopes } from \"../sqlite/principalHistoryRetentionSchema\";\nimport { principalHistoryStages } from \"../sqlite/principalHistoryStageSchema\";\nimport type { ClientSQLiteTransactionScope } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { releasePrincipalHistoryRoot } from \"./principalHistoryRootOwnership\";\n\nconst INCOMPLETE_STAGE_LIMIT = 8;\nconst RECLAIM_BATCH_LIMIT = 16;\n\n/** Disposable work only: completed artifacts and trust pins are unaffected. */\nexport async function reclaimIncompletePrincipalHistoryStages(\n tx: ClientSQLiteTransactionScope,\n current: {\n readonly id: string;\n readonly scopeId: string;\n readonly organizationId: string;\n readonly complete: boolean;\n },\n) {\n const obsolete = await tx\n .select({ id: principalHistoryStages.id })\n .from(principalHistoryStageScopes)\n .innerJoin(\n principalHistoryStages,\n eq(principalHistoryStageScopes.id, principalHistoryStages.id),\n )\n .where(\n and(\n eq(principalHistoryStageScopes.scopeId, current.scopeId),\n eq(principalHistoryStageScopes.organizationId, current.organizationId),\n eq(principalHistoryStageScopes.complete, false),\n eq(principalHistoryStages.organizationId, current.organizationId),\n eq(principalHistoryStages.complete, false),\n ne(principalHistoryStageScopes.id, current.id),\n ),\n )\n .orderBy(\n desc(principalHistoryStageScopes.touchedAt),\n asc(principalHistoryStageScopes.id),\n )\n // The writer always keeps its own stage, even when recency hints tie.\n .offset(INCOMPLETE_STAGE_LIMIT - (current.complete ? 0 : 1))\n .limit(RECLAIM_BATCH_LIMIT);\n const ids = obsolete.map(({ id }) => id);\n for (const id of ids) await releasePrincipalHistoryRoot(tx, `stage:${id}`);\n if (ids.length === 0) return;\n await tx\n .delete(principalHistoryStages)\n .where(inArray(principalHistoryStages.id, ids))\n .run();\n await tx\n .delete(principalHistoryStageScopes)\n .where(inArray(principalHistoryStageScopes.id, ids))\n .run();\n}\n"]}