UNPKG

@mochabug/adapt-plugin-toolkit

Version:

The API toolkit to facilitate mochabug adapt plugin development

503 lines 24.9 kB
import { ConfiguratorApi, ExecutorApi, SessionExecutorApi, StopExecutorApi } from './api'; import { SignalData } from './genproto/mochabugapis/adapt/graph/signal_data_pb'; import { CronTriggerRequest, ExchangeResultRequest, StartExecutionRequest, StopExecutionRequest } from './genproto/mochabugapis/adapt/runtime/v1/incoming_pb'; import { ConfiguratorEnvironment, ExecutionContext, ExecutorEnvironment } from './types'; export interface ExchangeResultWrapper extends ExchangeResultRequest { getSignal<T>(key: string): T; getSignalBinary(key: string): SignalData; } /** * Takes a sequence of path segments and joins them together into a single path. * This function follows Linux-style path semantics, and behaves similarly to the `path.join()` method in Node.js. * * It can handle relative path components (e.g., '..') and will correctly ascend directories when they are encountered. * Note that it will not resolve '..' that ascend beyond the root directory. * Leading and trailing slashes on individual path segments are ignored. * However, if the original first path starts with a slash, the final result will also start with a slash. * * @example * joinPaths('/foo', 'bar', 'baz/asdf', 'quux', '..'); // Returns: "/foo/bar/baz" * * @param {...string[]} paths - The path segments to join. Each entry should be a string representing a path segment. * These can include both directories and filenames, and can be absolute or relative paths. * Each argument can also include multiple path segments separated by slashes. * @returns {string} A string representing the joined path. The resulting path is normalized * (i.e., '..' and '.' path segments are resolved), and any redundant slashes are removed. * If the original first path starts with a slash, the final result will also start with a slash. */ export declare function joinPaths(...paths: string[]): string; /** * Represents a middleware function in the routing system. * * Middleware functions are designed to: * - Perform operations on the incoming request. * - Modify the execution context with additional data. * - Short-circuit the request handling by directly returning a response. * They are executed in the order they are added to the router. * * Common use cases for middleware include: * - Logging incoming requests. * - Authentication and authorization checks. * - Request validation. * - Error handling. * - Modifying the execution context. * * @template T * The type of the API that this middleware can handle. This can be: * - `ConfiguratorApi`: An API tailored for configuration tasks. * - `ExecutorApi`: An API tailored for execution tasks. * * @template C * The type of the execution context passed through the middleware during the request's lifecycle. * This context can be used to share data or state across different parts of the request processing pipeline. * * @template R * The return type of the middleware. By default, it can be `void` or `Response`, but can be constrained * to just `void` if needed. * * @param req * The incoming web request, providing details such as headers, body content, method, URL, etc. * Middleware can inspect or modify the request before it reaches the route handler. * * @param api * The API-specific functionalities, which could be an instance of `ConfiguratorApi` or `ExecutorApi`. * Middleware can utilize this API for tasks or checks related to the API's capabilities. * * @param ctx * The execution context for the current request. Middleware can read or modify this context to share * data with subsequent middleware or route handlers. For instance, an authentication middleware might * add a user object to the context after verifying a user's credentials. * * @param next * A function that passes control to the next middleware in the chain. If the current middleware is the * last in the chain, calling `next` will pass control to the route handler. Unless returning a response, * middleware should call this function to continue the request handling process. * * @returns * A promise that resolves to either `void` or a `Response` object. If the middleware returns `void`, the * next middleware or route handler is executed. If it returns a `Response`, the middleware chain is * short-circuited, and the response is sent to the client, bypassing subsequent middleware or route handlers. */ export type Middleware<T extends ConfiguratorApi | ExecutorApi, C extends ExecutionContext = ExecutionContext, R = void | Response> = (req: Request, api: T, ctx: C, next: () => Promise<R>) => Promise<R>; /** * Represents an HTTP request method. */ export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; /** * Represent the method HTTP request options */ export type RequestMethodOption = RequestMethod | RequestMethod[] | '*'; /** * Represents a set of key-value pairs for parameters. */ export type Params = Record<string, string>; /** * Represents the structure of the route information for a request in a server environment. * This is similar to the routing structure used in frameworks like Express.js. * * It provides a comprehensive view of the route which a request is being handled by, * encompassing the actual path, URL path parameters, and search (query) parameters. * * - `path`: Holds the route path string that the server listens on. This defines the endpoint * of your API and is used to match incoming requests. * * - `params`: Represents dynamic parameters within the request path. Useful for routes * with path parameters, e.g., `/users/:userId`, where `:userId` is a dynamic segment * and its actual value is captured as a parameter. * * - `searchParams`: Reflects the search (query) parameters from the request's URL. * Useful for filtering or altering the server's response based on these parameters. * * @property path - The path of the route to match incoming requests. * @property params - An object representing the path parameters. * @property searchParams - An object representing search (query) parameters. */ export type RouteInfo = { path: string; params: Params; searchParams: Params; }; /** * Represents a route handler function for processing web requests. * * The handler receives the incoming request and the associated route information. * It's expected to return a Promise that resolves to the appropriate response. * * - `req`: Contains detailed information about the incoming request, including headers, * body content, method, etc. * * - `route`: Provides structured information about the matched route, including the path, * any dynamic path parameters, and search (query) parameters. * * @typedef RouteHandler * @param req - The incoming web request. * @param route - Information about the matched route. * @returns A Promise that resolves to the appropriate server response. */ export type RouteHandler = (req: Request, route: RouteInfo) => Promise<Response>; /** * Represents a route handler function tailored for APIs of type `ConfiguratorApi` * or `ExecutorApi`. This handler processes incoming requests by leveraging specific * API functionalities and returns an appropriate response. * * @template T * The type of the API being used in the handler. This can be either `ConfiguratorApi` or `ExecutorApi`. * @template C * The type of the execution context that provides additional information about the ongoing process or operation. * * @param req * The incoming web request, containing details like headers, body content, and method. * @param api * The specific API instance, representing either `ConfiguratorApi` or `ExecutorApi` functionalities. * @param route * Structured information about the matched route, including path, dynamic path parameters, and query parameters. * @param ctx * The execution context providing additional data or state for the route handler. * * @returns {Promise<Response>} * A Promise that resolves to the appropriate server response. Errors during processing should be caught and * reflected in the resulting `Response`. */ export type ApiRouteHandler<T extends ConfiguratorApi | ExecutorApi, C extends ExecutionContext = ExecutionContext> = (req: Request, api: T, route: RouteInfo, ctx: C) => Promise<Response>; /** * Represents a route handler function designed for APIs of type `StopExecutorApi` * or `SessionExecutorApi`. This handler processes incoming requests using specific * API functionalities. * * @template T * The type of the API being used in the handler, either `StopExecutorApi` or `SessionExecutorApi`. * @template C * The type of the execution context providing additional information about the ongoing process or operation. * * @param req * The incoming web request. * @param api * The specific API instance, representing functionalities of either `StopExecutorApi` or `SessionExecutorApi`. * @param ctx * The execution context providing additional data or state for the route handler. * * @returns {Promise<void>} * A Promise that resolves once the handler has processed the request. Errors should be caught and handled appropriately. */ export type InternalRouteHandler<R extends StartExecutionRequest | StopExecutionRequest | CronTriggerRequest, T extends StopExecutorApi | SessionExecutorApi, C extends ExecutionContext = ExecutionContext> = (req: R, api: T, ctx: C) => Promise<void>; /** * Represents a route handler function tailored for the `SessionExecutorApi`. This handler * processes incoming requests using the functionalities of `SessionExecutorApi` and responds * based on the specific exchange that triggered the handler. * * @template T * The type of the API being used in the handler, specifically `SessionExecutorApi`. * @template C * The type of the execution context providing additional information about the ongoing process or operation. * * @param req * The incoming web request. * @param api * The specific API instance, representing `SessionExecutorApi` functionalities. * @param name * The name of the exchange that triggered the handler. * @param ctx * The execution context providing additional data or state for the route handler. * * @returns * A Promise that resolves once the handler has processed the request. Errors should be caught and handled appropriately. */ export type ExchangeRouteHandler<R extends ExchangeResultWrapper, T extends SessionExecutorApi, C extends ExecutionContext = ExecutionContext> = (req: R, api: T, name: string, ctx: C) => Promise<void>; /** * Represents an individual route, providing functionalities to match HTTP methods * and URL paths against pre-defined templates. */ export declare class Route { private method; private matcher; /** * Constructs a new `Route` instance. * * @param {RequestMethodOption} method - The HTTP method or methods the route responds to. * @param {string} template - The URL path template, which may include parameters, that the route matches against. * * @throws {Error} Throws an error if the provided template is invalid. */ constructor(method: RequestMethodOption, template: string); /** * Determines if the provided HTTP method and URL path match the route. * * If a match is found, it returns the dynamic parameters extracted from the URL. * If no match is found, it returns null. * * @param {RequestMethod} method - The HTTP method to check against the route's method. * @param {string} path - The URL path to check against the route's template. * * @return {Params | null} Returns an object with matching parameters if a match is found, otherwise null. */ match(method: RequestMethod, path: string): Params | null; } interface RouterEntrypoint<T extends ConfiguratorEnvironment | ExecutorEnvironment, C extends ExecutionContext = ExecutionContext> { entrypoint: (req: Request, env: T, ctx: C) => Promise<Response>; } /** * `BaseRouter` serves as an abstract foundation for building routers that can process * web requests by matching them to predefined routes and subsequently delegating the * request handling to the appropriate handler. * * This base class provides core functionalities such as: * - Storing a collection of routes and their associated handlers. * - Mechanisms to add new routes. * - Logic to match incoming requests to the correct route. * - Delegating the request to the matched route's handler. * - Registering and executing middleware functions. * * Derived classes can extend this base class to introduce more specific behaviors or * to support additional types of route handlers. * * @template T * Represents the type of route handler that this router can handle. This can be: * - A basic route handler (`RouteHandler`), which processes the request and returns a response. * - An API-specific route handler (`ApiRouteHandler`), tailored for specific API types like * `ConfiguratorApi` or `ExecutorApi`. * * @template C extends ExecutionContext * Represents the type of the execution context that will be passed through the middleware * and route handlers during the request's lifecycle. This context can be used to share * data or state across different parts of the request processing pipeline. * By default, it uses the base `ExecutionContext`, but users can extend this to add * custom properties that are relevant to their application's logic. * * @template A * Represents the type of the API that the middleware and route handlers can handle. This ensures * that the middleware's API type matches the route handler's API type. Depending on the context, * this could be an instance of `ConfiguratorApi` or `ExecutorApi`. * * @example * // Creating a new router that handles basic route handlers and uses a custom execution context. * class MyRouter extends BaseRouter<RouteHandler, MyExecutionContext> { ... } * * // Creating a new router that handles API-specific route handlers for `ConfiguratorApi`. * class ConfiguratorRouter extends BaseRouter<ApiRouteHandler<ConfiguratorApi>, MyExecutionContext> { ... } */ declare abstract class BaseRouter<T extends RouteHandler | ApiRouteHandler<any, C>, C extends ExecutionContext = ExecutionContext, A extends ConfiguratorApi | ExecutorApi = T extends ApiRouteHandler<infer U, C> ? U : never> { protected routes: { route: Route; handler: T; }[]; protected middlewares: Middleware<A, C, Response>[]; constructor(); /** * Registers a middleware function to log details of incoming requests. * * This middleware captures and logs essential details about the incoming request, * including the URL, time of the request, and certain headers that provide information * about the request's origin and protocol. The logged headers include `X-Forwarded-Host`, * `X-Forwarded-Proto`, and `X-Forwarded-For`, which are commonly used in scenarios where * the application is behind a proxy or load balancer. * * The log is structured for easy reading, with separators to distinguish between individual * log entries. This middleware is particularly useful for monitoring and debugging purposes. * * @returns * Returns the current router instance, allowing for method chaining. * * @example * const router = new MyRouter(); * * // Add request logging middleware to the router * router.useRequestLogging(); */ useRequestLogging(): this; useErrorHandling(handler: (e: unknown) => Promise<Response>): this; /** * Registers a middleware function to handle Bearer token authorization for specific paths. * * This middleware checks the incoming request's `Authorization` header for a Bearer token. * If the token is present, it attempts to authorize the token using the provided API. * If the token is invalid or missing, the middleware returns a 401 Unauthorized response. * * The middleware can be configured to protect specific paths (those that require authorization) * and to exclude certain paths (those that should skip authorization). * * @param protectedPaths * An optional array of path prefixes that should be protected by Bearer token authorization. * If a request's path starts with any of the prefixes in this array, it will be subject to * authorization checks. If this parameter is omitted or empty, all paths will be protected by default. * * @param unprotectedPaths * An optional array of path prefixes that should be excluded from Bearer token authorization. * If a request's path starts with any of the prefixes in this array, it will skip the authorization checks. * * @returns * Returns the current router instance, allowing for method chaining. * * @example * const router = new MyRouter(); * * // Protect all paths under '/api' and exclude paths under '/public' * router.useBearerAuthorization(['/api'], ['/public']); * * // Protect all paths under '/api' without any exclusions * router.useBearerAuthorization(['/api']); * * // Protect all paths by default, excluding paths under '/public' * router.useBearerAuthorization([], ['/public']); */ useBearerAuthorization(protectedPaths?: string[], unprotectedPaths?: string[]): this; /** * Registers a middleware function to be executed before reaching the route handlers. * * Middleware functions are designed to perform operations on the incoming request, * potentially modify the execution context, or even short-circuit the request handling * by directly returning a response. They are executed in the order they are added to the router. * * This method allows for the chaining of middleware additions, enabling a fluent API style. * * @param middleware * The middleware function to be added. This function will have access to the request, * the execution context, and a `next` function. It can either modify the request or context * and call `next` to continue the middleware chain, or return a `Response` to short-circuit * the request handling. * * @returns * Returns the current router instance, allowing for method chaining. * * @example * // Creating a new router instance * const router = new MyRouter(); * * // Using middleware for Bearer token authentication * router.use(async (req, ctx, next) => { * const authHeader = req.headers['authorization']; * if (authHeader && authHeader.startsWith('Bearer ')) { * const token = authHeader.split(' ')[1]; * // Validate the token and set user in context (pseudo-code) * ctx.user = await validateToken(token); * await next(); * } else { * return new Response('Unauthorized', { status: 401 }); * } * }); * * // Using middleware to check for a specific query parameter * router.use((req, ctx, next) => { * if (req.searchParams.has('myParam')) { * await next(); * } else { * return new Response('Bad Request', { status: 400 }); * } * }); * * // Using middleware to check for a specific cookie * router.use((req, ctx, next) => { * const cookies = parseCookies(req.headers.cookie); // Assuming a function to parse cookies * if (cookies['myCookie']) { * ctx.myCookieValue = cookies['myCookie']; * await next(); * } else { * return new Response('Cookie not found', { status: 400 }); * } * }); */ use(middleware: Middleware<A, C, Response>): this; /** * Adds a new route to the router. * * @param method - The HTTP method(s) for the route. * @param template - The URL template for the route. * @param handler - The handler that should be invoked when the route is matched. * @returns - Returns the router instance for chaining. */ add(method: RequestMethodOption, template: string, handler: T): this; /** * Matches an incoming request to a route and invokes the appropriate handler. * * @param req - The incoming request. * @param handlerCallback - The callback function that * handles the request once a matching route is found. * @returns - Returns the response from the handler or appropriate error response. */ protected routeRequest(req: Request, handlerCallback: (handler: T, routeInfo: RouteInfo) => Promise<Response>): Promise<Response>; } /** * Router specialized in handling routes for the `ExecutorApi`. */ export declare class ExternalExecutorRouter<C extends ExecutionContext = ExecutionContext> extends BaseRouter<ApiRouteHandler<ExecutorApi, C>, C> implements RouterEntrypoint<ExecutorEnvironment, C> { constructor(); entrypoint(req: Request, env: ExecutorEnvironment, ctx: C): Promise<Response>; } /** * `InternalExecutorRouter` is a specialized router designed to handle routes specifically for the `SessionExecutorApi`. * * This router provides functionalities to: * - Register routes with associated handlers. * - Register exchange routes with associated handlers. * - Add middleware functions that can process and potentially modify incoming requests before they reach the route handlers. * * @template C * Represents the type of the execution context that will be passed through the middleware and route handlers during the request's lifecycle. * This context can be used to share data or state across different parts of the request processing pipeline. * By default, it uses the base `ExecutionContext`, but users can extend this to add custom properties that are relevant to their application's logic. */ export declare class InternalExecutorRouter<C extends ExecutionContext = ExecutionContext> implements RouterEntrypoint<ExecutorEnvironment, C> { private startRoute?; private stopRoute?; private exchangeRoutes; protected cronRoute?: { route: Route; handler: InternalRouteHandler<CronTriggerRequest, any, C>; }; /** * Creates a new instance of InternalExecutorRouter. */ constructor(); entrypoint(req: Request, env: ExecutorEnvironment, ctx: C): Promise<Response>; /** * Registers a start handler for the vertex start endpoint * * @public * @param handle - The route handler for the start event. * @returns - Returns the instance of the router for method chaining. */ onStart(handle: InternalRouteHandler<StartExecutionRequest, SessionExecutorApi, C>): this; /** * Registers a stop handler in case the vertex execution is stopped. Typically used for triggers and * vertices that requires cleanup * * @public * @param handle - The route handler for the stop event. * @returns - Returns the instance of the router for method chaining. */ onStop(handle: InternalRouteHandler<StopExecutionRequest, StopExecutorApi, C>): this; /** * Registers a stream handler for a stream callback. * * @public * @param handle - The route handler for the stream event. * @returns - Returns the instance of the router for method chaining. */ onExchange(handle: ExchangeRouteHandler<ExchangeResultWrapper, SessionExecutorApi, C>): this; } export declare class CronExecutorRouter<C extends ExecutionContext = ExecutionContext> extends InternalExecutorRouter<C> { constructor(); /** * Registers a cron handler for the cron events. * * @public * @param handle - The route handler for the stop event. * @returns - Returns the instance of the router for method chaining. */ onCron(handle: InternalRouteHandler<CronTriggerRequest, SessionExecutorApi, C>): this; } /** * Router specialized in handling routes for the `ConfiguratorApi`. */ export declare class ExternalConfiguratorRouter<C extends ExecutionContext = ExecutionContext> extends BaseRouter<ApiRouteHandler<ConfiguratorApi, C>, C> implements RouterEntrypoint<ConfiguratorEnvironment, C> { constructor(); entrypoint(req: Request, env: ConfiguratorEnvironment, ctx: C): Promise<Response>; } /** * Router specialized in handling routes for the `ConfiguratorApi`. */ export declare class InternalConfiguratorRouter implements RouterEntrypoint<ConfiguratorEnvironment, ExecutionContext> { constructor(); entrypoint(_req: Request, _env: ConfiguratorEnvironment, _ctx: ExecutionContext): Promise<Response>; } export {}; //# sourceMappingURL=router.d.ts.map