refactor(server): replace AppContext undefined sentinels with Feature<T>

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019e5550-4435-7118-8393-cdcc97042178
This commit is contained in:
Aarnav Tale
2026-05-23 16:32:22 -04:00
parent fb4b0b1404
commit d4eee702e9
25 changed files with 253 additions and 124 deletions
+7 -2
View File
@@ -24,7 +24,7 @@ export async function loader({ request, context }: Route.LoaderArgs) {
const qp = new URL(request.url).searchParams;
const urlState = qp.get("s") ?? undefined;
const oidcService = context.oidc?.service;
const oidcService = context.oidc.state === "enabled" ? context.oidc.value : undefined;
const oidcStatus = oidcService
? await oidcService.discover().then(
(r) => (r.ok ? oidcService.status() : oidcService.status()),
@@ -32,7 +32,12 @@ export async function loader({ request, context }: Route.LoaderArgs) {
)
: undefined;
if (context.oidc?.disableApiKeyLogin && oidcStatus?.state === "ready" && urlState !== "logout") {
if (
oidcService &&
context.config.oidc?.disable_api_key_login &&
oidcStatus?.state === "ready" &&
urlState !== "logout"
) {
return redirect("/oidc/start");
}
+9 -4
View File
@@ -23,15 +23,20 @@ export async function action({ request, context }: ActionFunctionArgs<AppContext
// ended. Disabled by default because the post_logout_redirect_uri must be
// pre-registered on the IdP — turning this on without registering it would
// strand users on the IdP's error page.
if (principal?.kind === "oidc" && context.oidc?.useEndSession && context.oidc.service) {
const status = context.oidc.service.status();
if (
principal?.kind === "oidc" &&
context.oidc.state === "enabled" &&
context.config.oidc?.use_end_session
) {
const service = context.oidc.value;
const status = service.status();
if (status.state !== "ready") {
// Trigger discovery if it hasn't happened yet so we can find the
// end_session_endpoint without forcing a re-login.
await context.oidc.service.discover();
await service.discover();
}
const endSessionUrl = context.oidc.service.buildEndSessionUrl(principal.idToken);
const endSessionUrl = service.buildEndSessionUrl(principal.idToken);
if (endSessionUrl) {
url = endSessionUrl;
}
+4 -4
View File
@@ -7,10 +7,10 @@ import { createOidcStateCookie } from "~/utils/oidc-state";
import type { Route } from "./+types/oidc-callback";
export async function loader({ request, context }: Route.LoaderArgs) {
const service = context.oidc?.service;
if (!service) {
throw data("OIDC is not enabled or misconfigured", { status: 501 });
if (context.oidc.state !== "enabled") {
throw data(`OIDC is unavailable: ${context.oidc.reason}`, { status: 501 });
}
const service = context.oidc.value;
const url = new URL(request.url);
if (url.searchParams.toString().length === 0) {
@@ -68,7 +68,7 @@ export async function loader({ request, context }: Route.LoaderArgs) {
// Only persist the id_token when RP-initiated logout is enabled — otherwise
// we'd be storing a credential we never use.
const idToken = context.oidc?.useEndSession ? identity.idToken : undefined;
const idToken = context.config.oidc?.use_end_session ? identity.idToken : undefined;
return redirect("/", {
headers: {
+3 -3
View File
@@ -10,10 +10,10 @@ export async function loader({ request, context }: Route.LoaderArgs) {
return redirect("/");
} catch {}
const service = context.oidc?.service;
if (!service) {
throw data("OIDC is not enabled or misconfigured", { status: 501 });
if (context.oidc.state !== "enabled") {
throw data(`OIDC is unavailable: ${context.oidc.reason}`, { status: 501 });
}
const service = context.oidc.value;
const result = await service.startFlow();
if (!result.ok) {