NextRush

@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 middleware

Full 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; // Alias

HTTP 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 error

Constants

// 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

PropertyTypeDescription
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) => voidExtend the context object with additional properties

Router Types

RouterOptions

RouterOptions

PropertyTypeDescription
prefix?stringPath prefix for all routes
caseSensitive?boolean= falseCase-sensitive matching
strict?boolean= falseStrict 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

PropertyTypeDescription
runtimeRuntimeDetected runtime identifier
versionstring | undefinedRuntime version string
capabilitiesRuntimeCapabilitiesFeature support flags

RuntimeCapabilities

RuntimeCapabilities

PropertyTypeDescription
nodeStreamsbooleanSupports Node.js streams
webStreamsbooleanSupports Web Streams API
fileSystembooleanSupports file system operations
webSocketbooleanSupports WebSocket
fetchbooleanSupports native fetch API
cryptoSubtlebooleanSupports crypto.subtle API
workersbooleanSupports 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

PropertyTypeDescription
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:

  1. Tree-shaking: Types are erased at compile time
  2. No bloat: Installing types doesn't add bundle size
  3. Fast installs: No transitive dependencies to resolve
  4. Safe sharing: Can be used by any package without conflicts

See Also

On this page