API Reference

Types API Reference

Complete TypeScript type definitions for MoroJS. Build type-safe applications with full IntelliSense support and compile-time validation.

Core Types

Essential TypeScript interfaces and types for building MoroJS applications.

Application Types
1import type { 
2  Moro,
3  MoroConfig,
4  MoroOptions,
5  RuntimeAdapter
6} from '@morojs/moro';
7
8// Main application interface
9interface Moro {
10  // HTTP methods. Called with a path only, they return a chainable route
11  // builder; called with a handler, they register the route directly.
12  // The handler may be a function, the response body itself
13  // (StaticBody: a string or Buffer), or param(name) (ParamEcho) - see
14  // Literal Handlers.
15  get(path: string): UnifiedRouteBuilder;
16  get(path: string, handler: RouteHandler | StaticBody | ParamEcho, options?: RouteOptions): this;
17  post(path: string): UnifiedRouteBuilder;
18  post(path: string, handler: RouteHandler | StaticBody | ParamEcho, options?: RouteOptions): this;
19  put(path: string): UnifiedRouteBuilder;
20  put(path: string, handler: RouteHandler | StaticBody | ParamEcho, options?: RouteOptions): this;
21  delete(path: string): UnifiedRouteBuilder;
22  delete(path: string, handler: RouteHandler | StaticBody | ParamEcho, options?: RouteOptions): this;
23  patch(path: string): UnifiedRouteBuilder;
24  patch(path: string, handler: RouteHandler | StaticBody | ParamEcho, options?: RouteOptions): this;
25
26  // Schema-first registration
27  route(schema: RouteSchema): void;
28
29  // Application methods
30  use(...middleware: MiddlewareFunction[]): void;
31  group(prefix: string, callback: (group: Moro) => void): void;
32  listen(port: number, host?: string, callback?: () => void): void;
33  close(): Promise<void>;
34  
35  // Configuration
36  configure(config: Partial<MoroConfig>): void;
37  getConfig(): MoroConfig;
38  getConfig<K extends keyof MoroConfig>(key: K): MoroConfig[K];
39  
40  // Environment
41  env(): Record<string, string>;
42  env<T = Record<string, string>>(): T;
43  env(key: string): string | undefined;
44  env(schema: EnvSchema): void;
45}
46
47// Configuration interface
48interface MoroConfig {
49  server?: ServerConfig;
50  security?: SecurityConfig;
51  database?: DatabaseConfig;
52  logging?: LoggingConfig;
53  features?: FeaturesConfig;
54}
55
56// Runtime adapter interface
57interface RuntimeAdapter {
58  name: 'node' | 'edge' | 'lambda' | 'worker';
59  createHandler(app: Moro): any;
60  transformRequest(request: any): Request;
61  transformResponse(response: Response): any;
62}

Request/Response Types

Handler and Context Types
1// Route handler: the request and the response, the same on every
2// server MoroJS runs on. A returned value other than undefined is sent
3// as JSON; use res directly for anything else.
4type RouteHandler<T = any> = (req: HttpRequest, res: HttpResponse) => T | Promise<T>;
5
6// What .handler() accepts in place of a function: the response body itself
7type StaticBody = string | Buffer;
8
9// The reply a literal handler sends, in the engine's shape. Set on the
10// RouteSchema by the framework when a literal handler has nothing else
11// configured, so a server that can answer it natively (@morojs/engine
12// >= 1.1.6) does so without calling into JS.
13interface StaticResponse {
14  status: number;
15  headers: string[] | null;   // [name, value, name, value, ...]
16  body: string | Buffer | null;
17}
18
19// The marker param(name) produces: "answer with this path parameter as
20// the body", as res.end(req.params[name]) would
21interface ParamEcho {
22  readonly [PARAM_ECHO]: true;  // brand, set by param()
23  readonly name: string;
24}
25
26// The engine shape of a param(name) handler on a bare route with exactly
27// that one parameter: the path segment between prefix and suffix is the
28// body. Framework-set; @morojs/engine >= 1.1.9 (paramRoutes) answers it
29// without calling into JS, every other server runs the equivalent handler.
30interface ParamRouteReply {
31  name: string;
32  prefix: string;
33  suffix: string;
34  status: number;
35  headers: string[] | null;   // [name, value, name, value, ...]
36}
37
38// The request: Node's IncomingMessage plus what MoroJS parses and attaches
39interface HttpRequest extends IncomingMessage {
40  params: Record<string, string>;
41  query: Record<string, string>;
42  body: any;
43  rawBody: Buffer | null;   // the undecoded body bytes (JSON included), null when none
44  path: string;
45  headers: Record<string, string>;
46  ip: string;
47  requestId: string;
48  cookies?: Record<string, string>;
49  signedCookies?: Record<string, string>;  // verified signatures only; needs a cookie secret
50  files?: Record<string, any>;
51
52  // Per-request typed context: pass data between middlewares without patching req
53  context: Record<string, any>;
54
55  // Express-compatible helpers
56  get(name: string): string | undefined;
57  header(name: string): string | undefined;
58  is(type: string): boolean;
59  accepts(types?: string | string[]): string | false;
60  acceptsLanguages(langs?: string | string[]): string | false;
61  hostname: string;
62  protocol: string;
63  secure: boolean;
64  xhr: boolean;
65  originalUrl: string;
66  ips: string[];
67  subdomains: string[];
68}
69
70// The response: Node's ServerResponse plus MoroJS's helpers
71type HttpResponse = ServerResponse & MoroResponseMethods;
72
73interface MoroResponseMethods {
74  json(data: any): void;
75  status(code: number): HttpResponse;
76  send(data: string | Buffer): void;
77  cookie(name: string, value: string, options?: CookieOptions): HttpResponse;
78  clearCookie(name: string, options?: CookieOptions): HttpResponse;
79  redirect(url: string, status?: number): void;
80  sendFile(filePath: string): Promise<void>;
81  render?(template: string, data?: any): Promise<void>;
82  locals: Record<string, any>;  // per-response state bag (Express-compatible)
83
84  // Express-compatible helpers
85  set(field: string | Record<string, string | string[] | number>, value?: string | string[] | number): HttpResponse;
86  get(field: string): string | number | string[] | undefined;
87  append(field: string, value: string | string[]): HttpResponse;
88  type(contentType: string): HttpResponse;
89  sendStatus(code: number): void;
90  location(url: string): HttpResponse;
91  vary(field: string | string[]): HttpResponse;
92  links(links: Record<string, string>): HttpResponse;
93  attachment(filename?: string): HttpResponse;
94  download(filePath: string, filename?: string): Promise<void>;
95  format(handlers: Record<string, () => any | Promise<any>>): void;
96
97  // Header and state utilities
98  hasHeader(name: string): boolean;
99  setBulkHeaders(headers: Record<string, string | number>): HttpResponse;
100  appendHeader(name: string, value: string | string[]): HttpResponse;
101  canSetHeaders(): boolean;
102  getResponseState(): ResponseState;
103
104  // Standardized helpers (see Response Helpers)
105  success<T = any>(data: T, message?: string): void;
106  error(error: string, code?: string, message?: string): void;
107  unauthorized(message?: string): void;
108  forbidden(message?: string): void;
109  notFound(resource?: string): void;
110  badRequest(message?: string): void;
111  conflict(message: string): void;
112  internalError(message?: string): void;
113  validationError(errors: Array<{ field: string; message: string; code?: string }>): void;
114  rateLimited(retryAfter?: number): void;
115  created<T = any>(data: T, location?: string): void;
116  noContent(): void;
117  paginated<T = any>(data: T[], pagination: { page: number; limit: number; total: number }): void;
118}
119
120// HTTP method type
121type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
122
123// Cookie options
124interface CookieOptions {
125  maxAge?: number;
126  expires?: Date;
127  httpOnly?: boolean;
128  secure?: boolean;
129  sameSite?: 'strict' | 'lax' | 'none';
130  domain?: string;
131  path?: string;
132  signed?: boolean;          // sign the value; needs a cookie middleware secret
133  critical?: boolean;        // mark as critical: throws if set after headers were sent
134  throwOnLateSet?: boolean;  // force a throw if headers were already sent
135}

Route Configuration Types

Route Configuration Interface
1// The chainable route builder returned by app.get('/path') etc.
2// Every method returns the builder, so calls chain in any order -
3// execution order is fixed by the pipeline, not by chain order.
4interface UnifiedRouteBuilder {
5  // Validation
6  body(schema: ValidationSchema): this;
7  query(schema: ValidationSchema): this;
8  params(schema: ValidationSchema): this;
9  headers(schema: ValidationSchema): this;
10  validate(config: ValidationConfig): this;
11
12  // Route features
13  auth(config: AuthConfig): this;
14  rateLimit(config: RateLimitConfig): this;
15  cache(config: CacheConfig): this;
16
17  // Custom middleware, by phase
18  before(...middleware: Middleware[]): this;
19  transform(...middleware: Middleware[]): this;
20  after(...middleware: Middleware[]): this;
21  use(...middleware: Middleware[]): this;  // alias for after()
22
23  // Metadata
24  describe(description: string): this;
25  tag(...tags: string[]): this;
26
27  // Terminal - registers the route. A function handles the request;
28  // a string or Buffer IS the response body (as res.send would send it);
29  // param(name) echoes that path parameter (as res.end would send it)
30  handler(fn: RouteHandler | StaticBody | ParamEcho): void;
31}
32
33// Options accepted by the direct form: app.get(path, handler, options)
34interface RouteOptions {
35  middleware?: Middleware[];
36  validation?: ValidationConfig;
37  rateLimit?: RateLimitConfig;
38  cache?: CacheConfig;
39}
40
41// The schema behind app.route({ ... }) and the chainable builder.
42// Chainable calls populate exactly these fields.
43interface RouteSchema {
44  method: HttpMethod;
45  path: string;
46  handler: RouteHandler | StaticBody | ParamEcho;  // a function, the body itself, or param(name)
47  static?: StaticResponse;         // fixed reply of a literal handler (framework-set)
48  paramEcho?: ParamRouteReply;     // engine shape of a param(name) handler (framework-set)
49
50  validation?: ValidationConfig;   // .body() / .query() / .params() / .headers() / .validate()
51  auth?: AuthConfig;               // .auth()
52  rateLimit?: RateLimitConfig;     // .rateLimit()
53  cache?: CacheConfig;             // .cache()
54  middleware?: MiddlewarePhases;   // .before() / .transform() / .after() / .use()
55  description?: string;            // .describe()
56  tags?: string[];                 // .tag()
57}
58
59interface ValidationConfig {
60  body?: ValidationSchema;
61  query?: ValidationSchema;
62  params?: ValidationSchema;
63  headers?: ValidationSchema;
64  // Shapes the 4xx when a schema rejects the request. Route-level handler
65  // wins over the global one passed to createApp().
66  onValidationError?: (
67    errors: ValidationErrorDetail[],
68    context: ValidationErrorContext
69  ) => ValidationErrorResponse;
70}
71
72interface AuthConfig {
73  roles?: string[];
74  permissions?: string[];
75  optional?: boolean;
76}
77
78interface RateLimitConfig {
79  requests: number;                // allowed requests per window
80  window: number;                  // window length in milliseconds
81  skipSuccessfulRequests?: boolean;
82}
83
84interface CacheConfig {
85  ttl: number;                     // SECONDS (note: rateLimit.window is milliseconds)
86  key?: string;                    // static cache key (not a function)
87  tags?: string[];
88}
89
90// Custom middleware is placed by phase, then runs in declaration order
91// within that phase.
92interface MiddlewarePhases {
93  before?: Middleware[];     // ahead of rate limiting and auth
94  transform?: Middleware[];  // after validation, before the cache check
95  after?: Middleware[];      // just before the handler (.use() lands here)
96}
97
98interface ValidationErrorDetail {
99  field: string;
100  message: string;
101  code?: string;
102  value?: any;
103  path?: (string | number)[];
104}
105
106interface ValidationErrorResponse {
107  status: number;
108  body: any;
109  headers?: Record<string, string>;
110}
111
112type ValidationSchema = z.ZodSchema<any>;

Middleware Types

Middleware Function Types
1// Middleware function type
2type MiddlewareFunction = (
3  context: RequestContext,
4  next: NextFunction
5) => void | Promise<void>;
6
7// Next function type
8type NextFunction = () => void | Promise<void>;
9
10// Middleware factory type (for configurable middleware)
11type MiddlewareFactory<T = any> = (options?: T) => MiddlewareFunction;
12
13// Built-in middleware options
14interface CorsOptions {
15  origin?: string | string[] | ((origin: string) => boolean);
16  methods?: string[];
17  allowedHeaders?: string[];
18  exposedHeaders?: string[];
19  credentials?: boolean;
20  maxAge?: number;
21  preflightContinue?: boolean;
22  optionsSuccessStatus?: number;
23}
24
25interface RateLimitOptions {
26  requests?: number;  // or max
27  max?: number;
28  window?: number;    // milliseconds; or windowMs
29  windowMs?: number;
30  message?: string;
31  statusCode?: number;            // default 429
32  skipSuccessfulRequests?: boolean;
33  skipFailedRequests?: boolean;
34}
35
36interface HelmetOptions {
37  contentSecurityPolicy?: {
38    directives?: Record<string, string[]>;
39    reportOnly?: boolean;
40  };
41  crossOriginEmbedderPolicy?: boolean;
42  crossOriginOpenerPolicy?: boolean;
43  crossOriginResourcePolicy?: { policy: 'same-site' | 'same-origin' | 'cross-origin' };
44  dnsPrefetchControl?: boolean;
45  frameguard?: { action: 'deny' | 'sameorigin' };
46  hidePoweredBy?: boolean;
47  hsts?: {
48    maxAge?: number;
49    includeSubDomains?: boolean;
50    preload?: boolean;
51  };
52  ieNoOpen?: boolean;
53  noSniff?: boolean;
54  originAgentCluster?: boolean;
55  permittedCrossDomainPolicies?: boolean;
56  referrerPolicy?: string;
57  xssFilter?: boolean;
58}
59
60// Rate limit store interface
61interface RateLimitStore {
62  get(key: string): Promise<number | null>;
63  set(key: string, value: number, ttl: number): Promise<void>;
64  increment(key: string, ttl: number): Promise<number>;
65  reset(key: string): Promise<void>;
66}

Configuration Types

Configuration Interfaces
1// Server configuration
2interface ServerConfig {
3  port?: number;
4  host?: string;
5  environment?: 'development' | 'staging' | 'production';
6  gracefulShutdown?: {
7    timeout?: number;
8    signals?: string[];
9  };
10  keepAlive?: boolean;
11  bodyLimit?: string;
12}
13
14// Security configuration
15interface SecurityConfig {
16  cors?: CorsOptions;
17  helmet?: HelmetOptions;
18  rateLimit?: {
19    global?: RateLimitOptions;
20    api?: RateLimitOptions;
21  };
22  csrf?: {
23    enabled?: boolean;
24    secret?: string;
25    cookie?: CookieOptions;
26  };
27}
28
29// Database configuration
30interface DatabaseConfig {
31  default?: {
32    type?: 'postgresql' | 'mysql' | 'sqlite' | 'mongodb';
33    url?: string;
34    pool?: {
35      min?: number;
36      max?: number;
37      acquireTimeoutMillis?: number;
38      idleTimeoutMillis?: number;
39      createTimeoutMillis?: number;
40    };
41    migrations?: {
42      directory?: string;
43      autoRun?: boolean;
44      table?: string;
45    };
46    ssl?: boolean | {
47      rejectUnauthorized?: boolean;
48      ca?: string;
49      key?: string;
50      cert?: string;
51    };
52  };
53  cache?: {
54    type?: 'redis' | 'memory' | 'file';
55    url?: string;
56    ttl?: string;
57    prefix?: string;
58    maxSize?: number;
59  };
60}
61
62// Logging configuration
63interface LoggingConfig {
64  level?: 'debug' | 'info' | 'warn' | 'error';
65  format?: 'json' | 'pretty';
66  destinations?: Array<{
67    type: 'console' | 'file' | 'http';
68    path?: string;
69    url?: string;
70    level?: string;
71  }>;
72  requestLogging?: {
73    enabled?: boolean;
74    skipHealthChecks?: boolean;
75    skipPaths?: string[];
76    format?: string;
77  };
78}
79
80// Features configuration
81interface FeaturesConfig {
82  websockets?: boolean | {
83    enabled?: boolean;
84    path?: string;
85    cors?: CorsOptions;
86  };
87  fileUploads?: {
88    enabled?: boolean;
89    maxSize?: string;
90    allowedTypes?: string[];
91    destination?: string;
92  };
93  apiDocs?: {
94    enabled?: boolean;
95    path?: string;
96    title?: string;
97    version?: string;
98    description?: string;
99  };
100  clustering?: {
101    enabled?: boolean;
102    workers?: number | 'auto';
103    memoryPerWorkerGB?: number;
104  };
105}
106
107// Environment schema
108interface EnvSchema {
109  [key: string]: {
110    required?: boolean;
111    type?: 'string' | 'number' | 'boolean';
112    default?: any;
113    enum?: string[];
114    minLength?: number;
115    maxLength?: number;
116    min?: number;
117    max?: number;
118  };
119}

Utility Types

Helper Types and Utilities
1// Generic utility types
2type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
3type Required<T, K extends keyof T> = T & Required<Pick<T, K>>;
4
5// Route parameter extraction
6type ExtractParams<T extends string> = T extends `${infer Start}:${infer Param}/${infer Rest}`
7  ? { [K in Param]: string } & ExtractParams<Rest>
8  : T extends `${infer Start}:${infer Param}`
9  ? { [K in Param]: string }
10  : {};
11
12// Type-safe route handler with parameter inference
13type TypedRouteHandler<TPath extends string, TBody = any, TResponse = any> = (
14  context: RequestContext & {
15    params: ExtractParams<TPath>;
16    body: TBody;
17  }
18) => TResponse | Promise<TResponse>;
19
20// WebSocket types
21interface WebSocketConnection {
22  id: string;
23  send(data: any): void;
24  close(code?: number, reason?: string): void;
25  ping(data?: Buffer): void;
26  pong(data?: Buffer): void;
27  on(event: 'message' | 'close' | 'error' | 'ping' | 'pong', handler: Function): void;
28  off(event: string, handler: Function): void;
29}
30
31interface WebSocketManager {
32  connections: Map<string, WebSocketConnection>;
33  broadcast(data: any, filter?: (connection: WebSocketConnection) => boolean): void;
34  getConnection(id: string): WebSocketConnection | undefined;
35  closeConnection(id: string): void;
36  closeAll(): void;
37}
38
39// Event system types
40interface EventBus {
41  emit(event: string, data?: any): void;
42  on(event: string, handler: (data: any) => void): void;
43  off(event: string, handler: (data: any) => void): void;
44  once(event: string, handler: (data: any) => void): void;
45  removeAllListeners(event?: string): void;
46}
47
48// Cache types
49interface CacheStore {
50  get<T = any>(key: string): Promise<T | null>;
51  set<T = any>(key: string, value: T, options?: { ttl?: string | number }): Promise<void>;
52  delete(key: string): Promise<boolean>;
53  clear(): Promise<void>;
54  has(key: string): Promise<boolean>;
55  keys(pattern?: string): Promise<string[]>;
56}
57
58// Logger types
59interface Logger {
60  debug(message: string, meta?: any): void;
61  info(message: string, meta?: any): void;
62  warn(message: string, meta?: any): void;
63  error(message: string, meta?: any): void;
64  child(meta: any): Logger;
65}

Type Safety Benefits

  • Full IntelliSense and autocomplete support
  • Compile-time type checking for routes and handlers
  • Automatic parameter type inference from route paths
  • Schema-based request/response validation
  • Type-safe configuration and environment variables

Next Steps