104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import type { Context } from "@wrnexus/core";
|
|
import type { AuthEngine } from "./engine.ts";
|
|
import type { AuthPasskeyHttpOptions } from "./http/index.ts";
|
|
import type { AuthSessionVerificationHandler } from "./types.ts";
|
|
import { resolveAuthSchemas, type AuthSchemaOverrides, type AuthSchemaSet } from "./validation.ts";
|
|
|
|
export interface DefaultAuthRouteOptions {
|
|
baseUrl?: string;
|
|
csrf?: boolean;
|
|
passkey?: AuthPasskeyHttpOptions;
|
|
|
|
onSignedIn?: (ctx: Context, returnTo?: string) => Response | Promise<Response>;
|
|
|
|
onSignedOut?: (ctx: Context) => Response | Promise<Response>;
|
|
sessionCookieName?: string;
|
|
onSessionVerification?: AuthSessionVerificationHandler;
|
|
}
|
|
|
|
interface AuthRuntimeState {
|
|
engine?: AuthEngine;
|
|
schemas: AuthSchemaSet;
|
|
routeOptions: DefaultAuthRouteOptions;
|
|
}
|
|
|
|
/**
|
|
* A Symbol.for registry is used instead of module-local variables.
|
|
*
|
|
* The dev server may import the auth plugin and route modules using
|
|
* different module URLs during HMR. Those modules still execute inside
|
|
* the same JavaScript global realm, so Symbol.for keeps the runtime
|
|
* configuration shared between them.
|
|
*/
|
|
const AUTH_RUNTIME_STATE_KEY = Symbol.for("@wrnexus/auth:runtime-state:v1");
|
|
|
|
function runtimeState(): AuthRuntimeState {
|
|
const registry = globalThis as unknown as Record<PropertyKey, unknown>;
|
|
|
|
const existing = registry[AUTH_RUNTIME_STATE_KEY] as AuthRuntimeState | undefined;
|
|
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
|
|
const created: AuthRuntimeState = {
|
|
schemas: resolveAuthSchemas(),
|
|
routeOptions: {},
|
|
};
|
|
|
|
registry[AUTH_RUNTIME_STATE_KEY] = created;
|
|
|
|
return created;
|
|
}
|
|
|
|
export function setDefaultAuthEngine(engine: AuthEngine): void {
|
|
runtimeState().engine = engine;
|
|
}
|
|
|
|
/**
|
|
* Clear auth state when an application removes config.auth.engine
|
|
* during development or when another application starts in the
|
|
* same process.
|
|
*/
|
|
export function clearDefaultAuthEngine(): void {
|
|
delete runtimeState().engine;
|
|
}
|
|
|
|
export function setDefaultAuthSchemas(schemas: AuthSchemaOverrides | AuthSchemaSet = {}): void {
|
|
runtimeState().schemas = resolveAuthSchemas(schemas);
|
|
}
|
|
|
|
export function setDefaultAuthRouteOptions(options: DefaultAuthRouteOptions = {}): void {
|
|
runtimeState().routeOptions = {
|
|
...options,
|
|
};
|
|
}
|
|
|
|
export function tryGetDefaultAuthEngine(): AuthEngine | undefined {
|
|
return runtimeState().engine;
|
|
}
|
|
|
|
export function getDefaultAuthEngine(): AuthEngine {
|
|
const engine = runtimeState().engine;
|
|
|
|
if (!engine) {
|
|
throw new Error(
|
|
"WRN-AUTH-NOT-CONFIGURED: configure auth.engine or call setDefaultAuthEngine(createAuthEngine(...)) at startup",
|
|
);
|
|
}
|
|
|
|
return engine;
|
|
}
|
|
|
|
export function getDefaultAuthSchemas(): AuthSchemaSet {
|
|
return runtimeState().schemas;
|
|
}
|
|
|
|
export function getDefaultAuthRouteOptions(): DefaultAuthRouteOptions {
|
|
return runtimeState().routeOptions;
|
|
}
|
|
|
|
export function hasDefaultAuthEngine(): boolean {
|
|
return Boolean(runtimeState().engine);
|
|
}
|