CI: Update Pages (2025-11-23 11:20:49)
This commit is contained in:
53
v0.2.1/src/Interfaces/IContext.ts
Normal file
53
v0.2.1/src/Interfaces/IContext.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import type { Params, Query, State } from '../Types/mod.ts';
|
||||
|
||||
/**
|
||||
* Represents the complete context for a single HTTP request,
|
||||
* passed through the middleware pipeline and to the final route handler.
|
||||
*
|
||||
* This context object encapsulates all relevant runtime data for a request,
|
||||
* including the original request, path parameters, query parameters,
|
||||
* and a shared, mutable application state.
|
||||
*
|
||||
* @template TState Structured per-request state shared across middlewares and handlers.
|
||||
* @template TParams Parsed URL path parameters, typically derived from route templates.
|
||||
* @template TQuery Parsed query string parameters, preserving multi-value semantics.
|
||||
*/
|
||||
export interface IContext<
|
||||
TState extends State = State,
|
||||
TParams extends Params = Params,
|
||||
TQuery extends Query = Query,
|
||||
> {
|
||||
/**
|
||||
* The original HTTP request object as received by Deno.
|
||||
* Contains all standard fields like headers, method, body, etc.
|
||||
*/
|
||||
req: Request;
|
||||
|
||||
/**
|
||||
* Route parameters parsed from the URL path, based on route definitions
|
||||
* that include dynamic segments (e.g., `/users/:id` → `{ id: "123" }`).
|
||||
*
|
||||
* These parameters are considered read-only and are set by the router.
|
||||
*/
|
||||
params: TParams;
|
||||
|
||||
/**
|
||||
* Query parameters extracted from the request URL's search string.
|
||||
*
|
||||
* Values may occur multiple times (e.g., `?tag=ts&tag=deno`), and are therefore
|
||||
* represented as either a string or an array of strings, depending on occurrence.
|
||||
*
|
||||
* Use this field to access filters, flags, pagination info, or similar modifiers.
|
||||
*/
|
||||
query: TQuery;
|
||||
|
||||
/**
|
||||
* A typed, mutable object used to pass structured data between middlewares and handlers.
|
||||
*
|
||||
* This object is ideal for sharing validated input, user identity, trace information,
|
||||
* or other contextual state throughout the request lifecycle.
|
||||
*
|
||||
* Type-safe access to fields is ensured by the generic `TState` type.
|
||||
*/
|
||||
state: TState;
|
||||
}
|
||||
40
v0.2.1/src/Interfaces/IHttpErrorHandlers.ts
Normal file
40
v0.2.1/src/Interfaces/IHttpErrorHandlers.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import type { IContext } from '../Interfaces/mod.ts';
|
||||
import type { HttpErrorHandler, validHttpErrorCodes } from '../Types/mod.ts';
|
||||
|
||||
/**
|
||||
* A mapping of HTTP status codes to their corresponding error handlers.
|
||||
*
|
||||
* This interface defines required handlers for common critical status codes (404 and 500)
|
||||
* and allows optional handlers for all other known error codes defined in `validHttpErrorCodes`.
|
||||
*
|
||||
* This hybrid approach ensures predictable handling for key failure cases,
|
||||
* while remaining flexible for less common codes.
|
||||
*
|
||||
* @template TContext - The context type used in all error handlers.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const errorHandlers: IHttpErrorHandlers = {
|
||||
* 404: (ctx) => new Response("Not Found", { status: 404 }),
|
||||
* 500: (ctx, err) => {
|
||||
* console.error(err);
|
||||
* return new Response("Internal Server Error", { status: 500 });
|
||||
* },
|
||||
* 429: (ctx) => new Response("Too Many Requests", { status: 429 }),
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export interface IHttpErrorHandlers<TContext extends IContext = IContext>
|
||||
extends
|
||||
Partial<
|
||||
Record<
|
||||
Exclude<typeof validHttpErrorCodes[number], 404 | 500>,
|
||||
HttpErrorHandler<TContext>
|
||||
>
|
||||
> {
|
||||
/** Required error handler for HTTP 404 (Not Found). */
|
||||
404: HttpErrorHandler<TContext>;
|
||||
|
||||
/** Required error handler for HTTP 500 (Internal Server Error). */
|
||||
500: HttpErrorHandler<TContext>;
|
||||
}
|
||||
49
v0.2.1/src/Interfaces/IHttpKernel.ts
Normal file
49
v0.2.1/src/Interfaces/IHttpKernel.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { IContext } from './IContext.ts';
|
||||
import type { IRouteBuilder } from './IRouteBuilder.ts';
|
||||
import type { IRouteDefinition } from './IRouteDefinition.ts';
|
||||
|
||||
/**
|
||||
* The `IHttpKernel` interface defines the public API for a type-safe, middleware-driven HTTP dispatching system.
|
||||
*
|
||||
* Implementations of this interface are responsible for:
|
||||
* - Registering routes with optional per-route context typing
|
||||
* - Handling incoming requests by matching and dispatching to appropriate handlers
|
||||
* - Managing the complete middleware pipeline and final response generation
|
||||
*
|
||||
* The kernel operates on a customizable `IContext` type to support strongly typed request parameters, state,
|
||||
* and query values across the entire routing lifecycle.
|
||||
*
|
||||
* @typeParam TContext - The default context type used for all routes unless overridden per-route.
|
||||
*/
|
||||
export interface IHttpKernel<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* Registers a new HTTP route (static or dynamic) and returns a route builder for middleware/handler chaining.
|
||||
*
|
||||
* This method supports contextual polymorphism via the `_TContext` type parameter, enabling fine-grained
|
||||
* typing of route-specific `params`, `query`, and `state` values. The route is not registered until
|
||||
* `.handle()` is called on the returned builder.
|
||||
*
|
||||
* @typeParam _TContext - An optional override for the context type specific to this route.
|
||||
* Falls back to the global `TContext` of the kernel if omitted.
|
||||
*
|
||||
* @param definition - A route definition specifying the HTTP method and path or custom matcher.
|
||||
* @returns A fluent builder interface to define middleware and attach a final handler.
|
||||
*/
|
||||
route<_TContext extends IContext = TContext>(
|
||||
definition: IRouteDefinition,
|
||||
): IRouteBuilder<_TContext>;
|
||||
|
||||
/**
|
||||
* Handles an incoming HTTP request and produces a `Response`.
|
||||
*
|
||||
* The kernel matches the request against all registered routes by method and matcher,
|
||||
* constructs a typed context, and executes the middleware/handler pipeline.
|
||||
* If no route matches, a 404 error handler is invoked.
|
||||
*
|
||||
* This method is designed to be passed directly to `Deno.serve()` or similar server frameworks.
|
||||
*
|
||||
* @param request - The incoming HTTP request object.
|
||||
* @returns A `Promise` resolving to a complete HTTP response.
|
||||
*/
|
||||
handle(request: Request): Promise<Response>;
|
||||
}
|
||||
10
v0.2.1/src/Interfaces/IHttpKernelConfig.ts
Normal file
10
v0.2.1/src/Interfaces/IHttpKernelConfig.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { ResponseDecorator } from '../Types/mod.ts';
|
||||
import type { IContext } from './IContext.ts';
|
||||
import type { IHttpErrorHandlers } from './IHttpErrorHandlers.ts';
|
||||
import type { IRouteBuilderFactory } from './IRouteBuilder.ts';
|
||||
|
||||
export interface IHttpKernelConfig<TContext extends IContext = IContext> {
|
||||
decorateResponse: ResponseDecorator<TContext>;
|
||||
routeBuilderFactory: IRouteBuilderFactory;
|
||||
httpErrorHandlers: IHttpErrorHandlers<TContext>;
|
||||
}
|
||||
64
v0.2.1/src/Interfaces/IInternalRoute.ts
Normal file
64
v0.2.1/src/Interfaces/IInternalRoute.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import type { Handler, HttpMethod, Middleware } from '../Types/mod.ts';
|
||||
import type { IContext, IRouteMatcher } from './mod.ts';
|
||||
|
||||
/**
|
||||
* Represents an internally registered route within the HttpKernel.
|
||||
*
|
||||
* Contains all data required to match an incoming request and dispatch it
|
||||
* through the associated middleware chain and final handler.
|
||||
*/
|
||||
export interface IInternalRoute<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* The HTTP method (e.g. 'GET', 'POST') that this route responds to.
|
||||
* The method should always be in uppercase.
|
||||
*/
|
||||
method: HttpMethod;
|
||||
|
||||
/**
|
||||
* A matcher function used to determine whether this route matches a given request.
|
||||
*
|
||||
* If the matcher returns `null`, the route does not apply to the request.
|
||||
* If it returns a params object, the route is considered matched and the extracted
|
||||
* parameters are passed into the request context.
|
||||
*
|
||||
* @param url - The parsed URL object from the incoming request.
|
||||
* @param req - The original Request object.
|
||||
* @returns An object with extracted path parameters, or `null` if not matched.
|
||||
*/
|
||||
matcher: IRouteMatcher;
|
||||
|
||||
/**
|
||||
* An ordered list of middleware functions to be executed before the handler.
|
||||
*/
|
||||
middlewares: Middleware<TContext>[];
|
||||
|
||||
/**
|
||||
* The final handler that generates the HTTP response after all middleware has run.
|
||||
*/
|
||||
handler: Handler<TContext>;
|
||||
|
||||
/**
|
||||
* The fully compiled execution pipeline for this route.
|
||||
*
|
||||
* This function is generated at route registration time and encapsulates the
|
||||
* entire middleware chain as well as the final handler. It is called by the
|
||||
* HttpKernel during request dispatch when a route has been matched.
|
||||
*
|
||||
* Internally, `runRoute` ensures that each middleware is invoked in the correct order
|
||||
* and receives a `next()` callback to pass control downstream. The final handler is
|
||||
* invoked once all middleware has completed or short-circuited the pipeline.
|
||||
*
|
||||
* It is guaranteed that:
|
||||
* - The function is statically compiled and does not perform dynamic dispatching.
|
||||
* - Each middleware can only call `next()` once; repeated invocations will throw.
|
||||
* - The return value is either a `Response` or a Promise resolving to one.
|
||||
*
|
||||
* @param ctx - The context object carrying route, request, response and other scoped data.
|
||||
* @returns A `Response` object or a Promise resolving to a `Response`.
|
||||
*
|
||||
* @throws {Error} If a middleware calls `next()` more than once.
|
||||
*/
|
||||
runRoute: (
|
||||
ctx: TContext,
|
||||
) => Promise<Response> | Response;
|
||||
}
|
||||
39
v0.2.1/src/Interfaces/IRouteBuilder.ts
Normal file
39
v0.2.1/src/Interfaces/IRouteBuilder.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { Handler, Middleware } from '../Types/mod.ts';
|
||||
import type { IInternalRoute } from './IInternalRoute.ts';
|
||||
import type { IRouteDefinition } from './IRouteDefinition.ts';
|
||||
import type { IContext } from './mod.ts';
|
||||
|
||||
export interface IRouteBuilderFactory<TContext extends IContext = IContext> {
|
||||
new (
|
||||
registerRoute: (route: IInternalRoute<TContext>) => void,
|
||||
def: IRouteDefinition,
|
||||
mws?: Middleware<TContext>[],
|
||||
): IRouteBuilder<TContext>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a fluent API to build a single route configuration by chaining
|
||||
* middleware and setting the final request handler.
|
||||
*/
|
||||
export interface IRouteBuilder<TContext extends IContext = IContext> {
|
||||
/**
|
||||
* Adds a middleware to the current route.
|
||||
* Middleware will be executed in the order of registration.
|
||||
*
|
||||
* @param mw - A middleware function.
|
||||
* @returns The route builder for further chaining.
|
||||
*/
|
||||
middleware(
|
||||
mw: Middleware<TContext>,
|
||||
): IRouteBuilder<TContext>;
|
||||
|
||||
/**
|
||||
* Sets the final request handler for the route.
|
||||
* Calling this finalizes the route and registers it in the kernel.
|
||||
*
|
||||
* @param handler - The function to execute when this route is matched.
|
||||
*/
|
||||
handle(
|
||||
handler: Handler<TContext>,
|
||||
): void;
|
||||
}
|
||||
91
v0.2.1/src/Interfaces/IRouteDefinition.ts
Normal file
91
v0.2.1/src/Interfaces/IRouteDefinition.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { type HttpMethod, isHttpMethod } from '../Types/mod.ts';
|
||||
import type { IRouteMatcher } from './IRouteMatcher.ts';
|
||||
|
||||
/**
|
||||
* Defines a static route using a path pattern with optional parameters.
|
||||
*
|
||||
* Suitable for conventional routes like "/users/:id", which can be parsed
|
||||
* into named parameters using a path-matching library.
|
||||
*/
|
||||
export interface IStaticRouteDefinition {
|
||||
/**
|
||||
* The HTTP method this route should match (e.g. "GET", "POST").
|
||||
*/
|
||||
method: HttpMethod;
|
||||
|
||||
/**
|
||||
* A static path pattern for the route, which may include named parameters
|
||||
* (e.g. "/caches/:id"). Internally, this can be converted to a regex matcher.
|
||||
*/
|
||||
path: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a dynamic route using a custom matcher function instead of a static path.
|
||||
*
|
||||
* Useful for complex URL structures that cannot easily be expressed using a static pattern,
|
||||
* such as routes with variable prefixes or conditional segment logic.
|
||||
*/
|
||||
export interface IDynamicRouteDefinition {
|
||||
/**
|
||||
* The HTTP method this route should match (e.g. "GET", "POST").
|
||||
*/
|
||||
method: HttpMethod;
|
||||
|
||||
/**
|
||||
* A custom matcher function that receives the parsed URL and raw request.
|
||||
* If the function returns `null`, the route does not match.
|
||||
* If the function returns a params object, the route is considered matched.
|
||||
*/
|
||||
matcher: IRouteMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* A route definition can either be a conventional static route with a path pattern,
|
||||
* or a dynamic route with a custom matcher function for advanced matching logic.
|
||||
*/
|
||||
export type IRouteDefinition = IStaticRouteDefinition | IDynamicRouteDefinition;
|
||||
|
||||
/**
|
||||
* Type guard to check whether a route definition is a valid static route definition.
|
||||
*
|
||||
* Ensures that the object:
|
||||
* - has a `method` property of type `HttpMethod`
|
||||
* - has a `path` property of type `string`
|
||||
* - does NOT have a `matcher` function (to avoid ambiguous mixed types)
|
||||
*/
|
||||
export function isStaticRouteDefinition(
|
||||
def: IRouteDefinition,
|
||||
): def is IStaticRouteDefinition {
|
||||
return (
|
||||
def &&
|
||||
typeof def === 'object' &&
|
||||
'method' in def &&
|
||||
isHttpMethod(def.method) &&
|
||||
'path' in def &&
|
||||
typeof (def as { path?: unknown }).path === 'string' &&
|
||||
!('matcher' in def)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to check whether a route definition is a valid dynamic route definition.
|
||||
*
|
||||
* Ensures that the object:
|
||||
* - has a `method` property of type `HttpMethod`
|
||||
* - has a `matcher` property of type `function`
|
||||
* - does NOT have a `path` property (to avoid ambiguous mixed types)
|
||||
*/
|
||||
export function isDynamicRouteDefinition(
|
||||
def: IRouteDefinition,
|
||||
): def is IDynamicRouteDefinition {
|
||||
return (
|
||||
def &&
|
||||
typeof def === 'object' &&
|
||||
'method' in def &&
|
||||
isHttpMethod(def.method) &&
|
||||
'matcher' in def &&
|
||||
typeof (def as { matcher?: unknown }).matcher === 'function' &&
|
||||
!('path' in def)
|
||||
);
|
||||
}
|
||||
6
v0.2.1/src/Interfaces/IRouteMatch.ts
Normal file
6
v0.2.1/src/Interfaces/IRouteMatch.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { Params, Query } from '../Types/mod.ts';
|
||||
|
||||
export interface IRouteMatch {
|
||||
params?: Params;
|
||||
query?: Query;
|
||||
}
|
||||
35
v0.2.1/src/Interfaces/IRouteMatcher.ts
Normal file
35
v0.2.1/src/Interfaces/IRouteMatcher.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import type { IRouteDefinition } from './IRouteDefinition.ts';
|
||||
import type { IRouteMatch } from './IRouteMatch.ts';
|
||||
|
||||
/**
|
||||
* Defines a route matcher function that evaluates whether a route applies to a given request.
|
||||
*
|
||||
* If the route matches, the matcher returns an object containing extracted route parameters.
|
||||
* Otherwise, it returns `null`.
|
||||
*/
|
||||
export interface IRouteMatcher {
|
||||
/**
|
||||
* Evaluates whether the given URL and request match a defined route.
|
||||
*
|
||||
* @param url - The full URL of the incoming request.
|
||||
* @param req - The raw Request object (may be used for context or headers).
|
||||
* @returns An object containing path parameters if matched, or `null` if not matched.
|
||||
*/
|
||||
(url: URL, req: Request): null | IRouteMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a factory for creating route matcher functions from route definitions.
|
||||
*
|
||||
* This allows the matcher logic to be injected or replaced (e.g. for testing,
|
||||
* pattern libraries, or advanced routing scenarios).
|
||||
*/
|
||||
export interface IRouteMatcherFactory {
|
||||
/**
|
||||
* Creates a matcher function based on a given route definition.
|
||||
*
|
||||
* @param def - The route definition (static or dynamic).
|
||||
* @returns A matcher function that checks if a request matches and extracts parameters.
|
||||
*/
|
||||
(def: IRouteDefinition): IRouteMatcher;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { assertEquals } from 'https://deno.land/std@0.204.0/assert/mod.ts';
|
||||
import {
|
||||
type IRouteDefinition,
|
||||
isDynamicRouteDefinition,
|
||||
isStaticRouteDefinition,
|
||||
} from '../IRouteDefinition.ts';
|
||||
|
||||
Deno.test('isStaticRouteDefinition returns true for static route', () => {
|
||||
const staticDef: IRouteDefinition = {
|
||||
method: 'GET',
|
||||
path: '/users/:id',
|
||||
};
|
||||
|
||||
assertEquals(isStaticRouteDefinition(staticDef), true);
|
||||
assertEquals(isDynamicRouteDefinition(staticDef), false);
|
||||
});
|
||||
|
||||
Deno.test('isDynamicRouteDefinition returns true for dynamic route', () => {
|
||||
const dynamicDef: IRouteDefinition = {
|
||||
method: 'POST',
|
||||
matcher: (_url, _req) => ({ params: {} }),
|
||||
};
|
||||
|
||||
assertEquals(isDynamicRouteDefinition(dynamicDef), true);
|
||||
assertEquals(isStaticRouteDefinition(dynamicDef), false);
|
||||
});
|
||||
|
||||
Deno.test('isStaticRouteDefinition returns false for invalid object', () => {
|
||||
const invalidDef = {
|
||||
method: 'GET',
|
||||
} as unknown as IRouteDefinition;
|
||||
|
||||
assertEquals(isStaticRouteDefinition(invalidDef), false);
|
||||
});
|
||||
|
||||
Deno.test('isDynamicRouteDefinition returns false for object with no matcher', () => {
|
||||
const def = {
|
||||
method: 'DELETE',
|
||||
path: '/something',
|
||||
};
|
||||
|
||||
assertEquals(isDynamicRouteDefinition(def as IRouteDefinition), false);
|
||||
});
|
||||
19
v0.2.1/src/Interfaces/mod.ts
Normal file
19
v0.2.1/src/Interfaces/mod.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// deno-coverage-ignore-file
|
||||
|
||||
export type { IContext } from './IContext.ts';
|
||||
export type { IHttpErrorHandlers } from './IHttpErrorHandlers.ts';
|
||||
export type { IHttpKernel } from './IHttpKernel.ts';
|
||||
export type { IHttpKernelConfig } from './IHttpKernelConfig.ts';
|
||||
export type { IInternalRoute } from './IInternalRoute.ts';
|
||||
export type { IRouteBuilder, IRouteBuilderFactory } from './IRouteBuilder.ts';
|
||||
export {
|
||||
isDynamicRouteDefinition,
|
||||
isStaticRouteDefinition,
|
||||
} from './IRouteDefinition.ts';
|
||||
export type {
|
||||
IDynamicRouteDefinition,
|
||||
IRouteDefinition,
|
||||
IStaticRouteDefinition,
|
||||
} from './IRouteDefinition.ts';
|
||||
export type { IRouteMatch } from './IRouteMatch.ts';
|
||||
export type { IRouteMatcher, IRouteMatcherFactory } from './IRouteMatcher.ts';
|
||||
Reference in New Issue
Block a user