349 lines
9.4 KiB
TypeScript
349 lines
9.4 KiB
TypeScript
|
|
/**
|
||
|
|
* Core interfaces for @push.rocks/smartserve
|
||
|
|
* Uses Web Standards API (Request/Response) for cross-platform compatibility
|
||
|
|
*/
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// HTTP Types
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
export type THttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'ALL';
|
||
|
|
|
||
|
|
export type TRuntime = 'node' | 'deno' | 'bun';
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Request Context
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Request context passed to handlers and interceptors
|
||
|
|
* Wraps Web Standard Request with additional utilities
|
||
|
|
*/
|
||
|
|
export interface IRequestContext<TBody = unknown> {
|
||
|
|
/** Original Web Standards Request */
|
||
|
|
readonly request: Request;
|
||
|
|
/** Parsed request body (typed) */
|
||
|
|
readonly body: TBody;
|
||
|
|
/** URL path parameters extracted from route */
|
||
|
|
readonly params: Record<string, string>;
|
||
|
|
/** URL query parameters */
|
||
|
|
readonly query: Record<string, string>;
|
||
|
|
/** Request headers accessor */
|
||
|
|
readonly headers: Headers;
|
||
|
|
/** Matched route path pattern */
|
||
|
|
readonly path: string;
|
||
|
|
/** HTTP method */
|
||
|
|
readonly method: THttpMethod;
|
||
|
|
/** Full URL object */
|
||
|
|
readonly url: URL;
|
||
|
|
/** Runtime environment */
|
||
|
|
readonly runtime: TRuntime;
|
||
|
|
/** Route-specific state bag for passing data between interceptors */
|
||
|
|
state: Record<string, unknown>;
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Interceptor Types
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Request interceptor - runs BEFORE the handler
|
||
|
|
* Can:
|
||
|
|
* - Return modified context to continue
|
||
|
|
* - Return Response to short-circuit
|
||
|
|
* - Return void/undefined to continue with original context
|
||
|
|
* - Throw to trigger error handling
|
||
|
|
*/
|
||
|
|
export type TRequestInterceptor<TBody = unknown> = (
|
||
|
|
ctx: IRequestContext<TBody>
|
||
|
|
) => Promise<IRequestContext<TBody> | Response | void> | IRequestContext<TBody> | Response | void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Response interceptor - runs AFTER the handler
|
||
|
|
* Can:
|
||
|
|
* - Return modified response data
|
||
|
|
* - Return a Response object directly
|
||
|
|
*/
|
||
|
|
export type TResponseInterceptor<TRes = unknown> = (
|
||
|
|
response: TRes,
|
||
|
|
ctx: IRequestContext
|
||
|
|
) => Promise<TRes | Response> | TRes | Response;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Guard function - simplified boolean check for authorization
|
||
|
|
* Returns true to allow, false to reject with 403
|
||
|
|
*/
|
||
|
|
export type TGuardFunction<TBody = unknown> = (
|
||
|
|
ctx: IRequestContext<TBody>
|
||
|
|
) => Promise<boolean> | boolean;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Combined interceptor options for @Intercept decorator
|
||
|
|
*/
|
||
|
|
export interface IInterceptOptions<TBody = unknown, TRes = unknown> {
|
||
|
|
/** Request interceptors (run before handler) */
|
||
|
|
request?: TRequestInterceptor<TBody> | TRequestInterceptor<TBody>[];
|
||
|
|
/** Response interceptors (run after handler) */
|
||
|
|
response?: TResponseInterceptor<TRes> | TResponseInterceptor<TRes>[];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Options for @Guard decorator
|
||
|
|
*/
|
||
|
|
export interface IGuardOptions {
|
||
|
|
/** Custom response when guard rejects (default: 403 Forbidden) */
|
||
|
|
onReject?: (ctx: IRequestContext) => Response | Promise<Response>;
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Route Handler Types
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Route handler function signature
|
||
|
|
*/
|
||
|
|
export type TRouteHandler<TReq = unknown, TRes = unknown> = (
|
||
|
|
ctx: IRequestContext<TReq>
|
||
|
|
) => Promise<TRes> | TRes;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Options for method decorators (@Get, @Post, etc.)
|
||
|
|
*/
|
||
|
|
export interface IMethodOptions {
|
||
|
|
/** Path segment (appended to class route) */
|
||
|
|
path?: string;
|
||
|
|
/** Content-Type for response */
|
||
|
|
contentType?: string;
|
||
|
|
/** HTTP status code for successful response */
|
||
|
|
statusCode?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Options for @Route class decorator
|
||
|
|
*/
|
||
|
|
export interface IRouteOptions {
|
||
|
|
/** Base path for all routes in this controller */
|
||
|
|
path?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// WebSocket Types
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* WebSocket message types
|
||
|
|
*/
|
||
|
|
export interface IWebSocketMessage {
|
||
|
|
type: 'text' | 'binary';
|
||
|
|
text?: string;
|
||
|
|
data?: Uint8Array;
|
||
|
|
size: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* WebSocket peer connection
|
||
|
|
*/
|
||
|
|
export interface IWebSocketPeer {
|
||
|
|
/** Unique connection ID */
|
||
|
|
id: string;
|
||
|
|
/** Connection URL */
|
||
|
|
url: string;
|
||
|
|
/** WebSocket ready state */
|
||
|
|
readyState: 0 | 1 | 2 | 3;
|
||
|
|
/** Negotiated subprotocol */
|
||
|
|
protocol: string;
|
||
|
|
/** Negotiated extensions */
|
||
|
|
extensions: string;
|
||
|
|
/** Send text message */
|
||
|
|
send(data: string): void;
|
||
|
|
/** Send binary message */
|
||
|
|
sendBinary(data: Uint8Array | ArrayBuffer): void;
|
||
|
|
/** Close connection */
|
||
|
|
close(code?: number, reason?: string): void;
|
||
|
|
/** Send ping */
|
||
|
|
ping(data?: Uint8Array): void;
|
||
|
|
/** Force close without handshake */
|
||
|
|
terminate(): void;
|
||
|
|
/** Request context from upgrade */
|
||
|
|
context: IRequestContext;
|
||
|
|
/** Custom per-peer data storage */
|
||
|
|
data: Map<string, unknown>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* WebSocket event hooks
|
||
|
|
*/
|
||
|
|
export interface IWebSocketHooks {
|
||
|
|
onOpen?: (peer: IWebSocketPeer) => void | Promise<void>;
|
||
|
|
onMessage?: (peer: IWebSocketPeer, message: IWebSocketMessage) => void | Promise<void>;
|
||
|
|
onClose?: (peer: IWebSocketPeer, code: number, reason: string) => void | Promise<void>;
|
||
|
|
onError?: (peer: IWebSocketPeer, error: Error) => void | Promise<void>;
|
||
|
|
onPing?: (peer: IWebSocketPeer, data: Uint8Array) => void | Promise<void>;
|
||
|
|
onPong?: (peer: IWebSocketPeer, data: Uint8Array) => void | Promise<void>;
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Server Configuration
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* TLS/SSL configuration
|
||
|
|
*/
|
||
|
|
export interface ITLSConfig {
|
||
|
|
/** Certificate (PEM format) */
|
||
|
|
cert: string | Uint8Array;
|
||
|
|
/** Private key (PEM format) */
|
||
|
|
key: string | Uint8Array;
|
||
|
|
/** CA chain (PEM format) */
|
||
|
|
ca?: string | Uint8Array;
|
||
|
|
/** ALPN protocols */
|
||
|
|
alpnProtocols?: string[];
|
||
|
|
/** Minimum TLS version */
|
||
|
|
minVersion?: 'TLSv1.2' | 'TLSv1.3';
|
||
|
|
/** Passphrase for encrypted key */
|
||
|
|
passphrase?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Keep-alive configuration
|
||
|
|
*/
|
||
|
|
export interface IKeepAliveConfig {
|
||
|
|
enabled: boolean;
|
||
|
|
timeout?: number;
|
||
|
|
maxRequests?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Static file serving options
|
||
|
|
*/
|
||
|
|
export interface IStaticOptions {
|
||
|
|
/** Root directory path */
|
||
|
|
root: string;
|
||
|
|
/** Index files to look for */
|
||
|
|
index?: string[];
|
||
|
|
/** How to handle dotfiles */
|
||
|
|
dotFiles?: 'allow' | 'deny' | 'ignore';
|
||
|
|
/** Generate ETags */
|
||
|
|
etag?: boolean;
|
||
|
|
/** Add Last-Modified header */
|
||
|
|
lastModified?: boolean;
|
||
|
|
/** Cache-Control header value or function */
|
||
|
|
cacheControl?: string | ((path: string) => string);
|
||
|
|
/** File extensions to try */
|
||
|
|
extensions?: string[];
|
||
|
|
/** Enable directory listing */
|
||
|
|
directoryListing?: boolean | IDirectoryListingOptions;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Directory listing options
|
||
|
|
*/
|
||
|
|
export interface IDirectoryListingOptions {
|
||
|
|
/** Custom template function */
|
||
|
|
template?: (files: IFileEntry[]) => string | Response;
|
||
|
|
/** Show hidden files */
|
||
|
|
showHidden?: boolean;
|
||
|
|
/** Sort field */
|
||
|
|
sortBy?: 'name' | 'size' | 'modified';
|
||
|
|
/** Sort order */
|
||
|
|
sortOrder?: 'asc' | 'desc';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* File entry for directory listing
|
||
|
|
*/
|
||
|
|
export interface IFileEntry {
|
||
|
|
name: string;
|
||
|
|
path: string;
|
||
|
|
isDirectory: boolean;
|
||
|
|
size: number;
|
||
|
|
modified: Date;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* WebDAV configuration
|
||
|
|
*/
|
||
|
|
export interface IWebDAVConfig {
|
||
|
|
/** Root directory path */
|
||
|
|
root: string;
|
||
|
|
/** Authentication handler */
|
||
|
|
auth?: (ctx: IRequestContext) => boolean | Promise<boolean>;
|
||
|
|
/** Enable locking */
|
||
|
|
locking?: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Main server configuration
|
||
|
|
*/
|
||
|
|
export interface ISmartServeOptions {
|
||
|
|
/** Port to listen on */
|
||
|
|
port: number;
|
||
|
|
/** Hostname to bind to */
|
||
|
|
hostname?: string;
|
||
|
|
/** TLS configuration for HTTPS */
|
||
|
|
tls?: ITLSConfig;
|
||
|
|
/** WebSocket configuration */
|
||
|
|
websocket?: IWebSocketHooks;
|
||
|
|
/** Static file serving */
|
||
|
|
static?: IStaticOptions | string;
|
||
|
|
/** WebDAV configuration */
|
||
|
|
webdav?: IWebDAVConfig;
|
||
|
|
/** Connection timeout (ms) */
|
||
|
|
connectionTimeout?: number;
|
||
|
|
/** Keep-alive settings */
|
||
|
|
keepAlive?: IKeepAliveConfig;
|
||
|
|
/** Global error handler */
|
||
|
|
onError?: (error: Error, request?: Request) => Response | Promise<Response>;
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Server Instance
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Server statistics
|
||
|
|
*/
|
||
|
|
export interface IServerStats {
|
||
|
|
uptime: number;
|
||
|
|
requestsTotal: number;
|
||
|
|
requestsActive: number;
|
||
|
|
connectionsTotal: number;
|
||
|
|
connectionsActive: number;
|
||
|
|
bytesReceived: number;
|
||
|
|
bytesSent: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Running server instance
|
||
|
|
*/
|
||
|
|
export interface ISmartServeInstance {
|
||
|
|
/** Listening port */
|
||
|
|
port: number;
|
||
|
|
/** Bound hostname */
|
||
|
|
hostname: string;
|
||
|
|
/** Is HTTPS enabled */
|
||
|
|
secure: boolean;
|
||
|
|
/** Runtime environment */
|
||
|
|
runtime: TRuntime;
|
||
|
|
/** Stop the server */
|
||
|
|
stop(): Promise<void>;
|
||
|
|
/** Get server statistics */
|
||
|
|
stats(): IServerStats;
|
||
|
|
}
|
||
|
|
|
||
|
|
// =============================================================================
|
||
|
|
// Connection Info
|
||
|
|
// =============================================================================
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Connection information
|
||
|
|
*/
|
||
|
|
export interface IConnectionInfo {
|
||
|
|
remoteAddr: string;
|
||
|
|
remotePort: number;
|
||
|
|
localAddr: string;
|
||
|
|
localPort: number;
|
||
|
|
encrypted: boolean;
|
||
|
|
tlsVersion?: string;
|
||
|
|
}
|