@nextrush/typesTypes
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.
Source & internals
$ 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';
// Extension types
import type {
Extension,
ExtensionContext,
ExtensionHost,
} 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;
}Generated Reference
The table below is generated directly from packages/types/src/context.ts at build time —
it is not hand-maintained, so it cannot drift from the code the way the block above can.
Prop
Type
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;Extension Types
Extensions are the rare (~0.1%) long-lived, app-scoped services that need a boot phase and a teardown phase — see Extending NextRush for when to reach for one instead of middleware or a registrar.
interface ExtensionHost {
/** Register middleware on the application. */
use(middleware: Middleware): this;
/** Whether a decoration already occupies `name`. */
hasDecorator(name: string): boolean;
}
interface ExtensionContext {
/** The application instance — add middleware, read decorations. */
readonly app: ExtensionHost;
/** The app logger (structured, pluggable). */
readonly logger: Logger;
/** The app's DI container, if one was configured. */
readonly container?: Container;
/** Environment mode. */
readonly env: 'development' | 'production' | 'test';
/** This extension's own name (for scoped diagnostics). */
readonly name: string;
/** Attach a value to the app under `name`. Throws on name collision. */
decorate<V>(name: string, value: V): void;
}
interface Extension {
/** Unique name — used for collision detection, dependency assertion, diagnostics. */
readonly name: string;
/** Names of other extensions that MUST already be registered before this one. */
readonly needs?: readonly string[];
/** Set up the extension. Runs once, at `app.ready()`, in registration order. */
setup(ctx: ExtensionContext): void | Promise<void>;
/** Tear down on `app.close()`. Runs in reverse registration order. */
destroy?(): void | Promise<void>;
}ExtensionContext
| Property | Type | Description |
|---|---|---|
app | ExtensionHost | The subset of Application an extension may use during setup() |
logger | Logger | The app logger |
container? | Container | The app's per-app DI container, if one was configured |
env | 'development' | 'production' | 'test' | Environment mode |
name | string | This extension's own name |
decorate | <V>(name: string, value: V) => void | Attach a value to the app under `name`. Throws on collision. |
There is no public app.decorate() — attaching a value to the app is only possible through
ctx.decorate() inside setup(). The public, read-only check for a decoration from outside an
extension is app.hasDecorator(name).
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, Extension } 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