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 { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { AuthPageCard } from "@/client/features/auth/AuthPage";
|
import { AuthPageCard } from "@/client/features/auth/AuthPage";
|
||||||
import {
|
import {
|
||||||
bootstrapTeamOwner,
|
bootstrapTeamOwner,
|
||||||
@ -7,27 +7,38 @@ import {
|
|||||||
} from "@/client/features/auth/teamSetup";
|
} from "@/client/features/auth/teamSetup";
|
||||||
import { authClient } from "@/lib/auth-client";
|
import { authClient } from "@/lib/auth-client";
|
||||||
|
|
||||||
// First-run screen for `team` mode: creates the single owner account. It
|
// First-run screen for `team` mode: creates the single owner account. The
|
||||||
// redirects to /sign-in the moment an owner exists, so it can't be used to add
|
// "already has an owner?" check runs client-side (it needs a DB round trip via
|
||||||
// more users.
|
// /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")({
|
export const Route = createFileRoute("/_auth/setup")({
|
||||||
beforeLoad: async () => {
|
|
||||||
const status = await fetchTeamSetupStatus();
|
|
||||||
if (!status.needsOwner) {
|
|
||||||
throw redirect({ to: "/sign-in", search: {} });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
component: SetupPage,
|
component: SetupPage,
|
||||||
});
|
});
|
||||||
|
|
||||||
function SetupPage() {
|
function SetupPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [checking, setChecking] = useState(true);
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
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) {
|
async function handleSubmit(event: React.FormEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setError(null);
|
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 (
|
return (
|
||||||
<AuthPageCard
|
<AuthPageCard
|
||||||
title="Create the owner account"
|
title="Create the owner account"
|
||||||
|
|||||||
@ -27,6 +27,7 @@ const CHECK_ENV_VARS = [
|
|||||||
"DATAFORSEO_API_KEY",
|
"DATAFORSEO_API_KEY",
|
||||||
"GOOGLE_CLIENT_ID",
|
"GOOGLE_CLIENT_ID",
|
||||||
"GOOGLE_CLIENT_SECRET",
|
"GOOGLE_CLIENT_SECRET",
|
||||||
|
"BETTER_AUTH_URL",
|
||||||
"BETTER_AUTH_SECRET",
|
"BETTER_AUTH_SECRET",
|
||||||
"OPENROUTER_API_KEY",
|
"OPENROUTER_API_KEY",
|
||||||
] as const;
|
] as const;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user