Fix team-mode first-run: /setup no longer bounces to /sign-in
- _auth.setup.tsx: the "owner already exists?" check ran in beforeLoad, which executes during SSR where fetchTeamSetupStatus's relative fetch to /api/team-setup fails — so it always concluded an owner existed and redirected to /sign-in, making the create-owner screen unreachable. Move the check into a client-side effect with a loading state. - setup-status.ts: add BETTER_AUTH_URL to CHECK_ENV_VARS so /api/health stops falsely reporting "team mode requires BETTER_AUTH_URL" when it is set (the Docker preflight already saw it; only the runtime health check's env allowlist was missing it). Verified locally end to end against a D1 build in AUTH_MODE=team: owner bootstrap, self-disable + 409 on repeat, Better Auth sign-in issues a session cookie, and get-session resolves the shared organization. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
acc35c055c
commit
29bda614a4
@ -1,5 +1,5 @@
|
||||
import { createFileRoute, redirect, useNavigate } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AuthPageCard } from "@/client/features/auth/AuthPage";
|
||||
import {
|
||||
bootstrapTeamOwner,
|
||||
@ -7,27 +7,38 @@ import {
|
||||
} from "@/client/features/auth/teamSetup";
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
|
||||
// First-run screen for `team` mode: creates the single owner account. It
|
||||
// redirects to /sign-in the moment an owner exists, so it can't be used to add
|
||||
// more users.
|
||||
// First-run screen for `team` mode: creates the single owner account. The
|
||||
// "already has an owner?" check runs client-side (it needs a DB round trip via
|
||||
// /api/team-setup, which a server-side beforeLoad can't reach with a relative
|
||||
// URL) and redirects to /sign-in once an owner exists.
|
||||
export const Route = createFileRoute("/_auth/setup")({
|
||||
beforeLoad: async () => {
|
||||
const status = await fetchTeamSetupStatus();
|
||||
if (!status.needsOwner) {
|
||||
throw redirect({ to: "/sign-in", search: {} });
|
||||
}
|
||||
},
|
||||
component: SetupPage,
|
||||
});
|
||||
|
||||
function SetupPage() {
|
||||
const navigate = useNavigate();
|
||||
const [checking, setChecking] = useState(true);
|
||||
const [name, setName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
void fetchTeamSetupStatus().then((status) => {
|
||||
if (cancelled) return;
|
||||
if (!status.needsOwner) {
|
||||
void navigate({ to: "/sign-in", search: {} });
|
||||
return;
|
||||
}
|
||||
setChecking(false);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [navigate]);
|
||||
|
||||
async function handleSubmit(event: React.FormEvent) {
|
||||
event.preventDefault();
|
||||
setError(null);
|
||||
@ -57,6 +68,14 @@ function SetupPage() {
|
||||
}
|
||||
}
|
||||
|
||||
if (checking) {
|
||||
return (
|
||||
<div className="flex justify-center py-10">
|
||||
<span className="loading loading-spinner loading-md" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthPageCard
|
||||
title="Create the owner account"
|
||||
|
||||
@ -27,6 +27,7 @@ const CHECK_ENV_VARS = [
|
||||
"DATAFORSEO_API_KEY",
|
||||
"GOOGLE_CLIENT_ID",
|
||||
"GOOGLE_CLIENT_SECRET",
|
||||
"BETTER_AUTH_URL",
|
||||
"BETTER_AUTH_SECRET",
|
||||
"OPENROUTER_API_KEY",
|
||||
] as const;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user