UNPKG

@withstudiocms/effect

Version:

Effect-TS Utilities for Astro

179 lines (178 loc) 8.17 kB
import type { APIContext, APIRoute, MiddlewareNext } from 'astro'; import type { Effect } from '../effect.js'; /** * Represents a middleware handler function for processing API requests within the Effect system. * * @param context - The API context object containing request and environment information. * @param next - The next middleware function in the chain. * @returns An Effect that resolves to either a Response or a Promise of Response. */ export type EffectMiddlewareHandler = (context: APIContext, next: MiddlewareNext) => Effect.Effect<Promise<Response> | Response, unknown, never>; /** * Represents an entry in the middleware router configuration. * * @property includePaths - Optional path(s) to include for this middleware. Can be a string or an array of strings. * @property excludePaths - Optional path(s) to exclude from this middleware. Can be a string or an array of strings. * @property priority - Optional priority for the middleware, determining the order of execution. Lower numbers execute first. * @property handler - The middleware handler function to execute for matched paths. */ export interface EffectMiddlewareRouterEntry { includePaths?: string | string[]; excludePaths?: string | string[]; priority?: number; handler: EffectMiddlewareHandler; } /** * Represents a handler function for an API route using the Effect system. * * @param context - The API context provided to the route handler. * @returns An Effect that resolves to a `Response` or a `Promise<Response>`. */ export type EffectAPIRouteHandler = (context: APIContext) => Effect.Effect<Promise<Response> | Response, unknown, never>; /** * Options for configuring the response of an API endpoint. * * @property allowedOrigins - An optional array of allowed origin URLs for CORS. * @property headers - An optional record of additional HTTP headers to include in the response. */ export interface AllResponseOpts { allowedOrigins?: string[]; headers?: HeadersInit; } /** * Extends {@link AllResponseOpts} to include HTTP methods allowed for the response. * * @remarks * This interface is typically used to specify additional options for API responses, * including which HTTP methods are permitted. * * @extends AllResponseOpts * * @property allowedMethods - An array of strings representing the HTTP methods that are allowed (e.g., 'GET', 'POST'). */ export interface OptionsResponseOpts extends AllResponseOpts { allowedMethods: string[]; } /** * Options for creating a response object, extending all base response options. * * @extends AllResponseOpts * @property {number} [status] - Optional HTTP status code for the response. * @property {string} [statusText] - Optional HTTP status text for the response. */ export interface CreateResponseOpts extends AllResponseOpts { status?: number; statusText?: string; } /** * Represents the resolved type of the body content from an Astro API request, * based on the specified body parsing method. * * @template T - The type of body parsing method to use. Can be 'json', 'text', or 'formData'. * - 'json': Resolves to the parsed JSON object. * - 'text': Resolves to the request body as a string. * - 'formData': Resolves to a FormData object. * * This utility type extracts the return type of the corresponding method on `APIContext['request']` * and awaits it, providing the actual type you will receive after calling the method. * * @example * type JsonBody = AstroAPIRequestBody<'json'>; // Parsed JSON object * type TextBody = AstroAPIRequestBody<'text'>; // string * type FormDataBody = AstroAPIRequestBody<'formData'>; // FormData */ export type AstroAPIRequestBody<T extends 'json' | 'text' | 'formData'> = Awaited<ReturnType<APIContext['request'][T]>>; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; /** * Options for configuring an Effect API route. * * @property onError - Optional callback invoked when an error occurs during route handling. * Receives the error and the current API context. Should return a `Response` or a promise resolving to a `Response`. * * @property onSuccess - Optional callback invoked after a successful response is generated. * Receives the response and the current API context. Should return a `Response` or a promise resolving to a `Response`. * * @property onBeforeEffect - Optional callback invoked before the main effect is executed. * Receives the current API context and can return a modified context or a promise resolving to one. * * @property cors - Optional CORS configuration for the route. * - `origin`: Allowed origins (string, array of strings, or boolean). * - `methods`: Allowed HTTP methods. * - `headers`: Allowed headers. * - `credentials`: Whether credentials are allowed. * * @property timeout - Optional timeout in milliseconds for the route handler. * * @property validate - Optional validation functions for incoming request data. * - `params`: Function to validate route parameters. * - `query`: Function to validate query parameters. * - `body`: Function to validate the request body, parameterized by body type. */ export interface EffectRouteOptions { onError?: (error: unknown, context: APIContext) => Response | Promise<Response>; onSuccess?: (response: Response, context: APIContext) => Response | Promise<Response>; onBeforeEffect?: (context: APIContext) => APIContext | Promise<APIContext>; cors?: { origin?: string | string[] | boolean; methods?: ReadonlyArray<HTTPMethod>; headers?: string[]; credentials?: boolean; }; timeout?: number; validate?: { params?: (params: APIContext['params']) => boolean | Promise<boolean>; query?: (query: APIContext['url']['searchParams']) => boolean | Promise<boolean>; body?: { kind: 'json'; json: (body: any) => boolean | Promise<boolean>; } | { kind: 'text'; text: (body: string) => boolean | Promise<boolean>; } | { kind: 'formData'; formData: (body: FormData) => boolean | Promise<boolean>; }; }; } /** * Configuration options for an API route handler. * * Extends {@link EffectRouteOptions} to provide additional configuration, * including the ability to specify method-specific overrides. * * @property methods - An optional object allowing you to override route options * for specific HTTP methods. Each key corresponds to an HTTP method and its value * is a partial set of {@link EffectRouteOptions} for that method. * Supported methods include: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, and ALL. */ export interface RouteHandlerConfig extends EffectRouteOptions { methods?: Partial<Record<HTTPMethod | 'ALL', Partial<EffectRouteOptions>>>; } /** * Represents a collection of HTTP method handlers for an API route. * Each property corresponds to a standard HTTP method and is optional. * * @property GET - Handler for HTTP GET requests. * @property POST - Handler for HTTP POST requests. * @property PUT - Handler for HTTP PUT requests. * @property DELETE - Handler for HTTP DELETE requests. * @property PATCH - Handler for HTTP PATCH requests. * @property HEAD - Handler for HTTP HEAD requests. * @property OPTIONS - Handler for HTTP OPTIONS requests. * @property ALL - Handler for all HTTP methods. */ export type RouteHandlers = Partial<Record<HTTPMethod | 'ALL', EffectAPIRouteHandler>>; /** * Extracts the defined routes from a collection of route handlers. * * @template T - The type of the route handlers. * @returns An object type where each key corresponds to a defined route handler, * and the value is the corresponding APIRoute type. * * @remarks * This utility type filters out any undefined properties from the provided route handlers, * ensuring that only valid routes are included in the resulting type. */ export type ExtractDefinedRoutes<T extends RouteHandlers> = { [K in keyof T as T[K] extends EffectAPIRouteHandler ? K : never]: APIRoute; };