alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
1,449 lines • 58.6 kB
TypeScript
import { Alepha, AlephaError, Async, FileLike, KIND, Middleware, PipelineHandler, PipelinePrimitive, PipelinePrimitiveOptions, Primitive, SchemaOutput, Static, StreamLike, TArray, TFile, TObject, TRecord, TSchema, TStream, TString, TVoid } from "alepha";
import { Readable, Transform } from "node:stream";
import { DateTimeProvider, DurationLike } from "alepha/datetime";
import { ReadableStream as ReadableStream$1 } from "node:stream/web";
import { CryptoProvider } from "alepha/crypto";
import { Route, RouterProvider } from "alepha/router";
import { IncomingMessage, Server, ServerResponse as ServerResponse$1 } from "node:http";
import { ServerResponse as ServerResponse$2, ServerRoute as ServerRoute$1 } from "alepha/server";
import { Socket } from "node:net";
//#region ../../src/server/core/schemas/errorSchema.d.ts
declare const errorSchema: import("zod").ZodObject<{
error: import("zod").ZodString;
status: import("zod").ZodInt;
message: import("zod").ZodString;
details: import("zod").ZodOptional<import("zod").ZodString>;
requestId: import("zod").ZodOptional<import("zod").ZodString>;
cause: import("zod").ZodOptional<import("zod").ZodObject<{
name: import("zod").ZodString;
message: import("zod").ZodString;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>;
type ErrorSchema = Static<typeof errorSchema>;
//#endregion
//#region ../../src/server/core/errors/HttpError.d.ts
declare const isHttpError: (error: unknown, status?: number) => error is HttpErrorLike;
declare class HttpError extends AlephaError {
name: string;
static is: typeof isHttpError;
static toJSON(error: HttpError): ErrorSchema;
readonly error: string;
readonly status: number;
readonly requestId?: string;
readonly details?: string;
readonly reason?: {
name: string;
message: string;
};
constructor(options: Partial<ErrorSchema>, cause?: unknown);
}
declare const errorNameByStatus: Record<number, string>;
interface HttpErrorLike extends Error {
status: number;
}
//#endregion
//#region ../../src/server/core/constants/routeMethods.d.ts
declare const routeMethods: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "CONNECT", "TRACE"];
type RouteMethod = (typeof routeMethods)[number];
//#endregion
//#region ../../src/server/core/helpers/ServerReply.d.ts
/**
* Helper for building server replies.
*/
declare class ServerReply {
headers: Record<string, string> & {
"set-cookie"?: string[];
};
status?: number;
body?: any;
/**
* Redirect to a given URL with optional status code (default 302).
*/
redirect(url: string, status?: number): void;
/**
* Set the response status code.
*/
setStatus(status: number): this;
/**
* Set a response header.
*/
setHeader(name: string, value: string): this;
/**
* Set the response body.
*/
setBody(body: any): this;
}
//#endregion
//#region ../../src/server/core/services/UserAgentParser.d.ts
interface UserAgentInfo {
os: "Windows" | "Android" | "Ubuntu" | "MacOS" | "iOS" | "Linux" | "FreeBSD" | "OpenBSD" | "ChromeOS" | "BlackBerry" | "Symbian" | "Windows Phone";
browser: "Chrome" | "Firefox" | "Safari" | "Edge" | "Opera" | "Internet Explorer" | "Brave" | "Vivaldi" | "Samsung Browser" | "UC Browser" | "Yandex";
device: "MOBILE" | "DESKTOP" | "TABLET";
}
/**
* Simple User-Agent parser to detect OS, browser, and device type.
* This parser is not exhaustive and may not cover all edge cases.
*
* Use result for non
*/
declare class UserAgentParser {
parse(userAgent?: string): UserAgentInfo;
}
//#endregion
//#region ../../src/server/core/interfaces/ServerRequest.d.ts
type TRequestBody = TObject | TString | TArray | TRecord | TStream;
type TResponseBody = TObject | TString | TRecord | TFile | TArray | TStream | TVoid;
interface RequestConfigSchema {
body?: TRequestBody;
params?: TObject;
query?: TObject;
headers?: TObject;
response?: TResponseBody;
}
interface ServerRequestConfig<TConfig extends RequestConfigSchema = RequestConfigSchema> {
body: SchemaOutput<TConfig["body"], any>;
headers: SchemaOutput<TConfig["headers"], Record<string, string>>;
params: SchemaOutput<TConfig["params"], Record<string, string>>;
query: SchemaOutput<TConfig["query"], Record<string, any>>;
}
type ServerRequestConfigEntry<TConfig extends RequestConfigSchema = RequestConfigSchema> = Partial<ServerRequestConfig<TConfig>>;
interface ServerRequest<TConfig extends RequestConfigSchema = RequestConfigSchema> extends ServerRequestConfig<TConfig> {
/**
* HTTP method used for this request.
*/
method: RouteMethod;
/**
* Full request URL.
*/
url: URL;
/**
* Unique request ID assigned to this request.
*/
requestId: string;
/**
* Client IP address.
* Uses `X-Forwarded-For` header when `TRUST_PROXY=true`.
*/
ip?: string;
/**
* Value of the `Host` header sent by the client.
*/
host?: string;
/**
* Browser user agent information.
* Information are not guaranteed to be accurate. Use with caution.
*
* @see {@link UserAgentParser}
*/
userAgent: UserAgentInfo;
/**
* Geolocation information derived from proxy headers.
* Available when behind Cloudflare, Vercel, or similar CDNs.
*/
geo: RequestGeo;
/**
* Whether the request appears to be from a bot/crawler.
* Based on user-agent analysis.
*/
isBot: boolean;
/**
* Whether the request is from a mobile device.
* Based on user-agent analysis.
*/
isMobile: boolean;
/**
* Request protocol (http or https).
* Uses `X-Forwarded-Proto` header when behind a proxy.
*/
protocol: "http" | "https";
/**
* Preferred language from `Accept-Language` header.
* Returns the first/most preferred language code (e.g., "en", "fr", "en-US").
*/
language?: string;
/**
* Parsed referer information.
* Undefined if no Referer header or invalid URL.
*/
referer?: RequestReferer;
/**
* Arbitrary metadata attached to the request. Can be used by middlewares to store information.
*/
metadata: Record<string, any>;
/**
* Reply object to be used to send response.
*/
reply: ServerReply;
/**
* The raw underlying request object (Web Request).
*/
raw: ServerRawRequest;
}
interface ServerRoute<TConfig extends RequestConfigSchema = RequestConfigSchema> extends Route {
/**
* Handler function for this route.
*/
handler: PipelineHandler;
/**
* HTTP method for this route.
*/
method?: RouteMethod;
/**
* Request/response schema for this route.
*
* Request schema contains:
* - body, for POST/PUT/PATCH requests
* - params, for URL parameters (e.g. /user/:id)
* - query, for URL query parameters (e.g. /user?id=123)
* - headers, for HTTP headers
*
* Response schema contains:
* - response
*
* Response schema is used to validate and serialize the response sent by the handler.
*/
schema?: TConfig;
/**
* @see ServerLoggerProvider
*/
silent?: boolean;
/**
* Mark this `GET` route as prerenderable. When `true`, the build invokes the
* handler in-process and writes its body verbatim to `dist/public/{path}`,
* so the route is served as a static file (e.g. `sitemap.xml`, `robots.txt`).
* The route still serves live at request time for runtimes that have a server.
*/
static?: boolean;
}
/**
* Input type for `createRoute()`. Accepts both a `PipelineHandler` and a plain handler function.
* Plain functions are auto-wrapped in `PipelineHandler` by `createRoute()`.
*/
type ServerRouteInput<TConfig extends RequestConfigSchema = RequestConfigSchema> = Omit<ServerRoute<TConfig>, "handler"> & {
handler: PipelineHandler | ServerHandler<TConfig>;
};
type ServerResponseBody<TConfig extends RequestConfigSchema = RequestConfigSchema> = SchemaOutput<TConfig["response"], ResponseBodyType>;
type ResponseKind = "json" | "text" | "void" | "file" | "any";
type ResponseBodyType = string | Buffer | StreamLike | undefined | null | void;
type ServerHandler<TConfig extends RequestConfigSchema = RequestConfigSchema> = (request: ServerRequest<TConfig>) => Async<ServerResponseBody<TConfig>>;
interface ServerResponse {
body: string | Buffer | ArrayBuffer | Readable | ReadableStream$1;
headers: Record<string, string>;
status: number;
}
type ServerRouteRequestHandler = (request: ServerRequestData) => Promise<ServerResponse>;
interface ServerRouteMatcher extends Route {
handler: ServerRouteRequestHandler;
}
interface ServerRequestData {
readonly method: RouteMethod;
readonly url: URL;
readonly headers: Record<string, string>;
readonly query: Record<string, string>;
readonly params: Record<string, string>;
raw: ServerRawRequest;
}
interface ServerRawRequest {
node?: NodeRequestEvent;
web?: WebRequestEvent;
}
interface NodeRequestEvent {
req: IncomingMessage;
res: ServerResponse$1;
}
interface WebRequestEvent {
req: Request;
res?: Response;
}
/**
* Geolocation information from proxy headers (Cloudflare, Vercel, etc.)
*/
interface RequestGeo {
/**
* ISO 3166-1 alpha-2 country code (e.g., "US", "FR", "JP").
*/
country?: string;
/**
* City name (e.g., "San Francisco", "Paris").
*/
city?: string;
/**
* Region/state (e.g., "California", "Île-de-France").
*/
region?: string;
/**
* Latitude (if available).
*/
latitude?: string;
/**
* Longitude (if available).
*/
longitude?: string;
}
/**
* Parsed referer information.
*/
interface RequestReferer {
/**
* Full referer URL.
*/
url: string;
/**
* Hostname of the referer (e.g., "google.com").
*/
hostname: string;
/**
* Path of the referer URL.
*/
pathname: string;
}
//#endregion
//#region ../../src/server/core/services/ServerRequestParser.d.ts
declare class ServerRequestParser {
protected readonly alepha: Alepha;
protected readonly userAgentParser: UserAgentParser;
protected readonly cryptoProvider: CryptoProvider;
protected readonly env: {
TRUST_PROXY: boolean;
};
protected readonly rootURL: URL;
createServerRequest(partialRawRequest: Partial<ServerRequestData>): ServerRequest;
getRequestId(request: ServerRequestData): string;
getRequestUserAgent(request: ServerRequestData): import("alepha/server").UserAgentInfo;
getRequestIp(request: ServerRequestData): string | undefined;
protected getConnectionIp(request: ServerRequestData): string | undefined;
getRequestGeo(request: ServerRequestData): RequestGeo;
protected static readonly BOT_PATTERNS: RegExp[];
getIsBot(request: ServerRequestData): boolean;
protected static readonly MOBILE_PATTERNS: RegExp[];
getIsMobile(request: ServerRequestData): boolean;
getProtocol(request: ServerRequestData): "http" | "https";
getLanguage(request: ServerRequestData): string | undefined;
getReferer(request: ServerRequestData): RequestReferer | undefined;
}
//#endregion
//#region ../../src/server/core/providers/ServerTimingProvider.d.ts
type TimingMap = Record<string, [number, number]>;
declare class ServerTimingProvider {
protected readonly log: import("alepha/logger").Logger;
protected readonly dateTime: DateTimeProvider;
protected readonly alepha: Alepha;
options: {
prefix: string;
disabled: boolean;
};
readonly onRequest: import("alepha").HookPrimitive<"server:onRequest">;
readonly onResponse: import("alepha").HookPrimitive<"server:onResponse">;
protected get handlerName(): string;
beginTiming(name: string): void;
endTiming(name: string): void;
protected setDuration(name: string, timing: TimingMap): void;
}
//#endregion
//#region ../../src/server/core/providers/ServerRouterProvider.d.ts
/**
* Main router for all routes server side.
*
* Reminder:
* - $route => generic route
* - $action => action route (for API calls)
* - $page => React route (for React SSR)
*/
declare class ServerRouterProvider extends RouterProvider<ServerRouteMatcher> {
protected readonly log: import("alepha/logger").Logger;
protected readonly alepha: Alepha;
protected readonly crypto: CryptoProvider;
protected readonly routes: ServerRoute[];
protected readonly serverTimingProvider: ServerTimingProvider;
protected readonly serverRequestParser: ServerRequestParser;
protected readonly queryKeysCache: WeakMap<object, string[]>;
protected readonly globalMiddlewareRegistry: GlobalMiddlewareEntry[];
/**
* Get cached keys for a query schema, computing them lazily on first access.
*/
protected getQuerySchemaKeys(schema: {
properties: object;
}): string[];
pushMiddleware(pattern: string, middleware: Middleware[], options?: PushMiddlewareOptions): void;
/**
* Check if a route passes the middleware filter options (method, exclude).
*/
protected matchesMiddlewareFilter(route: ServerRoute, options?: PushMiddlewareOptions): boolean;
/**
* Check if a route path matches a pattern.
* Wildcard `*` at end = prefix match, otherwise exact match.
*/
protected matchesPattern(routePath: string, pattern: string): boolean;
/**
* Get all registered routes, optionally filtered by a pattern.
*
* Pattern accept simple wildcard '*' at the end.
* Example: '/api/*' will match all routes starting with '/api/' but '/api/' will match only that exact route.
*/
getRoutes(pattern?: string): ServerRoute[];
/**
* Create a new server route.
*
* Accepts both `PipelineHandler` and plain handler functions.
* Plain functions are auto-wrapped in `PipelineHandler`.
*/
createRoute<TConfig extends RequestConfigSchema = RequestConfigSchema>(input: ServerRouteInput<TConfig>): void;
/**
* Get or generate a context ID from request headers.
*
* It first checks for common headers like 'x-request-id' or 'x-correlation-id' that may be set by proxies or clients.
* If none of these headers are present, it generates a new UUID to ensure uniqueness.
*
* Note: In production environments, it's recommended to have a proxy (e.g. Nginx, Cloudflare) that sets a consistent request ID header for better traceability across services.
*/
protected getContextId(headers: Record<string, string>): string;
/**
* Process an incoming request through the full lifecycle:
* onRequest → handler → onSend → response → onResponse
*/
protected processRequest(request: ServerRequest, route: ServerRoute, responseKind: ResponseKind): Promise<{
status: number;
headers: Record<string, string> & {
"set-cookie"?: string[];
};
body: any;
}>;
/**
* Run the route handler with request validation and response serialization.
*/
protected runRouteHandler(route: ServerRoute, request: ServerRequest, responseKind: ResponseKind): Promise<void>;
/**
* Transform reply body based on response kind and route schema.
*/
serializeResponse(route: ServerRoute, reply: ServerReply, responseKind: ResponseKind): void;
/**
* Determine response type based on route schema.
*/
protected getResponseType(schema?: RequestConfigSchema): ResponseKind;
/**
* Handle errors during request processing.
*/
protected errorHandler(route: ServerRoute, request: ServerRequest, error: Error): Promise<void>;
/**
* Validate incoming request against route schema.
*/
validateRequest(route: {
schema?: RequestConfigSchema;
}, request: ServerRequestConfig): void;
/**
* Coerce a raw query/header value (always a string on the wire) to the JS
* type its schema declares, mirroring `z.coerce` at the HTTP boundary.
*
* Only the boundary coerces — request bodies and the ORM stay strict. Values
* that can't be coerced are passed through unchanged so the subsequent
* validation produces a proper rejection. Arrays coerce element-wise.
*/
protected coerceParam(schema: unknown, value: unknown): unknown;
}
interface PushMiddlewareOptions {
method?: RouteMethod | RouteMethod[];
exclude?: string[];
}
interface GlobalMiddlewareEntry extends PushMiddlewareOptions {
pattern: string;
middleware: Middleware[];
}
//#endregion
//#region ../../src/server/core/providers/ServerProvider.d.ts
/**
* Base server provider to handle incoming requests and route them.
*
* This is the default implementation for serverless environments.
*
* ServerProvider supports both Node.js HTTP requests and Web (Fetch API) requests.
*/
declare class ServerProvider {
protected readonly log: import("alepha/logger").Logger;
protected readonly alepha: Alepha;
protected readonly dateTimeProvider: DateTimeProvider;
protected readonly router: ServerRouterProvider;
protected readonly internalServerErrorMessage = "Internal Server Error";
protected readonly internalErrorResponse: Readonly<{
status: 500;
headers: Readonly<{
"content-type": "text/plain";
}>;
body: "Internal Server Error";
}>;
protected readonly handleInternalError: () => Readonly<{
status: 500;
headers: Readonly<{
"content-type": "text/plain";
}>;
body: "Internal Server Error";
}>;
protected readonly urlBaseCache: Map<string, string>;
/**
* Get cached URL base (protocol + host) for a given host header.
* Caches the result to avoid repeated string concatenation.
*/
protected getUrlBase(headers: Record<string, string>): string;
/**
* Parse query string manually - faster than new URL() + URLSearchParams.
* Returns empty object if no query string.
*/
protected parseQueryString(rawUrl: string): Record<string, string>;
/**
* Fast decode - only calls decodeURIComponent if needed.
*/
protected fastDecode(str: string): string;
get hostname(): string;
/**
* When a Node.js HTTP request is received from outside. (Vercel, AWS Lambda, etc.)
*/
protected readonly onNodeRequest: import("alepha").HookPrimitive<"node:request">;
/**
* When a Web (Fetch API) request is received from outside. (Netlify, Cloudflare Workers, etc.)
*/
protected readonly onWebRequest: import("alepha").HookPrimitive<"web:request">;
/**
* Handle Node.js HTTP request event.
*
* Optimized to avoid expensive URL parsing when possible.
*/
handleNodeRequest(nodeRequestEvent: NodeRequestEvent): Promise<void>;
/**
* Handle Web (Fetch API) request event.
*/
handleWebRequest(ev: WebRequestEvent): Promise<void>;
/**
* Convert response headers to Web API Headers.
*
* The `set-cookie` header requires special handling because it's stored
* as `string[]` (one entry per cookie) but the `Response` constructor
* would comma-join arrays, which breaks cookie parsing. We use
* `Headers.append()` to emit each cookie as a separate header.
*/
protected toWebHeaders(headers: Record<string, string | string[]>): Headers;
/**
* Helper for Vite development mode to let Vite handle (or not) 404.
*/
protected isViteNotFound(url?: string, route?: Route, params?: Record<string, string>): boolean;
}
//#endregion
//#region ../../src/server/core/services/HttpClient.d.ts
declare class HttpClient {
protected readonly log: import("alepha/logger").Logger;
protected readonly alepha: Alepha;
readonly cache: import("alepha/cache").CacheMiddlewareFn<HttpClientCache>;
protected readonly pendingRequests: HttpClientPendingRequests;
fetchAction(args: FetchActionArgs): Promise<FetchResponse>;
fetch<T extends TSchema>(url: string, request?: RequestInitWithOptions<T>): Promise<FetchResponse<Static<T>>>;
protected url(host: string, action: HttpAction, args: ServerRequestConfigEntry): string;
protected body(init: RequestInit, headers: Record<string, string>, action: HttpAction, args?: ServerRequestConfigEntry): Promise<void>;
protected responseData(response: Response, options: ResolvedFetchOptions): Promise<any>;
protected isMaybeFile(response: Response): boolean;
protected createFileLike(response: Response, defaultFileName?: string): FileLike;
pathVariables(url: string, action: {
schema?: {
params?: TObject;
};
}, args?: ServerRequestConfigEntry): string;
queryParams(url: string, action: {
schema?: {
query?: TObject;
};
}, args?: ServerRequestConfigEntry): string;
}
interface FetchOptions<T extends TSchema = TSchema> {
/**
* Key to identify the request in the pending requests.
*/
key?: string;
/**
* The schema to validate the response against.
*/
schema?: {
response?: T;
};
/**
* Built-in cache options.
*/
localCache?: boolean | number | DurationLike;
}
type RequestInitWithOptions<T extends TSchema = TSchema> = RequestInit & FetchOptions<T>;
/**
* Internal resolved fetch options — built in {@link HttpClient.fetch},
* consumed by {@link HttpClient.responseData} and the `client:beforeFetch`
* event. Distinct from the external {@link FetchOptions}: `schema` is the
* already-unwrapped response schema and `cache` is the resolved cache directive.
*/
interface ResolvedFetchOptions {
key?: string;
schema?: TSchema;
cache?: boolean | number | DurationLike;
}
interface FetchResponse<T = any> {
data: T;
status: number;
statusText: string;
headers: Headers;
raw?: Response;
}
type HttpClientPendingRequests = Record<string, Promise<any> | undefined>;
interface HttpClientCache {
data: any;
etag?: string;
}
interface FetchActionArgs {
action: HttpAction;
host?: string;
config?: ServerRequestConfigEntry;
options?: ClientRequestOptions;
}
interface HttpAction {
method?: string;
prefix?: string;
path: string;
contentType?: string;
requestBodyType?: string;
schema?: {
params?: TObject;
query?: TObject;
body?: TRequestBody;
response?: TResponseBody;
};
}
//#endregion
//#region ../../src/server/core/primitives/$action.d.ts
/**
* Creates a server action primitive for defining type-safe HTTP endpoints.
*
* Server actions are the core building blocks for REST APIs in Alepha, providing declarative
* HTTP endpoints with full type safety, automatic validation, and OpenAPI documentation.
*
* **Key Features**
* - Full TypeScript inference for request/response types
* - Automatic schema validation using TypeBox
* - Convention-based URL generation with customizable paths
* - Direct invocation (`run()`) or HTTP requests (`fetch()`)
* - Built-in authentication and authorization support
* - Automatic content-type handling (JSON, form-data, plain text)
*
* **URL Generation**
*
* **Important:** All `$action` paths are automatically prefixed with `/api`.
*
* ```ts
* $action({ path: "/users" }) // → GET /api/users
* $action({ path: "/users/:id" }) // → GET /api/users/:id
* $action({ path: "/hello" }) // → GET /api/hello
* ```
*
* This prefix is configurable via the `SERVER_API_PREFIX` environment variable.
* HTTP method defaults to GET, or POST if body schema is provided.
*
* **Common Use Cases**
* - CRUD operations with type safety
* - File upload and download endpoints
* - Microservice communication
*
* @example
* ```ts
* class UserController {
* getUsers = $action({
* path: "/users",
* schema: {
* query: z.object({
* page: z.number({ default: 1 }).optional(),
* limit: z.number({ default: 10 }).optional()
* }),
* response: z.object({
* users: z.array(z.object({
* id: z.text(),
* name: z.text(),
* email: z.text()
* })),
* total: z.number()
* })
* },
* handler: async ({ query }) => {
* const users = await this.userService.findUsers(query);
* return { users: users.items, total: users.total };
* }
* });
*
* createUser = $action({
* method: "POST",
* path: "/users",
* schema: {
* body: z.object({
* name: z.text(),
* email: z.text({ format: "email" })
* }),
* response: z.object({ id: z.text(), name: z.text() })
* },
* handler: async ({ body }) => {
* return await this.userService.create(body);
* }
* });
* }
* ```
*/
declare const $action: {
<TConfig extends RequestConfigSchema>(options: ActionPrimitiveOptions<TConfig>): ActionPrimitiveFn<TConfig>;
[KIND]: typeof ActionPrimitive;
};
interface ActionPrimitiveOptions<TConfig extends RequestConfigSchema> extends Omit<ServerRoute, "handler" | "path" | "schema" | "mapParams">, PipelinePrimitiveOptions {
/**
* Name of the action.
*
* - It will be used to generate the route path if `path` is not provided.
* - It will be used to generate the permission name if `security` is enabled.
*/
name?: string;
/**
* Group actions together.
*
* - If not provided, the service name containing the route will be used.
* - It will be used as Tag for documentation purposes.
* - It will be used for permission name generation if `security` is enabled.
*
* @example
* ```ts
* // group = "MyController"
* class MyController {
* hello = $action({ handler: () => "Hello World" });
* }
*
* // group = "users"
* class MyOtherController {
* group = "users";
* a1 = $action({ handler: () => "Action 1", group: this.group });
* a2 = $action({ handler: () => "Action 2", group: this.group });
* }
* ```
*/
group?: string;
/**
* Pathname of the route. If not provided, property key is used.
*/
path?: string;
/**
* The route method.
*
* - If not provided, it will be set to "GET" by default.
* - If not provider and a body is provided, it will be set to "POST".
*
* Wildcard methods are not supported for now. (e.g. "ALL", "ANY", etc.)
*/
method?: RouteMethod;
/**
* The config schema of the route.
* - body: The request body schema.
* - params: Path variables schema.
* - query: The request query-params schema.
* - response: The response schema.
*/
schema?: TConfig;
/**
* A short description of the action. Used for documentation purposes.
*/
description?: string;
/**
* Disable the route. Useful with env variables to disable one specific route.
* Route won't be available in the API nor locally.
*/
disabled?: boolean;
/**
* Main route handler. This is where the route logic is implemented.
*/
handler: ServerActionHandler<TConfig>;
}
/**
* Server API configuration atom.
*/
declare const serverApiOptions: import("alepha").Atom<import("zod").ZodObject<{
prefix: import("zod").ZodString;
}, import("zod/v4/core").$strip>, "alepha.server.api.options">;
type ServerApiOptions = Static<typeof serverApiOptions.schema>;
declare module "alepha" {
interface State {
[serverApiOptions.key]: ServerApiOptions;
}
}
declare class ActionPrimitive<TConfig extends RequestConfigSchema> extends PipelinePrimitive<ActionPrimitiveOptions<TConfig>> {
protected readonly log: import("alepha/logger").Logger;
protected readonly settings: Readonly<{
prefix: string;
}>;
protected readonly httpClient: HttpClient;
protected readonly serverProvider: ServerProvider;
protected readonly serverRouterProvider: ServerRouterProvider;
protected onInit(): void;
get prefix(): string;
get route(): ServerRoute;
/**
* Returns the name of the action.
*/
get name(): string;
/**
* Returns the group of the action. (e.g. "orders", "admin", etc.)
*/
get group(): string;
/**
* Returns the HTTP method of the action.
*/
get method(): RouteMethod;
/**
* Returns the path of the action.
*
* Path is prefixed by `/api` by default.
*/
get path(): string;
get schema(): TConfig | undefined;
getBodyContentType(): string | undefined;
/**
* Call the action handler directly.
* There is no HTTP layer involved.
*/
run(config?: ClientRequestEntry<TConfig>, options?: ClientRequestOptions): Promise<ClientRequestResponse<TConfig>>;
/**
* Works like `run`, but always fetches (http request) the route.
*/
fetch(config?: ClientRequestEntry<TConfig>, options?: ClientRequestOptions): Promise<FetchResponse<ClientRequestResponse<TConfig>>>;
}
interface ActionPrimitiveFn<TConfig extends RequestConfigSchema> extends ActionPrimitive<TConfig> {
(config?: ClientRequestEntry<TConfig>, options?: ClientRequestOptions): Promise<ClientRequestResponse<TConfig>>;
}
type ClientRequestEntry<TConfig extends RequestConfigSchema, T = ClientRequestEntryContainer<TConfig>> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K]; };
type ClientRequestEntryContainer<TConfig extends RequestConfigSchema> = {
body: SchemaOutput<TConfig["body"], undefined>;
params: SchemaOutput<TConfig["params"], undefined>;
headers?: SchemaOutput<TConfig["headers"], Record<string, string>>;
query?: Partial<SchemaOutput<TConfig["query"], Record<string, string>>>;
};
interface ClientRequestOptions extends FetchOptions {
/**
* Standard request fetch options.
*/
request?: RequestInit;
/**
* Add query parameters to the request URL. They will be merged with any query params defined in the action schema.
* This is useful for adding dynamic query params at runtime.
*/
query?: Record<string, string | number | boolean>;
}
type ClientRequestResponse<TConfig extends RequestConfigSchema> = SchemaOutput<TConfig["response"], any>;
/**
* Specific handler for server actions.
*/
type ServerActionHandler<TConfig extends RequestConfigSchema = RequestConfigSchema> = (request: ServerActionRequest<TConfig>) => Async<ServerResponseBody<TConfig>>;
/**
* Server Action Request Interface
*
* Can be extended with module augmentation to add custom properties (like `user` in Server Security).
*
* This is NOT Server Request, but a specific type for actions.
*/
interface ServerActionRequest<TConfig extends RequestConfigSchema> extends ServerRequest<TConfig> {}
//#endregion
//#region ../../src/server/core/errors/BadRequestError.d.ts
declare class BadRequestError extends HttpError {
constructor(message?: string, cause?: unknown);
}
//#endregion
//#region ../../src/server/core/errors/ConflictError.d.ts
declare class ConflictError extends HttpError {
constructor(message?: string, cause?: unknown);
}
//#endregion
//#region ../../src/server/core/errors/ForbiddenError.d.ts
declare class ForbiddenError extends HttpError {
constructor(message?: string, cause?: unknown);
}
//#endregion
//#region ../../src/server/core/errors/NotFoundError.d.ts
declare class NotFoundError extends HttpError {
constructor(message?: string, cause?: unknown);
}
//#endregion
//#region ../../src/server/core/errors/UnauthorizedError.d.ts
declare class UnauthorizedError extends HttpError {
readonly name = "UnauthorizedError";
constructor(message?: string, cause?: unknown);
}
//#endregion
//#region ../../src/server/core/errors/ValidationError.d.ts
declare class ValidationError extends HttpError {
constructor(message?: string, cause?: unknown);
}
//#endregion
//#region ../../src/server/core/helpers/isMultipart.d.ts
/**
* Checks if the route has multipart/form-data request body.
*/
declare const isMultipart: (options: {
schema?: RequestConfigSchema;
contentType?: string;
requestBodyType?: string;
}) => boolean;
//#endregion
//#region ../../src/server/core/schemas/okSchema.d.ts
declare const okSchema: import("zod").ZodObject<{
ok: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodInt]>>;
count: import("zod").ZodOptional<import("zod").ZodNumber>;
}, import("zod/v4/core").$strip>;
type Ok = Static<typeof okSchema>;
//#endregion
//#region ../../src/server/core/primitives/$circuit.d.ts
interface CircuitBreakerOptions {
/**
* Consecutive failures before opening the circuit.
*/
threshold: number;
/**
* Cooldown before transitioning from open to half-open.
*/
reset: DurationLike;
}
/**
* Middleware that implements the circuit breaker pattern.
*
* Three states:
* - **Closed** (normal) — calls pass through. Failures are counted.
* - **Open** (tripped) — calls are immediately rejected. No handler execution.
* - **Half-open** (probing) — one call is allowed. Success closes, failure re-opens.
*
* ```typescript
* class PaymentController {
* charge = $action({
* use: [$circuit({ threshold: 5, reset: [30, "seconds"] })],
* handler: async ({ body }) => this.paymentGateway.charge(body),
* });
* }
* ```
*/
declare const $circuit: (options: CircuitBreakerOptions) => Middleware;
//#endregion
//#region ../../src/server/core/primitives/$middleware.d.ts
declare const $middleware: {
(options: ServerMiddlewarePrimitiveOptions): ServerMiddlewarePrimitive;
[KIND]: typeof ServerMiddlewarePrimitive;
};
interface ServerMiddlewarePrimitiveOptions {
/**
* Path prefix. Middleware applies to all routes starting with this path.
*
* @example "/api" — matches "/api/users", "/api/orders", etc.
*/
path: string;
/**
* Middleware functions to apply to matching routes.
*/
use: Middleware[];
/**
* Limit middleware to specific HTTP methods.
* If not set, middleware applies to all methods.
*/
method?: RouteMethod | RouteMethod[];
/**
* Exclude specific route paths from middleware application.
*/
exclude?: string[];
}
declare class ServerMiddlewarePrimitive extends Primitive<ServerMiddlewarePrimitiveOptions> {
protected readonly serverRouterProvider: ServerRouterProvider;
protected onInit(): void;
}
//#endregion
//#region ../../src/server/core/primitives/$route.d.ts
/**
* Create a basic endpoint.
*
* It's a low level primitive. You probably want to use `$action` instead.
*
* @see {@link $action}
* @see {@link $page}
*/
declare const $route: {
<TConfig extends RequestConfigSchema>(options: RoutePrimitiveOptions<TConfig>): RoutePrimitive<TConfig>;
[KIND]: typeof RoutePrimitive;
};
interface RoutePrimitiveOptions<TConfig extends RequestConfigSchema = RequestConfigSchema> extends Omit<ServerRoute<TConfig>, "handler">, PipelinePrimitiveOptions<ServerHandler<TConfig>> {}
declare class RoutePrimitive<TConfig extends RequestConfigSchema> extends PipelinePrimitive<RoutePrimitiveOptions<TConfig>> {
protected readonly serverRouterProvider: ServerRouterProvider;
protected onInit(): void;
/**
* Invoke this route's handler in-process (no HTTP server) and return its path
* and body. Used by the build to snapshot `static` routes to files.
*
* Only meaningful for self-contained `GET` handlers that return a string or
* Buffer (e.g. `sitemap.xml`, `robots.txt`).
*/
prerender(): Promise<{
path: string;
body: string | Buffer;
}>;
}
//#endregion
//#region ../../src/server/core/primitives/$sse.d.ts
/**
* Schema configuration for an SSE endpoint.
*/
interface SseConfigSchema {
/**
* Request body schema.
*/
body?: TObject;
/**
* Path parameters schema.
*/
params?: TObject;
/**
* Query parameters schema.
*/
query?: TObject;
/**
* Request headers schema.
*/
headers?: TObject;
/**
* Schema for the data payload of each SSE event.
*/
data?: TSchema;
}
/**
* Context object passed to the SSE handler function.
*/
interface SseHandlerContext<TConfig extends SseConfigSchema> {
/**
* Parsed request body.
*/
body: TConfig["body"] extends TObject ? Static<TConfig["body"]> : any;
/**
* Parsed path parameters.
*/
params: TConfig["params"] extends TObject ? Static<TConfig["params"]> : Record<string, string>;
/**
* Parsed query parameters.
*/
query: TConfig["query"] extends TObject ? Partial<Static<TConfig["query"]>> : Record<string, any>;
/**
* Parsed request headers.
*/
headers: TConfig["headers"] extends TObject ? Static<TConfig["headers"]> : Record<string, string>;
/**
* The underlying server request object.
*/
request: ServerRequest;
/**
* Emit an SSE event to the client.
*/
emit: (data: TConfig["data"] extends TSchema ? Static<TConfig["data"]> : any) => void;
/**
* Close the SSE stream.
*/
close: () => void;
}
/**
* Handler function type for SSE endpoints.
*/
type SseHandler<TConfig extends SseConfigSchema = SseConfigSchema> = (context: SseHandlerContext<TConfig>) => Async<void>;
/**
* Options for the $sse primitive.
*/
interface SsePrimitiveOptions<TConfig extends SseConfigSchema> extends PipelinePrimitiveOptions {
/**
* Name of the SSE endpoint.
*/
name?: string;
/**
* Group SSE endpoints together.
*/
group?: string;
/**
* Pathname of the route. If not provided, property key is used.
*/
path?: string;
/**
* The config schema for the SSE endpoint.
*/
schema?: TConfig;
/**
* A short description of the endpoint. Used for documentation purposes.
*/
description?: string;
/**
* Disable the SSE endpoint.
*/
disabled?: boolean;
/**
* Main SSE handler. Receives context with emit/close functions.
*/
handler: SseHandler<TConfig>;
}
/**
* Async iterable stream of SSE events.
*
* Supports push-based event delivery via `push()`, error propagation
* via `fail()`, and clean termination via `end()`.
*/
declare class SseStream<T> implements AsyncIterable<T> {
protected queue: T[];
protected error: Error | null;
protected done: boolean;
protected resolve: (() => void) | null;
protected listeners: Array<(data: T) => void>;
/**
* Push a new event into the stream.
*/
push(data: T): void;
/**
* Signal an error on the stream.
*/
fail(error: Error): void;
/**
* End the stream gracefully.
*/
end(): void;
/**
* Subscribe to new events as they arrive.
*/
subscribe(listener: (data: T) => void): () => void;
[Symbol.asyncIterator](): AsyncIterator<T>;
}
/**
* Response wrapper for SSE fetch requests.
*
* Wraps a standard `Response` and parses the `text/event-stream` body
* into an async iterable of typed events.
*/
declare class SseFetchResponse<T> implements AsyncIterable<T> {
readonly response: Response;
constructor(response: Response);
/**
* HTTP status code of the response.
*/
get status(): number;
/**
* HTTP status text of the response.
*/
get statusText(): string;
/**
* Response headers.
*/
get headers(): Headers;
[Symbol.asyncIterator](): AsyncIterator<T>;
}
/**
* Creates a Server-Sent Events (SSE) primitive for streaming typed events to clients.
*
* SSE endpoints provide a unidirectional stream from server to client over HTTP,
* with full type safety for event data. The handler receives `emit()` and `close()`
* functions to control the stream.
*
* **Key Features**
* - Full TypeScript inference for event data types
* - Automatic schema validation using TypeBox
* - Convention-based URL generation with customizable paths
* - Direct invocation (`run()`) returns an `SseStream` async iterable
* - HTTP requests (`fetch()`) returns an `SseFetchResponse` async iterable
* - Built-in `text/event-stream` content-type handling
*
* **URL Generation**
*
* All `$sse` paths are automatically prefixed with `/api`.
*
* ```ts
* $sse({ path: "/events" }) // POST /api/events
* $sse({ path: "/feed/:id" }) // POST /api/feed/:id
* ```
*
* The HTTP method is always POST.
*
* @example
* ```ts
* class NotificationController {
* events = $sse({
* schema: {
* data: z.object({
* type: z.text(),
* message: z.text(),
* }),
* },
* handler: async ({ emit, close }) => {
* emit({ type: "welcome", message: "Connected!" });
* // ... stream events ...
* close();
* },
* });
* }
* ```
*/
declare const $sse: {
<TConfig extends SseConfigSchema>(options: SsePrimitiveOptions<TConfig>): SsePrimitiveFn<TConfig>;
[KIND]: typeof SsePrimitive;
};
/**
* The SSE primitive class extending PipelinePrimitive.
*
* Registers a POST route that streams `text/event-stream` responses.
* Supports direct invocation via `run()` and HTTP via `fetch()`.
*/
declare class SsePrimitive<TConfig extends SseConfigSchema> extends PipelinePrimitive<SsePrimitiveOptions<TConfig>> {
protected readonly log: import("alepha/logger").Logger;
protected readonly settings: Readonly<{
prefix: string;
}>;
protected readonly serverProvider: ServerProvider;
protected readonly serverRouterProvider: ServerRouterProvider;
protected onInit(): void;
/**
* Returns the /api prefix.
*/
get prefix(): string;
/**
* Returns the name of the SSE endpoint.
*/
get name(): string;
/**
* Returns the group of the SSE endpoint.
*/
get group(): string;
/**
* Returns the HTTP method. SSE always uses POST.
*/
get method(): RouteMethod;
/**
* Returns the path of the SSE endpoint.
*/
get path(): string;
/**
* Returns the schema configuration.
*/
get schema(): TConfig | undefined;
/**
* Constructs a RequestConfigSchema from the SSE config for route registration.
*/
protected get requestConfigSchema(): RequestConfigSchema | undefined;
/**
* Call the SSE handler directly and return a typed async iterable stream.
* There is no HTTP layer involved.
*/
run(config?: SseRequestEntry<TConfig>): SseStream<SseEventData<TConfig>>;
/**
* Works like `run`, but always fetches (http request) the route.
* Returns an `SseFetchResponse` that can be async-iterated for typed events.
*/
fetch(config?: SseRequestEntry<TConfig>): Promise<SseFetchResponse<SseEventData<TConfig>>>;
/**
* HTTP handler for the registered route.
* Returns a ReadableStream with SSE-formatted events.
*/
protected httpHandler(request: ServerRequest): ReadableStream;
/**
* Build the fetch URL with path variables and query params.
*/
protected buildFetchUrl(host: string, config?: SseRequestEntry<TConfig>): string;
}
/**
* Combined callable + SsePrimitive interface.
*/
interface SsePrimitiveFn<TConfig extends SseConfigSchema> extends SsePrimitive<TConfig> {
(config?: SseRequestEntry<TConfig>): SseStream<SseEventData<TConfig>>;
}
/**
* Infer the event data type from an SSE config schema.
*/
type SseEventData<TConfig extends SseConfigSchema> = TConfig["data"] extends TSchema ? Static<TConfig["data"]> : any;
/**
* Request entry type for SSE endpoints (body, params, query, headers).
*/
type SseRequestEntry<TConfig extends SseConfigSchema, T = SseRequestEntryContainer<TConfig>> = { [K in keyof T as T[K] extends undefined ? never : K]: T[K]; };
/**
* Full container type for SSE request entries.
*/
type SseRequestEntryContainer<TConfig extends SseConfigSchema> = {
body: TConfig["body"] extends TObject ? Static<TConfig["body"]> : undefined;
params: TConfig["params"] extends TObject ? Static<TConfig["params"]> : undefined;
headers?: TConfig["headers"] extends TObject ? Static<TConfig["headers"]> : Record<string, string>;
query?: TConfig["query"] extends TObject ? Partial<Static<TConfig["query"]>> : Record<string, string>;
};
//#endregion
//#region ../../src/server/core/providers/BunHttpServerProvider.d.ts
declare const envSchema$1: import("zod").ZodObject<{
SERVER_PORT: import("zod").ZodDefault<import("zod").ZodInt>;
SERVER_HOST: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare module "alepha" {
interface Env extends Partial<Static<typeof envSchema$1>> {}
}
declare class BunHttpServerProvider extends ServerProvider {
protected readonly alepha: Alepha;
protected readonly dateTimeProvider: DateTimeProvider;
protected readonly log: import("alepha/logger").Logger;
protected readonly env: {
SERVER_PORT: number;
SERVER_HOST: string;
};
protected readonly router: ServerRouterProvider;
protected bunServer?: ReturnType<typeof Bun.serve>;
get hostname(): string;
readonly start: import("alepha").HookPrimitive<"start">;
protected readonly stop: import("alepha").HookPrimitive<"stop">;
protected listen(): Promise<void>;
protected close(): Promise<void>;
}
//#endregion
//#region ../../src/server/core/providers/NodeHttpServerProvider.d.ts
declare const envSchema: import("zod").ZodObject<{
SERVER_PORT: import("zod").ZodDefault<import("zod").ZodInt>;
SERVER_HOST: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare module "alepha" {
interface Env extends Partial<Static<typeof envSchema>> {}
}
declare class NodeHttpServerProvider extends ServerProvider {
protected readonly alepha: Alepha;
protected readonly dateTimeProvider: DateTimeProvider;
protected readonly log: import("alepha/logger").Logger;
protected readonly env: {
SERVER_PORT: number;
SERVER_HOST: string;
};
protected readonly router: ServerRouterProvider;
/**
* Track active connections for fast shutdown.
*/
protected readonly connections: Set<Socket>;
/**
* Get number of active connections.
*/
getConnectionsCount(): number;
/**
* Server options.
*/
readonly options: {
/**
* Graceful shutdown timeout in ms.
* After this, remaining connections are forcefully closed.
* @default 30000
*/
shutdownTimeout: number;
};
get hostname(): string;
protected readonly handleRequestError: (res: ServerResponse$1, err: Error) => void;
server: Server;
readonly configure: import("alepha").HookPrimitive<"configure">;
readonly start: import("alepha").HookPrimitive<"start">;
protected requestListener: (req: IncomingMessage, res: ServerResponse$1) => void;
protected connectionListener: (socket: Socket) => void;
protected createHttpServer(): Server;
protected readonly stop: import("alepha").HookPrimitive<"stop">;
protected listen(): Promise<void>;
protected close(): Promise<void>;
protected destroyAllConnections(): void;
}
//#endregion
//#region ../../src/server/core/providers/ServerCompressProvider.d.ts
/**
* Compression configuration atom.
*/
declare const compressOptions: import("alepha").Atom<import("zod").ZodObject<{
disabled: import("zod").ZodOptional<import("zod").ZodBoolean>;
allowedContentTypes: import("zod").ZodArray<import("zod").ZodString>;
}, import("zod/v4/core").$strip>, "alepha.server.compress.options">;
type CompressOptions = Static<typeof compressOptions.schema>;
declare module "alepha" {
interface State {
[compressOptions.key]: CompressOptions;
}
}
declare class ServerCompressProvider {
static compressors: Record<string, {
compress: (...args: any[]) => Promise<Buffer>;
stream: (options?: any) => Transform;
} | undefined>;
protected readonly alepha: Alepha;
protected readonly options: Readonly<{
disabled?: boolean | undefined;
allowedContentTypes: string[];
}>;
readonly onResponse: import("alepha").HookPrimitive<"server:onResponse">;
protected isAllowedContentType(contentType: string | undefined): boolean;
protected compress(encoding: keyof typeof ServerCompressProvider.compressors, response: ServerResponse$2): Promise<void>;
/**
* Create a compressed stream that flushes after each chunk.
* This is essential for streaming SSR - ensures each chunk is sent immediately.
*/
protected createFlushingCompressStream(input: ReadableStream$1, createCompressor: (options?: any) => Transform, encoding: string, params: Record<number, any>): ReadableStream$1<Uint8Array>;
protected getParams(encoding: keyof typeof ServerCompressProvider.compressors): Record<number, any>;
protected setHeaders(response: ServerResponse$2, encoding: keyof typeof ServerCompressProvider.compressors): void;
}
//#endregion
//#region ../../src/server/core/providers/ServerHelmetProvider.d.ts
/**
* Helmet security headers configuration atom
*/
declare const helmetOptions: import("alepha").Atom<import("zod").ZodObject<{
disabled: import("zod").ZodOptional<import("zod").ZodBoolean>;
isSecure: import("zod").ZodOptional<import("zod").ZodBoolean>;
strictTransportSecurity: import("zod").ZodOptional<import("zod").ZodObject<{
maxAge: import("zod").ZodOptional<import("zod").ZodNumber>;
includeSubDomains: import("zod").ZodOptional<import("zod").ZodBoolean>;
preload: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod/v4/core").$strip>>;
xContentTypeOptions: import("zod").ZodOptional<import("zod").ZodBoolean>;
xFrameOptions: import("zod").ZodOptional<import("zod").ZodEnum<{
DENY: "DENY";
SAMEORIGIN: "SAMEORIGIN";
}>>;
xXssProtection: import("zod").ZodOptional<import("zod").ZodBoolean>;
contentSecurityPolicy: import("zod").ZodOptional<import("zod").ZodObject<{
directives: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>;
}, import("zod/v4/core").$strip>>;
referrerPolicy: import("zod").ZodOptional<import("zod").ZodEnum<{
"no-referrer": "no-referrer";
"no-referrer-when-downgrade": "no-referrer-when-downgrade";
origin: "origin";
"origin-when-cross-origin": "origin-when-cross-origin";
"same-origin": "same-origin";
"strict-origin": "strict-origin";
"strict-origin-when-cross-origin": "strict-origin-when-cross-origin";
"unsafe-url": "unsafe-url";
}>>;
}, import("zod/v4/core").$strip>, "alepha.server.helmet.options">;
type HelmetOptions = Static<typeof helmetOptions.schema>;
declare module "alepha" {
interface State {
[helmetOptions.key]: HelmetOptions;
}
}
type CspDirective = string | string[];
interface CspDirectives {
"default-src"?: CspDirective;
"script-src"?: CspDirective;
"style-src"?: CspDirective;
"img-src"?: CspDirective;
"connect-src"?: CspDirective;
"font-src"?: CspDirective;
"object-src"?: CspDirective;
"media-src"?: CspDirective;
"frame-src"?: CspDirective;
sandbox?: CspDirective | boolean;
"report-uri"?: string;
"child-src"?: CspDirective;
"form-action"?: CspDirective;
"frame-ancestors"?: CspDirective;
"plugin-types"?: CspDirective;
"base-uri"?: CspDirective;
[key: string]: CspDirective | undefined | boolean;
}
interface CspOptions {
directives: CspDirectives;
}
interface HstsOptions {
maxAge?: number;
includeSubDomains?: boolean;
preload?: boolean;
}
/**
* Provides a configurable way to apply essential HTTP security headers
* to every se