@withstudiocms/effect
Version:
Effect-TS Utilities for Astro
118 lines (117 loc) • 5.56 kB
TypeScript
import type { APIContext, APIRoute } from 'astro';
import type { EffectAPIRouteHandler, EffectRouteOptions, ExtractDefinedRoutes, RouteHandlerConfig, RouteHandlers } from './types.js';
/**
* Defines an API route handler for Astro using an effect-based approach.
*
* @param context - The API context provided by Astro for the current request.
* @returns A function that takes an `EffectAPIRouteHandler`, executes it with the provided context,
* and returns a `Promise<Response>` representing the HTTP response.
*
* @example
* ```typescript
* export const GET = defineAPIRoute(context)(async (ctx) => {
* // Your effectful logic here
* return new Response("Hello, world!");
* });
* ```
*
* @deprecated Use `createEffectRoute` instead for better clarity and consistency.
*/
export declare const defineAPIRoute: (context: APIContext) => (fn: EffectAPIRouteHandler) => Promise<Response>;
/**
* Creates an Astro API route handler that executes the provided effectful handler function.
*
* @param fn - The effectful API route handler function to be executed. It should accept an `APIContext` and return an effect.
* @returns An Astro `APIRoute` handler that runs the effect and returns a `Response`.
*/
export declare const createEffectAPIRoute: (fn: EffectAPIRouteHandler) => APIRoute;
/**
* Wraps an API route handler with effectful middleware, including CORS, validation, timeout, and custom hooks.
*
* @param fn - The main effectful API route handler function to execute.
* @param options - Optional configuration for the route, including CORS, validation, timeout, and middleware hooks.
* @returns An `APIRoute` function compatible with Astro's API routes.
*
* @remarks
* This utility provides a standardized way to handle API routes with common concerns such as:
* - Applying CORS headers and handling preflight requests.
* - Running pre-effect middleware (`onBeforeEffect`).
* - Validating incoming requests (`validate`).
* - Enforcing a timeout for the effect execution.
* - Running post-success (`onSuccess`) and error (`onError`) middleware.
* - Ensuring CORS headers are present on all responses, including errors.
*
* @example
* ```typescript
* export const POST = withEffect(async (context) => {
* // Your effect logic here
* }, {
* cors: { origin: '*' },
* validate: { body: z.object({ name: z.string() }) },
* timeout: 5000,
* onSuccess: async (response, context) => response,
* onError: async (error, context) => new Response('Error', { status: 500 }),
* });
* ```
*/
export declare const withEffectAPI: (fn: EffectAPIRouteHandler, options?: EffectRouteOptions) => APIRoute;
/**
* Creates API route handlers with effect support for each HTTP method provided.
*
* This function takes a set of route handlers and an optional configuration object,
* then returns an object mapping HTTP methods to their corresponding API route handlers,
* each wrapped with effect middleware and merged configuration.
*
* The return type is precisely typed to only include the methods that were provided
* in the handlers parameter, eliminating undefined from the union types.
*
* @param handlers - An object containing route handlers keyed by HTTP method (e.g., 'GET', 'POST').
* @param config - Optional global configuration for all handlers. Can include method-specific overrides via the `methods` property.
* @returns An object mapping each provided HTTP method to its configured API route handler.
*/
export declare const createEffectAPIRoutes: <T extends RouteHandlers>(handlers: T, config?: RouteHandlerConfig) => ExtractDefinedRoutes<T>;
/**
* A builder class for defining API route handlers with optional per-method and global configuration.
*
* Provides a fluent interface for registering HTTP method handlers (`get`, `post`, `put`, `delete`, `patch`, `all`)
* and setting global or per-method options. Use `build()` to generate the final route configuration.
*
* Each method returns a new builder type that accumulates the added methods, ensuring precise typing
* in the final built routes object.
*
* @example
* ```typescript
* const routes = new EffectRouteBuilder()
* .withGlobalConfig({ cors: { origin: true } })
* .get(getHandler, { timeout: 3000 })
* .post(postHandler)
* .build();
* // routes has type: { GET: APIRoute, POST: APIRoute } (no undefined!)
* ```
*/
export declare class EffectAPIRouteBuilder<T extends Partial<RouteHandlers> = {}> {
private handlers;
private config;
constructor(handlers?: T);
withGlobalConfig(config: EffectRouteOptions): EffectAPIRouteBuilder<T>;
private addHandler;
get<U extends EffectAPIRouteHandler>(handler: U, options?: Partial<EffectRouteOptions>): EffectAPIRouteBuilder<T & {
GET: U;
}>;
post<U extends EffectAPIRouteHandler>(handler: U, options?: Partial<EffectRouteOptions>): EffectAPIRouteBuilder<T & {
POST: U;
}>;
put<U extends EffectAPIRouteHandler>(handler: U, options?: Partial<EffectRouteOptions>): EffectAPIRouteBuilder<T & {
PUT: U;
}>;
delete<U extends EffectAPIRouteHandler>(handler: U, options?: Partial<EffectRouteOptions>): EffectAPIRouteBuilder<T & {
DELETE: U;
}>;
patch<U extends EffectAPIRouteHandler>(handler: U, options?: Partial<EffectRouteOptions>): EffectAPIRouteBuilder<T & {
PATCH: U;
}>;
all<U extends EffectAPIRouteHandler>(handler: U, options?: Partial<EffectRouteOptions>): EffectAPIRouteBuilder<T & {
ALL: U;
}>;
build(): ExtractDefinedRoutes<T>;
}