@tearleads/client-sdk 0.1.11 → 0.1.13
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.
- package/README.md +18 -2
- package/client/Tearleads.d.ts +4 -0
- package/client/Tearleads.js +5 -0
- package/client/Tearleads.js.map +1 -1
- package/client/index.d.ts +1 -0
- package/client/index.js.map +1 -1
- package/client/principalHistoryProtection.d.ts +19 -0
- package/client/principalHistoryProtection.js +76 -0
- package/client/principalHistoryProtection.js.map +1 -0
- package/client/workflowRuntime.d.ts +5 -0
- package/client/workflowRuntime.js +34 -5
- package/client/workflowRuntime.js.map +1 -1
- package/data/containers/shared/authorAccess.d.ts +2 -2
- package/data/containers/shared/authorAccess.js.map +1 -1
- package/data/containers/shared/heldContainerHeads.js.map +1 -1
- package/data/containers/shared/principalPolicies.js.map +1 -1
- package/data/containers/shared/types.d.ts +3 -2
- package/data/containers/shared/types.js.map +1 -1
- package/data/keyingProjectionVerification/accessManifestCheckpointEnforcement.js.map +1 -1
- package/data/keyingProjectionVerification/checkpointContext.d.ts +4 -3
- package/data/keyingProjectionVerification/checkpointContext.js.map +1 -1
- package/data/keyingProjectionVerification/containerManifestVerification.js.map +1 -1
- package/data/keyingProjectionVerification/containerPathVerification.js.map +1 -1
- package/data/keyingProjectionVerification/containerProjectionVerification.d.ts +4 -3
- package/data/keyingProjectionVerification/containerProjectionVerification.js.map +1 -1
- package/data/keyingProjectionVerification/documentManifestPolicies.js.map +1 -1
- package/data/keyingProjectionVerification/documentManifestVerification.js.map +1 -1
- package/data/keyingProjectionVerification/documentProjectionVerification.d.ts +3 -2
- package/data/keyingProjectionVerification/documentProjectionVerification.js.map +1 -1
- package/data/keyingProjectionVerification/organizationFounderBinding.js +9 -4
- package/data/keyingProjectionVerification/organizationFounderBinding.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicyCache.js +3 -4
- package/data/keyingProjectionVerification/principalPolicyCache.js.map +1 -1
- package/data/keyingProjectionVerification/principalPolicyVerification.js +12 -2
- package/data/keyingProjectionVerification/principalPolicyVerification.js.map +1 -1
- package/data/keyingProjectionVerification/projectionAuthorizationEvidence.js.map +1 -1
- package/data/keyingProjectionVerification/resolvedPrincipalPolicy.js +70 -0
- package/data/keyingProjectionVerification/resolvedPrincipalPolicy.js.map +1 -0
- package/data/keyingProjectionVerification/types.d.ts +17 -2
- package/data/keyingProjectionVerification/types.js +12 -0
- package/data/keyingProjectionVerification/types.js.map +1 -1
- package/data/persistence/organizationFounderPersistence.js +3 -2
- package/data/persistence/organizationFounderPersistence.js.map +1 -1
- package/data/persistence/principalHistoryEvidencePersistence.js +91 -0
- package/data/persistence/principalHistoryEvidencePersistence.js.map +1 -0
- package/data/persistence/principalHistoryPrefixPersistence.js +52 -0
- package/data/persistence/principalHistoryPrefixPersistence.js.map +1 -0
- package/data/persistence/principalHistoryStagePersistence.js +9 -2
- package/data/persistence/principalHistoryStagePersistence.js.map +1 -1
- package/data/persistence/principalKeyEnvelopeCandidates.js +67 -0
- package/data/persistence/principalKeyEnvelopeCandidates.js.map +1 -0
- package/data/principals/principalHistoryPrefixProtection.js +29 -0
- package/data/principals/principalHistoryPrefixProtection.js.map +1 -0
- package/data/principals/principalHistoryProtection.d.ts +10 -0
- package/data/principals/principalHistoryProtection.js +14 -0
- package/data/principals/principalHistoryProtection.js.map +1 -0
- package/data/principals/principalHistoryStageProtection.js.map +1 -1
- package/data/principals/principalPolicyCrypto.js +11 -21
- package/data/principals/principalPolicyCrypto.js.map +1 -1
- package/data/principals/principalPolicyEvidence.d.ts +4 -0
- package/data/principals/principalPolicyEvidence.js +12 -0
- package/data/principals/principalPolicyEvidence.js.map +1 -0
- package/data/sqlite/principalHistoryEvidenceSchema.js +46 -0
- package/data/sqlite/principalHistoryEvidenceSchema.js.map +1 -0
- package/data/sqlite/principalKeyFingerprintJson.js +9 -0
- package/data/sqlite/principalKeyFingerprintJson.js.map +1 -0
- package/data/sqlite/principalPolicySchema.js +4 -0
- package/data/sqlite/principalPolicySchema.js.map +1 -1
- package/data/sqlite/schema.d.ts +304 -0
- package/data/sqlite/schema.js +5 -0
- package/data/sqlite/schema.js.map +1 -1
- package/data/sqlite/sqlTableSchema.js +1 -1
- package/data/sqlite/sqlTableSchema.js.map +1 -1
- package/index.d.ts +3 -3
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/internal/api-client/principalPolicyPages.d.ts +2 -0
- package/internal/api-client/principalPolicyPages.js +11 -2
- package/internal/api-client/principalPolicyPages.js.map +1 -1
- package/internal/crypto/index.d.ts +1 -1
- package/internal/crypto/index.js +1 -1
- package/internal/crypto/index.js.map +1 -1
- package/internal/crypto/keying/index.d.ts +1 -1
- package/internal/crypto/keying/index.js +1 -1
- package/internal/crypto/keying/index.js.map +1 -1
- package/internal/crypto/keying/principalPolicyHistoryIndex.d.ts +6 -2
- package/internal/crypto/keying/principalPolicyHistoryIndex.js +11 -5
- package/internal/crypto/keying/principalPolicyHistoryIndex.js.map +1 -1
- package/internal/crypto/keying/principalPolicyHistoryReferences.d.ts +2 -0
- package/internal/crypto/keying/principalPolicyHistoryReferences.js +19 -2
- package/internal/crypto/keying/principalPolicyHistoryReferences.js.map +1 -1
- package/package.json +1 -1
- package/workflows/containers/child/create.js.map +1 -1
- package/workflows/containers/child/move.js.map +1 -1
- package/workflows/containers/child/moveWraps.js.map +1 -1
- package/workflows/containers/child/mutationRequestCore.js.map +1 -1
- package/workflows/containers/child/recitePlan.js.map +1 -1
- package/workflows/containers/child/rekey.d.ts +3 -2
- package/workflows/containers/child/rekey.js.map +1 -1
- package/workflows/containers/child/revoke.d.ts +2 -2
- package/workflows/containers/child/revoke.js.map +1 -1
- package/workflows/containers/child/rotationPrincipalPolicies.js.map +1 -1
- package/workflows/containers/child/rotationWraps.js.map +1 -1
- package/workflows/containers/child/sharePlanCore.d.ts +11 -10
- package/workflows/containers/child/sharePlanCore.js.map +1 -1
- package/workflows/documents/linkSetAuthority.js.map +1 -1
- package/workflows/principals/index.d.ts +1 -0
- package/workflows/principals/index.js +1 -0
- package/workflows/principals/index.js.map +1 -1
- package/workflows/principals/principalHistoryRecoveryPrefix.js +65 -0
- package/workflows/principals/principalHistoryRecoveryPrefix.js.map +1 -0
- package/workflows/principals/principalHistoryRecoveryReferences.js +60 -0
- package/workflows/principals/principalHistoryRecoveryReferences.js.map +1 -0
- package/workflows/principals/principalHistoryRecoveryStage.js +38 -2
- package/workflows/principals/principalHistoryRecoveryStage.js.map +1 -1
- package/workflows/principals/principalHistoryRecoveryTypes.d.ts +9 -1
- package/workflows/principals/principalHistoryRecoveryTypes.js +7 -0
- package/workflows/principals/principalHistoryRecoveryTypes.js.map +1 -1
- package/workflows/principals/principalHistoryRecoveryVerification.js +24 -0
- package/workflows/principals/principalHistoryRecoveryVerification.js.map +1 -0
- package/workflows/principals/principalRecoveryDirectory.d.ts +10 -0
- package/workflows/principals/principalRecoveryDirectory.js +107 -0
- package/workflows/principals/principalRecoveryDirectory.js.map +1 -0
- package/workflows/principals/principalRecoveryMemo.js +46 -0
- package/workflows/principals/principalRecoveryMemo.js.map +1 -0
- package/workflows/principals/principalRecoveryOutage.js +40 -0
- package/workflows/principals/principalRecoveryOutage.js.map +1 -0
- package/workflows/principals/principalRecoveryQueue.js +22 -0
- package/workflows/principals/principalRecoveryQueue.js.map +1 -0
- package/workflows/principals/recoverPrincipalPolicyHistory.d.ts +1 -0
- package/workflows/principals/recoverPrincipalPolicyHistory.js +108 -36
- package/workflows/principals/recoverPrincipalPolicyHistory.js.map +1 -1
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.d.ts +13 -0
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.js +150 -0
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.js.map +1 -0
- package/workflows/principals/runtimePolicyRecovery.js +65 -0
- package/workflows/principals/runtimePolicyRecovery.js.map +1 -0
- package/workflows/principals/runtimePolicyWarmer.js +5 -1
- package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
- package/workflows/sync/remoteResetPrincipalScope.js +10 -0
- package/workflows/sync/remoteResetPrincipalScope.js.map +1 -1
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import type { ReferencedPrincipalHead,
|
|
1
|
+
import type { ReferencedPrincipalHead, VerifiedPrincipalPolicyCurrent } from "../../internal/crypto/index.js";
|
|
2
2
|
import type { PrincipalPolicyBundleResponse } from "../../internal/validators/response/index.js";
|
|
3
|
+
import type { PrincipalPolicyCurrentEvidence } from "../principals/principalPolicyEvidence.js";
|
|
3
4
|
import type { TrustedUserIdentity } from "../trustedUserIdentity/index.js";
|
|
4
5
|
export type ProjectionUserKey = TrustedUserIdentity;
|
|
5
6
|
export type ProjectionUserKeyResolver = (userId: string) => Promise<ProjectionUserKey | null>;
|
|
6
|
-
export type PrincipalPolicyCache = Map<string,
|
|
7
|
+
export type PrincipalPolicyCache = Map<string, PrincipalPolicyCurrentEvidence>;
|
|
8
|
+
export interface PrincipalPolicyResolveRequest {
|
|
9
|
+
/** Identity of one projection collection, never caller-supplied evidence. */
|
|
10
|
+
readonly recoveryBatch?: object | undefined;
|
|
11
|
+
readonly organizationId: string;
|
|
12
|
+
readonly reference: ReferencedPrincipalHead;
|
|
13
|
+
readonly stillCurrent?: (() => boolean) | undefined;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedPrincipalPolicyEvidence {
|
|
16
|
+
readonly stillCurrent: () => boolean;
|
|
17
|
+
readonly organizationId: string;
|
|
18
|
+
readonly policy: VerifiedPrincipalPolicyCurrent;
|
|
19
|
+
readonly dependencies: readonly VerifiedPrincipalPolicyCurrent[];
|
|
20
|
+
}
|
|
7
21
|
export interface ReferencedPrincipalPolicyWarmRequest {
|
|
8
22
|
readonly organizationId: string;
|
|
9
23
|
readonly references: readonly ReferencedPrincipalHead[];
|
|
@@ -17,6 +31,7 @@ export interface PrincipalPolicyBundleCacheRequest {
|
|
|
17
31
|
export type PrincipalPolicyBundleCacher = (input: PrincipalPolicyBundleCacheRequest) => Promise<void>;
|
|
18
32
|
export type ReferencedPrincipalPolicyWarmer = ((input: ReferencedPrincipalPolicyWarmRequest) => Promise<void>) & {
|
|
19
33
|
readonly cacheBundles?: PrincipalPolicyBundleCacher | undefined;
|
|
34
|
+
readonly resolveReference?: ((input: PrincipalPolicyResolveRequest) => Promise<ResolvedPrincipalPolicyEvidence>) | undefined;
|
|
20
35
|
};
|
|
21
36
|
export declare class ProjectionVerificationCancelledError extends Error {
|
|
22
37
|
constructor();
|
|
@@ -37,7 +37,19 @@ export function generationGuardedPrincipalPolicyWarmer(warmer, stillCurrent) {
|
|
|
37
37
|
};
|
|
38
38
|
const guardWithCapabilities = (operation) => {
|
|
39
39
|
const guarded = guard(operation);
|
|
40
|
+
const resolve = operation.resolveReference;
|
|
40
41
|
return Object.assign(guarded, {
|
|
42
|
+
...(resolve
|
|
43
|
+
? {
|
|
44
|
+
resolveReference: async (input) => {
|
|
45
|
+
const current = () => stillCurrent() && input.stillCurrent?.() !== false;
|
|
46
|
+
assertProjectionVerificationCurrent(current);
|
|
47
|
+
const result = await resolve({ ...input, stillCurrent: current });
|
|
48
|
+
assertProjectionVerificationCurrent(current);
|
|
49
|
+
return result;
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
: {}),
|
|
41
53
|
...(operation.cacheBundles
|
|
42
54
|
? {
|
|
43
55
|
cacheBundles: async (input) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ReferencedPrincipalHead,\n VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } 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 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 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 return Object.assign(guarded, {\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,5 +1,6 @@
|
|
|
1
|
-
import { KeyingVerificationError
|
|
1
|
+
import { KeyingVerificationError } from "../../internal/crypto/index.js";
|
|
2
2
|
import { eq } from "drizzle-orm";
|
|
3
|
+
import { principalPolicyEvidenceEntries, } from "../principals/principalPolicyEvidence.js";
|
|
3
4
|
import { organizationFounders } from "../sqlite/organizationFounderSchema.js";
|
|
4
5
|
import { keyingCheckpointTables } from "../sqlite/schema.js";
|
|
5
6
|
import { getClientSQLitePersistenceRuntime } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
@@ -22,7 +23,7 @@ export async function loadOrganizationFounder(execSql, organizationId) {
|
|
|
22
23
|
}
|
|
23
24
|
/** Pin verified genesis, never a later administrator or a folder's creator. */
|
|
24
25
|
export async function rememberOrganizationFounder(input) {
|
|
25
|
-
const genesis = input.organization.
|
|
26
|
+
const genesis = principalPolicyEvidenceEntries(input.organization).find(({ state }) => state.version === 1)?.state;
|
|
26
27
|
if (genesis?.principalType !== "organization" ||
|
|
27
28
|
genesis.prevStateHash !== null)
|
|
28
29
|
throw new KeyingVerificationError("missing_dependency", "Organization founder requires verified genesis");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organizationFounderPersistence.js","sourceRoot":"","sources":["organizationFounderPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"organizationFounderPersistence.js","sourceRoot":"","sources":["organizationFounderPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { eq } from \"drizzle-orm\";\nimport {\n type PrincipalPolicyCheckpointEvidence,\n principalPolicyEvidenceEntries,\n} from \"../principals/principalPolicyEvidence\";\nimport { organizationFounders } from \"../sqlite/organizationFounderSchema\";\nimport { keyingCheckpointTables } from \"../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\n\nfunction assertSameFounder(\n stored: typeof organizationFounders.$inferSelect,\n founder: typeof organizationFounders.$inferInsert,\n): void {\n if (\n stored.userId !== founder.userId ||\n stored.signingKeyFingerprint !== founder.signingKeyFingerprint ||\n stored.genesisStateHash !== founder.genesisStateHash\n )\n throw new KeyingVerificationError(\n \"equivocation\",\n \"Organization founder conflicts with its durable genesis binding\",\n );\n}\n\nexport async function loadOrganizationFounder(\n execSql: ExecSql,\n organizationId: string,\n): Promise<typeof organizationFounders.$inferSelect | null> {\n await ensureSqlTables(execSql, keyingCheckpointTables);\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const [stored] = await runtime.db\n .select()\n .from(organizationFounders)\n .where(eq(organizationFounders.organizationId, organizationId))\n .limit(1);\n return stored ?? null;\n}\n\n/** Pin verified genesis, never a later administrator or a folder's creator. */\nexport async function rememberOrganizationFounder(input: {\n readonly execSql: ExecSql;\n readonly organization: PrincipalPolicyCheckpointEvidence;\n}): Promise<void> {\n const genesis = principalPolicyEvidenceEntries(input.organization).find(\n ({ state }) => state.version === 1,\n )?.state;\n if (\n genesis?.principalType !== \"organization\" ||\n genesis.prevStateHash !== null\n )\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization founder requires verified genesis\",\n );\n const founder = {\n organizationId: genesis.principalId,\n userId: genesis.signerUserId,\n signingKeyFingerprint: genesis.signerUserKeyFingerprint,\n genesisStateHash: genesis.stateHash,\n };\n const held = await loadOrganizationFounder(\n input.execSql,\n founder.organizationId,\n );\n if (held) {\n assertSameFounder(held, founder);\n return;\n }\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n await runtime.transaction(\n async (tx) => {\n const [stored] = await tx\n .select()\n .from(organizationFounders)\n .where(eq(organizationFounders.organizationId, founder.organizationId))\n .limit(1);\n if (stored) {\n assertSameFounder(stored, founder);\n return;\n }\n await tx\n .insert(organizationFounders)\n .values(founder)\n .onConflictDoNothing()\n .run();\n },\n { behavior: \"immediate\" },\n );\n}\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { compareCanonicalStrings, KeyingVerificationError, PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT, principalHistoryIndexLeaf, resolvePrincipalHistoryIndexProof, } from "../../internal/crypto/index.js";
|
|
2
|
+
import { isPrincipalPolicyStateChainEntryResponse, } from "../../internal/validators/response/index.js";
|
|
3
|
+
import { and, eq } from "drizzle-orm";
|
|
4
|
+
import { principalHistoryEntries, principalHistoryEvidenceTables, principalHistoryNodes, } from "../sqlite/principalHistoryEvidenceSchema.js";
|
|
5
|
+
import { getClientSQLitePersistenceRuntime, } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
6
|
+
import { ensureSqlTables } from "../sqlite/sqlSchema.js";
|
|
7
|
+
/** Prepare only a page accepted by the signature/authorization verifier. */
|
|
8
|
+
export async function preparePrincipalHistoryEvidencePage(input) {
|
|
9
|
+
if (input.entries.length > PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT ||
|
|
10
|
+
input.nodes.length > 2 * PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT)
|
|
11
|
+
throw new KeyingVerificationError("invalid_shape", "Principal evidence page exceeds its batch budget");
|
|
12
|
+
const owned = structuredClone(input);
|
|
13
|
+
return {
|
|
14
|
+
...owned,
|
|
15
|
+
entries: await Promise.all(owned.entries.map(async (entry) => ({
|
|
16
|
+
leafHash: await principalHistoryIndexLeaf(entry.state),
|
|
17
|
+
entryJson: JSON.stringify(entry),
|
|
18
|
+
}))),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Publish in the same guarded transaction as the accepted page's progress. */
|
|
22
|
+
export async function writePrincipalHistoryEvidencePage(tx, page) {
|
|
23
|
+
const scope = { scopeId: page.scopeId, organizationId: page.organizationId };
|
|
24
|
+
for (const entry of [...page.entries].sort((a, b) => compareCanonicalStrings(a.leafHash, b.leafHash))) {
|
|
25
|
+
const row = { ...scope, ...entry };
|
|
26
|
+
await tx
|
|
27
|
+
.insert(principalHistoryEntries)
|
|
28
|
+
.values(row)
|
|
29
|
+
.onConflictDoUpdate({
|
|
30
|
+
target: [
|
|
31
|
+
principalHistoryEntries.scopeId,
|
|
32
|
+
principalHistoryEntries.leafHash,
|
|
33
|
+
],
|
|
34
|
+
set: row,
|
|
35
|
+
})
|
|
36
|
+
.run();
|
|
37
|
+
}
|
|
38
|
+
for (const node of [...page.nodes].sort((a, b) => compareCanonicalStrings(a.hash, b.hash))) {
|
|
39
|
+
const row = { ...scope, ...node };
|
|
40
|
+
await tx
|
|
41
|
+
.insert(principalHistoryNodes)
|
|
42
|
+
.values(row)
|
|
43
|
+
.onConflictDoUpdate({
|
|
44
|
+
target: [principalHistoryNodes.scopeId, principalHistoryNodes.hash],
|
|
45
|
+
set: row,
|
|
46
|
+
})
|
|
47
|
+
.run();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Returns untrusted material. The caller must verify it against the issued root. */
|
|
51
|
+
export async function loadPrincipalHistoryReference(input) {
|
|
52
|
+
await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);
|
|
53
|
+
const { db } = getClientSQLitePersistenceRuntime(input.execSql);
|
|
54
|
+
const resolved = await resolvePrincipalHistoryIndexProof({
|
|
55
|
+
rootHash: input.history.indexRootHash,
|
|
56
|
+
treeSize: input.history.currentEntry.state.version,
|
|
57
|
+
version: input.version,
|
|
58
|
+
readNode: async (hash) => {
|
|
59
|
+
const [row] = await db
|
|
60
|
+
.select()
|
|
61
|
+
.from(principalHistoryNodes)
|
|
62
|
+
.where(and(eq(principalHistoryNodes.scopeId, input.scopeId), eq(principalHistoryNodes.hash, hash)))
|
|
63
|
+
.limit(1);
|
|
64
|
+
return row ?? null;
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
const [row] = await db
|
|
68
|
+
.select()
|
|
69
|
+
.from(principalHistoryEntries)
|
|
70
|
+
.where(and(eq(principalHistoryEntries.scopeId, input.scopeId), eq(principalHistoryEntries.leafHash, resolved.leafHash)))
|
|
71
|
+
.limit(1);
|
|
72
|
+
let entry;
|
|
73
|
+
try {
|
|
74
|
+
entry = row ? JSON.parse(row.entryJson) : null;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
entry = null;
|
|
78
|
+
}
|
|
79
|
+
if (!isPrincipalPolicyStateChainEntryResponse(entry))
|
|
80
|
+
throw new KeyingVerificationError("missing_dependency", "Principal history entry is missing or corrupt");
|
|
81
|
+
const reference = input.expectedReference ?? {
|
|
82
|
+
principalType: entry.state.principalType,
|
|
83
|
+
principalId: entry.state.principalId,
|
|
84
|
+
version: entry.state.version,
|
|
85
|
+
keyEpoch: entry.state.keyEpoch,
|
|
86
|
+
stateHash: entry.state.stateHash,
|
|
87
|
+
keyFingerprint: entry.state.keyFingerprint,
|
|
88
|
+
};
|
|
89
|
+
return { reference, entry, proof: resolved.proof };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=principalHistoryEvidencePersistence.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { and, eq } from "drizzle-orm";
|
|
2
|
+
import { assertProjectionVerificationCurrent } from "../keyingProjectionVerification/types.js";
|
|
3
|
+
import { principalHistoryEvidenceTables, principalHistoryPrefixes, } from "../sqlite/principalHistoryEvidenceSchema.js";
|
|
4
|
+
import { getClientSQLitePersistenceRuntime } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
5
|
+
import { ensureSqlTables } from "../sqlite/sqlSchema.js";
|
|
6
|
+
export async function loadPrincipalHistoryPrefix(execSql, scopeId) {
|
|
7
|
+
await ensureSqlTables(execSql, principalHistoryEvidenceTables);
|
|
8
|
+
const { db } = getClientSQLitePersistenceRuntime(execSql);
|
|
9
|
+
const [prefix] = await db
|
|
10
|
+
.select()
|
|
11
|
+
.from(principalHistoryPrefixes)
|
|
12
|
+
.where(eq(principalHistoryPrefixes.scopeId, scopeId))
|
|
13
|
+
.limit(1);
|
|
14
|
+
return prefix ?? null;
|
|
15
|
+
}
|
|
16
|
+
/** Keep one completed prefix per principal/trust scope; older readers cannot replace it. */
|
|
17
|
+
export async function savePrincipalHistoryPrefix(input) {
|
|
18
|
+
const prefix = { ...input.prefix };
|
|
19
|
+
await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);
|
|
20
|
+
const runtime = getClientSQLitePersistenceRuntime(input.execSql);
|
|
21
|
+
const result = await runtime.guardedTransaction(async (tx) => {
|
|
22
|
+
const [previous] = await tx
|
|
23
|
+
.select()
|
|
24
|
+
.from(principalHistoryPrefixes)
|
|
25
|
+
.where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))
|
|
26
|
+
.limit(1);
|
|
27
|
+
if (previous && previous.version > prefix.version)
|
|
28
|
+
return;
|
|
29
|
+
await tx
|
|
30
|
+
.insert(principalHistoryPrefixes)
|
|
31
|
+
.values(prefix)
|
|
32
|
+
.onConflictDoUpdate({
|
|
33
|
+
target: principalHistoryPrefixes.scopeId,
|
|
34
|
+
set: prefix,
|
|
35
|
+
})
|
|
36
|
+
.run();
|
|
37
|
+
}, input.stillCurrent, { behavior: "immediate" });
|
|
38
|
+
assertProjectionVerificationCurrent(() => result.committed);
|
|
39
|
+
}
|
|
40
|
+
/** Invalid hints are disposable, but a losing reader must preserve a newer hint. */
|
|
41
|
+
export async function discardPrincipalHistoryPrefix(input) {
|
|
42
|
+
const prefix = { ...input.prefix };
|
|
43
|
+
const runtime = getClientSQLitePersistenceRuntime(input.execSql);
|
|
44
|
+
const result = await runtime.guardedTransaction(async (tx) => {
|
|
45
|
+
await tx
|
|
46
|
+
.delete(principalHistoryPrefixes)
|
|
47
|
+
.where(and(eq(principalHistoryPrefixes.scopeId, prefix.scopeId), eq(principalHistoryPrefixes.progress, prefix.progress)))
|
|
48
|
+
.run();
|
|
49
|
+
}, input.stillCurrent, { behavior: "immediate" });
|
|
50
|
+
assertProjectionVerificationCurrent(() => result.committed);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=principalHistoryPrefixPersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principalHistoryPrefixPersistence.js","sourceRoot":"","sources":["principalHistoryPrefixPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport { assertProjectionVerificationCurrent } from \"../keyingProjectionVerification/types\";\nimport {\n principalHistoryEvidenceTables,\n principalHistoryPrefixes,\n} from \"../sqlite/principalHistoryEvidenceSchema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\n\nexport type PrincipalHistoryPrefix =\n typeof principalHistoryPrefixes.$inferSelect;\n\nexport async function loadPrincipalHistoryPrefix(\n execSql: ExecSql,\n scopeId: string,\n) {\n await ensureSqlTables(execSql, principalHistoryEvidenceTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [prefix] = await db\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, scopeId))\n .limit(1);\n return prefix ?? null;\n}\n\n/** Keep one completed prefix per principal/trust scope; older readers cannot replace it. */\nexport async function savePrincipalHistoryPrefix(input: {\n readonly execSql: ExecSql;\n readonly prefix: PrincipalHistoryPrefix;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const prefix = { ...input.prefix };\n await ensureSqlTables(input.execSql, principalHistoryEvidenceTables);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const result = await runtime.guardedTransaction(\n async (tx) => {\n const [previous] = await tx\n .select()\n .from(principalHistoryPrefixes)\n .where(eq(principalHistoryPrefixes.scopeId, prefix.scopeId))\n .limit(1);\n if (previous && previous.version > prefix.version) return;\n await tx\n .insert(principalHistoryPrefixes)\n .values(prefix)\n .onConflictDoUpdate({\n target: principalHistoryPrefixes.scopeId,\n set: prefix,\n })\n .run();\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => result.committed);\n}\n\n/** Invalid hints are disposable, but a losing reader must preserve a newer hint. */\nexport async function discardPrincipalHistoryPrefix(input: {\n readonly execSql: ExecSql;\n readonly prefix: PrincipalHistoryPrefix;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const prefix = { ...input.prefix };\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const result = await runtime.guardedTransaction(\n async (tx) => {\n await tx\n .delete(principalHistoryPrefixes)\n .where(\n and(\n eq(principalHistoryPrefixes.scopeId, prefix.scopeId),\n eq(principalHistoryPrefixes.progress, prefix.progress),\n ),\n )\n .run();\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => result.committed);\n}\n"]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { and, eq } from "drizzle-orm";
|
|
2
2
|
import { assertProjectionVerificationCurrent } from "../keyingProjectionVerification/types.js";
|
|
3
|
+
import { principalHistoryEvidenceTables } from "../sqlite/principalHistoryEvidenceSchema.js";
|
|
3
4
|
import { principalHistoryStages, principalHistoryStageTables, } from "../sqlite/principalHistoryStageSchema.js";
|
|
4
5
|
import { getClientSQLitePersistenceRuntime } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
5
6
|
import { ensureSqlTables } from "../sqlite/sqlSchema.js";
|
|
7
|
+
import { writePrincipalHistoryEvidencePage, } from "./principalHistoryEvidencePersistence.js";
|
|
6
8
|
class PrincipalHistoryStageChangedError extends Error {
|
|
7
9
|
code = "principal_history_stage_changed";
|
|
8
10
|
constructor() {
|
|
@@ -20,10 +22,14 @@ export async function loadPrincipalHistoryStage(execSql, id) {
|
|
|
20
22
|
.limit(1);
|
|
21
23
|
return row ?? null;
|
|
22
24
|
}
|
|
23
|
-
/**
|
|
25
|
+
/** Publish accepted entries and index nodes atomically with authenticated progress. */
|
|
24
26
|
export async function savePrincipalHistoryStage(input) {
|
|
25
27
|
const stage = { ...input.stage };
|
|
26
|
-
|
|
28
|
+
const evidence = structuredClone(input.evidence);
|
|
29
|
+
await ensureSqlTables(input.execSql, [
|
|
30
|
+
...principalHistoryStageTables,
|
|
31
|
+
...principalHistoryEvidenceTables,
|
|
32
|
+
]);
|
|
27
33
|
const runtime = getClientSQLitePersistenceRuntime(input.execSql);
|
|
28
34
|
const saved = await runtime.guardedTransaction(async (tx) => {
|
|
29
35
|
const [previous] = await tx
|
|
@@ -33,6 +39,7 @@ export async function savePrincipalHistoryStage(input) {
|
|
|
33
39
|
.limit(1);
|
|
34
40
|
if ((previous?.progress ?? null) !== input.previousProgress)
|
|
35
41
|
throw new PrincipalHistoryStageChangedError();
|
|
42
|
+
await writePrincipalHistoryEvidencePage(tx, evidence);
|
|
36
43
|
await tx
|
|
37
44
|
.insert(principalHistoryStages)
|
|
38
45
|
.values(stage)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalHistoryStagePersistence.js","sourceRoot":"","sources":["principalHistoryStagePersistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,mCAAmC,EAAE,MAAM,uCAAuC,CAAC;AAC5F,OAAO,EACL,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,iCAAiC,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAgB,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"principalHistoryStagePersistence.js","sourceRoot":"","sources":["principalHistoryStagePersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport { assertProjectionVerificationCurrent } from \"../keyingProjectionVerification/types\";\nimport { principalHistoryEvidenceTables } from \"../sqlite/principalHistoryEvidenceSchema\";\nimport {\n principalHistoryStages,\n principalHistoryStageTables,\n} from \"../sqlite/principalHistoryStageSchema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport {\n type PrincipalHistoryEvidencePage,\n writePrincipalHistoryEvidencePage,\n} from \"./principalHistoryEvidencePersistence\";\n\nexport type PrincipalHistoryStage = typeof principalHistoryStages.$inferSelect;\n\nclass PrincipalHistoryStageChangedError extends Error {\n readonly code = \"principal_history_stage_changed\";\n constructor() {\n super(\n \"Another operation changed the saved principal history; resume from its current state\",\n );\n this.name = \"PrincipalHistoryStageChangedError\";\n }\n}\n\nexport async function loadPrincipalHistoryStage(execSql: ExecSql, id: string) {\n await ensureSqlTables(execSql, principalHistoryStageTables);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const [row] = await db\n .select()\n .from(principalHistoryStages)\n .where(eq(principalHistoryStages.id, id))\n .limit(1);\n return row ?? null;\n}\n\n/** Publish accepted entries and index nodes atomically with authenticated progress. */\nexport async function savePrincipalHistoryStage(input: {\n readonly execSql: ExecSql;\n readonly stage: PrincipalHistoryStage;\n readonly evidence: PrincipalHistoryEvidencePage;\n readonly previousProgress: string | null;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const stage = { ...input.stage };\n const evidence = structuredClone(input.evidence);\n await ensureSqlTables(input.execSql, [\n ...principalHistoryStageTables,\n ...principalHistoryEvidenceTables,\n ]);\n const runtime = getClientSQLitePersistenceRuntime(input.execSql);\n const saved = await runtime.guardedTransaction(\n async (tx) => {\n const [previous] = await tx\n .select({ progress: principalHistoryStages.progress })\n .from(principalHistoryStages)\n .where(eq(principalHistoryStages.id, stage.id))\n .limit(1);\n if ((previous?.progress ?? null) !== input.previousProgress)\n throw new PrincipalHistoryStageChangedError();\n await writePrincipalHistoryEvidencePage(tx, evidence);\n await tx\n .insert(principalHistoryStages)\n .values(stage)\n .onConflictDoUpdate({ target: principalHistoryStages.id, set: stage })\n .run();\n },\n input.stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => saved.committed);\n}\n\nexport async function discardPrincipalHistoryStage(\n execSql: ExecSql,\n stage: PrincipalHistoryStage,\n stillCurrent: () => boolean,\n) {\n const runtime = getClientSQLitePersistenceRuntime(execSql);\n const discarded = await runtime.guardedTransaction(\n async (db) => {\n await db\n .delete(principalHistoryStages)\n .where(\n and(\n eq(principalHistoryStages.id, stage.id),\n eq(principalHistoryStages.progress, stage.progress),\n ),\n )\n .run();\n },\n stillCurrent,\n { behavior: \"immediate\" },\n );\n assertProjectionVerificationCurrent(() => discarded.committed);\n}\n"]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { isCurrentPrincipalMemberEnvelopesResponse, } from "../../internal/validators/response/index.js";
|
|
2
|
+
import { desc, eq, sql } from "drizzle-orm";
|
|
3
|
+
import { principalHistoryEvidenceTables, principalHistoryPrefixes, } from "../sqlite/principalHistoryEvidenceSchema.js";
|
|
4
|
+
import { principalCurrentFingerprintJson, principalStateFingerprintJson, } from "../sqlite/principalKeyFingerprintJson.js";
|
|
5
|
+
import { principalPolicies, principalPolicyBundleHistory, } from "../sqlite/principalPolicySchema.js";
|
|
6
|
+
import { principalPolicyTables } from "../sqlite/schema.js";
|
|
7
|
+
import { getClientSQLitePersistenceRuntime } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
8
|
+
import { ensureSqlTables } from "../sqlite/sqlSchema.js";
|
|
9
|
+
/**
|
|
10
|
+
* Untrusted encrypted key candidates, never authorization evidence. The actual
|
|
11
|
+
* private key must open the requested recipient wrap; the projection verifier
|
|
12
|
+
* separately checks the signed KEK material identity and all policy authority.
|
|
13
|
+
* Read only envelopes for the requested fingerprints, never signed histories.
|
|
14
|
+
*/
|
|
15
|
+
export async function loadPrincipalKeyEnvelopeCandidates(execSql, fingerprints) {
|
|
16
|
+
await ensureSqlTables(execSql, [
|
|
17
|
+
...principalPolicyTables,
|
|
18
|
+
...principalHistoryEvidenceTables,
|
|
19
|
+
]);
|
|
20
|
+
const { db } = getClientSQLitePersistenceRuntime(execSql);
|
|
21
|
+
const candidates = [];
|
|
22
|
+
for (const fingerprint of new Set(fingerprints)) {
|
|
23
|
+
const encoded = [];
|
|
24
|
+
for (const table of [principalPolicies, principalPolicyBundleHistory]) {
|
|
25
|
+
const [row] = await db
|
|
26
|
+
.select({ envelopes: table.currentMemberEnvelopesJson })
|
|
27
|
+
.from(table)
|
|
28
|
+
.where(eq(principalStateFingerprintJson(table.currentStateJson), fingerprint))
|
|
29
|
+
.orderBy(desc(table.updatedAt))
|
|
30
|
+
.limit(1);
|
|
31
|
+
if (row)
|
|
32
|
+
encoded.push(row.envelopes);
|
|
33
|
+
}
|
|
34
|
+
const [prefix] = await db
|
|
35
|
+
.select({
|
|
36
|
+
envelopes: sql `json_extract(${principalHistoryPrefixes.currentJson}, '$.currentMemberEnvelopes')`,
|
|
37
|
+
})
|
|
38
|
+
.from(principalHistoryPrefixes)
|
|
39
|
+
.where(eq(principalCurrentFingerprintJson(principalHistoryPrefixes.currentJson), fingerprint))
|
|
40
|
+
.orderBy(desc(principalHistoryPrefixes.version))
|
|
41
|
+
.limit(1);
|
|
42
|
+
if (prefix)
|
|
43
|
+
encoded.push(prefix.envelopes);
|
|
44
|
+
for (const json of encoded) {
|
|
45
|
+
let envelopes;
|
|
46
|
+
try {
|
|
47
|
+
envelopes = JSON.parse(json);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!isCurrentPrincipalMemberEnvelopesResponse(envelopes))
|
|
53
|
+
continue;
|
|
54
|
+
candidates.push({
|
|
55
|
+
currentState: {
|
|
56
|
+
principalType: envelopes.principalType,
|
|
57
|
+
principalId: envelopes.principalId,
|
|
58
|
+
stateHash: envelopes.stateHash,
|
|
59
|
+
keyFingerprint: fingerprint,
|
|
60
|
+
},
|
|
61
|
+
currentMemberEnvelopes: envelopes,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return candidates;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=principalKeyEnvelopeCandidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principalKeyEnvelopeCandidates.js","sourceRoot":"","sources":["principalKeyEnvelopeCandidates.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type CurrentPrincipalMemberEnvelopesResponse,\n isCurrentPrincipalMemberEnvelopesResponse,\n} from \"@tearleads/validators/response\";\nimport { desc, eq, sql } from \"drizzle-orm\";\nimport {\n principalHistoryEvidenceTables,\n principalHistoryPrefixes,\n} from \"../sqlite/principalHistoryEvidenceSchema\";\nimport {\n principalCurrentFingerprintJson,\n principalStateFingerprintJson,\n} from \"../sqlite/principalKeyFingerprintJson\";\nimport {\n principalPolicies,\n principalPolicyBundleHistory,\n} from \"../sqlite/principalPolicySchema\";\nimport { principalPolicyTables } from \"../sqlite/schema\";\nimport { getClientSQLitePersistenceRuntime } from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\n\nexport interface PrincipalKeyEnvelopeCandidate {\n readonly currentState: {\n readonly principalType: \"group\" | \"organization\";\n readonly principalId: string;\n readonly stateHash: string;\n readonly keyFingerprint: string;\n };\n readonly currentMemberEnvelopes: CurrentPrincipalMemberEnvelopesResponse;\n}\n\n/**\n * Untrusted encrypted key candidates, never authorization evidence. The actual\n * private key must open the requested recipient wrap; the projection verifier\n * separately checks the signed KEK material identity and all policy authority.\n * Read only envelopes for the requested fingerprints, never signed histories.\n */\nexport async function loadPrincipalKeyEnvelopeCandidates(\n execSql: ExecSql,\n fingerprints: readonly string[],\n): Promise<PrincipalKeyEnvelopeCandidate[]> {\n await ensureSqlTables(execSql, [\n ...principalPolicyTables,\n ...principalHistoryEvidenceTables,\n ]);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const candidates: PrincipalKeyEnvelopeCandidate[] = [];\n for (const fingerprint of new Set(fingerprints)) {\n const encoded: string[] = [];\n for (const table of [principalPolicies, principalPolicyBundleHistory]) {\n const [row] = await db\n .select({ envelopes: table.currentMemberEnvelopesJson })\n .from(table)\n .where(\n eq(\n principalStateFingerprintJson(table.currentStateJson),\n fingerprint,\n ),\n )\n .orderBy(desc(table.updatedAt))\n .limit(1);\n if (row) encoded.push(row.envelopes);\n }\n const [prefix] = await db\n .select({\n envelopes: sql<string>`json_extract(${principalHistoryPrefixes.currentJson}, '$.currentMemberEnvelopes')`,\n })\n .from(principalHistoryPrefixes)\n .where(\n eq(\n principalCurrentFingerprintJson(principalHistoryPrefixes.currentJson),\n fingerprint,\n ),\n )\n .orderBy(desc(principalHistoryPrefixes.version))\n .limit(1);\n if (prefix) encoded.push(prefix.envelopes);\n for (const json of encoded) {\n let envelopes: unknown;\n try {\n envelopes = JSON.parse(json);\n } catch {\n continue;\n }\n if (!isCurrentPrincipalMemberEnvelopesResponse(envelopes)) continue;\n candidates.push({\n currentState: {\n principalType: envelopes.principalType,\n principalId: envelopes.principalId,\n stateHash: envelopes.stateHash,\n keyFingerprint: fingerprint,\n },\n currentMemberEnvelopes: envelopes,\n });\n }\n }\n return candidates;\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { serializeKeyingCanonicalJson, toFingerprint, } from "../../internal/crypto/index.js";
|
|
2
|
+
// Signed entries and index nodes are content-addressed public evidence. Keep
|
|
3
|
+
// their storage namespace stable across local-key replacement; authenticating a
|
|
4
|
+
// prefix still requires the current private key. An unreadable prefix is discarded
|
|
5
|
+
// and rebuilt from signatures, reusing rows only after checking the new root.
|
|
6
|
+
export async function principalHistoryEvidenceScopeId(input) {
|
|
7
|
+
return toFingerprint(new TextEncoder().encode(serializeKeyingCanonicalJson([
|
|
8
|
+
"tearleads.sdk.principal-history-evidence.v2",
|
|
9
|
+
input.organizationId,
|
|
10
|
+
input.head.principalType,
|
|
11
|
+
input.head.principalId,
|
|
12
|
+
input.protection.context,
|
|
13
|
+
])));
|
|
14
|
+
}
|
|
15
|
+
export async function principalHistoryPrefixProtection(protection, prefix) {
|
|
16
|
+
return {
|
|
17
|
+
localKey: protection.localKey,
|
|
18
|
+
context: serializeKeyingCanonicalJson({
|
|
19
|
+
domain: "tearleads.sdk.principal-history-prefix.v2",
|
|
20
|
+
context: protection.context,
|
|
21
|
+
scopeId: prefix.scopeId,
|
|
22
|
+
organizationId: prefix.organizationId,
|
|
23
|
+
version: prefix.version,
|
|
24
|
+
headJson: prefix.headJson,
|
|
25
|
+
currentDigest: await toFingerprint(new TextEncoder().encode(prefix.currentJson)),
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=principalHistoryPrefixProtection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principalHistoryPrefixProtection.js","sourceRoot":"","sources":["principalHistoryPrefixProtection.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,4BAA4B,EAC5B,aAAa,GACd,MAAM,mBAAmB,CAAC;AAG3B,6EAA6E;AAC7E,gFAAgF;AAChF,mFAAmF;AACnF,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,KAIrD;IACC,OAAO,aAAa,CAClB,IAAI,WAAW,EAAE,CAAC,MAAM,CACtB,4BAA4B,CAAC;QAC3B,6CAA6C;QAC7C,KAAK,CAAC,cAAc;QACpB,KAAK,CAAC,IAAI,CAAC,aAAa;QACxB,KAAK,CAAC,IAAI,CAAC,WAAW;QACtB,KAAK,CAAC,UAAU,CAAC,OAAO;KACzB,CAAC,CACH,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,UAAiD,EACjD,MAAgD;IAEhD,OAAO;QACL,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,OAAO,EAAE,4BAA4B,CAAC;YACpC,MAAM,EAAE,2CAA2C;YACnD,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,aAAa,EAAE,MAAM,aAAa,CAChC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAC7C;SACF,CAAC;KACH,CAAC;AACJ,CAAC","sourcesContent":["import {\n type PrincipalPolicyHistoryProgressOptions,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n toFingerprint,\n} from \"@tearleads/crypto\";\nimport type { PrincipalHistoryPrefix } from \"../persistence/principalHistoryPrefixPersistence\";\n\n// Signed entries and index nodes are content-addressed public evidence. Keep\n// their storage namespace stable across local-key replacement; authenticating a\n// prefix still requires the current private key. An unreadable prefix is discarded\n// and rebuilt from signatures, reusing rows only after checking the new root.\nexport async function principalHistoryEvidenceScopeId(input: {\n readonly organizationId: string;\n readonly head: Pick<ReferencedPrincipalHead, \"principalType\" | \"principalId\">;\n readonly protection: PrincipalPolicyHistoryProgressOptions;\n}): Promise<string> {\n return toFingerprint(\n new TextEncoder().encode(\n serializeKeyingCanonicalJson([\n \"tearleads.sdk.principal-history-evidence.v2\",\n input.organizationId,\n input.head.principalType,\n input.head.principalId,\n input.protection.context,\n ]),\n ),\n );\n}\n\nexport async function principalHistoryPrefixProtection(\n protection: PrincipalPolicyHistoryProgressOptions,\n prefix: Omit<PrincipalHistoryPrefix, \"progress\">,\n): Promise<PrincipalPolicyHistoryProgressOptions> {\n return {\n localKey: protection.localKey,\n context: serializeKeyingCanonicalJson({\n domain: \"tearleads.sdk.principal-history-prefix.v2\",\n context: protection.context,\n scopeId: prefix.scopeId,\n organizationId: prefix.organizationId,\n version: prefix.version,\n headJson: prefix.headJson,\n currentDigest: await toFingerprint(\n new TextEncoder().encode(prefix.currentJson),\n ),\n }),\n };\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type PrincipalPolicyHistoryProgressOptions } from "../../internal/crypto/index.js";
|
|
2
|
+
export type PrincipalHistoryProtectionLease = <T>(operation: (input: {
|
|
3
|
+
readonly protection: PrincipalPolicyHistoryProgressOptions;
|
|
4
|
+
readonly stillCurrent: () => boolean;
|
|
5
|
+
}) => Promise<T>) => Promise<T>;
|
|
6
|
+
/** Own private key bytes before any asynchronous discovery or verification. */
|
|
7
|
+
export declare function ownPrincipalHistoryProtection(protection: PrincipalPolicyHistoryProgressOptions): {
|
|
8
|
+
context: string;
|
|
9
|
+
localKey: Uint8Array<ArrayBuffer>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { KeyingVerificationError, } from "../../internal/crypto/index.js";
|
|
2
|
+
/** Own private key bytes before any asynchronous discovery or verification. */
|
|
3
|
+
export function ownPrincipalHistoryProtection(protection) {
|
|
4
|
+
if (!(protection.localKey instanceof Uint8Array) ||
|
|
5
|
+
protection.localKey.byteLength !== 32 ||
|
|
6
|
+
typeof protection.context !== "string" ||
|
|
7
|
+
protection.context.length === 0)
|
|
8
|
+
throw new KeyingVerificationError("invalid_shape", "Principal history recovery requires a private 32-byte key and trust context");
|
|
9
|
+
return {
|
|
10
|
+
context: protection.context,
|
|
11
|
+
localKey: new Uint8Array(protection.localKey),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=principalHistoryProtection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principalHistoryProtection.js","sourceRoot":"","sources":["principalHistoryProtection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAExB,MAAM,mBAAmB,CAAC;AAS3B,+EAA+E;AAC/E,MAAM,UAAU,6BAA6B,CAC3C,UAAiD;IAEjD,IACE,CAAC,CAAC,UAAU,CAAC,QAAQ,YAAY,UAAU,CAAC;QAC5C,UAAU,CAAC,QAAQ,CAAC,UAAU,KAAK,EAAE;QACrC,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ;QACtC,UAAU,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAE/B,MAAM,IAAI,uBAAuB,CAC/B,eAAe,EACf,6EAA6E,CAC9E,CAAC;IACJ,OAAO;QACL,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,QAAQ,EAAE,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC;KAC9C,CAAC;AACJ,CAAC","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicyHistoryProgressOptions,\n} from \"@tearleads/crypto\";\n\nexport type PrincipalHistoryProtectionLease = <T>(\n operation: (input: {\n readonly protection: PrincipalPolicyHistoryProgressOptions;\n readonly stillCurrent: () => boolean;\n }) => Promise<T>,\n) => Promise<T>;\n\n/** Own private key bytes before any asynchronous discovery or verification. */\nexport function ownPrincipalHistoryProtection(\n protection: PrincipalPolicyHistoryProgressOptions,\n) {\n if (\n !(protection.localKey instanceof Uint8Array) ||\n protection.localKey.byteLength !== 32 ||\n typeof protection.context !== \"string\" ||\n protection.context.length === 0\n )\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Principal history recovery requires a private 32-byte key and trust context\",\n );\n return {\n context: protection.context,\n localKey: new Uint8Array(protection.localKey),\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalHistoryStageProtection.js","sourceRoot":"","sources":["principalHistoryStageProtection.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,4BAA4B,EAC5B,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAG/E,MAAM,UAAU,uBAAuB,CACrC,cAAsB,EACtB,IAA6B,EAC7B,OAAe,EACf,kBAAsD;IAEtD,OAAO,aAAa,CAClB,IAAI,WAAW,EAAE,CAAC,MAAM,CACtB,4BAA4B,CAAC;QAC3B,0CAA0C;QAC1C,cAAc;QACd,IAAI,CAAC,aAAa;QAClB,IAAI,CAAC,WAAW;QAChB,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,QAAQ;QACb,IAAI,CAAC,SAAS;QACd,IAAI,CAAC,cAAc;QACnB,OAAO;QACP,CAAC,GAAG,kBAAkB,CAAC;aACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;aACrC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;YAClB,SAAS,CAAC,aAAa;YACvB,SAAS,CAAC,WAAW;YACrB,SAAS,CAAC,OAAO;YACjB,SAAS,CAAC,QAAQ;YAClB,SAAS,CAAC,SAAS;YACnB,SAAS,CAAC,cAAc;SACzB,CAAC;KACL,CAAC,CACH,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,UAAiD,EACjD,YAAqC,EACrC,KAA8C;IAE9C,OAAO;QACL,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,OAAO,EAAE,4BAA4B,CAAC;YACpC,MAAM,EAAE,0CAA0C;YAClD,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,EAAE,GAAG,YAAY,EAAE;YACjC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,MAAM,aAAa,CAChC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAC5C;SACF,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,
|
|
1
|
+
{"version":3,"file":"principalHistoryStageProtection.js","sourceRoot":"","sources":["principalHistoryStageProtection.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,4BAA4B,EAC5B,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAG/E,MAAM,UAAU,uBAAuB,CACrC,cAAsB,EACtB,IAA6B,EAC7B,OAAe,EACf,kBAAsD;IAEtD,OAAO,aAAa,CAClB,IAAI,WAAW,EAAE,CAAC,MAAM,CACtB,4BAA4B,CAAC;QAC3B,0CAA0C;QAC1C,cAAc;QACd,IAAI,CAAC,aAAa;QAClB,IAAI,CAAC,WAAW;QAChB,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,QAAQ;QACb,IAAI,CAAC,SAAS;QACd,IAAI,CAAC,cAAc;QACnB,OAAO;QACP,CAAC,GAAG,kBAAkB,CAAC;aACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;aACrC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;YAClB,SAAS,CAAC,aAAa;YACvB,SAAS,CAAC,WAAW;YACrB,SAAS,CAAC,OAAO;YACjB,SAAS,CAAC,QAAQ;YAClB,SAAS,CAAC,SAAS;YACnB,SAAS,CAAC,cAAc;SACzB,CAAC;KACL,CAAC,CACH,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,UAAiD,EACjD,YAAqC,EACrC,KAA8C;IAE9C,OAAO;QACL,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,OAAO,EAAE,4BAA4B,CAAC;YACpC,MAAM,EAAE,0CAA0C;YAClD,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,EAAE,GAAG,YAAY,EAAE;YACjC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,MAAM,aAAa,CAChC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAC5C;SACF,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,KAAkE;IAElE,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QACnE,OAAO,IAAI,CAAC;IACd,MAAM,IAAI,GAAG;QACX,GAAG,OAAO;QACV,cAAc,EAAE,EAAE;QAClB,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,gBAAgB,EAAE,IAAI,EAAE;KAC1E,CAAC;IACF,IACE,CAAC,6BAA6B,CAAC,IAAI,CAAC;QACpC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO;QAE/C,OAAO,IAAI,CAAC;IACd,OAAO;QACL,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,sBAAsB,EAAE,IAAI,CAAC,sBAAsB;KACpD,CAAC;AACJ,CAAC","sourcesContent":["import type { PrincipalPolicyPageCurrent } from \"@tearleads/api-client\";\nimport {\n type PrincipalPolicyHistoryProgressOptions,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n toFingerprint,\n} from \"@tearleads/crypto\";\nimport { isPrincipalPolicyPageResponse } from \"@tearleads/validators/response\";\nimport type { PrincipalHistoryStage } from \"../persistence/principalHistoryStagePersistence\";\n\nexport function principalHistoryStageId(\n organizationId: string,\n head: ReferencedPrincipalHead,\n context: string,\n retainedReferences: readonly ReferencedPrincipalHead[],\n) {\n return toFingerprint(\n new TextEncoder().encode(\n serializeKeyingCanonicalJson([\n \"tearleads.sdk.principal-history-stage.v1\",\n organizationId,\n head.principalType,\n head.principalId,\n head.version,\n head.keyEpoch,\n head.stateHash,\n head.keyFingerprint,\n context,\n [...retainedReferences]\n .sort((a, b) => a.version - b.version)\n .map((reference) => [\n reference.principalType,\n reference.principalId,\n reference.version,\n reference.keyEpoch,\n reference.stateHash,\n reference.keyFingerprint,\n ]),\n ]),\n ),\n );\n}\n\nexport async function principalHistoryStageProtection(\n protection: PrincipalPolicyHistoryProgressOptions,\n expectedHead: ReferencedPrincipalHead,\n stage: Omit<PrincipalHistoryStage, \"progress\">,\n): Promise<PrincipalPolicyHistoryProgressOptions> {\n return {\n localKey: protection.localKey,\n context: serializeKeyingCanonicalJson({\n domain: \"tearleads.sdk.principal-history-stage.v1\",\n context: protection.context,\n id: stage.id,\n organizationId: stage.organizationId,\n expectedHead: { ...expectedHead },\n afterVersion: stage.afterVersion,\n complete: stage.complete,\n currentDigest: await toFingerprint(\n new TextEncoder().encode(stage.currentJson),\n ),\n }),\n };\n}\n\nexport function parsePrincipalHistoryStageCurrent(\n stage: Pick<PrincipalHistoryStage, \"currentJson\" | \"afterVersion\">,\n): PrincipalPolicyPageCurrent | null {\n let current: unknown;\n try {\n current = JSON.parse(stage.currentJson);\n } catch {\n return null;\n }\n if (!current || typeof current !== \"object\" || Array.isArray(current))\n return null;\n const page = {\n ...current,\n previousStates: [],\n historyPage: { afterVersion: stage.afterVersion, nextAfterVersion: null },\n };\n if (\n !isPrincipalPolicyPageResponse(page) ||\n stage.afterVersion >= page.currentState.version\n )\n return null;\n return {\n currentState: page.currentState,\n currentPayload: page.currentPayload,\n currentProjection: page.currentProjection,\n currentGrants: page.currentGrants,\n currentMemberEnvelopes: page.currentMemberEnvelopes,\n };\n}\n"]}
|