Skip to content

Commit 6c7e41c

Browse files
committed
Final fixes
1 parent ba88e99 commit 6c7e41c

14 files changed

Lines changed: 815 additions & 116 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { resetBranchConfigOverrideKeys, resetEnvironmentConfigOverrideKeys } from "@/lib/config";
2+
import { createSmartRouteHandler } from "@/route-handlers/smart-route-handler";
3+
import { adaptSchema, adminAuthTypeSchema, yupArray, yupNumber, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
4+
5+
const levelSchema = yupString().oneOf(["branch", "environment"]).defined();
6+
7+
const levelConfigs = {
8+
branch: {
9+
reset: (options: { projectId: string, branchId: string, keysToReset: string[] }) =>
10+
resetBranchConfigOverrideKeys(options),
11+
},
12+
environment: {
13+
reset: (options: { projectId: string, branchId: string, keysToReset: string[] }) =>
14+
resetEnvironmentConfigOverrideKeys(options),
15+
},
16+
};
17+
18+
export const POST = createSmartRouteHandler({
19+
metadata: {
20+
hidden: true,
21+
summary: 'Reset config override keys',
22+
description: 'Remove specific keys (and their nested descendants) from the config override at a given level. Uses the same nested key logic as the override algorithm.',
23+
tags: ['Config'],
24+
},
25+
request: yupObject({
26+
auth: yupObject({
27+
type: adminAuthTypeSchema,
28+
tenancy: adaptSchema,
29+
}).defined(),
30+
params: yupObject({
31+
level: levelSchema,
32+
}).defined(),
33+
body: yupObject({
34+
keys: yupArray(yupString().defined()).defined(),
35+
}).defined(),
36+
}),
37+
response: yupObject({
38+
statusCode: yupNumber().oneOf([200]).defined(),
39+
bodyType: yupString().oneOf(["success"]).defined(),
40+
}),
41+
handler: async (req) => {
42+
const levelConfig = levelConfigs[req.params.level];
43+
44+
await levelConfig.reset({
45+
projectId: req.auth.tenancy.project.id,
46+
branchId: req.auth.tenancy.branchId,
47+
keysToReset: req.body.keys,
48+
});
49+
50+
return {
51+
statusCode: 200 as const,
52+
bodyType: "success" as const,
53+
};
54+
},
55+
});

apps/backend/src/lib/config.tsx

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Prisma } from "@/generated/prisma/client";
2-
import { Config, getInvalidConfigReason, normalize, override } from "@stackframe/stack-shared/dist/config/format";
2+
import { Config, getInvalidConfigReason, normalize, override, removeKeysFromConfig } from "@stackframe/stack-shared/dist/config/format";
33
import { BranchConfigOverride, BranchConfigOverrideOverride, BranchIncompleteConfig, BranchRenderedConfig, CompleteConfig, EnvironmentConfigOverride, EnvironmentConfigOverrideOverride, EnvironmentIncompleteConfig, EnvironmentRenderedConfig, OrganizationConfigOverride, OrganizationConfigOverrideOverride, OrganizationIncompleteConfig, ProjectConfigOverride, ProjectConfigOverrideOverride, ProjectIncompleteConfig, ProjectRenderedConfig, applyBranchDefaults, applyEnvironmentDefaults, applyOrganizationDefaults, applyProjectDefaults, assertNoConfigOverrideErrors, branchConfigSchema, environmentConfigSchema, getConfigOverrideErrors, getIncompleteConfigWarnings, migrateConfigOverride, organizationConfigSchema, projectConfigSchema, sanitizeBranchConfig, sanitizeEnvironmentConfig, sanitizeOrganizationConfig, sanitizeProjectConfig } from "@stackframe/stack-shared/dist/config/schema";
44
import { ProjectsCrud } from "@stackframe/stack-shared/dist/interface/crud/projects";
55
import { branchConfigSourceSchema, yupBoolean, yupMixed, yupObject, yupRecord, yupString, yupUnion } from "@stackframe/stack-shared/dist/schema-fields";
@@ -457,6 +457,75 @@ export function overrideOrganizationConfigOverride(options: {
457457
}
458458

459459

460+
// ---------------------------------------------------------------------------------------------------------------------
461+
// reset functions (remove specific keys from config override)
462+
// ---------------------------------------------------------------------------------------------------------------------
463+
// Uses the same nested key logic as the `override` function: resetting key "a.b" also resets "a.b.c".
464+
465+
export async function resetProjectConfigOverrideKeys(options: {
466+
projectId: string,
467+
keysToReset: string[],
468+
}): Promise<void> {
469+
// TODO put this in a serializable transaction (or a single SQL query) to prevent race conditions
470+
const oldConfig = await rawQuery(globalPrismaClient, getProjectConfigOverrideQuery(options));
471+
const newConfig = removeKeysFromConfig(oldConfig, options.keysToReset);
472+
473+
await setProjectConfigOverride({
474+
projectId: options.projectId,
475+
projectConfigOverride: newConfig as ProjectConfigOverride,
476+
});
477+
}
478+
479+
export async function resetBranchConfigOverrideKeys(options: {
480+
projectId: string,
481+
branchId: string,
482+
keysToReset: string[],
483+
}): Promise<void> {
484+
// TODO put this in a serializable transaction (or a single SQL query) to prevent race conditions
485+
const oldConfig = await rawQuery(globalPrismaClient, getBranchConfigOverrideQuery(options));
486+
const newConfig = removeKeysFromConfig(oldConfig, options.keysToReset);
487+
488+
await setBranchConfigOverride({
489+
projectId: options.projectId,
490+
branchId: options.branchId,
491+
branchConfigOverride: newConfig as BranchConfigOverride,
492+
});
493+
}
494+
495+
export async function resetEnvironmentConfigOverrideKeys(options: {
496+
projectId: string,
497+
branchId: string,
498+
keysToReset: string[],
499+
}): Promise<void> {
500+
// TODO put this in a serializable transaction (or a single SQL query) to prevent race conditions
501+
const oldConfig = await rawQuery(globalPrismaClient, getEnvironmentConfigOverrideQuery(options));
502+
const newConfig = removeKeysFromConfig(oldConfig, options.keysToReset);
503+
504+
await setEnvironmentConfigOverride({
505+
projectId: options.projectId,
506+
branchId: options.branchId,
507+
environmentConfigOverride: newConfig as EnvironmentConfigOverride,
508+
});
509+
}
510+
511+
export async function resetOrganizationConfigOverrideKeys(options: {
512+
projectId: string,
513+
branchId: string,
514+
organizationId: string | null,
515+
keysToReset: string[],
516+
}): Promise<void> {
517+
// TODO put this in a serializable transaction (or a single SQL query) to prevent race conditions
518+
const oldConfig = await rawQuery(globalPrismaClient, getOrganizationConfigOverrideQuery(options));
519+
const newConfig = removeKeysFromConfig(oldConfig, options.keysToReset);
520+
521+
await setOrganizationConfigOverride({
522+
projectId: options.projectId,
523+
branchId: options.branchId,
524+
organizationId: options.organizationId,
525+
organizationConfigOverride: newConfig as OrganizationConfigOverride,
526+
});
527+
}
528+
460529
// ---------------------------------------------------------------------------------------------------------------------
461530
// internal functions
462531
// ---------------------------------------------------------------------------------------------------------------------

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/auth-methods/page-client.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { allProviders } from "@stackframe/stack-shared/dist/utils/oauth";
1313
import { typedFromEntries } from "@stackframe/stack-shared/dist/utils/objects";
1414
import { generateUuid } from "@stackframe/stack-shared/dist/utils/uuids";
1515
import { useMemo, useState } from "react";
16-
import { CardSubtitle } from "../../../../../../../../../packages/stack-ui/dist/components/ui/card";
1716
import { AppEnabledGuard } from "../app-enabled-guard";
1817
import { PageLayout } from "../page-layout";
1918
import { useAdminApp } from "../use-admin-app";
@@ -434,9 +433,9 @@ export default function PageClient() {
434433
onSave={handleAuthMethodsSave}
435434
onDiscard={handleAuthMethodsDiscard}
436435
/>
437-
<CardSubtitle className="mt-2">
436+
<Typography variant="secondary" className="mt-2">
438437
SSO Providers
439-
</CardSubtitle>
438+
</Typography>
440439

441440
{enabledProviders.map(([, provider]) => provider)
442441
.filter((provider): provider is AdminOAuthProviderConfig => !!provider).map(provider => {

0 commit comments

Comments
 (0)