API ReferenceCore
@nextrush/types
Shared TypeScript type definitions for the NextRush ecosystem
The types package provides shared TypeScript definitions for the entire NextRush ecosystem. It has zero runtime dependencies.
$ pnpm add @nextrush/types
Peer Dependency
This package is typically installed as a peer dependency of other NextRush packages. You rarely need to install it directly.
What It Provides
// Context and middleware types
import type {
Context,
ContextState,
ContextOptions,
Middleware,
Next,
RouteHandler,
RouteParams,
QueryParams,
} from '@nextrush/types';
// HTTP types
import type {
HttpMethod,
CommonHttpMethod,
HttpStatusCode,
ContentTypeValue,
IncomingHeaders,
OutgoingHeaders,
ParsedBody,
ResponseBody,
RawHttp,
NodeStreamLike,
WebStreamLike,
} from '@nextrush/types';
// HTTP constants
import { HttpStatus, ContentType, HTTP_METHODS } from '@nextrush/types';
// Plugin types
import type {
Plugin,
PluginWithHooks,
PluginFactory,
PluginMeta,
ApplicationLike,
} from '@nextrush/types';
// Router types
import type {
Router,
RouterOptions,
Route,
RouteMatch,
RouteParam,
RoutePattern,
} from '@nextrush/types';
// Runtime types
import type {
Runtime,
RuntimeInfo,
RuntimeCapabilities,
BodySource,
BodySourceOptions,
} from '@nextrush/types';Context Interface
The Context interface is the heart of NextRush. It provides unified access to request data and response methods.
Design Philosophy
// INPUT (Request)
ctx.method; // HTTP method
ctx.url; // Full URL with query
ctx.path; // Path without query
ctx.query; // Parsed query params
ctx.params; // Route parameters
ctx.headers; // Request headers
ctx.body; // Parsed request body
ctx.ip; // Client IP
// OUTPUT (Response)
ctx.status; // Status code
ctx.json(); // Send JSON
ctx.send(); // Send text/buffer
ctx.html(); // Send HTML
ctx.redirect(); // Redirect
// SHARED
ctx.state; // Middleware state bag
ctx.next(); // Call next middlewareFull Interface
interface Context {
// Request (read-only)
readonly method: HttpMethod;
readonly url: string;
readonly path: string;
readonly query: QueryParams;
readonly headers: IncomingHeaders;
readonly ip: string;
readonly runtime: Runtime;
readonly raw: RawHttp;
readonly bodySource: BodySource;
// Request body (set by body parser)
body: unknown;
// Route params (set by router)
params: RouteParams;
// Response
status: number;
json(data: unknown): void;
send(data: ResponseBody): void;
html(content: string): void;
redirect(url: string, status?: number): void;
// Headers
get(field: string): string | undefined;
set(field: string, value: string | number | string[]): void;
// Error helpers
throw(status: number, message?: string): never;
assert(condition: unknown, status: number, message?: string): asserts condition;
// Middleware
next(): Promise<void>;
readonly responded: boolean;
// State
state: ContextState;
}Middleware Type
Middleware supports both modern and Koa-style syntax:
// Modern syntax: ctx.next()
const middleware: Middleware = async (ctx) => {
console.log('Before');
await ctx.next();
console.log('After');
};
// Koa-style: (ctx, next) parameter
const middleware: Middleware = async (ctx, next) => {
console.log('Before');
await next();
console.log('After');
};The type signature supports both:
type Next = () => Promise<void>;
type Middleware = (ctx: Context, next: Next) => void | Promise<void>;
type RouteHandler = Middleware; // AliasHTTP Types
HttpMethod
type HttpMethod =
| 'GET'
| 'POST'
| 'PUT'
| 'DELETE'
| 'PATCH'
| 'HEAD'
| 'OPTIONS'
| 'TRACE'
| 'CONNECT';
type CommonHttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
// Tuple for iteration (excludes TRACE and CONNECT for security reasons)
const HTTP_METHODS: readonly HttpMethod[] = [
'GET',
'POST',
'PUT',
'DELETE',
'PATCH',
'HEAD',
'OPTIONS',
];HttpStatusCode
type HttpStatusCode =
| 200
| 201
| 202
| 204 // Success
| 301
| 302
| 303
| 304
| 307
| 308 // Redirect
| 400
| 401
| 403
| 404
| 405
| 406 // Client error
| 409
| 410
| 422
| 429 // Client error (continued)
| 500
| 501
| 502
| 503
| 504; // Server errorConstants
// HTTP status codes
const HttpStatus = {
OK: 200,
CREATED: 201,
ACCEPTED: 202,
NO_CONTENT: 204,
MOVED_PERMANENTLY: 301,
FOUND: 302,
SEE_OTHER: 303,
NOT_MODIFIED: 304,
TEMPORARY_REDIRECT: 307,
PERMANENT_REDIRECT: 308,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_ALLOWED: 405,
NOT_ACCEPTABLE: 406,
CONFLICT: 409,
GONE: 410,
UNPROCESSABLE_ENTITY: 422,
TOO_MANY_REQUESTS: 429,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
} as const;
// Content types
const ContentType = {
JSON: 'application/json',
HTML: 'text/html',
TEXT: 'text/plain',
XML: 'application/xml',
FORM: 'application/x-www-form-urlencoded',
MULTIPART: 'multipart/form-data',
OCTET_STREAM: 'application/octet-stream',
} as const;Plugin Types
interface Plugin {
/** Unique plugin name */
readonly name: string;
/** Plugin version (semver format) */
readonly version?: string;
/** Install the plugin on an application */
install(app: ApplicationLike): void | Promise<void>;
/** Optional cleanup on shutdown */
destroy?(): void | Promise<void>;
}
interface PluginWithHooks extends Plugin {
/** Called before each request */
onRequest?(ctx: Context): void | Promise<void>;
/** Called after each response */
onResponse?(ctx: Context): void | Promise<void>;
/** Called when an error occurs */
onError?(error: Error, ctx: Context): void | Promise<void>;
/** Extend the context object */
extendContext?(ctx: Context): void;
}PluginWithHooks Lifecycle Methods
| Property | Type | Description |
|---|---|---|
onRequest? | (ctx: Context) => void | Promise<void> | Called before each request |
onResponse? | (ctx: Context) => void | Promise<void> | Called after each response |
onError? | (error: Error, ctx: Context) => void | Promise<void> | Called when an error occurs |
extendContext? | (ctx: Context) => void | Extend the context object with additional properties |
Router Types
RouterOptions
RouterOptions
| Property | Type | Description |
|---|---|---|
prefix? | string | Path prefix for all routes |
caseSensitive? | boolean= false | Case-sensitive matching |
strict? | boolean= false | Strict trailing slash |
RouteMatch
interface RouteMatch {
/** Route handler function */
handler: RouteHandler;
/** Extracted route parameters */
params: RouteParams;
/** Route-specific middleware */
middleware: Middleware[];
}
interface Route {
method: HttpMethod;
path: string;
handler: RouteHandler;
middleware?: Middleware[];
}Runtime Types
Runtime
type Runtime =
| 'node'
| 'bun'
| 'deno'
| 'deno-deploy'
| 'cloudflare-workers'
| 'vercel-edge'
| 'edge'
| 'unknown';RuntimeInfo
interface RuntimeInfo {
runtime: Runtime;
version: string | undefined;
capabilities: RuntimeCapabilities;
}RuntimeInfo
| Property | Type | Description |
|---|---|---|
runtime | Runtime | Detected runtime identifier |
version | string | undefined | Runtime version string |
capabilities | RuntimeCapabilities | Feature support flags |
RuntimeCapabilities
RuntimeCapabilities
| Property | Type | Description |
|---|---|---|
nodeStreams | boolean | Supports Node.js streams |
webStreams | boolean | Supports Web Streams API |
fileSystem | boolean | Supports file system operations |
webSocket | boolean | Supports WebSocket |
fetch | boolean | Supports native fetch API |
cryptoSubtle | boolean | Supports crypto.subtle API |
workers | boolean | Supports Web Workers / Worker Threads |
Body Source
Cross-runtime abstraction for reading request bodies:
interface BodySource {
/** Read body as UTF-8 string */
text(): Promise<string>;
/** Read body as Uint8Array buffer */
buffer(): Promise<Uint8Array>;
/** Read body as parsed JSON */
json<T = unknown>(): Promise<T>;
/** Get the underlying stream */
stream(): NodeStreamLike | WebStreamLike;
/** Whether the body has been consumed */
readonly consumed: boolean;
/** Content-Length header value (if available) */
readonly contentLength: number | undefined;
/** Content-Type header value (if available) */
readonly contentType: string | undefined;
}BodySourceOptions
| Property | Type | Description |
|---|---|---|
limit? | number= 1048576 (1MB) | Maximum body size in bytes |
encoding? | 'utf-8' | 'utf8' | 'ascii' | 'latin1' | 'iso-8859-1' | 'utf-16le' | 'utf-16be'= 'utf-8' | Encoding for text() method |
Type Utilities
RouteParams and QueryParams
// Route params are always strings
type RouteParams = Record<string, string>;
// Query params can be string, array, or undefined
type QueryParams = Record<string, string | string[] | undefined>;
// Usage
const id: string = ctx.params.id;
const page: string | string[] | undefined = ctx.query.page;ContextState
// Default state is Record<string | symbol, unknown>
type ContextState = Record<string | symbol, unknown>;
// Type your state for better safety
interface AppState extends ContextState {
user?: { id: string; email: string };
requestId: string;
}
// Usage
ctx.state.user = { id: '123', email: 'user@example.com' };Common Import Patterns
Type-Only Imports
// Import types only (no runtime code)
import type { Context, Middleware, Plugin } from '@nextrush/types';Constants
// Import runtime constants
import { HttpStatus, ContentType, HTTP_METHODS } from '@nextrush/types';
ctx.status = HttpStatus.NOT_FOUND;
ctx.set('Content-Type', ContentType.JSON);Extending Types
import type { Context, ContextState } from '@nextrush/types';
// Extend context state
interface MyAppState extends ContextState {
user: { id: string; role: 'admin' | 'user' };
locale: string;
}
// Use in middleware
const authMiddleware = async (ctx: Context) => {
const state = ctx.state as MyAppState;
state.user = await authenticate(ctx);
await ctx.next();
};Why Zero Dependencies?
The types package has no runtime dependencies because:
- Tree-shaking: Types are erased at compile time
- No bloat: Installing types doesn't add bundle size
- Fast installs: No transitive dependencies to resolve
- Safe sharing: Can be used by any package without conflicts