release: WRNexusJS 0.8.0
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import type { Context } from "@wrnexus/core";
|
||||
import type { AuthEngine } from "./engine.ts";
|
||||
import type { AuthSession, AuthUser } from "./types.ts";
|
||||
|
||||
export type AuthRouteName =
|
||||
| "signIn"
|
||||
| "signUp"
|
||||
| "signOut"
|
||||
| "forgotPassword"
|
||||
| "resetPassword"
|
||||
| "verifyEmail"
|
||||
| "verifyPhone"
|
||||
| "twoFactor"
|
||||
| "sessions"
|
||||
| "passkeys";
|
||||
|
||||
const DEFAULT_AUTH_ROUTES: Record<AuthRouteName, string> = {
|
||||
signIn: "/sign-in",
|
||||
signUp: "/sign-up",
|
||||
signOut: "/api/auth/logout",
|
||||
forgotPassword: "/forgot-password",
|
||||
resetPassword: "/reset-password",
|
||||
verifyEmail: "/verify-email",
|
||||
verifyPhone: "/verify-phone",
|
||||
twoFactor: "/two-factor",
|
||||
sessions: "/account/sessions",
|
||||
passkeys: "/account/passkeys",
|
||||
};
|
||||
|
||||
export function authRoute(
|
||||
name: AuthRouteName,
|
||||
options: { basePath?: string; overrides?: Partial<Record<AuthRouteName, string>> } = {},
|
||||
): string {
|
||||
const route = options.overrides?.[name] ?? DEFAULT_AUTH_ROUTES[name];
|
||||
if (!options.basePath || route.startsWith("http://") || route.startsWith("https://"))
|
||||
return route;
|
||||
return `${options.basePath.replace(/\/$/, "")}/${route.replace(/^\//, "")}`;
|
||||
}
|
||||
|
||||
export function authSuccess<T extends Record<string, unknown>>(
|
||||
data: T,
|
||||
init: ResponseInit = {},
|
||||
): Response {
|
||||
return Response.json({ ok: true, ...data }, { status: init.status ?? 200, ...init });
|
||||
}
|
||||
|
||||
export function authFailure(
|
||||
code: string,
|
||||
message: string,
|
||||
status = 400,
|
||||
details?: Record<string, unknown>,
|
||||
): Response {
|
||||
return Response.json(
|
||||
{ ok: false, error: { code, message, ...(details ? { details } : {}) } },
|
||||
{ status },
|
||||
);
|
||||
}
|
||||
|
||||
export function requireAuthUser(ctx: Context): AuthUser {
|
||||
if (!ctx.user || typeof ctx.user !== "object") {
|
||||
throw new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
return ctx.user as AuthUser;
|
||||
}
|
||||
|
||||
export function optionalAuthUser(ctx: Context): AuthUser | null {
|
||||
return ctx.user && typeof ctx.user === "object" ? (ctx.user as AuthUser) : null;
|
||||
}
|
||||
|
||||
export async function currentAuthSession(
|
||||
engine: AuthEngine,
|
||||
sessionId: string | undefined,
|
||||
): Promise<AuthSession | null> {
|
||||
if (!sessionId) return null;
|
||||
const session = await engine.store.findSession(sessionId);
|
||||
return session ?? null;
|
||||
}
|
||||
|
||||
export function authComponentProps(
|
||||
input: Record<string, unknown>,
|
||||
defaults: { color?: string; size?: string; class?: string } = {},
|
||||
): Record<string, unknown> {
|
||||
return {
|
||||
color: defaults.color ?? "primary",
|
||||
size: defaults.size ?? "md",
|
||||
class: defaults.class ?? "",
|
||||
...input,
|
||||
};
|
||||
}
|
||||
@@ -101,3 +101,5 @@ export {
|
||||
type AuthSchemaSet,
|
||||
type AuthSchemaOverrides,
|
||||
} from "./validation.ts";
|
||||
|
||||
export * from "./helpers.ts";
|
||||
|
||||
@@ -297,7 +297,7 @@ export function authPlugin(options: AuthPluginOptions = {}) {
|
||||
|
||||
return definePlugin({
|
||||
name: "@wrnexus/auth",
|
||||
version: "0.5.0",
|
||||
version: "0.8.0",
|
||||
enforce: "post",
|
||||
|
||||
componentDirs(context) {
|
||||
|
||||
@@ -166,10 +166,55 @@ export interface LoginAttempt {
|
||||
riskLevel: AuthRiskLevel;
|
||||
}
|
||||
|
||||
export const AUTH_SECURITY_EVENT_TYPES = [
|
||||
"account.registered",
|
||||
"account.status-changed",
|
||||
"delivery.failed",
|
||||
"device.revoked",
|
||||
"device.trusted",
|
||||
"identity.email-verification-requested",
|
||||
"identity.email-verified",
|
||||
"identity.otp-verified",
|
||||
"identity.phone-verification-requested",
|
||||
"identity.phone-verified",
|
||||
"impersonation.denied",
|
||||
"impersonation.ended",
|
||||
"impersonation.started",
|
||||
"invitation.accepted",
|
||||
"invitation.created",
|
||||
"login.failed",
|
||||
"login.magic-link",
|
||||
"login.oauth",
|
||||
"login.otp",
|
||||
"login.otp-verified",
|
||||
"login.passkey",
|
||||
"login.succeeded",
|
||||
"mfa.failed",
|
||||
"mfa.otp-verified",
|
||||
"mfa.recovery-code-used",
|
||||
"mfa.recovery-codes-generated",
|
||||
"mfa.succeeded",
|
||||
"mfa.totp-disabled",
|
||||
"mfa.totp-enabled",
|
||||
"mfa.totp-verified",
|
||||
"oauth.linked",
|
||||
"oauth.unlinked",
|
||||
"passkey.registered",
|
||||
"password.changed",
|
||||
"password.reset",
|
||||
"password.reset-requested",
|
||||
"session.revoked",
|
||||
"session.revoked-all",
|
||||
] as const;
|
||||
|
||||
export type KnownAuthSecurityEventType = (typeof AUTH_SECURITY_EVENT_TYPES)[number];
|
||||
/** Known framework events plus application-defined extension events. */
|
||||
export type AuthSecurityEventType = KnownAuthSecurityEventType | (string & {});
|
||||
|
||||
export interface AuthSecurityEvent {
|
||||
id: string;
|
||||
userId?: string;
|
||||
type: string;
|
||||
type: AuthSecurityEventType;
|
||||
severity: "info" | "warning" | "critical";
|
||||
actorUserId?: string;
|
||||
sessionId?: string;
|
||||
|
||||
Reference in New Issue
Block a user