API reference: Middleware & helpers
Built-in middleware, the every/some/except composition primitives, typed dependencies, config validation, structured logging, the startup banner, and connection-info helpers. Everything on this page is exported from the root @daloyjs/core barrel. See the API reference overview for the full module map.
Platform hygieneapplied by secureDefaults
requestId()secureHeaders()
Traffic shaping
rateLimit()loadShedding()compression()
Authentication & access
bearerAuth()jwk()requireScopes()csrf()
Route handlertyped ctx, typed response
Built-in middleware
ts
requestId(opts?: RequestIdOptions): Hooks
secureHeaders(opts?: SecureHeadersOptions): Hooks
cors(opts: CorsOptions): Hooks
rateLimit(opts: RateLimitOptions): Hooks
loginThrottle(opts?: LoginThrottleOptions): Hooks
timing(headerName?: string): Hooks
compression(opts?: CompressionOptions): Hooks
bearerAuth(opts: BearerAuthOptions): Hooks
basicAuth(opts: BasicAuthOptions): Hooks
markAuthHook(hooks: Hooks): Hooks
const AUTH_HOOK_MARKER: unique symbol // stamped by built-ins and markAuthHook()
csrf(opts?: CsrfOptions): Hooks
fetchMetadata(opts?: FetchMetadataOptions): Hooks // Sec-Fetch-Site/Mode/Dest enforcement
requireScopes(scopes: string | string[]
| { all?: string[]; any?: string[] }): Hooks
ipRestriction(opts: IpRestrictionOptions): Hooks // CIDR allow/deny
loadShedding(opts?: LoadSheddingOptions): Hooks
etag(opts?: ETagOptions): Hooks // 304 + Set-Cookie / Cache-Control skip
interface RateLimitOptions {
windowMs: number;
max: number;
keyGenerator?: (ctx: RateLimitContext) => string; // may run on an early auth rejection
store?: RateLimitStore; // default in-memory; use redisRateLimitStore for clusters
trustProxyHeaders?: boolean; // rightmost XFF; spoofable if origin is reachable
trustedHops?: number; // multi-hop chain length (implies trust)
trustedProxies?: readonly string[]; // CIDR allowlist of proxy peers (peer-verified trust)
retryAfter?: boolean;
groupId?: string;
}
interface BearerAuthOptions {
validate: (token: string) => boolean | Promise<boolean>; // static check; token only
verify?: BearerAuthVerifyHook; // (token, ctx) => boolean | void; per-request revalidation
realm?: string;
}Composition primitives
ts
every(...layers: Hooks[]): Hooks // run every lifecycle phase in order
some (...layers: Hooks[]): Hooks // pass the first successful preBody/beforeHandle auth gate
except(when: ExceptPredicate, hooks: Hooks): Hooks // exempt paths from preBody + beforeHandle gates
type ExceptPredicate =
| string // path glob: "*" = one segment, "**" = any suffix
| string[] // any-of globs
| ((ctx) => boolean | Promise<boolean>);Dependencies (typed DI chain)
ts
defineDependency<TName, TValue, TStateKey>(opts: {
name: TName;
dependsOn?: readonly string[]; // refuses cycles at registration
stateKey?: TStateKey;
resolve: (ctx) => TValue | Promise<TValue>;
}): DependencyHooks // per-request cached; runs once per dependency per requestConfiguration
ts
defineConfig<S extends StandardSchemaV1>(opts: {
schema: S;
source?: ConfigSource; // default: "env" (process.env)
stderr?: { write(chunk: string): void } | false;
}): Promise<StandardSchemaV1.InferOutput<S>>;
// Async. Validates once at startup; throws ConfigValidationError on missing/invalid values.
type ConfigSource =
| "env"
| { kind: "env"; env: Record<string, string | undefined> }
| { kind: "file"; path: string; parse?: (text: string) => unknown }
| { kind: "object"; data: Record<string, unknown> }
| { kind: "custom"; resolve: () => Promise<Record<string, unknown>> };
class ConfigValidationError extends Error {
readonly issues: ReadonlyArray<{ key: string; message: string }>;
}Logging
ts
type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
createLogger(opts?: ConsoleLoggerOptions): Logger;
const noopLogger: Logger;
const DEFAULT_REDACT_KEYS: ReadonlyArray<string>; // password, token, secret, authorization, ...
interface ConsoleLoggerOptions {
level?: LogLevel;
bindings?: Record<string, unknown>;
write?: (line: string) => void;
redact?: LoggerRedactionOptions; // { keys?, replacer? }
}
interface Logger {
trace(obj?, msg?): void;
debug(obj?, msg?): void;
info (obj?, msg?): void;
warn (obj?, msg?): void;
error(obj?, msg?): void;
fatal(obj?, msg?): void;
child(bindings: Record<string, unknown>): Logger;
}Startup banner
ts
interface StartupBannerLink { label: string; url: string }
interface StartupBannerOptions {
name?: string; // default: "DaloyJS"
version?: string;
url: string;
runtime?: string; // e.g. "Node.js", "Bun"
links?: StartupBannerLink[];
color?: boolean;
ascii?: boolean;
}
formatStartupBanner(opts: StartupBannerOptions): string;
printStartupBanner(opts: StartupBannerOptions): void;Connection info & proxy posture
ts
type BehindProxyConfig = "none" | "loopback" | { hops: number } | { cidrs: readonly string[] };
interface ConnInfo { remoteAddress?: string; remotePort?: number; tls?: boolean }
getConnInfo(req: Request): ConnInfo | undefined;
setConnInfo(req: Request, info: ConnInfo): void; // adapter helper
assertBehindProxy(cfg: BehindProxyConfig | undefined): void;
resolveClientIp(ctx, cfg?: BehindProxyConfig): string | undefined;
readRemoteAddress(ctx): string | undefined;
readRemotePort(ctx): number | undefined;
pickForwardedForByHops(header: string, hops: number): string | undefined;
// Spoof-resistant client IP: reads `hops` entries from the RIGHT of
// X-Forwarded-For (the slots your own proxy chain wrote). Falls back to
// X-Real-IP only when hops === 1; past that a chain shorter than the
// declaration yields undefined rather than a caller-settable header.
resolveForwardedClientIp(req: Request, hops?: number): string | undefined;Subdomains (Public-Suffix-aware)
ts
subdomains(hostname: string, opts?: SubdomainsOptions): SubdomainsResult;
interface SubdomainsResult {
subdomain: string | undefined; // e.g. "api" for "api.example.co.uk"
registrableDomain: string | undefined;
publicSuffix: string | undefined;
}
const PSL_SNAPSHOT_DATE: string; // ISO date of the bundled PSL snapshot
const MAX_SNAPSHOT_AGE_DAYS: number; // refuses to use a stale snapshot
const PSL_PUBLIC_SUFFIXES: ReadonlySet<string>;Next up: security & auth helpers.