@tearleads/client-sdk 0.1.47 → 0.1.49
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/client/organizations/currentPrincipalMutations.js +36 -17
- package/client/organizations/currentPrincipalMutations.js.map +1 -1
- package/client/organizations/principalContainerMutations.js +1 -0
- package/client/organizations/principalContainerMutations.js.map +1 -1
- package/client/organizations/principalMutations.js +2 -2
- package/client/organizations/principalMutations.js.map +1 -1
- package/data/persistence/documents/internal/documentRows.js +37 -41
- package/data/persistence/documents/internal/documentRows.js.map +1 -1
- package/data/persistence/principalHistoryEvidencePersistence.js +17 -18
- package/data/persistence/principalHistoryEvidencePersistence.js.map +1 -1
- package/data/persistence/principalHistoryNodeRetention.js +164 -39
- package/data/persistence/principalHistoryNodeRetention.js.map +1 -1
- package/data/persistence/principalPolicyReferenceIndexPersistence.js +101 -38
- package/data/persistence/principalPolicyReferenceIndexPersistence.js.map +1 -1
- package/data/principals/principalMutationJournalShape.js +6 -0
- package/data/principals/principalMutationJournalShape.js.map +1 -1
- package/data/sqlite/sqliteUpsert.js +9 -0
- package/data/sqlite/sqliteUpsert.js.map +1 -0
- package/internal/api-client/ApiClient.d.ts +122 -0
- package/internal/api-client/principalPolicyRequests.d.ts +122 -0
- package/internal/validators/operation/principals.d.ts +1026 -206
- package/internal/validators/request/principal.d.ts +332 -0
- package/internal/validators/request/principal.js +1 -0
- package/internal/validators/request/principal.js.map +1 -1
- package/internal/validators/response/principal.d.ts +488 -0
- package/internal/validators/response/principal.js +1 -0
- package/internal/validators/response/principal.js.map +1 -1
- package/package.json +1 -1
- package/workflows/containers/child/rekeyProjection.d.ts +6 -1
- package/workflows/containers/child/rekeyProjection.js +41 -0
- package/workflows/containers/child/rekeyProjection.js.map +1 -1
- package/workflows/organizations/authoredPrincipalPolicyWarmer.js +25 -0
- package/workflows/organizations/authoredPrincipalPolicyWarmer.js.map +1 -0
- package/workflows/organizations/commitCurrentGroupPolicyMutation.js +101 -34
- package/workflows/organizations/commitCurrentGroupPolicyMutation.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationContext.d.ts +5 -52
- package/workflows/organizations/groupPolicyMutationContext.js +2 -65
- package/workflows/organizations/groupPolicyMutationContext.js.map +1 -1
- package/workflows/organizations/precedingPrincipalRematerialization.js +31 -0
- package/workflows/organizations/precedingPrincipalRematerialization.js.map +1 -0
- package/workflows/organizations/principalContainerRematerialization.js +39 -7
- package/workflows/organizations/principalContainerRematerialization.js.map +1 -1
- package/workflows/organizations/principalContainerRematerializationPlanning.js +6 -1
- package/workflows/organizations/principalContainerRematerializationPlanning.js.map +1 -1
- package/workflows/organizations/principalContainerRematerializationTargets.js +0 -11
- package/workflows/organizations/principalContainerRematerializationTargets.js.map +1 -1
- package/workflows/organizations/principalMutationReceipt.js +6 -0
- package/workflows/organizations/principalMutationReceipt.js.map +1 -1
- package/workflows/organizations/principalPolicyApi.d.ts +33 -0
- package/workflows/organizations/principalPolicyApi.js +2 -0
- package/workflows/organizations/principalPolicyApi.js.map +1 -0
- package/workflows/organizations/runtimeCurrentGroupMutation.js +36 -19
- package/workflows/organizations/runtimeCurrentGroupMutation.js.map +1 -1
- package/workflows/organizations/submitGroupPolicyCommit.d.ts +22 -0
- package/workflows/organizations/submitGroupPolicyCommit.js +71 -0
- package/workflows/organizations/submitGroupPolicyCommit.js.map +1 -0
|
@@ -16,30 +16,49 @@ export function createCurrentPrincipalMutation(input) {
|
|
|
16
16
|
signerUserId: input.signerUserId,
|
|
17
17
|
stillCurrent: input.stillCurrent,
|
|
18
18
|
}, async (context) => {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
context,
|
|
26
|
-
request,
|
|
27
|
-
resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,
|
|
28
|
-
prepareContainerMutations: (nextPolicy) => preparePrincipalContainerMutations({
|
|
29
|
-
currentPolicy: context.currentPolicy,
|
|
19
|
+
const prepareChange = async (selected, change) => ({
|
|
20
|
+
context: selected,
|
|
21
|
+
request: await buildCurrentMutationRequest(input, selected, change),
|
|
22
|
+
prepareContainerMutations: (nextPolicy, preceding) => preparePrincipalContainerMutations({
|
|
23
|
+
preceding,
|
|
24
|
+
currentPolicy: selected.currentPolicy,
|
|
30
25
|
nextPolicy,
|
|
31
|
-
groupId,
|
|
26
|
+
groupId: selected.currentPolicy.currentState.principalId,
|
|
32
27
|
organizationId: input.organizationId,
|
|
33
28
|
runtime: input.runtime,
|
|
34
|
-
stillCurrent:
|
|
29
|
+
stillCurrent: selected.stillCurrent,
|
|
35
30
|
recitationStillCurrent: input.stillCurrent,
|
|
36
|
-
resolveAuthoredPolicyReferences:
|
|
37
|
-
revokedContainerId:
|
|
38
|
-
?
|
|
31
|
+
resolveAuthoredPolicyReferences: selected.resolveAuthoredPolicyReferences,
|
|
32
|
+
revokedContainerId: change.kind === "revoke"
|
|
33
|
+
? change.revokedContainerId
|
|
39
34
|
: undefined,
|
|
40
35
|
}),
|
|
41
36
|
});
|
|
42
|
-
|
|
37
|
+
const primary = await prepareChange(context, mutation);
|
|
38
|
+
let member;
|
|
39
|
+
if (mutation.kind === "add" && groupId !== context.memberGroupId) {
|
|
40
|
+
const members = await context.loadGroup(context.memberGroupId);
|
|
41
|
+
if (!members.currentPolicy.currentProjection.some((entry) => entry.userId === mutation.targetUserId)) {
|
|
42
|
+
member = await prepareChange(members, {
|
|
43
|
+
...mutation,
|
|
44
|
+
expectedGroupName: "Members",
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
49
|
+
const response = await commitCurrentGroupPolicyMutation({
|
|
50
|
+
...input,
|
|
51
|
+
apiClient: input.runtime.apiClient,
|
|
52
|
+
groupId,
|
|
53
|
+
...primary,
|
|
54
|
+
member,
|
|
55
|
+
resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
response,
|
|
59
|
+
memberGroupId: context.memberGroupId,
|
|
60
|
+
enrolled: Boolean(member),
|
|
61
|
+
};
|
|
43
62
|
});
|
|
44
63
|
}
|
|
45
64
|
async function buildCurrentMutationRequest(input, context, mutation) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"currentPrincipalMutations.js","sourceRoot":"","sources":["currentPrincipalMutations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SigningKeyPair } from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { commitCurrentGroupPolicyMutation } from \"../../workflows/organizations/commitCurrentGroupPolicyMutation\";\nimport { assertGroupMembershipName } from \"../../workflows/organizations/groupMembershipName\";\nimport { createRuntimeGroupMetadataAccess } from \"../../workflows/organizations/groupMetadataRuntime\";\nimport {\n buildAddGroupUserPolicyRequest,\n buildGroupAccessSetShrinkPolicyRequest,\n buildRemoveGroupUserPolicyRequest,\n} from \"../../workflows/organizations/groupPolicyRequests\";\nimport {\n createRuntimeCurrentGroupMutation,\n type RuntimeCurrentGroupMutationContext,\n} from \"../../workflows/organizations/runtimeCurrentGroupMutation\";\nimport {\n projectionUserIds,\n resolveRequiredUserIdentities,\n} from \"../../workflows/organizations/trustedOrganizationUsers\";\nimport type { InternalWorkflowRuntimeInput } from \"../workflowRuntime\";\nimport { preparePrincipalContainerMutations } from \"./principalContainerMutations\";\n\ntype CurrentGroupMutation =\n | {\n readonly kind: \"add\";\n readonly expectedGroupName: string;\n readonly targetUserId: string;\n }\n | {\n readonly kind: \"remove\";\n readonly expectedGroupName: string;\n readonly removedUserId: string;\n }\n | { readonly kind: \"revoke\"; readonly revokedContainerId: string };\n\n/** Built-in hosts with private custody use bounded current-policy mutation work. */\ninterface CurrentPrincipalMutationInput {\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly signingFingerprint: string;\n readonly signingKeyPair: SigningKeyPair;\n readonly stillCurrent: () => boolean;\n}\n\nexport function createCurrentPrincipalMutation(\n input: CurrentPrincipalMutationInput,\n) {\n const mutate = createRuntimeCurrentGroupMutation(input.runtime);\n if (!mutate) return undefined;\n return (groupId: string, mutation: CurrentGroupMutation) =>\n mutate(\n {\n groupId,\n organizationId: input.organizationId,\n signerUserId: input.signerUserId,\n stillCurrent: input.stillCurrent,\n },\n async (context) => {\n const request = await buildCurrentMutationRequest(\n input,\n context,\n mutation,\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n const response = await commitCurrentGroupPolicyMutation({\n ...input,\n apiClient: input.runtime.apiClient,\n groupId,\n context,\n request,\n resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,\n prepareContainerMutations: (nextPolicy) =>\n preparePrincipalContainerMutations({\n currentPolicy: context.currentPolicy,\n nextPolicy,\n groupId,\n organizationId: input.organizationId,\n runtime: input.runtime,\n stillCurrent: context.stillCurrent,\n recitationStillCurrent: input.stillCurrent,\n resolveAuthoredPolicyReferences:\n context.resolveAuthoredPolicyReferences,\n revokedContainerId:\n mutation.kind === \"revoke\"\n ? mutation.revokedContainerId\n : undefined,\n }),\n });\n return { response, memberGroupId: context.memberGroupId };\n },\n );\n}\n\nasync function buildCurrentMutationRequest(\n input: CurrentPrincipalMutationInput,\n context: RuntimeCurrentGroupMutationContext,\n mutation: CurrentGroupMutation,\n): Promise<PutPrincipalPolicyRequest> {\n const shared = {\n ...context,\n signerUserId: input.signerUserId,\n signingFingerprint: input.signingFingerprint,\n signingKeyPair: input.signingKeyPair,\n };\n if (mutation.kind !== \"revoke\") {\n await assertGroupMembershipName(\n context.currentPolicy,\n mutation.expectedGroupName,\n createRuntimeGroupMetadataAccess(\n input.runtime,\n input.organizationId,\n context.stillCurrent,\n context.verifyMetadataContainer,\n ).readName,\n );\n }\n const resolveUsers = (userIds: readonly string[]) =>\n resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,\n userIds,\n });\n const projection = context.currentPolicy.currentProjection;\n let request: PutPrincipalPolicyRequest;\n if (mutation.kind === \"add\") {\n const currentUserSecretKey =\n input.runtime.crypto.encapsulationKeyPair?.secretKey;\n if (!currentUserSecretKey)\n throw new Error(\"Organization encryption context is unavailable\");\n const identities = await resolveUsers([\n ...projectionUserIds(projection),\n mutation.targetUserId,\n ]);\n const targetUser = identities.find(\n (identity) => identity.userId === mutation.targetUserId,\n );\n if (!targetUser) throw new Error(\"Group target identity is unavailable\");\n request = await buildAddGroupUserPolicyRequest({\n ...shared,\n currentUserSecretKey,\n targetUser,\n currentUsers: identities.filter(\n (identity) => identity.userId !== mutation.targetUserId,\n ),\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n });\n } else if (mutation.kind === \"remove\") {\n request = await buildRemoveGroupUserPolicyRequest({\n ...shared,\n removedUserId: mutation.removedUserId,\n remainingUsers: await resolveUsers(\n projectionUserIds(\n projection.filter(\n (member) => member.userId !== mutation.removedUserId,\n ),\n ),\n ),\n });\n } else {\n request = await buildGroupAccessSetShrinkPolicyRequest({\n ...shared,\n revokedContainerId: mutation.revokedContainerId,\n currentUsers: await resolveUsers(projectionUserIds(projection)),\n });\n }\n\n return request;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"currentPrincipalMutations.js","sourceRoot":"","sources":["currentPrincipalMutations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SigningKeyPair } from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { commitCurrentGroupPolicyMutation } from \"../../workflows/organizations/commitCurrentGroupPolicyMutation\";\nimport { assertGroupMembershipName } from \"../../workflows/organizations/groupMembershipName\";\nimport { createRuntimeGroupMetadataAccess } from \"../../workflows/organizations/groupMetadataRuntime\";\nimport {\n buildAddGroupUserPolicyRequest,\n buildGroupAccessSetShrinkPolicyRequest,\n buildRemoveGroupUserPolicyRequest,\n} from \"../../workflows/organizations/groupPolicyRequests\";\nimport {\n createRuntimeCurrentGroupMutation,\n type RuntimeCurrentGroupMutationContext,\n} from \"../../workflows/organizations/runtimeCurrentGroupMutation\";\nimport {\n projectionUserIds,\n resolveRequiredUserIdentities,\n} from \"../../workflows/organizations/trustedOrganizationUsers\";\nimport type { InternalWorkflowRuntimeInput } from \"../workflowRuntime\";\nimport { preparePrincipalContainerMutations } from \"./principalContainerMutations\";\n\ntype CurrentGroupMutation =\n | {\n readonly kind: \"add\";\n readonly expectedGroupName: string;\n readonly targetUserId: string;\n }\n | {\n readonly kind: \"remove\";\n readonly expectedGroupName: string;\n readonly removedUserId: string;\n }\n | { readonly kind: \"revoke\"; readonly revokedContainerId: string };\n\n/** Built-in hosts with private custody use bounded current-policy mutation work. */\ninterface CurrentPrincipalMutationInput {\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly signingFingerprint: string;\n readonly signingKeyPair: SigningKeyPair;\n readonly stillCurrent: () => boolean;\n}\n\nexport function createCurrentPrincipalMutation(\n input: CurrentPrincipalMutationInput,\n) {\n const mutate = createRuntimeCurrentGroupMutation(input.runtime);\n if (!mutate) return undefined;\n return (groupId: string, mutation: CurrentGroupMutation) =>\n mutate(\n {\n groupId,\n organizationId: input.organizationId,\n signerUserId: input.signerUserId,\n stillCurrent: input.stillCurrent,\n },\n async (context) => {\n const prepareChange = async (\n selected: RuntimeCurrentGroupMutationContext,\n change: CurrentGroupMutation,\n ) => ({\n context: selected,\n request: await buildCurrentMutationRequest(input, selected, change),\n prepareContainerMutations: (\n nextPolicy: Parameters<\n typeof preparePrincipalContainerMutations\n >[0][\"nextPolicy\"],\n preceding?: Parameters<\n typeof preparePrincipalContainerMutations\n >[0][\"preceding\"],\n ) =>\n preparePrincipalContainerMutations({\n preceding,\n currentPolicy: selected.currentPolicy,\n nextPolicy,\n groupId: selected.currentPolicy.currentState.principalId,\n organizationId: input.organizationId,\n runtime: input.runtime,\n stillCurrent: selected.stillCurrent,\n recitationStillCurrent: input.stillCurrent,\n resolveAuthoredPolicyReferences:\n selected.resolveAuthoredPolicyReferences,\n revokedContainerId:\n change.kind === \"revoke\"\n ? change.revokedContainerId\n : undefined,\n }),\n });\n const primary = await prepareChange(context, mutation);\n let member: Awaited<ReturnType<typeof prepareChange>> | undefined;\n if (mutation.kind === \"add\" && groupId !== context.memberGroupId) {\n const members = await context.loadGroup(context.memberGroupId);\n if (\n !members.currentPolicy.currentProjection.some(\n (entry) => entry.userId === mutation.targetUserId,\n )\n ) {\n member = await prepareChange(members, {\n ...mutation,\n expectedGroupName: \"Members\",\n });\n }\n }\n assertProjectionVerificationCurrent(context.stillCurrent);\n const response = await commitCurrentGroupPolicyMutation({\n ...input,\n apiClient: input.runtime.apiClient,\n groupId,\n ...primary,\n member,\n resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,\n });\n return {\n response,\n memberGroupId: context.memberGroupId,\n enrolled: Boolean(member),\n };\n },\n );\n}\n\nasync function buildCurrentMutationRequest(\n input: CurrentPrincipalMutationInput,\n context: RuntimeCurrentGroupMutationContext,\n mutation: CurrentGroupMutation,\n): Promise<PutPrincipalPolicyRequest> {\n const shared = {\n ...context,\n signerUserId: input.signerUserId,\n signingFingerprint: input.signingFingerprint,\n signingKeyPair: input.signingKeyPair,\n };\n if (mutation.kind !== \"revoke\") {\n await assertGroupMembershipName(\n context.currentPolicy,\n mutation.expectedGroupName,\n createRuntimeGroupMetadataAccess(\n input.runtime,\n input.organizationId,\n context.stillCurrent,\n context.verifyMetadataContainer,\n ).readName,\n );\n }\n const resolveUsers = (userIds: readonly string[]) =>\n resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,\n userIds,\n });\n const projection = context.currentPolicy.currentProjection;\n let request: PutPrincipalPolicyRequest;\n if (mutation.kind === \"add\") {\n const currentUserSecretKey =\n input.runtime.crypto.encapsulationKeyPair?.secretKey;\n if (!currentUserSecretKey)\n throw new Error(\"Organization encryption context is unavailable\");\n const identities = await resolveUsers([\n ...projectionUserIds(projection),\n mutation.targetUserId,\n ]);\n const targetUser = identities.find(\n (identity) => identity.userId === mutation.targetUserId,\n );\n if (!targetUser) throw new Error(\"Group target identity is unavailable\");\n request = await buildAddGroupUserPolicyRequest({\n ...shared,\n currentUserSecretKey,\n targetUser,\n currentUsers: identities.filter(\n (identity) => identity.userId !== mutation.targetUserId,\n ),\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n });\n } else if (mutation.kind === \"remove\") {\n request = await buildRemoveGroupUserPolicyRequest({\n ...shared,\n removedUserId: mutation.removedUserId,\n remainingUsers: await resolveUsers(\n projectionUserIds(\n projection.filter(\n (member) => member.userId !== mutation.removedUserId,\n ),\n ),\n ),\n });\n } else {\n request = await buildGroupAccessSetShrinkPolicyRequest({\n ...shared,\n revokedContainerId: mutation.revokedContainerId,\n currentUsers: await resolveUsers(projectionUserIds(projection)),\n });\n }\n\n return request;\n}\n"]}
|
|
@@ -8,6 +8,7 @@ export async function preparePrincipalContainerMutations(input) {
|
|
|
8
8
|
throw new Error("Organization container rematerialization context is unavailable");
|
|
9
9
|
}
|
|
10
10
|
return preparePrincipalContainerRematerializationBatch({
|
|
11
|
+
preceding: input.preceding,
|
|
11
12
|
stillCurrent: input.stillCurrent,
|
|
12
13
|
recitationStillCurrent: input.recitationStillCurrent,
|
|
13
14
|
reportSecurityIncident: input.runtime.util.reportSecurityIncident,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalContainerMutations.js","sourceRoot":"","sources":["principalContainerMutations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAEL,+CAA+C,GAChD,MAAM,mEAAmE,CAAC;
|
|
1
|
+
{"version":3,"file":"principalContainerMutations.js","sourceRoot":"","sources":["principalContainerMutations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAEL,+CAA+C,GAChD,MAAM,mEAAmE,CAAC;AAE3E,OAAO,EAAE,kCAAkC,EAAE,MAAM,gDAAgD,CAAC;AAGpG,MAAM,CAAC,KAAK,UAAU,kCAAkC,CAAC,KAaxD;IACC,MAAM,MAAM,GAAG,2BAA2B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,SAAS,CAAC;IAC7E,IAAI,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;IACJ,CAAC;IACD,OAAO,+CAA+C,CAAC;QACrD,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;QACpD,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB;QACjE,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS;QAClC,MAAM;QACN,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;QACpC,MAAM,EAAE;YACN,GAAG,IAAI,GAAG,CACR,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,aAAa,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CACpE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAU,CAC/C,CACF,CAAC,MAAM,EAAE;SACX;QACD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;QACtE,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,0BAA0B,EAAE,KAAK,CAAC,OAAO,CAAC,0BAA0B;QACpE,eAAe;QACf,+BAA+B,EAAE,kCAAkC,CACjE,KAAK,CAAC,OAAO,CACd;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport type { CurrentPolicyReferenceResolver } from \"../../data/principals/currentPolicyReferenceResolver\";\nimport type { PrincipalPolicyCurrentEvidence } from \"../../data/principals/principalPolicyEvidence\";\nimport { resolveDocumentCreateAuthor } from \"../../workflows/documents\";\nimport {\n type PreparedPrincipalContainerRematerializationBatch,\n preparePrincipalContainerRematerializationBatch,\n} from \"../../workflows/organizations/principalContainerRematerialization\";\nimport type { PrincipalRematerializationPredecessor } from \"../../workflows/organizations/principalContainerRematerializationPlanning\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../workflows/principals/runtimePolicyWarmer\";\nimport type { InternalWorkflowRuntimeInput } from \"../workflowRuntime\";\n\nexport async function preparePrincipalContainerMutations(input: {\n readonly preceding?: PrincipalRematerializationPredecessor | undefined;\n readonly currentPolicy: Pick<PrincipalPolicyBundleResponse, \"currentGrants\">;\n readonly groupId: string;\n readonly nextPolicy: PrincipalPolicyCurrentEvidence;\n readonly resolveAuthoredPolicyReferences?:\n | CurrentPolicyReferenceResolver\n | undefined;\n readonly organizationId: string;\n readonly revokedContainerId?: string | undefined;\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly stillCurrent: () => boolean;\n readonly recitationStillCurrent?: (() => boolean) | undefined;\n}): Promise<PreparedPrincipalContainerRematerializationBatch> {\n const author = resolveDocumentCreateAuthor(input.runtime);\n const targetSecretKey = input.runtime.crypto.encapsulationKeyPair?.secretKey;\n if (!author || !targetSecretKey) {\n throw new Error(\n \"Organization container rematerialization context is unavailable\",\n );\n }\n return preparePrincipalContainerRematerializationBatch({\n preceding: input.preceding,\n stillCurrent: input.stillCurrent,\n recitationStillCurrent: input.recitationStillCurrent,\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n apiClient: input.runtime.apiClient,\n author,\n execSql: input.runtime.infra.execSql,\n grants: [\n ...new Map(\n [...input.currentPolicy.currentGrants, ...input.nextPolicy.grants].map(\n (grant) => [grant.containerId, grant] as const,\n ),\n ).values(),\n ],\n groupId: input.groupId,\n nextPolicy: input.nextPolicy,\n resolveAuthoredPolicyReferences: input.resolveAuthoredPolicyReferences,\n revokedContainerId: input.revokedContainerId,\n resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,\n targetSecretKey,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.runtime,\n ),\n });\n}\n"]}
|
|
@@ -44,12 +44,12 @@ export async function addUserToOrganizationGroup(input) {
|
|
|
44
44
|
});
|
|
45
45
|
if (!mutateCurrent)
|
|
46
46
|
throw new ProjectionDependencyUnavailableError("Principal history recovery is unavailable");
|
|
47
|
-
const { memberGroupId, response: bundle } = await mutateCurrent(input.groupId, {
|
|
47
|
+
const { memberGroupId, response: bundle, enrolled, } = await mutateCurrent(input.groupId, {
|
|
48
48
|
kind: "add",
|
|
49
49
|
expectedGroupName: input.expectedGroupName,
|
|
50
50
|
targetUserId: input.targetUserId,
|
|
51
51
|
});
|
|
52
|
-
if (input.groupId === memberGroupId) {
|
|
52
|
+
if (input.groupId === memberGroupId || enrolled) {
|
|
53
53
|
await syncOrganizationMetadataProfile({
|
|
54
54
|
containerContents: input.containerContents,
|
|
55
55
|
log: input.runtime.util.log,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalMutations.js","sourceRoot":"","sources":["principalMutations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContainerGrantSubjectType } from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport { revokeOrganizationContainerGrant } from \"../../workflows/organizations\";\nimport { createCurrentOrganizationGroup } from \"../../workflows/organizations/createCurrentOrganizationGroup\";\nimport { createSelectedCurrentGroupMetadataContainerVerifier } from \"../../workflows/organizations/currentGroupMetadataAuthority\";\nimport { deleteCurrentOrganizationGroup } from \"../../workflows/organizations/deleteCurrentOrganizationGroup\";\nimport { createRuntimeGroupMetadataAccess } from \"../../workflows/organizations/groupMetadataRuntime\";\nimport { createRuntimeCurrentOrganizationMutation } from \"../../workflows/organizations/runtimeCurrentOrganizationMutation\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../workflows/principals/runtimePolicyWarmer\";\nimport type { ContainerContents } from \"../containerContents\";\nimport type { InternalWorkflowRuntimeInput } from \"../workflowRuntime\";\nimport { createCurrentPrincipalMutation } from \"./currentPrincipalMutations\";\nimport { syncOrganizationMetadataProfile } from \"./organizationMetadataProfileSync\";\nimport type { OrganizationReadModelCoordinator } from \"./organizationReadModels\";\n\nexport interface OrganizationGrantRef {\n containerId: string;\n subjectId: string;\n subjectType: ContainerGrantSubjectType;\n}\n\nexport interface OrganizationGroupUserMutationInput {\n groupId: string;\n expectedGroupName: string;\n}\n\nexport interface AddOrganizationGroupUserInput\n extends OrganizationGroupUserMutationInput {\n targetUserId: string;\n}\n\nexport interface RemoveOrganizationGroupUserInput\n extends OrganizationGroupUserMutationInput {\n removedUserId: string;\n}\n\ninterface OrganizationSigningContext {\n organizationId: string;\n signerUserId: string;\n signingFingerprint: string;\n signingKeyPair: NonNullable<\n InternalWorkflowRuntimeInput[\"crypto\"][\"signingKeyPair\"]\n >;\n}\n\nfunction requireSigningContext(\n runtime: InternalWorkflowRuntimeInput,\n): OrganizationSigningContext {\n if (\n !runtime.auth.organizationId ||\n !runtime.auth.userId ||\n !runtime.crypto.signingFingerprint ||\n !runtime.crypto.signingKeyPair\n ) {\n throw new Error(\"Organization signing context is unavailable\");\n }\n\n return {\n organizationId: runtime.auth.organizationId,\n signerUserId: runtime.auth.userId,\n signingFingerprint: runtime.crypto.signingFingerprint,\n signingKeyPair: runtime.crypto.signingKeyPair,\n };\n}\n\nfunction requireEncapsulationKeyPair(\n runtime: InternalWorkflowRuntimeInput,\n): NonNullable<InternalWorkflowRuntimeInput[\"crypto\"][\"encapsulationKeyPair\"]> {\n if (!runtime.crypto.encapsulationKeyPair) {\n throw new Error(\"Organization encryption context is unavailable\");\n }\n\n return runtime.crypto.encapsulationKeyPair;\n}\n\ninterface PrincipalMutationRuntime {\n readonly stillCurrent: () => boolean;\n readonly containerContents: ContainerContents;\n readonly readModelCoordinator: OrganizationReadModelCoordinator;\n readonly runtime: InternalWorkflowRuntimeInput;\n}\n\nexport async function addUserToOrganizationGroup(\n input: PrincipalMutationRuntime & AddOrganizationGroupUserInput,\n) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.groupId,\n objectKind: \"principal\",\n operation: \"group.member.add\",\n organizationId: signingContext.organizationId,\n },\n async () => {\n const mutateCurrent = createCurrentPrincipalMutation({\n ...signingContext,\n runtime: input.runtime,\n stillCurrent: input.stillCurrent,\n });\n if (!mutateCurrent)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n const { memberGroupId, response: bundle } = await mutateCurrent(\n input.groupId,\n {\n kind: \"add\",\n expectedGroupName: input.expectedGroupName,\n targetUserId: input.targetUserId,\n },\n );\n if (input.groupId === memberGroupId) {\n await syncOrganizationMetadataProfile({\n containerContents: input.containerContents,\n log: input.runtime.util.log,\n organizationId: signingContext.organizationId,\n });\n }\n await input.readModelCoordinator.reconcileAfterMutation(\n signingContext.organizationId,\n );\n return bundle;\n },\n );\n}\n\nexport function createGroupForOrganization(input: {\n readonly name: string;\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly stillCurrent: () => boolean;\n}) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: signingContext.organizationId,\n objectKind: \"principal\",\n operation: \"group.create\",\n organizationId: signingContext.organizationId,\n },\n () => {\n const creatorEncapsulationKeyPair = requireEncapsulationKeyPair(\n input.runtime,\n );\n const mutate = createRuntimeCurrentOrganizationMutation(input.runtime);\n if (!mutate)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n return mutate(\n { ...signingContext, stillCurrent: input.stillCurrent },\n (context) =>\n createCurrentOrganizationGroup({\n ...signingContext,\n context,\n apiClient: input.runtime.apiClient,\n creatorEncapsulationKeyPair,\n execSql: input.runtime.infra.execSql,\n name: input.name,\n metadataAccess: createRuntimeGroupMetadataAccess(\n input.runtime,\n signingContext.organizationId,\n context.stillCurrent,\n createSelectedCurrentGroupMetadataContainerVerifier({\n authority: context,\n organizationId: signingContext.organizationId,\n stillCurrent: context.stillCurrent,\n }),\n ),\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n }),\n );\n },\n );\n}\n\nexport function deleteGroupForOrganization(input: {\n readonly groupId: string;\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly stillCurrent: () => boolean;\n}) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.groupId,\n objectKind: \"principal\",\n operation: \"group.delete\",\n organizationId: signingContext.organizationId,\n },\n () => {\n const mutate = createRuntimeCurrentOrganizationMutation(input.runtime);\n if (!mutate)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n return mutate(\n { ...signingContext, stillCurrent: input.stillCurrent },\n (context) =>\n deleteCurrentOrganizationGroup({\n ...signingContext,\n context,\n groupId: input.groupId,\n apiClient: input.runtime.apiClient,\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n }),\n );\n },\n );\n}\n\nexport async function removeUserFromOrganizationGroup(\n input: PrincipalMutationRuntime & RemoveOrganizationGroupUserInput,\n) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.groupId,\n objectKind: \"principal\",\n operation: \"group.member.remove\",\n organizationId: signingContext.organizationId,\n },\n async () => {\n const mutateCurrent = createCurrentPrincipalMutation({\n ...signingContext,\n runtime: input.runtime,\n stillCurrent: input.stillCurrent,\n });\n if (!mutateCurrent)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n const { memberGroupId, response: bundle } = await mutateCurrent(\n input.groupId,\n {\n kind: \"remove\",\n expectedGroupName: input.expectedGroupName,\n removedUserId: input.removedUserId,\n },\n );\n if (input.groupId === memberGroupId) {\n await syncOrganizationMetadataProfile({\n containerContents: input.containerContents,\n log: input.runtime.util.log,\n organizationId: signingContext.organizationId,\n });\n }\n await input.readModelCoordinator.reconcileAfterMutation(\n signingContext.organizationId,\n );\n return bundle;\n },\n );\n}\n\nexport async function revokeOrganizationGrant(\n input: PrincipalMutationRuntime & OrganizationGrantRef,\n) {\n const signingContext = requireSigningContext(input.runtime);\n const encapsulationKeyPair = requireEncapsulationKeyPair(input.runtime);\n if (input.runtime.infra.dbStatus !== \"ready\") {\n throw new Error(\"Organization local database is unavailable\");\n }\n\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.subjectId,\n objectKind: \"principal\",\n operation: \"principal.grant.revoke\",\n organizationId: signingContext.organizationId,\n },\n async () => {\n const revoke = async () => {\n if (input.subjectType === \"group\") {\n const mutateCurrent = createCurrentPrincipalMutation({\n ...signingContext,\n runtime: input.runtime,\n stillCurrent: input.stillCurrent,\n });\n if (!mutateCurrent)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n return (\n await mutateCurrent(input.subjectId, {\n kind: \"revoke\",\n revokedContainerId: input.containerId,\n })\n ).response;\n } else {\n return revokeOrganizationContainerGrant({\n stillCurrent: input.stillCurrent,\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n apiClient: input.runtime.apiClient,\n containerId: input.containerId,\n encapsulationKeyPair,\n execSql: input.runtime.infra.execSql,\n revokedSubject: {\n subjectId: input.subjectId,\n subjectType: input.subjectType,\n },\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.runtime,\n ),\n ...signingContext,\n });\n }\n };\n const response = await revoke();\n await input.readModelCoordinator.reconcileAfterMutation(\n signingContext.organizationId,\n );\n return response;\n },\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"principalMutations.js","sourceRoot":"","sources":["principalMutations.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContainerGrantSubjectType } from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport { revokeOrganizationContainerGrant } from \"../../workflows/organizations\";\nimport { createCurrentOrganizationGroup } from \"../../workflows/organizations/createCurrentOrganizationGroup\";\nimport { createSelectedCurrentGroupMetadataContainerVerifier } from \"../../workflows/organizations/currentGroupMetadataAuthority\";\nimport { deleteCurrentOrganizationGroup } from \"../../workflows/organizations/deleteCurrentOrganizationGroup\";\nimport { createRuntimeGroupMetadataAccess } from \"../../workflows/organizations/groupMetadataRuntime\";\nimport { createRuntimeCurrentOrganizationMutation } from \"../../workflows/organizations/runtimeCurrentOrganizationMutation\";\nimport { createRuntimePrincipalPolicyWarmer } from \"../../workflows/principals/runtimePolicyWarmer\";\nimport type { ContainerContents } from \"../containerContents\";\nimport type { InternalWorkflowRuntimeInput } from \"../workflowRuntime\";\nimport { createCurrentPrincipalMutation } from \"./currentPrincipalMutations\";\nimport { syncOrganizationMetadataProfile } from \"./organizationMetadataProfileSync\";\nimport type { OrganizationReadModelCoordinator } from \"./organizationReadModels\";\n\nexport interface OrganizationGrantRef {\n containerId: string;\n subjectId: string;\n subjectType: ContainerGrantSubjectType;\n}\n\nexport interface OrganizationGroupUserMutationInput {\n groupId: string;\n expectedGroupName: string;\n}\n\nexport interface AddOrganizationGroupUserInput\n extends OrganizationGroupUserMutationInput {\n targetUserId: string;\n}\n\nexport interface RemoveOrganizationGroupUserInput\n extends OrganizationGroupUserMutationInput {\n removedUserId: string;\n}\n\ninterface OrganizationSigningContext {\n organizationId: string;\n signerUserId: string;\n signingFingerprint: string;\n signingKeyPair: NonNullable<\n InternalWorkflowRuntimeInput[\"crypto\"][\"signingKeyPair\"]\n >;\n}\n\nfunction requireSigningContext(\n runtime: InternalWorkflowRuntimeInput,\n): OrganizationSigningContext {\n if (\n !runtime.auth.organizationId ||\n !runtime.auth.userId ||\n !runtime.crypto.signingFingerprint ||\n !runtime.crypto.signingKeyPair\n ) {\n throw new Error(\"Organization signing context is unavailable\");\n }\n\n return {\n organizationId: runtime.auth.organizationId,\n signerUserId: runtime.auth.userId,\n signingFingerprint: runtime.crypto.signingFingerprint,\n signingKeyPair: runtime.crypto.signingKeyPair,\n };\n}\n\nfunction requireEncapsulationKeyPair(\n runtime: InternalWorkflowRuntimeInput,\n): NonNullable<InternalWorkflowRuntimeInput[\"crypto\"][\"encapsulationKeyPair\"]> {\n if (!runtime.crypto.encapsulationKeyPair) {\n throw new Error(\"Organization encryption context is unavailable\");\n }\n\n return runtime.crypto.encapsulationKeyPair;\n}\n\ninterface PrincipalMutationRuntime {\n readonly stillCurrent: () => boolean;\n readonly containerContents: ContainerContents;\n readonly readModelCoordinator: OrganizationReadModelCoordinator;\n readonly runtime: InternalWorkflowRuntimeInput;\n}\n\nexport async function addUserToOrganizationGroup(\n input: PrincipalMutationRuntime & AddOrganizationGroupUserInput,\n) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.groupId,\n objectKind: \"principal\",\n operation: \"group.member.add\",\n organizationId: signingContext.organizationId,\n },\n async () => {\n const mutateCurrent = createCurrentPrincipalMutation({\n ...signingContext,\n runtime: input.runtime,\n stillCurrent: input.stillCurrent,\n });\n if (!mutateCurrent)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n const {\n memberGroupId,\n response: bundle,\n enrolled,\n } = await mutateCurrent(input.groupId, {\n kind: \"add\",\n expectedGroupName: input.expectedGroupName,\n targetUserId: input.targetUserId,\n });\n if (input.groupId === memberGroupId || enrolled) {\n await syncOrganizationMetadataProfile({\n containerContents: input.containerContents,\n log: input.runtime.util.log,\n organizationId: signingContext.organizationId,\n });\n }\n await input.readModelCoordinator.reconcileAfterMutation(\n signingContext.organizationId,\n );\n return bundle;\n },\n );\n}\n\nexport function createGroupForOrganization(input: {\n readonly name: string;\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly stillCurrent: () => boolean;\n}) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: signingContext.organizationId,\n objectKind: \"principal\",\n operation: \"group.create\",\n organizationId: signingContext.organizationId,\n },\n () => {\n const creatorEncapsulationKeyPair = requireEncapsulationKeyPair(\n input.runtime,\n );\n const mutate = createRuntimeCurrentOrganizationMutation(input.runtime);\n if (!mutate)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n return mutate(\n { ...signingContext, stillCurrent: input.stillCurrent },\n (context) =>\n createCurrentOrganizationGroup({\n ...signingContext,\n context,\n apiClient: input.runtime.apiClient,\n creatorEncapsulationKeyPair,\n execSql: input.runtime.infra.execSql,\n name: input.name,\n metadataAccess: createRuntimeGroupMetadataAccess(\n input.runtime,\n signingContext.organizationId,\n context.stillCurrent,\n createSelectedCurrentGroupMetadataContainerVerifier({\n authority: context,\n organizationId: signingContext.organizationId,\n stillCurrent: context.stillCurrent,\n }),\n ),\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n }),\n );\n },\n );\n}\n\nexport function deleteGroupForOrganization(input: {\n readonly groupId: string;\n readonly runtime: InternalWorkflowRuntimeInput;\n readonly stillCurrent: () => boolean;\n}) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.groupId,\n objectKind: \"principal\",\n operation: \"group.delete\",\n organizationId: signingContext.organizationId,\n },\n () => {\n const mutate = createRuntimeCurrentOrganizationMutation(input.runtime);\n if (!mutate)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n return mutate(\n { ...signingContext, stillCurrent: input.stillCurrent },\n (context) =>\n deleteCurrentOrganizationGroup({\n ...signingContext,\n context,\n groupId: input.groupId,\n apiClient: input.runtime.apiClient,\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n }),\n );\n },\n );\n}\n\nexport async function removeUserFromOrganizationGroup(\n input: PrincipalMutationRuntime & RemoveOrganizationGroupUserInput,\n) {\n const signingContext = requireSigningContext(input.runtime);\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.groupId,\n objectKind: \"principal\",\n operation: \"group.member.remove\",\n organizationId: signingContext.organizationId,\n },\n async () => {\n const mutateCurrent = createCurrentPrincipalMutation({\n ...signingContext,\n runtime: input.runtime,\n stillCurrent: input.stillCurrent,\n });\n if (!mutateCurrent)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n const { memberGroupId, response: bundle } = await mutateCurrent(\n input.groupId,\n {\n kind: \"remove\",\n expectedGroupName: input.expectedGroupName,\n removedUserId: input.removedUserId,\n },\n );\n if (input.groupId === memberGroupId) {\n await syncOrganizationMetadataProfile({\n containerContents: input.containerContents,\n log: input.runtime.util.log,\n organizationId: signingContext.organizationId,\n });\n }\n await input.readModelCoordinator.reconcileAfterMutation(\n signingContext.organizationId,\n );\n return bundle;\n },\n );\n}\n\nexport async function revokeOrganizationGrant(\n input: PrincipalMutationRuntime & OrganizationGrantRef,\n) {\n const signingContext = requireSigningContext(input.runtime);\n const encapsulationKeyPair = requireEncapsulationKeyPair(input.runtime);\n if (input.runtime.infra.dbStatus !== \"ready\") {\n throw new Error(\"Organization local database is unavailable\");\n }\n\n return runWithSecurityIncidentReporting(\n input.runtime.util.reportSecurityIncident,\n {\n objectId: input.subjectId,\n objectKind: \"principal\",\n operation: \"principal.grant.revoke\",\n organizationId: signingContext.organizationId,\n },\n async () => {\n const revoke = async () => {\n if (input.subjectType === \"group\") {\n const mutateCurrent = createCurrentPrincipalMutation({\n ...signingContext,\n runtime: input.runtime,\n stillCurrent: input.stillCurrent,\n });\n if (!mutateCurrent)\n throw new ProjectionDependencyUnavailableError(\n \"Principal history recovery is unavailable\",\n );\n return (\n await mutateCurrent(input.subjectId, {\n kind: \"revoke\",\n revokedContainerId: input.containerId,\n })\n ).response;\n } else {\n return revokeOrganizationContainerGrant({\n stillCurrent: input.stillCurrent,\n reportSecurityIncident: input.runtime.util.reportSecurityIncident,\n apiClient: input.runtime.apiClient,\n containerId: input.containerId,\n encapsulationKeyPair,\n execSql: input.runtime.infra.execSql,\n revokedSubject: {\n subjectId: input.subjectId,\n subjectType: input.subjectType,\n },\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n warmReferencedPrincipalPolicies: createRuntimePrincipalPolicyWarmer(\n input.runtime,\n ),\n ...signingContext,\n });\n }\n };\n const response = await revoke();\n await input.readModelCoordinator.reconcileAfterMutation(\n signingContext.organizationId,\n );\n return response;\n },\n );\n}\n"]}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { and, eq } from "drizzle-orm";
|
|
1
|
+
import { and, eq, lte } from "drizzle-orm";
|
|
2
2
|
import { normalizeEffectiveAccessLevel } from "../../../accessLevel.js";
|
|
3
3
|
import { DEFAULT_DOCUMENT_KIND } from "../../../documents/documentConstants.js";
|
|
4
4
|
import { deriveStoredDocumentTitle } from "../../../documents/documentKinds.js";
|
|
5
5
|
import { serializeDocumentSyncPullContinuation } from "../../../documents/shared/pullContinuation.js";
|
|
6
|
-
import { documentRecordSelection, mapSelectedDocumentRecord, } from "../../../sqlite/documentPersistence.js";
|
|
7
6
|
import { documentProjection, documentProjectionText, documents, } from "../../../sqlite/schema.js";
|
|
8
7
|
import { getClientSQLitePersistenceRuntime, } from "../../../sqlite/sqlitePersistenceRuntime.js";
|
|
9
8
|
import { DOCUMENTS_APP_KIND } from "./constants.js";
|
|
@@ -23,15 +22,6 @@ export async function hasDocumentRow(execSql, localId) {
|
|
|
23
22
|
.limit(1);
|
|
24
23
|
return rows.length > 0;
|
|
25
24
|
}
|
|
26
|
-
async function loadDocumentRecordInTransaction(input) {
|
|
27
|
-
const { localId, tx } = input;
|
|
28
|
-
const rows = await tx
|
|
29
|
-
.select(documentRecordSelection)
|
|
30
|
-
.from(documents)
|
|
31
|
-
.where(and(eq(documents.appKind, DOCUMENTS_APP_KIND), eq(documents.localId, localId)))
|
|
32
|
-
.limit(1);
|
|
33
|
-
return rows[0] ? mapSelectedDocumentRecord(rows[0]) : null;
|
|
34
|
-
}
|
|
35
25
|
function toDocumentRecordRow(input) {
|
|
36
26
|
const { document, updatedAt } = input;
|
|
37
27
|
return {
|
|
@@ -113,23 +103,22 @@ export async function createDocumentRowsIfAbsent(input) {
|
|
|
113
103
|
}
|
|
114
104
|
export async function saveDocumentRows(input) {
|
|
115
105
|
const { document, tx, updatedAt } = input;
|
|
116
|
-
const existing = await loadDocumentRecordInTransaction({
|
|
117
|
-
localId: document.id,
|
|
118
|
-
tx,
|
|
119
|
-
});
|
|
120
|
-
if (existing &&
|
|
121
|
-
(existing.recoveryGeneration ?? 0) > (document.recoveryGeneration ?? 0)) {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
106
|
const documentRow = toDocumentRecordRow({ document, updatedAt });
|
|
125
|
-
|
|
107
|
+
// The recovery-generation fence rides on the upsert: a stored row from a
|
|
108
|
+
// newer recovery generation is left untouched and returns no row, so a
|
|
109
|
+
// stale writer skips the projection writes without a separate read.
|
|
110
|
+
const saved = await tx
|
|
126
111
|
.insert(documents)
|
|
127
112
|
.values(documentRow)
|
|
128
113
|
.onConflictDoUpdate({
|
|
129
114
|
target: [documents.appKind, documents.localId],
|
|
130
115
|
set: documentRow,
|
|
116
|
+
setWhere: lte(documents.recoveryGeneration, documentRow.recoveryGeneration),
|
|
131
117
|
})
|
|
132
|
-
.
|
|
118
|
+
.returning({ localId: documents.localId });
|
|
119
|
+
if (saved.length === 0) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
133
122
|
await saveDocumentProjectionRows(input);
|
|
134
123
|
return true;
|
|
135
124
|
}
|
|
@@ -145,29 +134,36 @@ export async function resolveDocumentSaveTimestamp(input) {
|
|
|
145
134
|
if (options?.updatedAt) {
|
|
146
135
|
return options.updatedAt;
|
|
147
136
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
137
|
+
// One read for the stored row and its projection; the projection columns
|
|
138
|
+
// are not nullable, so they are null exactly when the projection is absent.
|
|
139
|
+
const [existing] = await tx
|
|
140
|
+
.select({
|
|
141
|
+
snapshotEndVersion: documents.snapshotEndVersion,
|
|
142
|
+
documentKind: documentProjection.documentKind,
|
|
143
|
+
text: documentProjectionText.text,
|
|
144
|
+
title: documentProjection.title,
|
|
145
|
+
updatedAt: documentProjection.updatedAt,
|
|
146
|
+
})
|
|
147
|
+
.from(documents)
|
|
148
|
+
.leftJoin(documentProjection, eq(documentProjection.localId, documents.localId))
|
|
149
|
+
.leftJoin(documentProjectionText, eq(documentProjectionText.localId, documentProjection.localId))
|
|
150
|
+
.where(and(eq(documents.appKind, DOCUMENTS_APP_KIND), eq(documents.localId, document.id)))
|
|
151
|
+
.limit(1);
|
|
152
|
+
const existingProjection = existing?.documentKind != null &&
|
|
153
|
+
existing.title != null &&
|
|
154
|
+
existing.updatedAt != null
|
|
155
|
+
? {
|
|
156
|
+
documentKind: existing.documentKind,
|
|
157
|
+
text: existing.text,
|
|
158
|
+
title: existing.title,
|
|
159
|
+
updatedAt: existing.updatedAt,
|
|
160
|
+
}
|
|
161
|
+
: undefined;
|
|
166
162
|
const now = new Date().toISOString();
|
|
167
|
-
return didStoredDocumentContentChange(
|
|
163
|
+
return didStoredDocumentContentChange(existing
|
|
168
164
|
? {
|
|
169
165
|
documentKind: getProjectionDocumentKind(existingProjection),
|
|
170
|
-
snapshotEndVersion:
|
|
166
|
+
snapshotEndVersion: existing.snapshotEndVersion,
|
|
171
167
|
text: getProjectionText(existingProjection),
|
|
172
168
|
title: getProjectionTitle(existingProjection),
|
|
173
169
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentRows.js","sourceRoot":"","sources":["documentRows.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq } from \"drizzle-orm\";\nimport { normalizeEffectiveAccessLevel } from \"../../../accessLevel\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../documents/documentConstants\";\nimport { deriveStoredDocumentTitle } from \"../../../documents/documentKinds\";\nimport { serializeDocumentSyncPullContinuation } from \"../../../documents/shared/pullContinuation\";\nimport {\n type DocumentRecord as BaseDocumentRecord,\n type DocumentScope,\n documentRecordSelection,\n mapSelectedDocumentRecord,\n} from \"../../../sqlite/documentPersistence\";\nimport {\n documentProjection,\n documentProjectionText,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport {\n getProjectionDocumentKind,\n getProjectionText,\n getProjectionTitle,\n getProjectionUpdatedAt,\n} from \"./documentProjectionRows\";\n\nexport function getDocumentScope(localId: string): DocumentScope {\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n };\n}\n\nexport async function hasDocumentRow(\n execSql: ExecSql,\n localId: string,\n): Promise<boolean> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, localId),\n ),\n )\n .limit(1);\n return rows.length > 0;\n}\n\nasync function loadDocumentRecordInTransaction(input: {\n localId: string;\n tx: ClientSQLiteTransactionScope;\n}): Promise<BaseDocumentRecord | null> {\n const { localId, tx } = input;\n const rows = await tx\n .select(documentRecordSelection)\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, localId),\n ),\n )\n .limit(1);\n\n return rows[0] ? mapSelectedDocumentRecord(rows[0]) : null;\n}\n\nfunction toDocumentRecordRow(input: {\n document: StoredDocumentRecord;\n updatedAt: string;\n}) {\n const { document, updatedAt } = input;\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId: document.id,\n documentId: document.documentId,\n recoveryGeneration: document.recoveryGeneration ?? 0,\n recoveryDocumentId: document.documentId\n ? null\n : (document.recoveryDocumentId ?? null),\n snapshotEndVersion: document.snapshotEndVersion,\n accessEpoch: document.accessEpoch,\n accessStateHash: document.accessStateHash ?? null,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n document.effectiveAccessLevel,\n ),\n lastCommitLsn: document.lastCommitLsn ?? null,\n documentManifestBundle: document.documentManifestBundle ?? null,\n contentKeyBundle: document.contentKeyBundle ?? null,\n documentKekTargets: document.documentKekTargets ?? null,\n // Only touch the outgoing-delta marker when the caller manages it. Callers\n // that leave it undefined (e.g. discovery upserts, registration bootstrap)\n // must not clobber a marker a device-first deferRemoteSync write persisted.\n ...(document.pendingBaseVersion === undefined\n ? {}\n : { pendingBaseVersion: document.pendingBaseVersion }),\n ...(document.pullContinuation === undefined\n ? {}\n : {\n pullContinuation: serializeDocumentSyncPullContinuation(\n document.pullContinuation,\n ),\n }),\n updatedAt,\n };\n}\n\nasync function saveDocumentProjectionRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const { document, tx, updatedAt } = input;\n const projectionRow = {\n localId: document.id,\n documentId: document.documentId,\n containerId: document.containerId,\n documentKind: document.documentKind ?? DEFAULT_DOCUMENT_KIND,\n title: document.title ?? deriveStoredDocumentTitle(document.text),\n updatedAt,\n };\n await tx\n .insert(documentProjection)\n .values(projectionRow)\n .onConflictDoUpdate({\n target: documentProjection.localId,\n set: projectionRow,\n })\n .run();\n\n const projectionTextRow = {\n localId: document.id,\n text: document.text,\n };\n await tx\n .insert(documentProjectionText)\n .values(projectionTextRow)\n .onConflictDoUpdate({\n target: documentProjectionText.localId,\n set: projectionTextRow,\n })\n .run();\n}\n\nexport async function createDocumentRowsIfAbsent(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n const inserted = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoNothing({\n target: [documents.appKind, documents.localId],\n })\n .returning({ localId: documents.localId });\n if (inserted.length === 0) {\n return false;\n }\n\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nexport async function saveDocumentRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const existing = await loadDocumentRecordInTransaction({\n localId: document.id,\n tx,\n });\n if (\n existing &&\n (existing.recoveryGeneration ?? 0) > (document.recoveryGeneration ?? 0)\n ) {\n return false;\n }\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoUpdate({\n target: [documents.appKind, documents.localId],\n set: documentRow,\n })\n .run();\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nfunction didStoredDocumentContentChange(\n existing: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n > | null,\n next: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n >,\n): boolean {\n return (\n existing === null ||\n existing.documentKind !== (next.documentKind ?? DEFAULT_DOCUMENT_KIND) ||\n existing.snapshotEndVersion !== next.snapshotEndVersion ||\n existing.text !== next.text ||\n existing.title !== (next.title ?? deriveStoredDocumentTitle(next.text))\n );\n}\n\nexport async function resolveDocumentSaveTimestamp(input: {\n document: StoredDocumentRecord;\n options?: { updatedAt?: string } | undefined;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const { document, options, tx } = input;\n if (options?.updatedAt) {\n return options.updatedAt;\n }\n\n const [existingRecord, projectionRows] = await Promise.all([\n loadDocumentRecordInTransaction({\n localId: document.id,\n tx,\n }),\n tx\n .select({\n documentKind: documentProjection.documentKind,\n text: documentProjectionText.text,\n title: documentProjection.title,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documentProjection)\n .leftJoin(\n documentProjectionText,\n eq(documentProjectionText.localId, documentProjection.localId),\n )\n .where(eq(documentProjection.localId, document.id))\n .limit(1),\n ]);\n const existingProjection = projectionRows[0];\n const now = new Date().toISOString();\n return didStoredDocumentContentChange(\n existingRecord\n ? {\n documentKind: getProjectionDocumentKind(existingProjection),\n snapshotEndVersion: existingRecord.snapshotEndVersion,\n text: getProjectionText(existingProjection),\n title: getProjectionTitle(existingProjection),\n }\n : null,\n document,\n )\n ? now\n : getProjectionUpdatedAt(existingProjection) || now;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"documentRows.js","sourceRoot":"","sources":["documentRows.ts"],"names":[],"mappings":"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","sourcesContent":["import { and, eq, lte } from \"drizzle-orm\";\nimport { normalizeEffectiveAccessLevel } from \"../../../accessLevel\";\nimport { DEFAULT_DOCUMENT_KIND } from \"../../../documents/documentConstants\";\nimport { deriveStoredDocumentTitle } from \"../../../documents/documentKinds\";\nimport { serializeDocumentSyncPullContinuation } from \"../../../documents/shared/pullContinuation\";\nimport type { DocumentScope } from \"../../../sqlite/documentPersistence\";\nimport {\n documentProjection,\n documentProjectionText,\n documents,\n} from \"../../../sqlite/schema\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../../../sqlite/sqlitePersistenceRuntime\";\nimport type { ExecSql } from \"../../../sqlite/sqlSchema\";\nimport type { StoredDocumentRecord } from \"../types\";\nimport { DOCUMENTS_APP_KIND } from \"./constants\";\nimport {\n getProjectionDocumentKind,\n getProjectionText,\n getProjectionTitle,\n getProjectionUpdatedAt,\n} from \"./documentProjectionRows\";\n\nexport function getDocumentScope(localId: string): DocumentScope {\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId,\n };\n}\n\nexport async function hasDocumentRow(\n execSql: ExecSql,\n localId: string,\n): Promise<boolean> {\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const rows = await db\n .select({ localId: documents.localId })\n .from(documents)\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, localId),\n ),\n )\n .limit(1);\n return rows.length > 0;\n}\n\nfunction toDocumentRecordRow(input: {\n document: StoredDocumentRecord;\n updatedAt: string;\n}) {\n const { document, updatedAt } = input;\n return {\n appKind: DOCUMENTS_APP_KIND,\n localId: document.id,\n documentId: document.documentId,\n recoveryGeneration: document.recoveryGeneration ?? 0,\n recoveryDocumentId: document.documentId\n ? null\n : (document.recoveryDocumentId ?? null),\n snapshotEndVersion: document.snapshotEndVersion,\n accessEpoch: document.accessEpoch,\n accessStateHash: document.accessStateHash ?? null,\n effectiveAccessLevel: normalizeEffectiveAccessLevel(\n document.effectiveAccessLevel,\n ),\n lastCommitLsn: document.lastCommitLsn ?? null,\n documentManifestBundle: document.documentManifestBundle ?? null,\n contentKeyBundle: document.contentKeyBundle ?? null,\n documentKekTargets: document.documentKekTargets ?? null,\n // Only touch the outgoing-delta marker when the caller manages it. Callers\n // that leave it undefined (e.g. discovery upserts, registration bootstrap)\n // must not clobber a marker a device-first deferRemoteSync write persisted.\n ...(document.pendingBaseVersion === undefined\n ? {}\n : { pendingBaseVersion: document.pendingBaseVersion }),\n ...(document.pullContinuation === undefined\n ? {}\n : {\n pullContinuation: serializeDocumentSyncPullContinuation(\n document.pullContinuation,\n ),\n }),\n updatedAt,\n };\n}\n\nasync function saveDocumentProjectionRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<void> {\n const { document, tx, updatedAt } = input;\n const projectionRow = {\n localId: document.id,\n documentId: document.documentId,\n containerId: document.containerId,\n documentKind: document.documentKind ?? DEFAULT_DOCUMENT_KIND,\n title: document.title ?? deriveStoredDocumentTitle(document.text),\n updatedAt,\n };\n await tx\n .insert(documentProjection)\n .values(projectionRow)\n .onConflictDoUpdate({\n target: documentProjection.localId,\n set: projectionRow,\n })\n .run();\n\n const projectionTextRow = {\n localId: document.id,\n text: document.text,\n };\n await tx\n .insert(documentProjectionText)\n .values(projectionTextRow)\n .onConflictDoUpdate({\n target: documentProjectionText.localId,\n set: projectionTextRow,\n })\n .run();\n}\n\nexport async function createDocumentRowsIfAbsent(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n const inserted = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoNothing({\n target: [documents.appKind, documents.localId],\n })\n .returning({ localId: documents.localId });\n if (inserted.length === 0) {\n return false;\n }\n\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nexport async function saveDocumentRows(input: {\n document: StoredDocumentRecord;\n tx: ClientSQLiteTransactionScope;\n updatedAt: string;\n}): Promise<boolean> {\n const { document, tx, updatedAt } = input;\n const documentRow = toDocumentRecordRow({ document, updatedAt });\n // The recovery-generation fence rides on the upsert: a stored row from a\n // newer recovery generation is left untouched and returns no row, so a\n // stale writer skips the projection writes without a separate read.\n const saved = await tx\n .insert(documents)\n .values(documentRow)\n .onConflictDoUpdate({\n target: [documents.appKind, documents.localId],\n set: documentRow,\n setWhere: lte(\n documents.recoveryGeneration,\n documentRow.recoveryGeneration,\n ),\n })\n .returning({ localId: documents.localId });\n if (saved.length === 0) {\n return false;\n }\n await saveDocumentProjectionRows(input);\n return true;\n}\n\nfunction didStoredDocumentContentChange(\n existing: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n > | null,\n next: Pick<\n StoredDocumentRecord,\n \"documentKind\" | \"snapshotEndVersion\" | \"text\" | \"title\"\n >,\n): boolean {\n return (\n existing === null ||\n existing.documentKind !== (next.documentKind ?? DEFAULT_DOCUMENT_KIND) ||\n existing.snapshotEndVersion !== next.snapshotEndVersion ||\n existing.text !== next.text ||\n existing.title !== (next.title ?? deriveStoredDocumentTitle(next.text))\n );\n}\n\nexport async function resolveDocumentSaveTimestamp(input: {\n document: StoredDocumentRecord;\n options?: { updatedAt?: string } | undefined;\n tx: ClientSQLiteTransactionScope;\n}): Promise<string> {\n const { document, options, tx } = input;\n if (options?.updatedAt) {\n return options.updatedAt;\n }\n\n // One read for the stored row and its projection; the projection columns\n // are not nullable, so they are null exactly when the projection is absent.\n const [existing] = await tx\n .select({\n snapshotEndVersion: documents.snapshotEndVersion,\n documentKind: documentProjection.documentKind,\n text: documentProjectionText.text,\n title: documentProjection.title,\n updatedAt: documentProjection.updatedAt,\n })\n .from(documents)\n .leftJoin(\n documentProjection,\n eq(documentProjection.localId, documents.localId),\n )\n .leftJoin(\n documentProjectionText,\n eq(documentProjectionText.localId, documentProjection.localId),\n )\n .where(\n and(\n eq(documents.appKind, DOCUMENTS_APP_KIND),\n eq(documents.localId, document.id),\n ),\n )\n .limit(1);\n const existingProjection =\n existing?.documentKind != null &&\n existing.title != null &&\n existing.updatedAt != null\n ? {\n documentKind: existing.documentKind,\n text: existing.text,\n title: existing.title,\n updatedAt: existing.updatedAt,\n }\n : undefined;\n const now = new Date().toISOString();\n return didStoredDocumentContentChange(\n existing\n ? {\n documentKind: getProjectionDocumentKind(existingProjection),\n snapshotEndVersion: existing.snapshotEndVersion,\n text: getProjectionText(existingProjection),\n title: getProjectionTitle(existingProjection),\n }\n : null,\n document,\n )\n ? now\n : getProjectionUpdatedAt(existingProjection) || now;\n}\n"]}
|
|
@@ -2,9 +2,12 @@ import { compareCanonicalStrings, KeyingVerificationError, PRINCIPAL_HISTORY_PAG
|
|
|
2
2
|
import { isPrincipalPolicyStateChainEntryResponse, } from "../../internal/validators/response/index.js";
|
|
3
3
|
import { and, eq } from "drizzle-orm";
|
|
4
4
|
import { principalHistoryEntries, principalHistoryEvidenceTables, principalHistoryNodes, } from "../sqlite/principalHistoryEvidenceSchema.js";
|
|
5
|
+
import { sqliteInsertBatchSize } from "../sqlite/sqliteBindBudget.js";
|
|
5
6
|
import { getClientSQLitePersistenceRuntime, } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
7
|
+
import { excludedValue } from "../sqlite/sqliteUpsert.js";
|
|
6
8
|
import { ensureSqlTables } from "../sqlite/sqlSchema.js";
|
|
7
|
-
import {
|
|
9
|
+
import { writePrincipalHistoryNodes } from "./principalHistoryNodeRetention.js";
|
|
10
|
+
const ENTRY_WRITE_BATCH_SIZE = sqliteInsertBatchSize(principalHistoryEntries);
|
|
8
11
|
/** Prepare only a page accepted by the signature/authorization verifier. */
|
|
9
12
|
export async function preparePrincipalHistoryEvidencePage(input) {
|
|
10
13
|
if (input.entries.length > PRINCIPAL_HISTORY_PAGE_ENTRY_LIMIT ||
|
|
@@ -22,32 +25,28 @@ export async function preparePrincipalHistoryEvidencePage(input) {
|
|
|
22
25
|
/** Publish in the same guarded transaction as the accepted page's progress. */
|
|
23
26
|
export async function writePrincipalHistoryEvidencePage(tx, page) {
|
|
24
27
|
const scope = { scopeId: page.scopeId, organizationId: page.organizationId };
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
// A repeated leaf keeps its last entry, as sequential upserts would.
|
|
29
|
+
const entries = new Map(page.entries.map((entry) => [
|
|
30
|
+
entry.leafHash,
|
|
31
|
+
{ ...scope, leafHash: entry.leafHash, entryJson: entry.entryJson },
|
|
32
|
+
]));
|
|
33
|
+
const rows = [...entries.values()].sort((a, b) => compareCanonicalStrings(a.leafHash, b.leafHash));
|
|
34
|
+
for (let index = 0; index < rows.length; index += ENTRY_WRITE_BATCH_SIZE)
|
|
27
35
|
await tx
|
|
28
36
|
.insert(principalHistoryEntries)
|
|
29
|
-
.values(
|
|
37
|
+
.values(rows.slice(index, index + ENTRY_WRITE_BATCH_SIZE))
|
|
30
38
|
.onConflictDoUpdate({
|
|
31
39
|
target: [
|
|
32
40
|
principalHistoryEntries.scopeId,
|
|
33
41
|
principalHistoryEntries.leafHash,
|
|
34
42
|
],
|
|
35
|
-
set:
|
|
43
|
+
set: {
|
|
44
|
+
organizationId: excludedValue(principalHistoryEntries.organizationId),
|
|
45
|
+
entryJson: excludedValue(principalHistoryEntries.entryJson),
|
|
46
|
+
},
|
|
36
47
|
})
|
|
37
48
|
.run();
|
|
38
|
-
|
|
39
|
-
for (const node of [...page.nodes].sort((a, b) => compareCanonicalStrings(a.hash, b.hash))) {
|
|
40
|
-
await recordPrincipalHistoryNodeEdges(tx, scope, node);
|
|
41
|
-
const row = { ...scope, ...node };
|
|
42
|
-
await tx
|
|
43
|
-
.insert(principalHistoryNodes)
|
|
44
|
-
.values(row)
|
|
45
|
-
.onConflictDoUpdate({
|
|
46
|
-
target: [principalHistoryNodes.scopeId, principalHistoryNodes.hash],
|
|
47
|
-
set: row,
|
|
48
|
-
})
|
|
49
|
-
.run();
|
|
50
|
-
}
|
|
49
|
+
await writePrincipalHistoryNodes(tx, scope, [...page.nodes].sort((a, b) => compareCanonicalStrings(a.hash, b.hash)));
|
|
51
50
|
}
|
|
52
51
|
/** Returns untrusted material. The caller must verify it against the issued root. */
|
|
53
52
|
export async function loadPrincipalHistoryReference(input) {
|
|
@@ -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\";\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"]}
|
|
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 { sqliteInsertBatchSize } from \"../sqlite/sqliteBindBudget\";\nimport {\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlite/sqlitePersistenceRuntime\";\nimport { excludedValue } from \"../sqlite/sqliteUpsert\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport { writePrincipalHistoryNodes } from \"./principalHistoryNodeRetention\";\n\nconst ENTRY_WRITE_BATCH_SIZE = sqliteInsertBatchSize(principalHistoryEntries);\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 // A repeated leaf keeps its last entry, as sequential upserts would.\n const entries = new Map(\n page.entries.map((entry) => [\n entry.leafHash,\n { ...scope, leafHash: entry.leafHash, entryJson: entry.entryJson },\n ]),\n );\n const rows = [...entries.values()].sort((a, b) =>\n compareCanonicalStrings(a.leafHash, b.leafHash),\n );\n for (let index = 0; index < rows.length; index += ENTRY_WRITE_BATCH_SIZE)\n await tx\n .insert(principalHistoryEntries)\n .values(rows.slice(index, index + ENTRY_WRITE_BATCH_SIZE))\n .onConflictDoUpdate({\n target: [\n principalHistoryEntries.scopeId,\n principalHistoryEntries.leafHash,\n ],\n set: {\n organizationId: excludedValue(principalHistoryEntries.organizationId),\n entryJson: excludedValue(principalHistoryEntries.entryJson),\n },\n })\n .run();\n await writePrincipalHistoryNodes(\n tx,\n scope,\n [...page.nodes].sort((a, b) => compareCanonicalStrings(a.hash, b.hash)),\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"]}
|