@beignet/core
Version:
Core framework primitives for Beignet
187 lines • 6.27 kB
TypeScript
import type { ActivityTenant } from "./audit.js";
/**
* Minimal request shape consumed by Beignet auth ports.
*
* Framework adapters can pass richer request objects, but auth providers should
* only rely on headers and the optional raw platform request unless they
* declare a more specific `RequestLike` type.
*/
export interface AuthRequestLike {
/**
* Request headers used for cookies, bearer tokens, API keys, or provider
* specific auth data.
*/
headers: Headers;
/**
* Raw platform request, when the runtime has one available.
*/
raw?: Request;
}
/**
* Normalized authenticated session returned by an `AuthPort`.
*
* `user` is the app/provider user object. `session` can carry provider-specific
* session state such as cookie session metadata or token claims.
*/
export interface AuthSession<User = unknown, Session = unknown> {
user: User;
session?: Session;
}
/**
* Error thrown by auth helpers when a route or workflow requires a user but no
* authenticated user is available.
*/
export declare class AuthUnauthorizedError extends Error {
readonly code = "UNAUTHORIZED";
/** HTTP status used when the server maps this framework error. */
readonly status = 401;
constructor(message?: string);
}
/**
* Error thrown by tenant helpers when a workflow requires a tenant scope but
* the current context has none.
*
* The server maps this to a framework-owned 403 response, mirroring how
* `AuthUnauthorizedError` maps to a framework-owned 401.
*/
export declare class TenantRequiredError extends Error {
readonly code = "TENANT_REQUIRED";
readonly status = 403;
constructor(message?: string);
}
/**
* Options accepted by the `requireX(ctx)` context helpers.
*/
export interface RequireOptions {
/**
* Create the error to throw instead of the framework default.
*/
error?: () => unknown;
}
/**
* Return the authenticated session from `ctx.auth` or throw.
*
* Throws `AuthUnauthorizedError` (a framework-owned 401) by default. Pass
* `options.error` to throw an app-owned error instead.
*
* @example
* ```ts
* const session = requireSession(ctx);
* ```
*/
export declare function requireSession<Session extends AuthSession>(ctx: {
auth?: Session | null;
}, options?: RequireOptions): Session;
/**
* Return the authenticated user from `ctx.auth` or throw.
*
* The user type is inferred from the app's `ctx.auth` session. Throws
* `AuthUnauthorizedError` (a framework-owned 401) by default.
*
* @example
* ```ts
* const user = requireUser(ctx);
* ```
*/
export declare function requireUser<User>(ctx: {
auth?: AuthSession<User> | null;
}, options?: RequireOptions): User;
/**
* Return the authenticated user's ID from `ctx.auth` or throw.
*
* Throws `AuthUnauthorizedError` (a framework-owned 401) by default.
*
* @example
* ```ts
* const userId = requireUserId(ctx);
* ```
*/
export declare function requireUserId(ctx: {
auth?: AuthSession<{
id: string;
}> | null;
}, options?: RequireOptions): string;
/**
* Return the tenant scope from `ctx.tenant` or throw.
*
* Throws `TenantRequiredError` (a framework-owned 403) by default. Pass
* `options.error` to throw an app-owned error instead.
*
* @example
* ```ts
* const tenant = requireTenant(ctx);
* ```
*/
export declare function requireTenant(ctx: {
tenant?: ActivityTenant | null;
}, options?: RequireOptions): ActivityTenant;
/**
* Return the tenant ID from `ctx.tenant` or throw.
*
* Throws `TenantRequiredError` (a framework-owned 403) by default.
*
* @example
* ```ts
* const tenantId = requireTenantId(ctx);
* ```
*/
export declare function requireTenantId(ctx: {
tenant?: ActivityTenant | null;
}, options?: RequireOptions): string;
/**
* App-facing authentication port.
*
* Implement this with a provider adapter such as Better Auth, a custom session
* lookup, or a test fake. The port identifies the current user; it does not
* decide whether that user may perform a business action. Keep authorization in
* policies or use cases.
*/
export interface AuthPort<User = unknown, Session = unknown, RequestLike extends AuthRequestLike = AuthRequestLike> {
/**
* Return the current session, or `null` when the request is unauthenticated.
*/
getSession(req: RequestLike): Promise<AuthSession<User, Session> | null>;
/**
* Return the current user, or `null` when unauthenticated.
*/
getUser(req: RequestLike): Promise<User | null>;
/**
* Return the current user or throw `AuthUnauthorizedError`.
*/
requireUser(req: RequestLike): Promise<User>;
}
type MaybePromise<T> = T | Promise<T>;
/**
* Request-aware factory for a static auth session.
*/
export type StaticAuthSessionFactory<User, Session, RequestLike extends AuthRequestLike> = (req: RequestLike) => MaybePromise<AuthSession<User, Session> | null>;
/**
* Create an auth port from a fixed session or request-aware session factory.
*
* This is useful for tests, examples, and simple apps. Production apps usually
* use a provider-backed auth port that verifies cookies, tokens, or sessions.
*
* @example
* ```ts
* const auth = createStaticAuth({
* user: { id: "user_1", name: "Ada" },
* });
* ```
*
* @param session - Fixed session, `null`, or a function that resolves a session
* from the request.
* @returns An `AuthPort` implementation backed by the provided session source.
*/
export declare function createStaticAuth<User, Session = unknown, RequestLike extends AuthRequestLike = AuthRequestLike>(session: AuthSession<User, Session> | null | StaticAuthSessionFactory<User, Session, RequestLike>): AuthPort<User, Session, RequestLike>;
/**
* Create an auth port that always treats requests as unauthenticated.
*
* Use this in tests or examples where auth is intentionally absent. It is not a
* security boundary; it simply returns `null` from `getSession`/`getUser` and
* throws from `requireUser`.
*
* @returns An `AuthPort` with no active session.
*/
export declare function createAnonymousAuth<User = unknown, Session = unknown, RequestLike extends AuthRequestLike = AuthRequestLike>(): AuthPort<User, Session, RequestLike>;
export {};
//# sourceMappingURL=auth.d.ts.map