UNPKG

alepha

Version:

Alepha is a convention-driven TypeScript framework for building robust, end-to-end type-safe applications, from serverless APIs to full-stack React apps.

656 lines (653 loc) 24.6 kB
import * as _alepha_core5 from "alepha"; import * as _alepha_core4 from "alepha"; import * as _alepha_core11 from "alepha"; import * as _alepha_core6 from "alepha"; import * as _alepha_core10 from "alepha"; import * as _alepha_core1 from "alepha"; import * as _alepha_core0 from "alepha"; import { Alepha, AlephaError, Async, Descriptor, FileLike, KIND, Static, StreamLike, TObject, TSchema } from "alepha"; import { Readable } from "node:stream"; import { ReadableStream } from "node:stream/web"; import { Route, RouterProvider } from "alepha/router"; import * as _alepha_cache0 from "alepha/cache"; import { IncomingMessage, ServerResponse as ServerResponse$1 } from "node:http"; import { DateTimeProvider, DurationLike } from "alepha/datetime"; import * as _sinclair_typebox0 from "@sinclair/typebox"; import * as _sinclair_typebox25 from "@sinclair/typebox"; import * as _sinclair_typebox35 from "@sinclair/typebox"; import * as http0 from "http"; //#region src/constants/routeMethods.d.ts declare const routeMethods: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "CONNECT", "TRACE"]; type RouteMethod = (typeof routeMethods)[number]; //# sourceMappingURL=routeMethods.d.ts.map //#endregion //#region src/helpers/ServerReply.d.ts declare class ServerReply { headers: Record<string, string> & { "set-cookie"?: string[]; }; status?: number; body?: any; redirect(url: string, status?: number): void; setStatus(status: number): void; setHeader(name: string, value: string): void; } //# sourceMappingURL=ServerReply.d.ts.map //#endregion //#region src/interfaces/ServerRequest.d.ts interface RequestConfigSchema { body?: TSchema; params?: TObject; query?: TObject; headers?: TObject; response?: TSchema; } interface ServerRequestConfig<TConfig extends RequestConfigSchema = RequestConfigSchema> { body: TConfig["body"] extends TSchema ? Static<TConfig["body"]> : any; headers: TConfig["headers"] extends TObject ? Static<TConfig["headers"]> : Record<string, string>; params: TConfig["params"] extends TObject ? Static<TConfig["params"]> : Record<string, string>; query: TConfig["query"] extends TObject ? Static<TConfig["query"]> : Record<string, string>; } type ServerRequestConfigEntry<TConfig extends RequestConfigSchema = RequestConfigSchema> = Partial<ServerRequestConfig<TConfig>>; interface ServerRequest<TConfig extends RequestConfigSchema = RequestConfigSchema> extends ServerRequestConfig<TConfig> { method: RouteMethod; url: URL; metadata: Record<string, any>; reply: ServerReply; raw: { node?: { req: IncomingMessage; res: ServerResponse$1; }; }; } interface ServerRoute<TConfig extends RequestConfigSchema = RequestConfigSchema> extends Route { handler: ServerHandler<TConfig>; method?: RouteMethod; schema?: TConfig; /** * @see ServerLoggerProvider */ silent?: boolean; } type ServerResponseBody<TConfig extends RequestConfigSchema = RequestConfigSchema> = TConfig["response"] extends TSchema ? Static<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>>; type ServerMiddlewareHandler<TConfig extends RequestConfigSchema = RequestConfigSchema> = (request: ServerRequest<TConfig>) => Async<ServerResponseBody<TConfig> | undefined>; interface ServerResponse { body: string | Buffer | ArrayBuffer | Readable | ReadableStream; headers: Record<string, string>; status: number; } interface ServerRouteMatcher extends Route { handler: (request: ServerRawRequest) => Promise<ServerResponse>; } interface ServerRawRequest { method: RouteMethod; url: URL; headers: Record<string, string>; query: Record<string, string>; params: Record<string, string>; raw: { node?: { req: IncomingMessage; res: ServerResponse$1; }; }; } //# sourceMappingURL=ServerRequest.d.ts.map //#endregion //#region src/providers/ServerProvider.d.ts declare abstract class ServerProvider { protected readonly alepha: Alepha; abstract get hostname(): string; protected isViteNotFound(url?: string, route?: Route, params?: Record<string, string>): boolean; } //# sourceMappingURL=ServerProvider.d.ts.map //#endregion //#region src/providers/ServerRouterProvider.d.ts /** * Main router for all routes on the server side. * * - $route => generic route * - $action => action route (for API calls) * - $page => React route (for SSR) */ declare class ServerRouterProvider extends RouterProvider<ServerRouteMatcher> { protected readonly alepha: Alepha; protected readonly routes: ServerRoute[]; getRoutes(): ServerRoute[]; createRoute<TConfig extends RequestConfigSchema = RequestConfigSchema>(route: ServerRoute<TConfig>): void; onRequest(route: ServerRoute, rawRequest: ServerRawRequest, responseKind: ResponseKind): Promise<ServerResponse>; protected processRequest(request: ServerRequest, route: ServerRoute, responseKind: ResponseKind): Promise<{ status: number; headers: Record<string, string> & { "set-cookie"?: string[]; }; body: any; }>; protected runRouteHandler(route: ServerRoute, request: ServerRequest, responseKind: ResponseKind): Promise<void>; protected getResponseType(schema?: RequestConfigSchema): ResponseKind; protected errorHandler(route: ServerRoute, request: ServerRequest, error: Error): Promise<void>; validateRequest(route: { schema?: RequestConfigSchema; }, request: ServerRequestConfig): void; serializeResponse(route: ServerRoute, reply: ServerReply, responseKind: ResponseKind): void; } //# sourceMappingURL=ServerRouterProvider.d.ts.map //#endregion //#region src/services/HttpClient.d.ts declare class HttpClient { protected readonly log: _alepha_core5.Logger; protected readonly alepha: Alepha; readonly cache: _alepha_cache0.CacheDescriptorFn<HttpClientCache, any[]>; protected readonly pendingRequests: HttpClientPendingRequests; clear(): Promise<void>; fetchAction(args: FetchActionArgs): Promise<FetchResponse>; fetch<T>(url: string, request?: RequestInit, // standard options options?: FetchOptions): Promise<FetchResponse<T>>; json<T = any>(url: string, options?: RequestInit): Promise<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: FetchOptions): 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 { /** * Key to identify the request in the pending requests. */ key?: string; /** * The schema to validate the response against. */ schema?: TSchema; /** * Built-in cache options. */ 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; schema?: { params?: TObject; query?: TObject; body?: TSchema; response?: TSchema; }; } //#endregion //#region src/descriptors/$action.d.ts /** * Create an action endpoint. * * By default, all actions are prefixed by `/api`. * If `name` is not provided, the action will be named after the property key. * If `path` is not provided, the action will be named after the function name. * * @example * ```ts * class MyController { * hello = $action({ * handler: () => "Hello World", * }) * } * // GET /api/hello -> "Hello World" * ``` */ declare const $action: { <TConfig extends RequestConfigSchema>(options: ActionDescriptorOptions<TConfig>): ActionDescriptor<TConfig>; [KIND]: typeof ActionDescriptor; }; interface ActionDescriptorOptions<TConfig extends RequestConfigSchema> extends Omit<ServerRoute, "handler" | "path" | "schema" | "mapParams"> { /** * 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 do disable one specific route. * Route won't be available in the API but can still be called locally! */ disabled?: boolean; /** * Main route handler. This is where the route logic is implemented. */ handler: ServerActionHandler<TConfig>; } declare class ActionDescriptor<TConfig extends RequestConfigSchema> extends Descriptor<ActionDescriptorOptions<TConfig>> { protected readonly log: _alepha_core4.Logger; protected readonly env: { SERVER_API_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>>>; } 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: TConfig["body"] extends TSchema ? Static<TConfig["body"]> : undefined; params: TConfig["params"] extends TSchema ? Static<TConfig["params"]> : undefined; headers?: TConfig["headers"] extends TSchema ? Static<TConfig["headers"]> : undefined; query?: TConfig["query"] extends TSchema ? Partial<Static<TConfig["query"]>> : undefined; }; interface ClientRequestOptions extends FetchOptions { /** * Standard request fetch options. */ request?: RequestInit; } type ClientRequestResponse<TConfig extends RequestConfigSchema> = TConfig["response"] extends TSchema ? Static<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> {} //# sourceMappingURL=$action.d.ts.map //#endregion //#region src/errors/HttpError.d.ts declare const isHttpError: (error: unknown, status?: number) => error is HttpErrorLike; declare class HttpError extends AlephaError { name: string; static is: (error: unknown, status?: number) => error is HttpErrorLike; static toJSON(error: HttpError): { status: number; error: string | undefined; message: string; cause: { name: string; message: string; }; } | { status: number; error: string | undefined; message: string; cause?: undefined; }; readonly status: number; readonly error?: string; readonly reason?: { name: string; message: string; }; constructor(options: { error?: string; message: string; status: number; cause?: { name: string; message: string; } | unknown; }, cause?: unknown); } declare const errorNameByStatus: Record<number, string>; interface HttpErrorLike extends Error { status: number; } //# sourceMappingURL=HttpError.d.ts.map //#endregion //#region src/descriptors/$route.d.ts /** * Create a basic endpoint. * * It's a low level descriptor. You probably want to use `$action` instead. * * @see {@link $action} * @see {@link $page} */ declare const $route: { <TConfig extends RequestConfigSchema>(options: RouteDescriptorOptions<TConfig>): RouteDescriptor<TConfig>; [KIND]: typeof RouteDescriptor; }; interface RouteDescriptorOptions<TConfig extends RequestConfigSchema = RequestConfigSchema> extends ServerRoute<TConfig> {} declare class RouteDescriptor<TConfig extends RequestConfigSchema> extends Descriptor<RouteDescriptorOptions<TConfig>> { protected readonly serverRouterProvider: ServerRouterProvider; protected onInit(): void; } //# sourceMappingURL=$route.d.ts.map //#endregion //#region src/errors/BadRequestError.d.ts declare class BadRequestError extends HttpError { constructor(message?: string, cause?: unknown); } //# sourceMappingURL=BadRequestError.d.ts.map //#endregion //#region src/errors/ConflictError.d.ts declare class ConflictError extends HttpError { constructor(message?: string, cause?: unknown); } //# sourceMappingURL=ConflictError.d.ts.map //#endregion //#region src/errors/ForbiddenError.d.ts declare class ForbiddenError extends HttpError { constructor(message?: string, cause?: unknown); } //# sourceMappingURL=ForbiddenError.d.ts.map //#endregion //#region src/errors/NotFoundError.d.ts declare class NotFoundError extends HttpError { constructor(message?: string, cause?: unknown); } //# sourceMappingURL=NotFoundError.d.ts.map //#endregion //#region src/errors/UnauthorizedError.d.ts declare class UnauthorizedError extends HttpError { constructor(message?: string, cause?: unknown); } //# sourceMappingURL=UnauthorizedError.d.ts.map //#endregion //#region src/errors/ValidationError.d.ts declare class ValidationError extends HttpError { constructor(message?: string, cause?: unknown); } //# sourceMappingURL=ValidationError.d.ts.map //#endregion //#region src/helpers/isMultipart.d.ts declare const isMultipart: (options: { schema?: RequestConfigSchema; }) => boolean; //# sourceMappingURL=isMultipart.d.ts.map //#endregion //#region src/schemas/apiLinksResponseSchema.d.ts declare const apiLinkSchema: _sinclair_typebox0.TObject<{ name: _sinclair_typebox0.TString; path: _sinclair_typebox0.TString; method: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; group: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; requestBodyType: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; service: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; }>; declare const apiLinksResponseSchema: _sinclair_typebox0.TObject<{ prefix: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; links: _sinclair_typebox0.TArray<_sinclair_typebox0.TObject<{ name: _sinclair_typebox0.TString; path: _sinclair_typebox0.TString; method: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; group: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; requestBodyType: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; service: _sinclair_typebox0.TOptional<_sinclair_typebox0.TString>; }>>; }>; type ApiLinksResponse = Static<typeof apiLinksResponseSchema>; type ApiLink = Static<typeof apiLinkSchema>; //# sourceMappingURL=apiLinksResponseSchema.d.ts.map //#endregion //#region src/schemas/errorSchema.d.ts declare const errorSchema: _sinclair_typebox25.TObject<{ error: _sinclair_typebox25.TString; status: _sinclair_typebox25.TNumber; message: _sinclair_typebox25.TString; details: _sinclair_typebox25.TOptional<_sinclair_typebox25.TString>; cause: _sinclair_typebox25.TOptional<_sinclair_typebox25.TObject<{ name: _sinclair_typebox25.TString; message: _sinclair_typebox25.TString; }>>; }>; //# sourceMappingURL=errorSchema.d.ts.map //#endregion //#region src/schemas/okSchema.d.ts declare const okSchema: _sinclair_typebox35.TObject<{ ok: _sinclair_typebox35.TBoolean; id: _sinclair_typebox35.TOptional<_sinclair_typebox35.TUnion<[_sinclair_typebox35.TString, _sinclair_typebox35.TInteger]>>; count: _sinclair_typebox35.TOptional<_sinclair_typebox35.TNumber>; }>; type Ok = Static<typeof okSchema>; //# sourceMappingURL=okSchema.d.ts.map //#endregion //#region src/providers/NodeHttpServerProvider.d.ts declare const envSchema: _alepha_core11.TObject<{ SERVER_PORT: _alepha_core11.TNumber; SERVER_HOST: _alepha_core11.TString; }>; 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: _alepha_core11.Logger; protected readonly env: { SERVER_PORT: number; SERVER_HOST: string; }; protected readonly router: ServerRouterProvider; protected readonly server: http0.Server<typeof IncomingMessage, typeof ServerResponse$1>; protected readonly onNodeRequest: _alepha_core11.HookDescriptor<"node:request">; handle(req: IncomingMessage, res: ServerResponse$1): Promise<void>; createRouterRequest(req: IncomingMessage, res: ServerResponse$1, params?: Record<string, string>): ServerRawRequest; getProtocol(req: IncomingMessage): "http" | "https"; get hostname(): string; readonly start: _alepha_core11.HookDescriptor<"start">; protected readonly stop: _alepha_core11.HookDescriptor<"stop">; protected listen(): Promise<void>; protected close(): Promise<void>; } //#endregion //#region src/providers/ServerLoggerProvider.d.ts declare class ServerLoggerProvider { protected readonly log: _alepha_core6.Logger; protected readonly alepha: Alepha; readonly onRequest: _alepha_core6.HookDescriptor<"server:onRequest">; readonly onError: _alepha_core6.HookDescriptor<"server:onError">; readonly onResponse: _alepha_core6.HookDescriptor<"server:onResponse">; } //# sourceMappingURL=ServerLoggerProvider.d.ts.map //#endregion //#region src/providers/ServerNotReadyProvider.d.ts /** * On every request, this provider checks if the server is ready. * * If the server is not ready, it responds with a 503 status code and a message indicating that the server is not ready yet. * * The response also includes a `Retry-After` header indicating that the client should retry after 5 seconds. */ declare class ServerNotReadyProvider { protected readonly alepha: Alepha; readonly onRequest: _alepha_core10.HookDescriptor<"server:onRequest">; } //# sourceMappingURL=ServerNotReadyProvider.d.ts.map //#endregion //#region src/providers/ServerTimingProvider.d.ts type TimingMap = Record<string, [number, number]>; declare class ServerTimingProvider { protected readonly log: _alepha_core1.Logger; protected readonly alepha: Alepha; readonly onRequest: _alepha_core1.HookDescriptor<"server:onRequest">; readonly onResponse: _alepha_core1.HookDescriptor<"server:onResponse">; protected get handlerName(): string; beginTiming(name: string): void; endTiming(name: string): void; protected setDuration(name: string, timing: TimingMap): void; } //#endregion //#region src/index.d.ts declare module "alepha" { interface Hooks { "action:onRequest": { action: ActionDescriptor<RequestConfigSchema>; request: ServerRequest; options: ClientRequestOptions; }; "action:onResponse": { action: ActionDescriptor<RequestConfigSchema>; request: ServerRequest; options: ClientRequestOptions; response: any; }; "server:onRequest": { route: ServerRoute; request: ServerRequest; }; "server:onError": { route: ServerRoute; request: ServerRequest; error: Error; }; "server:onSend": { route: ServerRoute; request: ServerRequest; }; "server:onResponse": { route: ServerRoute; request: ServerRequest; response: ServerResponse; }; "client:onRequest": { route: HttpAction; config: ServerRequestConfigEntry; options: ClientRequestOptions; headers: Record<string, string>; request: RequestInit; }; "client:beforeFetch": { url: string; options: FetchOptions; request: RequestInit; }; "client:onError": { route?: HttpAction; error: HttpError; }; "node:request": { req: IncomingMessage; res: ServerResponse$1; }; } } /** * Provides high-performance HTTP server capabilities with declarative routing and action descriptors. * * The server module enables building REST APIs and web applications using `$route` and `$action` descriptors * on class properties. It provides automatic request/response handling, schema validation, middleware support, * and seamless integration with other Alepha modules for a complete backend solution. * * @see {@link $route} * @see {@link $action} * @module alepha.server */ declare const AlephaServer: _alepha_core0.Service<_alepha_core0.Module>; //# sourceMappingURL=index.d.ts.map //#endregion export { $action, $route, ActionDescriptor, ActionDescriptorOptions, AlephaServer, ApiLink, ApiLinksResponse, BadRequestError, ClientRequestEntry, ClientRequestEntryContainer, ClientRequestOptions, ClientRequestResponse, ConflictError, FetchActionArgs, FetchOptions, FetchResponse, ForbiddenError, HttpAction, HttpClient, HttpClientPendingRequests, HttpError, HttpErrorLike, NodeHttpServerProvider, NotFoundError, Ok, RequestConfigSchema, ResponseBodyType, ResponseKind, RouteDescriptor, RouteDescriptorOptions, RouteMethod, ServerActionHandler, ServerActionRequest, ServerHandler, ServerLoggerProvider, ServerMiddlewareHandler, ServerNotReadyProvider, ServerProvider, ServerRawRequest, ServerReply, ServerRequest, ServerRequestConfig, ServerRequestConfigEntry, ServerResponse, ServerResponseBody, ServerRoute, ServerRouteMatcher, ServerRouterProvider, ServerTimingProvider, UnauthorizedError, ValidationError, apiLinkSchema, apiLinksResponseSchema, errorNameByStatus, errorSchema, isHttpError, isMultipart, okSchema, routeMethods }; //# sourceMappingURL=index.d.ts.map