diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth/urls-and-callbacks/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth/urls-and-callbacks/page-client.tsx
index bc7a0ebe1..24f1d173f 100644
--- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth/urls-and-callbacks/page-client.tsx
+++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/auth/urls-and-callbacks/page-client.tsx
@@ -1,6 +1,6 @@
"use client";
-import { IconButton, List, ListItem, ListDivider, Input, FormControl, FormLabel } from "@mui/joy";
+import { IconButton, List, ListItem, ListDivider, Input, FormControl, FormLabel, Checkbox, Typography, Box } from "@mui/joy";
import React, { use, useState } from "react";
import { Paragraph } from "@/components/paragraph";
import { Icon } from "@/components/icon";
@@ -9,6 +9,7 @@ import { AsyncButton } from "@/components/async-button";
import { useStrictMemo } from "@stackframe/stack-shared/src/hooks/use-strict-memo";
import { SimpleCard } from "@/components/simple-card";
import { useAdminApp } from "../../useAdminInterface";
+import { SmartSwitch } from "@/components/smart-switch";
export default function UrlsAndCallbacksClient() {
const stackAdminApp = useAdminApp();
@@ -32,47 +33,59 @@ export default function UrlsAndCallbacksClient() {
return (
<>
-
- Domains and Handler
-
+
+
+ {
+ await stackAdminApp.updateProject({
+ config: {
+ allowLocalhost: event.target.checked,
+ },
+ });
+ setInvalidationCounter(invalidationCounter + 1);
+ }}
+ >
+ Allow all localhost callbacks for development
+
+
-
-
- Please put in a list of your domains that you control and run the handler on.
-
+ {domains.size >= 0 || (
+
+ {[...domains].map(({ domain }, i) => (
+
+ {i !== 0 && }
+ setDeleteDialogDomain(domain)}
+ >
+
+
+ }
+ >
+ {domain}
+
+
+ ))}
+
+ )}
-
- {[...domains].map(({ domain }, i) => (
-
- {i !== 0 && }
- setDeleteDialogDomain(domain)}
- >
-
-
- }
- >
- {domain}
-
-
- ))}
-
setAddNewDialogOpen(true)}
- variant="plain"
+ variant="soft"
color="neutral"
+ sx={{ mt: 3 }}
>
- Add new prefix
+ Add new domain
diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/environment/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/environment/page-client.tsx
index b15fcb538..8d56d727b 100644
--- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/environment/page-client.tsx
+++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/settings/environment/page-client.tsx
@@ -56,7 +56,7 @@ export default function EnvironmentClient() {
}}
>
- Enable production mode
+ Enable production mode
diff --git a/packages/stack-server/src/app/api/v1/projects/[projectId]/route.tsx b/packages/stack-server/src/app/api/v1/projects/[projectId]/route.tsx
index 0d54db0fd..0053e0b9e 100644
--- a/packages/stack-server/src/app/api/v1/projects/[projectId]/route.tsx
+++ b/packages/stack-server/src/app/api/v1/projects/[projectId]/route.tsx
@@ -34,6 +34,7 @@ const putOrGetSchema = yup.object({
})
).optional(),
credentialEnabled: yup.boolean().optional(),
+ allowLocalhost: yup.boolean().optional(),
}).optional(),
}).nullable(),
});
@@ -47,7 +48,7 @@ const handler = smartRouteHandler(async (req: NextRequest, options: { params: {
"x-stack-admin-access-token": adminAccessToken,
},
body,
- } = await parseRequest(req, putOrGetSchema);
+ } = await parseRequest(req, putOrGetSchema);
const { showDisabledOauth, ...update } = body ?? {};
@@ -59,6 +60,8 @@ const handler = smartRouteHandler(async (req: NextRequest, options: { params: {
isProductionMode: update.isProductionMode,
config: update.config && {
domains: update.config.domains,
+ allowLocalhost: update.config.allowLocalhost,
+ credentialEnabled: update.config.credentialEnabled,
oauthProviders: update.config.oauthProviders && update.config.oauthProviders.map((provider) => {
if (sharedProviders.includes(provider.type as SharedProvider)) {
return {
@@ -86,7 +89,6 @@ const handler = smartRouteHandler(async (req: NextRequest, options: { params: {
throw new StatusError(StatusError.BadRequest, "Invalid oauth provider type");
}
}),
- credentialEnabled: update.config.credentialEnabled,
},
};
diff --git a/packages/stack-server/src/lib/projects.tsx b/packages/stack-server/src/lib/projects.tsx
index 66fb46185..c1acdee05 100644
--- a/packages/stack-server/src/lib/projects.tsx
+++ b/packages/stack-server/src/lib/projects.tsx
@@ -358,14 +358,22 @@ export async function updateProject(
}
}
+ // Update credentialEnabled
if (options.config?.credentialEnabled !== undefined) {
- // Update credentialEnabled
transaction.push(prismaClient.projectConfig.update({
where: { id: project.config.id },
data: { credentialEnabled: options.config.credentialEnabled },
}));
}
+ // Update allowLocalhost
+ if (options.config?.allowLocalhost !== undefined) {
+ transaction.push(prismaClient.projectConfig.update({
+ where: { id: project.config.id },
+ data: { allowLocalhost: options.config.allowLocalhost },
+ }));
+ }
+
if (options.isProductionMode !== undefined) {
// Update production mode
transaction.push(prismaClient.project.update({
diff --git a/packages/stack-shared/src/interface/adminInterface.ts b/packages/stack-shared/src/interface/adminInterface.ts
index 5d67b1e20..0bf34f67e 100644
--- a/packages/stack-shared/src/interface/adminInterface.ts
+++ b/packages/stack-shared/src/interface/adminInterface.ts
@@ -39,6 +39,7 @@ export type ProjectUpdateOptions = Readonly<{
}[],
oauthProviders?: OauthProviderUpdateOptions[],
credentialEnabled?: boolean,
+ allowLocalhost?: boolean,
},
}>
@@ -131,7 +132,7 @@ export class StackAdminInterface extends StackServerInterface {
headers: {
"content-type": "application/json",
},
- body: JSON.stringify(options || {}),
+ body: JSON.stringify(options ?? {}),
},
null,
);