@emeryld/rrroutes-server 2.6.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/routesV3.server.ts","../src/routesV3.server.sanitize.ts","../src/sockets/socket.server.debug.ts","../src/sockets/socket.server.sys.ts","../src/sockets/socket.server.index.ts","../src/sockets/socket.server.middleware.ts"],"sourcesContent":["export { keyOf as contractKeyOf } from '@emeryld/rrroutes-contract'\nexport * from './routesV3.server'\nexport * from './routesV3.server.sanitize'\nexport * from './sockets/socket.server.index'\nexport * from './sockets/socket.server.middleware'\n","/**\n * routesV3.server.ts\n * -----------------------------------------------------------------------------\n * Bind an Express router/app to a `finalize(...)` registry of AnyLeafs.\n * - Fully typed handlers (params/query/body/output)\n * - Zod parsing + optional output validation\n * - Structured middleware stages (sanitizer, preCtx, postCtx, per-route, uploads)\n * - buildCtx runs after payload resolution and before ctx-aware middlewares\n * - Helper to warn about unimplemented routes\n * - DX helpers to use `ctx` in any middleware with proper types\n */\n\nimport {\n AnyLeafLowProfile,\n buildLowProfileLeaf,\n FileField,\n HttpMethod,\n InferBody,\n InferOutput,\n InferParams,\n InferQuery,\n keyOf,\n lowProfileParse,\n} from '@emeryld/rrroutes-contract'\nimport type * as express from 'express'\nimport type { RequestHandler, Router } from 'express'\nimport multer from 'multer'\nimport {\n createRequestSanitizationMiddleware,\n type RequestSanitizationOptions,\n} from './routesV3.server.sanitize'\n\ntype MulterOptions = multer.Options\n/** Shape expected from optional logger implementations. */\nexport type LoggerLike = {\n info?: (...args: any[]) => void\n warn?: (...args: any[]) => void\n error?: (...args: any[]) => void\n debug?: (...args: any[]) => void\n verbose?: (...args: any[]) => void\n system?: (...args: any[]) => void\n log?: (...args: any[]) => void\n}\n\ntype RoutesLoggerCarrier = {\n routesLogger?: LoggerLike\n}\n\ntype CtxWithRoutesLogger<Ctx> = Ctx & RoutesLoggerCarrier\n\n// Debug logging --------------------------------------------------------------\nexport type RouteServerDebugMode = 'minimal' | 'complete'\n\ntype RouteServerDebugEventBase = {\n /** Optional logical name assigned via `RouteDef.debug?.debugName` (or `RouteDef.debugName`). */\n name?: string\n}\n\nexport type RouteServerDebugEvent =\n | (RouteServerDebugEventBase & {\n type: 'request'\n stage: 'start' | 'success' | 'error'\n method: Uppercase<HttpMethod>\n path: string\n url: string\n durationMs?: number\n params?: unknown\n query?: unknown\n body?: unknown\n bodyFiles?: BodyFilesMap | undefined\n output?: unknown\n error?: unknown\n })\n | (RouteServerDebugEventBase & {\n type: 'register'\n method: Uppercase<HttpMethod>\n path: string\n })\n | (RouteServerDebugEventBase & {\n type: 'buildCtx'\n stage: 'start' | 'success' | 'error'\n method: Uppercase<HttpMethod>\n path: string\n url: string\n durationMs?: number\n error?: unknown\n })\n | (RouteServerDebugEventBase & {\n type: 'handler'\n stage: 'start' | 'success' | 'error'\n method: Uppercase<HttpMethod>\n path: string\n durationMs?: number\n params?: unknown\n query?: unknown\n body?: unknown\n bodyFiles?: BodyFilesMap | undefined\n output?: unknown\n error?: unknown\n })\n\nexport type RouteServerDebugLogger = (event: RouteServerDebugEvent) => void\n\n/**\n * Configure server-side debug logging.\n * - Use booleans or `'minimal'/'complete'` for quick toggles.\n * - Pass a custom logger function to redirect structured events.\n * - Provide a map to enable specific event types, opt into verbose payload logging, or restrict logs via `only`.\n */\nexport type RouteServerDebugOptions<Names extends string = string> =\n RouteServerDebugToggleOptions<Names>\n\n/**\n * Fine-grained toggle map for server debug logging.\n * Enable individual event types, opt into verbose payload logging, override the logger, or restrict to named routes.\n * Use `RouteDef.debug?.debugName` (or the deprecated `RouteDef.debugName`) to set the name that `only` will match against.\n */\nexport type RouteServerDebugToggleOptions<Names extends string = string> =\n Partial<Record<RouteServerDebugEvent['type'], boolean>> & {\n verbose?: boolean\n logger?: RouteServerDebugLogger\n only?: Names[]\n }\n\n/**\n * Per-route debug overrides. Same toggles as `RouteServerDebugOptions`, but limited to a single route\n * and therefore replaces the `only` filter with a local `debugName`.\n */\nexport type RouteDefDebugOptions<Names extends string = string> = Omit<\n RouteServerDebugToggleOptions<Names>,\n 'only'\n> & {\n debugName?: Names\n}\n\nconst serverDebugEventTypes: RouteServerDebugEvent['type'][] = [\n 'register',\n 'request',\n 'buildCtx',\n 'handler',\n]\n\ntype ServerDebugEmitter<Names extends string> = {\n emit: (event: RouteServerDebugEvent, name?: Names) => void\n mode: RouteServerDebugMode\n}\n\nconst noopServerEmit = () => {}\n\nfunction createServerDebugEmitter<Names extends string>(\n option?: RouteServerDebugOptions<Names>,\n): ServerDebugEmitter<Names> {\n const disabled: ServerDebugEmitter<Names> = {\n emit: noopServerEmit,\n mode: 'minimal',\n }\n if (!option) return disabled\n\n if (typeof option === 'object') {\n const toggles = option as RouteServerDebugToggleOptions<Names>\n const verbose = Boolean(toggles.verbose)\n const enabledTypes = serverDebugEventTypes.filter((type) => toggles[type])\n if (enabledTypes.length === 0) {\n return { emit: noopServerEmit, mode: verbose ? 'complete' : 'minimal' }\n }\n const whitelist = new Set<RouteServerDebugEvent['type']>(enabledTypes)\n const onlySet =\n toggles.only && toggles.only.length > 0\n ? new Set<Names>(toggles.only)\n : undefined\n const logger = toggles.logger\n const emit: ServerDebugEmitter<Names>['emit'] = (event, name) => {\n if (!whitelist.has(event.type) || !logger) return\n if (onlySet && (!name || !onlySet.has(name))) return\n logger(name ? { ...event, name } : event)\n }\n return { emit, mode: verbose ? 'complete' : 'minimal' }\n }\n\n return disabled\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Keys + leaf helpers (derive keys from byKey to avoid template-literal pitfalls)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/** Keys like \"GET /v1/foo\" that *actually* exist in the registry */\nexport type KeysOfRegistry<\n R extends { byKey: Record<string, AnyLeafLowProfile> },\n> = keyof R['byKey'] & string\n\ntype MethodFromKey<K extends string> = K extends `${infer M} ${string}`\n ? Lowercase<M>\n : never\ntype PathFromKey<K extends string> = K extends `${string} ${infer P}`\n ? P\n : never\n\n/** Given a registry and a key, pick the exact leaf for that method+path */\nexport type LeafFromKey<\n R extends { all: readonly AnyLeafLowProfile[] },\n K extends string,\n> = Extract<\n R['all'][number],\n { method: MethodFromKey<K> & HttpMethod; path: PathFromKey<K> }\n>\n\n/** Optional-ify types if your core returns `never` when a schema isn't defined */\ntype Maybe<T> = [T] extends [never] ? void : T\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst decodeJsonLikeQueryValue = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => decodeJsonLikeQueryValue(entry))\n }\n if (isPlainObject(value)) {\n const next: Record<string, unknown> = {}\n for (const [key, child] of Object.entries(value)) {\n next[key] = decodeJsonLikeQueryValue(child)\n }\n return next\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n return JSON.parse(trimmed)\n } catch {\n return value\n }\n }\n }\n return value\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Context typing & DX helpers (so ctx is usable in *any* middleware)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * Unique symbol used to stash ctx on res.locals.\n * (Symbols are safer than string keys against collisions.)\n */\nexport const CTX_SYMBOL: unique symbol = Symbol.for('typedLeaves.ctx')\n\nconst REQUEST_PAYLOAD_SYMBOL: unique symbol = Symbol.for(\n 'typedLeaves.requestPayload',\n)\n\ntype BodyFilesMap = Record<string, express.Multer.File[] | undefined>\n\ntype BodyFileNamesFromLeaf<Leaf extends AnyLeafLowProfile> =\n Leaf['cfg']['bodyFiles'] extends readonly FileField[]\n ? Leaf['cfg']['bodyFiles'][number]['name']\n : never\ntype BodyFilesMapFromLeaf<Leaf extends AnyLeafLowProfile> =\n BodyFileNamesFromLeaf<Leaf> extends never\n ? undefined\n : Partial<Record<BodyFileNamesFromLeaf<Leaf>, express.Multer.File[]>> &\n BodyFilesMap\n\n/** Parsed params/query/body that are shared between middleware/handler. */\nexport type RouteRequestPayload<Leaf extends AnyLeafLowProfile> = {\n params: Maybe<InferParams<Leaf>>\n query: Maybe<InferQuery<Leaf>>\n body: Maybe<InferBody<Leaf>>\n bodyFiles: BodyFilesMapFromLeaf<Leaf>\n}\n\nfunction isMulterFile(value: unknown): value is express.Multer.File {\n if (!isPlainObject(value)) return false\n const candidate = value as Record<string, unknown>\n return typeof candidate.fieldname === 'string'\n}\n\nfunction collectMulterFiles(req: express.Request): express.Multer.File[] {\n const files: express.Multer.File[] = []\n const pushValue = (value: unknown) => {\n if (value === undefined || value === null) return\n if (Array.isArray(value)) {\n value.forEach(pushValue)\n return\n }\n if (isMulterFile(value)) {\n files.push(value)\n return\n }\n if (isPlainObject(value)) {\n Object.values(value).forEach(pushValue)\n }\n }\n\n pushValue((req as any).files)\n pushValue((req as any).file)\n return files\n}\n\nfunction resolveBodyFilesFromRequest(\n req: express.Request,\n fields: FileField[] | undefined,\n): BodyFilesMap | undefined {\n if (!fields?.length) return undefined\n const allowedNames = new Set(fields.map((field) => field.name))\n const collected = collectMulterFiles(req)\n if (collected.length === 0) return undefined\n\n const result: BodyFilesMap = {}\n for (const file of collected) {\n if (!allowedNames.has(file.fieldname)) continue\n const bucket = result[file.fieldname] ?? []\n bucket.push(file)\n result[file.fieldname] = bucket\n }\n\n return Object.keys(result).length ? result : undefined\n}\n\nfunction getRouteRequestPayload<Leaf extends AnyLeafLowProfile>(\n res: express.Response,\n): RouteRequestPayload<Leaf> {\n const payload = (res.locals as any)[REQUEST_PAYLOAD_SYMBOL]\n if (payload) {\n return payload as RouteRequestPayload<Leaf>\n }\n throw new Error('Request payload was not initialized before middleware')\n}\n\nfunction setRouteRequestPayload<Leaf extends AnyLeafLowProfile>(\n res: express.Response,\n payload: RouteRequestPayload<Leaf>,\n) {\n ;(res.locals as any)[REQUEST_PAYLOAD_SYMBOL] = payload\n}\n\n/** Response type that *has* a ctx on locals for DX in middlewares */\nexport type ResponseWithCtx<Ctx> =\n // Replace locals with an intersection that guarantees CTX_SYMBOL exists\n Omit<express.Response, 'locals'> & {\n locals: express.Response['locals'] & {\n [CTX_SYMBOL]: CtxWithRoutesLogger<Ctx>\n }\n }\n\n/** A middleware signature that can *use* ctx via `res.locals[CTX_SYMBOL]` */\nexport type CtxRequestHandler<Ctx> = (args: {\n req: express.Request\n res: express.Response\n next: express.NextFunction\n ctx: CtxWithRoutesLogger<Ctx>\n}) => any\n\nexport type RouteBeforeHandler<\n Leaf extends AnyLeafLowProfile,\n Ctx = unknown,\n> = (\n args: {\n req: express.Request\n res: express.Response\n next: express.NextFunction\n ctx: CtxWithRoutesLogger<Ctx>\n } & RouteRequestPayload<Leaf>,\n) => any\n\n/**\n * Safely read ctx from any Response.\n * @param res Express response whose locals contain the ctx symbol.\n * @returns Strongly typed context object.\n */\nexport function getCtx<Ctx = unknown>(\n res: express.Response,\n): CtxWithRoutesLogger<Ctx> {\n return (res.locals as any)[CTX_SYMBOL] as CtxWithRoutesLogger<Ctx>\n}\n\n/**\n * Wrap a ctx-typed middleware to a plain RequestHandler (for arrays, etc.).\n * @param mw Middleware that expects a typed response with ctx available.\n * @returns Standard Express request handler.\n */\nfunction adaptCtxMw<Ctx>(mw: CtxRequestHandler<Ctx>): RequestHandler {\n return (req, res, next) => {\n try {\n const result = mw({ req, res, next, ctx: getCtx<Ctx>(res) })\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).catch((err) => next(err))\n }\n return result as any\n } catch (err) {\n next(err as any)\n return undefined\n }\n }\n}\n\nfunction adaptRouteBeforeMw<Leaf extends AnyLeafLowProfile, Ctx = unknown>(\n mw: RouteBeforeHandler<Leaf, Ctx>,\n): RequestHandler {\n return (req, res, next) => {\n try {\n const result = mw({\n req,\n res,\n next,\n ctx: getCtx<Ctx>(res),\n ...getRouteRequestPayload<Leaf>(res),\n })\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).catch((err) => next(err))\n }\n return result as any\n } catch (err) {\n next(err as any)\n return undefined\n }\n }\n}\n\nfunction logHandlerDebugWithRoutesLogger(\n logger: LoggerLike | undefined,\n event: RouteServerDebugEvent,\n) {\n if (!logger || event.type !== 'handler') return\n const payload: [string, RouteServerDebugEvent] = [\n `[rrroutes-server][handler:${event.stage}] ${event.method} ${event.path}`,\n event,\n ]\n if (event.stage === 'error') {\n ;(\n logger.error ??\n logger.warn ??\n logger.debug ??\n logger.info ??\n logger.log ??\n logger.system\n )?.call(logger, ...payload)\n return\n }\n ;(\n logger.debug ??\n logger.verbose ??\n logger.info ??\n logger.log ??\n logger.system\n )?.call(logger, ...payload)\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Controller types — object form only (simpler, clearer typings)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/** Typed route handler for a specific leaf */\n\nexport type Handler<L extends AnyLeafLowProfile, Ctx = unknown> = (args: {\n req: express.Request\n res: express.Response\n next: express.NextFunction\n ctx: CtxWithRoutesLogger<Ctx>\n params: Maybe<InferParams<L>>\n query: Maybe<InferQuery<L>>\n body: Maybe<InferBody<L>>\n bodyFiles: RouteRequestPayload<L>['bodyFiles']\n}) => Promise<Maybe<InferOutput<L>>> | Maybe<InferOutput<L>>\n\n/** Route definition for one key */\nexport type RouteDef<\n L extends AnyLeafLowProfile,\n Ctx = unknown,\n Names extends string = string,\n> = {\n /** Middlewares before the handler (run after buildCtx/postCtx/derived) */\n before?: Array<RouteBeforeHandler<L, Ctx>>\n /** Your business logic */\n handler: Handler<L, Ctx>\n send?: (ex: express.Response, data: Maybe<InferOutput<L>>) => void\n /**\n * Optional per-route debug overrides. When provided, these replace the global debug options.\n */\n debug?: RouteDefDebugOptions<Names>\n}\n\n/** Map of registry keys -> route defs */\nexport type ControllerMap<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n> = {\n [P in KeysOfRegistry<R>]: RouteDef<LeafFromKey<R, P>, Ctx, Names>\n}\n\nexport type PartialControllerMap<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n> = Partial<ControllerMap<R, Ctx, Names>>\n\n// ──────────────────────────────────────────────────────────────────────────────\n/** Options + derivation helpers */\n// ──────────────────────────────────────────────────────────────────────────────\n\nexport type BuildCtxArgs = {\n req: express.Request\n res: express.Response\n}\n\nexport type BuildCtxHandler<Ctx> = (\n args: BuildCtxArgs,\n) => CtxWithRoutesLogger<Ctx> | Promise<CtxWithRoutesLogger<Ctx>>\n\nexport type RouteServerSanitizer = RequestSanitizationOptions | RequestHandler\n\nexport type RouteServerMiddlewareConfig<Ctx = unknown> = {\n /**\n * Middlewares that run before payload parsing and buildCtx.\n */\n preCtx?: Array<RequestHandler>\n /**\n * Middleware that sanitizes request data before payload parsing.\n * - If a RequestHandler is provided, it's used directly.\n * - If sanitization options are provided, a middleware is created from them.\n */\n sanitizer?: RouteServerSanitizer | undefined\n /**\n * Ctx-aware middlewares that run after buildCtx and before route-level middleware.\n */\n postCtx?: Array<CtxRequestHandler<Ctx>>\n}\n\ntype MulterOptionsResolver = (\n fields: FileField[] | undefined,\n) => MulterOptions | false | undefined\n\nconst defaultMulterOptions: MulterOptions = {\n storage: multer.memoryStorage(),\n}\n\nexport type RouteServerConfig<Ctx = unknown, Names extends string = string> = {\n /**\n * Build a request-scoped context. We wrap this in a middleware that runs\n * after payload resolution and before postCtx/route middlewares, and stash it on\n * `res.locals[CTX_SYMBOL]` so *all* later middlewares can use it.\n * You can optionally include `routesLogger` to override handler debug logging per request.\n */\n buildCtx: BuildCtxHandler<Ctx>\n\n /**\n * Middleware stages for the request pipeline.\n * Order: sanitizer -> preCtx -> resolve -> ctx -> postCtx -> route.before -> handler\n */\n middleware?: RouteServerMiddlewareConfig<Ctx>\n\n /**\n * Multer options used when a route declares `bodyFiles`.\n * - Provide `false` to skip Multer parsing for specific leaves.\n * - Provide a function to compute options per leaf.\n * - When omitted, a shared memory storage is used to parse multipart payloads.\n */\n multerOptions?: MulterOptions | MulterOptionsResolver\n\n /** Validate handler return values with outputSchema (default: true) */\n validateOutput?: boolean\n\n /** Custom responder (default: res.json(data)) */\n send?: (res: express.Response, data: unknown) => void\n\n /**\n * Optional debug logging for the request lifecycle.\n * Supports booleans/modes/loggers, or a toggle map with per-event enabling, verbose payload logging,\n * and `only` filters tied to `RouteDef.debug?.debugName` (or the deprecated `RouteDef.debugName`).\n */\n debug?: RouteServerDebugOptions<Names>\n}\n\n/** Default JSON responder (typed to avoid implicit-any diagnostics) */\nconst defaultSend: (res: express.Response, data: unknown) => void = (\n res,\n data,\n) => {\n res.json(data as any)\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Core builder\n// ──────────────────────────────────────────────────────────────────────────────\n\nconst REGISTERED_ROUTES_SYMBOL = Symbol.for('routesV3.registeredRoutes')\n\ntype RegisteredRouteStore = Set<string>\n\n/**\n * Retrieve or initialize the shared store of registered route keys.\n * @param router Express router/application that carries previously registered keys.\n * @returns Set of string keys describing registered routes.\n */\nfunction getRegisteredRouteStore(router: Router): RegisteredRouteStore {\n const existing = (router as any)[REGISTERED_ROUTES_SYMBOL] as\n | RegisteredRouteStore\n | undefined\n if (existing) return existing\n const store: RegisteredRouteStore = new Set()\n ;(router as any)[REGISTERED_ROUTES_SYMBOL] = store\n return store\n}\n\n/**\n * Inspect the Express layer stack to discover already-registered routes.\n * @param appOrRouter Express application or router to inspect.\n * @returns All keys in the form `\"METHOD /path\"` found on the stack.\n */\nfunction collectRoutesFromStack(appOrRouter: Router): string[] {\n const result: string[] = []\n const stack: any[] =\n (appOrRouter as any).stack ??\n ((appOrRouter as any)._router\n ? (appOrRouter as any)._router.stack\n : undefined) ??\n []\n\n if (!Array.isArray(stack)) return result\n\n for (const layer of stack) {\n const route = layer && layer.route\n if (!route) continue\n\n const paths = Array.isArray(route.path) ? route.path : [route.path]\n const methodEntries = Object.entries(route.methods ?? {}).filter(\n ([, enabled]) => enabled,\n )\n\n for (const path of paths) {\n for (const [method] of methodEntries) {\n result.push(`${method.toUpperCase()} ${path}`)\n }\n }\n }\n\n return result\n}\n\n/** Runtime helpers returned by `createRRRoute`. */\nexport type RouteServer<Ctx = unknown, Names extends string = string> = {\n router: Router\n register<L extends AnyLeafLowProfile>(\n leaf: L,\n def: RouteDef<L, Ctx, Names>,\n ): void\n registerControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n F extends boolean = false,\n >(\n registry: R,\n controllers: F extends false\n ? PartialControllerMap<R, Ctx, Names>\n : ControllerMap<R, Ctx, Names>,\n all?: F,\n ): void\n warnMissingControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n >(\n registry: R,\n logger: { warn: (...args: any[]) => void },\n ): void\n getRegisteredKeys(): string[]\n}\n\n/**\n * Create an Express binding helper that keeps routes and controllers in sync.\n * @param router Express router or app to register handlers on.\n * @param config Optional configuration controlling ctx building, auth, uploads, etc.\n * Middleware order: sanitizer -> preCtx -> resolve -> ctx -> postCtx -> route.before -> handler.\n * @returns Object with helpers to register controllers and inspect registered keys.\n */\nexport function createRRRoute<Ctx = unknown, Names extends string = string>(\n router: Router,\n config: RouteServerConfig<Ctx, Names>,\n): RouteServer<Ctx, Names> {\n const validateOutput = config.validateOutput ?? true\n const send = config.send ?? defaultSend\n const { emit: defaultEmitDebug, mode: defaultDebugMode } =\n createServerDebugEmitter<Names>(config.debug)\n\n const knownLeaves = new Map<string, AnyLeafLowProfile>()\n\n const decorateDebugEvent = <T extends RouteServerDebugEvent>(\n isVerbose: boolean,\n event: T,\n details?: Partial<RouteServerDebugEvent>,\n ): RouteServerDebugEvent => {\n if (!isVerbose || !details) return event\n return { ...event, ...details } as RouteServerDebugEvent\n }\n\n const middlewareConfig = config.middleware ?? {}\n const postCtxMws = [...(middlewareConfig.postCtx ?? [])].map((mw) =>\n adaptCtxMw<Ctx>(mw),\n )\n const preCtxMws = [...(middlewareConfig.preCtx ?? [])]\n const sanitizerMw =\n middlewareConfig.sanitizer === undefined\n ? undefined\n : typeof middlewareConfig.sanitizer === 'function'\n ? middlewareConfig.sanitizer\n : createRequestSanitizationMiddleware(middlewareConfig.sanitizer)\n const registered = getRegisteredRouteStore(router)\n\n const getMulterOptions = (fields: FileField[] | undefined) => {\n if (!fields || fields.length === 0) return undefined\n const resolved =\n typeof config.multerOptions === 'function'\n ? config.multerOptions(fields)\n : config.multerOptions\n if (resolved === false) return undefined\n return resolved ?? defaultMulterOptions\n }\n\n const runMulterHandler = (\n handler: RequestHandler,\n req: express.Request,\n res: express.Response,\n ) => {\n return new Promise<void>((resolve, reject) => {\n handler(req, res, (err?: any) => {\n if (err) {\n reject(err)\n return\n }\n resolve()\n })\n })\n }\n\n /** Register a single leaf/controller pair on the underlying router. */\n function register<L extends AnyLeafLowProfile>(\n leaf: L,\n def: RouteDef<L, Ctx, Names>,\n ) {\n const method = leaf.method as HttpMethod\n const methodUpper = method.toUpperCase() as Uppercase<HttpMethod>\n const path = leaf.path as string\n const key = keyOf(leaf.method, leaf.path, false)\n const defDebug = def.debug\n let debugName = undefined as Names | undefined\n let routeDebugEmitter: ServerDebugEmitter<Names> | undefined\n if (defDebug) {\n const { debugName: overrideName, ...rest } = defDebug\n const hasOverrides = Object.values(rest).some(\n (value) => value !== undefined,\n )\n if (hasOverrides) {\n routeDebugEmitter = createServerDebugEmitter<Names>({\n ...config.debug,\n ...rest,\n })\n }\n debugName = (overrideName ?? debugName) as Names | undefined\n }\n const activeEmit = routeDebugEmitter?.emit ?? defaultEmitDebug\n const activeDebugMode = routeDebugEmitter?.mode ?? defaultDebugMode\n const emit = (event: RouteServerDebugEvent) => activeEmit(event, debugName)\n const isVerboseDebug = activeDebugMode === 'complete'\n emit({ type: 'register', method: methodUpper, path })\n\n const routeSpecific = (def?.before ?? []).map((mw) =>\n adaptRouteBeforeMw<L, Ctx>(mw),\n )\n const resolvePayloadMw: RequestHandler = async (req, res, next) => {\n const requestUrl = req.originalUrl ?? path\n const startedAt = Date.now()\n let params: Maybe<InferParams<L>> | undefined\n let query: Maybe<InferQuery<L>> | undefined\n let body: Maybe<InferBody<L>> | undefined\n let bodyFiles: BodyFilesMap | undefined\n\n try {\n if (leaf.cfg.bodyFiles && leaf.cfg.bodyFiles.length > 0) {\n const uploadOptions = getMulterOptions(leaf.cfg.bodyFiles)\n if (uploadOptions) {\n const fieldDefs = leaf.cfg.bodyFiles.map(({ name, maxCount }) => ({\n name,\n maxCount,\n }))\n const uploader = multer(uploadOptions).fields(fieldDefs)\n await runMulterHandler(uploader, req, res)\n }\n }\n\n bodyFiles = resolveBodyFilesFromRequest(req, leaf.cfg.bodyFiles)\n params = leaf.cfg.paramsSchema\n ? (lowProfileParse(leaf.cfg.paramsSchema, req.params) as Maybe<\n InferParams<L>\n >)\n : ((Object.keys(req.params || {}).length\n ? (req.params as any)\n : undefined) as Maybe<InferParams<L>>)\n\n const hasQueryKeys =\n req.query && Object.keys(req.query || {}).length > 0\n const parsedQueryInput =\n leaf.cfg.querySchema && hasQueryKeys\n ? (decodeJsonLikeQueryValue(req.query) as Record<string, unknown>)\n : req.query\n if (leaf.cfg.querySchema) {\n try {\n query = lowProfileParse(\n leaf.cfg.querySchema,\n parsedQueryInput as Record<string, unknown>,\n ) as Maybe<InferQuery<L>>\n } catch (err) {\n const parseError = new Error(\n `Query parsing error: ${(err as Error).message ?? String(err)}`,\n )\n ;(parseError as any).raw = JSON.stringify(req.query)\n ;(parseError as any).cause = err\n throw parseError\n }\n } else {\n query = hasQueryKeys ? (req.query as any) : undefined\n }\n\n body = leaf.cfg.bodySchema\n ? (lowProfileParse(leaf.cfg.bodySchema, req.body) as Maybe<\n InferBody<L>\n >)\n : ((req.body !== undefined ? (req.body as any) : undefined) as Maybe<\n InferBody<L>\n >)\n } catch (err) {\n const payloadError = {\n params,\n query,\n body,\n bodyFiles,\n } as RouteRequestPayload<L>\n emit(\n decorateDebugEvent(\n isVerboseDebug,\n {\n type: 'request',\n stage: 'error',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n error: err,\n },\n isVerboseDebug ? payloadError : undefined,\n ),\n )\n next(err as any)\n return\n }\n\n const requestPayload = {\n params,\n query,\n body,\n bodyFiles,\n } as RouteRequestPayload<L>\n setRouteRequestPayload(res, requestPayload)\n next()\n }\n const ctxMw: RequestHandler = async (req, res, next) => {\n const requestUrl = req.originalUrl ?? path\n const startedAt = Date.now()\n emit({\n type: 'buildCtx',\n stage: 'start',\n method: methodUpper,\n path,\n url: requestUrl,\n })\n\n try {\n const ctx = await config.buildCtx({\n req,\n res,\n })\n ;(res.locals as any)[CTX_SYMBOL] = ctx\n emit({\n type: 'buildCtx',\n stage: 'success',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n })\n next()\n } catch (err) {\n emit({\n type: 'buildCtx',\n stage: 'error',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n error: err,\n })\n next(err as any)\n }\n }\n const before: RequestHandler[] = [\n ...(sanitizerMw ? [sanitizerMw] : []),\n ...preCtxMws,\n resolvePayloadMw,\n ctxMw,\n ...postCtxMws,\n ...routeSpecific,\n ]\n\n const wrapped: RequestHandler = async (req, res, next) => {\n const requestUrl = req.originalUrl.split('?')[0] ?? path\n const startedAt = Date.now()\n emit({\n type: 'request',\n stage: 'start',\n method: methodUpper,\n path,\n url: requestUrl,\n })\n const requestPayload = getRouteRequestPayload<L>(res)\n const params = requestPayload.params\n const query = requestPayload.query\n const body = requestPayload.body\n const bodyFiles = requestPayload.bodyFiles\n let responsePayload: InferOutput<L> | undefined\n let hasResponsePayload = false\n const downstreamNext: express.NextFunction = next\n\n const ctx = (res.locals as any)[CTX_SYMBOL] as CtxWithRoutesLogger<Ctx>\n const ctxRoutesLogger = ctx?.routesLogger\n const emitWithCtx = (\n event: RouteServerDebugEvent,\n details?: Partial<RouteServerDebugEvent>,\n ) => {\n const decorated = decorateDebugEvent(isVerboseDebug, event, details)\n if (!config.debug || !config.debug[decorated.type]) {\n return\n }\n if (ctxRoutesLogger) {\n logHandlerDebugWithRoutesLogger(ctxRoutesLogger, decorated)\n } else {\n emit(decorated)\n }\n }\n try {\n const handlerStartedAt = Date.now()\n emitWithCtx(\n {\n type: 'handler',\n stage: 'start',\n method: methodUpper,\n path,\n },\n isVerboseDebug ? { params, query, body, bodyFiles } : undefined,\n )\n\n let result\n try {\n result = await def.handler({\n req,\n res,\n next: downstreamNext,\n ctx,\n params: params as Maybe<InferParams<L>>,\n query: query as Maybe<InferQuery<L>>,\n body: body as Maybe<InferBody<L>>,\n bodyFiles: bodyFiles as RouteRequestPayload<L>['bodyFiles'],\n })\n emitWithCtx(\n {\n type: 'handler',\n stage: 'success',\n method: methodUpper,\n path,\n durationMs: Date.now() - handlerStartedAt,\n },\n isVerboseDebug\n ? {\n params,\n query,\n body,\n bodyFiles,\n ...(result !== undefined ? { output: result } : {}),\n }\n : undefined,\n )\n } catch (e) {\n emitWithCtx(\n {\n type: 'handler',\n stage: 'error',\n method: methodUpper,\n path,\n durationMs: Date.now() - handlerStartedAt,\n error: e,\n },\n isVerboseDebug ? { params, query, body, bodyFiles } : undefined,\n )\n throw e\n }\n\n const out =\n validateOutput && leaf.cfg.outputSchema\n ? lowProfileParse(leaf.cfg.outputSchema, result)\n : result\n responsePayload = out as InferOutput<L>\n hasResponsePayload = true\n def.send ? def.send(res, out as any) : send(res, out)\n\n emitWithCtx(\n {\n type: 'request',\n stage: 'success',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? {\n params,\n query,\n body,\n bodyFiles,\n ...(hasResponsePayload ? { output: responsePayload } : {}),\n }\n : undefined,\n )\n } catch (err) {\n emitWithCtx(\n {\n type: 'request',\n stage: 'error',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n error: err,\n },\n isVerboseDebug ? { params, query, body, bodyFiles } : undefined,\n )\n next(err as any)\n }\n }\n\n ;(router as any)[method](path, ...before, wrapped)\n registered.add(key)\n }\n\n /**\n * Register controller definitions for the provided keys.\n * @param registry Finalized registry of leaves.\n * @param controllers Partial controller map keyed by `\"METHOD /path\"`.\n * @param all Deprecated runtime toggle. Passing any truthy value will throw.\n */\n function registerControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n F extends boolean = false,\n >(registry: R, controllers: PartialControllerMap<R, Ctx, Names>, all?: F) {\n for (const leaf of registry.all) {\n const key = keyOf(leaf.method, leaf.path, false)\n knownLeaves.set(key, leaf)\n }\n\n const missingLeaves: string[] = []\n ;(Object.keys(controllers) as Array<KeysOfRegistry<R>>).forEach((key) => {\n const leaf = registry.byKey[key] as unknown as\n | LeafFromKey<R, typeof key>\n | undefined\n if (!leaf) {\n missingLeaves.push(key)\n return\n }\n const def = controllers[key]\n if (!def) return\n register(leaf as LeafFromKey<R, typeof key>, def)\n })\n if (all && missingLeaves.length > 0) {\n throw new Error(\n `Cannot register controllers: missing definitions for routes: ${missingLeaves.join(\n ', ',\n )}`,\n )\n }\n }\n\n /**\n * Warn about leaves that do not have a registered controller.\n * @param registry Finalized registry of leaves.\n * @param warnLogger Logger used for warning output.\n */\n function warnMissing<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n >(registry: R, warnLogger: { warn: (...args: any[]) => void }) {\n const registeredFromStore = new Set<string>(Array.from(registered))\n if (registeredFromStore.size === 0) {\n collectRoutesFromStack(router).forEach((key) =>\n registeredFromStore.add(key),\n )\n }\n for (const leaf of registry.all) {\n const key = keyOf(leaf.method, leaf.path, false)\n if (!registeredFromStore.has(key)) {\n warnLogger.warn(`No controller registered for route: ${key}`)\n }\n }\n }\n\n return {\n router,\n register,\n registerControllers,\n warnMissingControllers: warnMissing,\n getRegisteredKeys: () => Array.from(registered),\n }\n}\n\n/**\n * Bind only the controllers that are present in the provided map.\n * @param router Express router or app.\n * @param registry Finalized registry produced by `finalize(...)`.\n * @param controllers Partial map of controllers keyed by `\"METHOD /path\"`.\n * @param config Optional route server configuration.\n * @returns The same router instance for chaining.\n */\nexport function bindExpressRoutes<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n>(\n router: Router,\n registry: R,\n controllers: PartialControllerMap<R, Ctx, Names>,\n config: RouteServerConfig<Ctx, Names>,\n) {\n const server = createRRRoute<Ctx, Names>(router, config)\n server.registerControllers(registry, controllers)\n return router\n}\n\n/**\n * Bind controllers for every leaf. Missing entries fail at compile time.\n * @param router Express router or app.\n * @param registry Finalized registry produced by `finalize(...)`.\n * @param controllers Complete map of controllers keyed by `\"METHOD /path\"`.\n * @param config Optional route server configuration.\n * @returns The same router instance for chaining.\n */\nexport function bindAll<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n>(\n router: Router,\n registry: R,\n controllers: {\n [K in KeysOfRegistry<R>]: RouteDef<LeafFromKey<R, K>, Ctx, Names>\n },\n config: RouteServerConfig<Ctx, Names>,\n) {\n const server = createRRRoute<Ctx, Names>(router, config)\n server.registerControllers(registry, controllers)\n return router\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// DX helpers\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * Helper for great IntelliSense when authoring controller maps.\n * @returns Function that enforces key names while preserving partial flexibility.\n */\nexport const defineControllers =\n <\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n >() =>\n <M extends PartialControllerMap<R, Ctx, Names>>(m: M) =>\n m\n\n/**\n * Warn about leaves that don't have controllers.\n * Call this during startup to surface missing routes.\n * @param router Express router or app to inspect.\n * @param registry Finalized registry produced by `finalize(...)`.\n * @param logger Logger where warnings are emitted.\n */\nexport function warnMissingControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n>(router: Router, registry: R, logger: { warn: (...args: any[]) => void }) {\n const registeredStore = (router as any)[REGISTERED_ROUTES_SYMBOL] as\n | Set<string>\n | undefined\n const initial = registeredStore\n ? Array.from(registeredStore)\n : collectRoutesFromStack(router)\n const registeredKeys = new Set<string>(initial)\n\n for (const leaf of registry.all) {\n const k = keyOf(leaf.method, leaf.path, false)\n if (!registeredKeys.has(k)) {\n logger.warn(`No controller registered for route: ${k}`)\n }\n }\n}\n\nexport { buildLowProfileLeaf }\n","import type { Request, RequestHandler } from 'express'\n\nexport type RequestSanitizationTarget = 'params' | 'query' | 'body'\n\nexport type RequestSanitizationCallbackContext = {\n /**\n * Original Express request.\n */\n req: Request\n /**\n * Root request section currently being sanitized.\n */\n target: RequestSanitizationTarget\n /**\n * Path within the selected target.\n * Example: ['profile', 'emails', 0]\n */\n path: ReadonlyArray<string | number>\n /**\n * Current traversal depth for this value.\n */\n depth: number\n}\n\nexport type RequestSanitizationCallback = (\n value: unknown,\n context: RequestSanitizationCallbackContext,\n) => unknown\n\nexport type RequestSanitizationOptions = {\n /**\n * Request sections to sanitize.\n * Defaults to all: params, query, body.\n */\n targets?: RequestSanitizationTarget[]\n /**\n * Remove leading/trailing whitespace from all string values.\n * Defaults to false.\n */\n trimStrings?: boolean\n /**\n * Remove null bytes (`\\u0000`) from strings.\n * Defaults to true.\n */\n stripNullBytes?: boolean\n /**\n * Strip keys used in prototype pollution payloads.\n * Defaults to true.\n */\n stripBlockedKeys?: boolean\n /**\n * Keys to strip when `stripPrototypePollutionKeys` is enabled.\n * Defaults to ['__proto__', 'prototype', 'constructor'].\n */\n blockedKeys?: string[]\n /**\n * Maximum recursion depth while sanitizing nested structures.\n * Defaults to 20.\n */\n maxDepth?: number\n /**\n * Optional callback applied after built-in sanitization.\n * Useful for custom rules (e.g. slug normalization or HTML cleaning).\n */\n customSanitizer?: RequestSanitizationCallback\n /**\n * Log the duration (in ms) of each target sanitization step.\n * Format: [RequestSanitizationProfiler] METHOD URL target=TARGET durationMs=123.456\n * Defaults to false.\n */\n profiler?: boolean\n}\n\ntype NormalizedRequestSanitizationOptions = {\n targets: Set<RequestSanitizationTarget>\n trimStrings: boolean\n stripNullBytes: boolean\n stripBlockedKeys: boolean\n blockedKeys: Set<string>\n maxDepth: number\n customSanitizer?: RequestSanitizationCallback\n profiler: boolean\n}\n\nconst defaultTargets: RequestSanitizationTarget[] = ['params', 'query', 'body']\nconst defaultBlockedKeys = ['__proto__', 'prototype', 'constructor']\nconst defaultMaxDepth = 20\nconst nullBytePattern = /\\u0000/g\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\nconst normalizeOptions = (\n options: RequestSanitizationOptions,\n): NormalizedRequestSanitizationOptions => {\n return {\n targets: new Set(options.targets ?? defaultTargets),\n trimStrings: options.trimStrings ?? false,\n stripNullBytes: options.stripNullBytes ?? true,\n stripBlockedKeys: options.stripBlockedKeys ?? true,\n blockedKeys: new Set(options.blockedKeys ?? defaultBlockedKeys),\n maxDepth: options.maxDepth ?? defaultMaxDepth,\n customSanitizer: options.customSanitizer,\n profiler: options.profiler ?? false,\n }\n}\n\nconst applyCustomSanitizer = (\n value: unknown,\n options: NormalizedRequestSanitizationOptions,\n context: RequestSanitizationCallbackContext,\n): unknown => {\n if (!options.customSanitizer) return value\n return options.customSanitizer(value, context)\n}\n\nconst sanitizeString = (\n value: string,\n options: NormalizedRequestSanitizationOptions,\n) => {\n let next = value\n if (options.stripNullBytes && next.includes('\\u0000')) {\n next = next.replace(nullBytePattern, '')\n }\n if (options.trimStrings) {\n next = next.trim()\n }\n return next\n}\n\nconst sanitizeValue = (\n value: unknown,\n options: NormalizedRequestSanitizationOptions,\n depth: number,\n seen: WeakSet<object>,\n req: Request,\n target: RequestSanitizationTarget,\n path: Array<string | number>,\n): unknown => {\n const context: RequestSanitizationCallbackContext = {\n req,\n target,\n path,\n depth,\n }\n if (depth > options.maxDepth) {\n return applyCustomSanitizer(value, options, context)\n }\n\n if (typeof value === 'string') {\n const sanitized = sanitizeString(value, options)\n return applyCustomSanitizer(sanitized, options, context)\n }\n\n if (value && typeof value === 'object' && seen.has(value as object)) {\n return applyCustomSanitizer(value, options, context)\n }\n\n if (Array.isArray(value)) {\n seen.add(value)\n const next = value.map((entry, index) =>\n sanitizeValue(entry, options, depth + 1, seen, req, target, [\n ...path,\n index,\n ]),\n )\n seen.delete(value)\n return applyCustomSanitizer(next, options, context)\n }\n\n if (!isPlainObject(value)) {\n return applyCustomSanitizer(value, options, context)\n }\n\n seen.add(value)\n\n const source = value as Record<string, unknown>\n const objectTarget =\n Object.getPrototypeOf(source) === null ? Object.create(null) : {}\n for (const [key, entry] of Object.entries(source)) {\n if (options.stripBlockedKeys && options.blockedKeys.has(key)) {\n continue\n }\n ;(objectTarget as Record<string, unknown>)[key] = sanitizeValue(\n entry,\n options,\n depth + 1,\n seen,\n req,\n context.target,\n [...path, key],\n )\n }\n\n seen.delete(value)\n return applyCustomSanitizer(objectTarget, options, context)\n}\n\nconst findPropertyDescriptor = (\n source: object,\n key: PropertyKey,\n): PropertyDescriptor | undefined => {\n let cursor: object | null = source\n while (cursor) {\n const descriptor = Object.getOwnPropertyDescriptor(cursor, key)\n if (descriptor) return descriptor\n cursor = Object.getPrototypeOf(cursor)\n }\n return undefined\n}\n\nconst setRequestQuery = (req: Request, value: unknown): void => {\n const queryDescriptor = findPropertyDescriptor(req as object, 'query')\n if (!queryDescriptor || queryDescriptor.writable || queryDescriptor.set) {\n ;(req as any).query = value\n return\n }\n\n Object.defineProperty(req, 'query', {\n configurable: true,\n enumerable: true,\n writable: true,\n value,\n })\n}\n\nconst profileTargetSanitization = (\n options: NormalizedRequestSanitizationOptions,\n req: Request,\n target: RequestSanitizationTarget,\n sanitize: () => void,\n): void => {\n if (!options.profiler) {\n sanitize()\n return\n }\n\n const startedAt = process.hrtime.bigint()\n try {\n sanitize()\n } finally {\n const durationMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000\n const method = req.method ?? 'UNKNOWN'\n const url = req.originalUrl ?? req.url ?? ''\n console.info(\n `[RequestSanitizationProfiler] ${method} ${url} target=${target} durationMs=${durationMs.toFixed(3)}`,\n )\n }\n}\n\n/**\n * Build a request sanitizer middleware for Express.\n * Can be used in `RouteServerConfig.middleware.sanitizer` or on standalone routers.\n */\nexport const createRequestSanitizationMiddleware = (\n options: RequestSanitizationOptions = {},\n): RequestHandler => {\n const normalized = normalizeOptions(options)\n\n return (req, _res, next) => {\n try {\n if (normalized.targets.has('params') && req.params) {\n profileTargetSanitization(normalized, req, 'params', () => {\n req.params = sanitizeValue(\n req.params,\n normalized,\n 0,\n new WeakSet<object>(),\n req,\n 'params',\n [],\n ) as any\n })\n }\n if (normalized.targets.has('query')) {\n const query = req.query\n if (query) {\n profileTargetSanitization(normalized, req, 'query', () => {\n const sanitizedQuery = sanitizeValue(\n query,\n normalized,\n 0,\n new WeakSet<object>(),\n req,\n 'query',\n [],\n )\n setRequestQuery(req, sanitizedQuery)\n })\n }\n }\n if (normalized.targets.has('body') && req.body !== undefined) {\n profileTargetSanitization(normalized, req, 'body', () => {\n req.body = sanitizeValue(\n req.body,\n normalized,\n 0,\n new WeakSet<object>(),\n req,\n 'body',\n [],\n ) as any\n })\n }\n next()\n } catch (err) {\n next(err as any)\n }\n }\n}\n\n/**\n * Default sanitizer middleware.\n * - strips prototype-pollution keys\n * - strips null bytes from strings\n * - preserves whitespace by default\n */\nexport const requestSanitizationMiddleware: RequestHandler =\n createRequestSanitizationMiddleware()\n","// socket.server.debug.ts\nimport type { IncomingHttpHeaders } from 'http'\n\nexport type SocketServerConfigSnapshot = {\n url?: string\n transport?: string\n protocol?: string\n address?: string\n issued?: number\n time?: string\n query?: Record<string, unknown>\n auth?: Record<string, unknown>\n headers?: IncomingHttpHeaders\n}\n\nexport type SocketServerLifecycleStage =\n | 'server_init'\n | 'connection_listener_installed'\n | 'connection_init'\n | 'connection_handlers_attached'\n | 'connection_cleanup'\n | 'destroy_start'\n | 'destroy_complete'\n | 'connection_cleanup_fallback'\n\nexport type SocketServerHeartbeatPhase = 'ping' | 'pong' | 'skip'\n\nexport type SocketServerDebugEvent =\n | {\n type: 'register'\n action: 'register' | 'unregister'\n event: string\n msg?: string\n }\n | {\n type: 'handler'\n phase:\n | 'receive'\n | 'validation_error'\n | 'handler_success'\n | 'handler_error'\n event: string\n socketId?: string\n nsp?: string\n rooms?: string[]\n raw?: unknown\n issues?: any[]\n error?: unknown\n details?: Record<string, unknown>\n }\n | {\n type: 'emit'\n event: string\n rooms: string[]\n envelope?: unknown\n error?: {\n reason: string\n message?: string\n issues?: unknown\n }\n metadata?: unknown\n note?: string\n }\n | {\n type: 'rooms'\n action: 'join' | 'leave'\n rooms?: string | string[]\n socketId: string\n phase?: string\n payload?: unknown\n issues?: any[]\n }\n | {\n type: 'heartbeat'\n phase: SocketServerHeartbeatPhase\n socketId: string\n payload?: unknown\n issues?: any[]\n error?: boolean\n details?: Record<string, unknown>\n }\n | {\n type: 'config'\n socketId: string\n nsp: string\n snapshot: SocketServerConfigSnapshot\n }\n | {\n type: 'lifecycle'\n stage: SocketServerLifecycleStage\n socketId?: string\n nsp?: string\n details?: Record<string, unknown>\n }\n\nexport type SocketDebugOptions = {\n verbose?: boolean\n /** filters event-based logs (register/handler/emit) by event name */\n only?: string[]\n logger?: (e: SocketServerDebugEvent) => void\n} & {\n [P in SocketServerDebugEvent['type']]?: boolean\n}\n\nexport function createDebugger(options?: SocketDebugOptions) {\n const debug = options ?? {}\n\n return (maybeEvent: string | null, e: SocketServerDebugEvent) => {\n if (!debug.logger) return\n if (!debug[e.type]) return\n\n // only filter applies to event-shaped logs\n if (\n debug.only &&\n maybeEvent &&\n (e.type === 'register' || e.type === 'handler' || e.type === 'emit') &&\n !debug.only.includes(maybeEvent)\n ) {\n return\n }\n\n debug.logger(e)\n }\n}\n","// socket.server.sys.ts\nimport type {\n EventMap,\n Payload,\n SocketConnectionConfigOutput,\n SocketSchemaOutput,\n SysEventName,\n} from '@emeryld/rrroutes-contract'\nimport type { Socket } from 'socket.io'\nimport { z, ZodTypeAny } from 'zod'\nimport type {\n SocketServerConfigSnapshot,\n SocketServerDebugEvent,\n} from './socket.server.debug'\nimport type { HandlerCtxNoAck } from './socket.server.types'\n\nexport type SocketConnectionHelper<Events extends EventMap> = {\n // 1) Strict, typed, autocompleted events\n emit<K extends keyof Events & string>(\n event: K,\n payload: Payload<Events, K>,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n ): void\n\n // 2) Arbitrary events – no type checking on payload\n emit<K extends string>(\n eventName: Exclude<K, keyof Events & string>,\n payload: unknown,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n ): void\n}\n\n/** Heartbeat configuration that is not tied to payload shapes (which live in sys event schemas). */\nexport type HeartbeatServerOptions = {\n /** Enable/disable built-in heartbeat handling. Defaults to true. */\n enabled?: boolean\n}\n\nexport type SysServerEventMap<\n Config extends SocketConnectionConfigOutput = SocketConnectionConfigOutput,\n Events extends EventMap = EventMap,\n> = {\n 'sys:connect': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n /**\n * Call to proceed with the default connection initialization\n * (attaches heartbeat, join, leave and disconnect handlers).\n */\n complete: () => void\n }) => void | Promise<void>\n\n 'sys:disconnect': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n /** cleans up all handlers */\n cleanup: () => void\n reason: string\n }) => void | Promise<void>\n\n 'sys:ping': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n ping: SocketSchemaOutput<Config['pingPayload']>\n ctx: HandlerCtxNoAck\n }) =>\n | SocketSchemaOutput<Config['pongPayload']>\n | Promise<SocketSchemaOutput<Config['pongPayload']>>\n\n 'sys:room_join': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n rooms: string[]\n meta: SocketSchemaOutput<Config['joinMetaMessage']>\n join: (room: string) => Promise<void>\n }) => void | Promise<void>\n\n 'sys:room_leave': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n rooms: string[]\n meta: SocketSchemaOutput<Config['leaveMetaMessage']>\n leave: (room: string) => Promise<void>\n }) => void | Promise<void>\n}\n\nconst normalizeError = (error: unknown) => {\n if (error instanceof Error) {\n return { name: error.name, message: error.message }\n }\n if (typeof error === 'string') return { message: error }\n return { message: 'Unknown error' }\n}\n\nconst roomValueSchema = z.union([z.string(), z.array(z.string())])\n\nconst buildRoomPayloadSchema = <Meta extends z.ZodTypeAny>(metaSchema: Meta) =>\n z.object({\n rooms: roomValueSchema,\n meta: metaSchema,\n })\n\ntype DebugFn = (maybeEvent: string | null, e: SocketServerDebugEvent) => void\n\nconst toArray = (rooms?: string[] | string): string[] =>\n rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]\n\nconst snapshotSocketConfig = (socket: Socket): SocketServerConfigSnapshot => {\n const conn = socket.conn as\n | {\n transport?: { name?: string }\n protocol?: string | number\n remoteAddress?: string\n }\n | undefined\n const protocol = conn?.protocol\n return {\n url: socket.handshake.url,\n transport: conn?.transport?.name,\n protocol: protocol != null ? String(protocol) : undefined,\n address: conn?.remoteAddress ?? socket.handshake.address,\n issued: socket.handshake.issued,\n time: socket.handshake.time,\n query: socket.handshake.query as Record<string, unknown>,\n auth: socket.handshake.auth as Record<string, unknown>,\n headers: socket.handshake.headers,\n }\n}\n\nexport function createBuiltInConnectionHandlers<\n C extends SocketConnectionConfigOutput,\n Events extends EventMap,\n>(opts: {\n heartbeat?: HeartbeatServerOptions\n sys: SysServerEventMap<C, Events>\n dbg: DebugFn\n config: C\n createCtx: (socket: Socket) => HandlerCtxNoAck\n debugVerbose?: boolean\n createHelper: (socket: Socket) => SocketConnectionHelper<Events>\n}) {\n const { heartbeat, sys, dbg, config, createCtx, debugVerbose, createHelper } =\n opts\n\n const roomJoinEvent: SysEventName = 'sys:room_join'\n const roomLeaveEvent: SysEventName = 'sys:room_leave'\n const pingEvent: SysEventName = 'sys:ping'\n const pongEvent: SysEventName = 'sys:pong'\n const heartbeatEnabled = heartbeat?.enabled !== false\n\n const joinPayloadSchema = buildRoomPayloadSchema(\n config.joinMetaMessage as any as ZodTypeAny,\n )\n const leavePayloadSchema = buildRoomPayloadSchema(\n config.leaveMetaMessage as any as ZodTypeAny,\n )\n const pingPayloadSchema = config.pingPayload as C['pingPayload']\n const pongPayloadSchema = config.pongPayload as C['pongPayload']\n\n const sysEvents = sys\n const getSysEvent = <\n K extends keyof SysServerEventMap<C, Events> & SysEventName,\n >(\n name: K,\n ) => sysEvents[name]\n\n /** Track per-socket teardown for built-in handlers to ensure explicit cleanup on destroy(). */\n const socketTeardowns = new WeakMap<Socket, (reason: string) => void>()\n\n const builtInConnectionListener = (socket: Socket) => {\n const helper = createHelper(socket)\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_init',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: {\n rooms: Array.from(socket.rooms),\n handshakeIssued: socket.handshake.issued,\n },\n })\n dbg(null, {\n type: 'config',\n socketId: socket.id,\n nsp: socket.nsp.name,\n snapshot: snapshotSocketConfig(socket),\n })\n\n const defaultConnect = () => {\n const includeRaw = debugVerbose === true\n\n // built-in room handlers (wrapped with sys:room_join / sys:room_leave)\n const joinHandler = async (msg: unknown) => {\n dbg(roomJoinEvent, {\n type: 'rooms',\n phase: 'receive',\n action: 'join',\n socketId: socket.id,\n payload: msg,\n })\n const parsed = joinPayloadSchema.safeParse(msg)\n\n if (!parsed.success) {\n socket.emit(`${roomJoinEvent}:error`, {\n eventName: roomJoinEvent,\n issues: parsed.error.issues,\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n action: 'join',\n phase: 'validation_error',\n socketId: socket.id,\n issues: parsed.error.issues,\n payload: msg,\n })\n return\n }\n const list = toArray(parsed.data.rooms)\n\n const join = async (room: string) => {\n await socket.join(room)\n dbg(null, {\n type: 'rooms',\n action: 'join',\n rooms: room,\n socketId: socket.id,\n })\n }\n\n const run = async () => {\n await getSysEvent('sys:room_join')({\n socket,\n helper,\n rooms: list,\n meta: parsed.data.meta as SocketSchemaOutput<C['joinMetaMessage']>,\n join,\n })\n }\n\n try {\n await run()\n } catch (error) {\n socket.emit(`${roomJoinEvent}:error`, {\n error: normalizeError(error),\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n action: 'join',\n phase: 'handler_error',\n payload: includeRaw\n ? { rooms: list, meta: parsed.data.meta }\n : undefined,\n socketId: socket.id,\n issues: [error],\n })\n }\n }\n\n const leaveHandler = async (msg: unknown) => {\n dbg(roomLeaveEvent, {\n type: 'rooms',\n phase: 'receive',\n action: 'leave',\n socketId: socket.id,\n payload: msg,\n })\n const parsed = leavePayloadSchema.safeParse(msg)\n if (!parsed.success) {\n socket.emit(`${roomLeaveEvent}:error`, {\n eventName: roomLeaveEvent,\n issues: parsed.error.issues,\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n action: 'leave',\n phase: 'validation_error',\n socketId: socket.id,\n issues: parsed.error.issues,\n payload: msg,\n })\n return\n }\n\n const list = toArray(parsed.data.rooms)\n\n const leave = async (room: string) => {\n await socket.leave(room)\n dbg(null, {\n type: 'rooms',\n action: 'leave',\n rooms: room,\n socketId: socket.id,\n })\n }\n\n const run = async () => {\n await getSysEvent('sys:room_leave')({\n socket,\n helper,\n rooms: list,\n meta: parsed.data.meta as SocketSchemaOutput<C['leaveMetaMessage']>,\n leave,\n })\n }\n\n try {\n await run()\n } catch (error) {\n socket.emit(`${roomLeaveEvent}:error`, {\n error: normalizeError(error),\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n phase: 'handler_error',\n payload: { rooms: list, meta: parsed.data.meta },\n socketId: socket.id,\n issues: [error],\n action: 'join',\n })\n }\n }\n\n // heartbeat, wrapped with sys:ping/sys:pong\n const pingHandler = async (msg: unknown) => {\n if (!heartbeatEnabled) {\n dbg(null, {\n type: 'heartbeat',\n phase: 'skip',\n socketId: socket.id,\n details: { reason: 'heartbeat_disabled' },\n error: false,\n })\n return\n }\n\n const parsedPing = pingPayloadSchema.safeParse(msg)\n if (!parsedPing.success) {\n socket.emit(`${pingEvent}:error`, {\n eventName: pingEvent,\n issues: parsedPing.error.issues,\n })\n dbg(null, {\n type: 'heartbeat',\n phase: 'ping',\n socketId: socket.id,\n payload: includeRaw ? msg : undefined,\n issues: parsedPing.error.issues,\n error: true,\n details: { step: 'parse' },\n })\n return\n }\n const ctx = createCtx(socket)\n\n dbg(null, {\n type: 'heartbeat',\n phase: 'ping',\n socketId: socket.id,\n payload: parsedPing.data,\n error: false,\n })\n\n let pongPayload: SocketSchemaOutput<C['pongPayload']>\n try {\n pongPayload = await getSysEvent('sys:ping')({\n ping: parsedPing.data as SocketSchemaOutput<C['pingPayload']>,\n ctx,\n socket,\n helper,\n })\n } catch (error) {\n socket.emit(`${pingEvent}:error`, { error: normalizeError(error) })\n dbg(null, {\n type: 'heartbeat',\n phase: 'ping',\n socketId: socket.id,\n payload: parsedPing.data,\n error: true,\n details: { step: 'sys_handler_error' },\n })\n return\n }\n\n const parsedPong = pongPayloadSchema.safeParse(pongPayload)\n if (!parsedPong.success) {\n socket.emit(`${pongEvent}:error`, {\n eventName: pongEvent,\n issues: parsedPong.error.issues,\n })\n dbg(null, {\n type: 'heartbeat',\n phase: 'pong',\n socketId: socket.id,\n payload: includeRaw ? pongPayload : undefined,\n issues: parsedPong.error.issues,\n error: true,\n details: { step: 'parse' },\n })\n return\n }\n socket.emit(pongEvent, parsedPong.data)\n dbg(null, {\n type: 'heartbeat',\n phase: 'pong',\n socketId: socket.id,\n payload: parsedPong.data,\n error: false,\n })\n }\n\n // attach built-in handlers\n socket.on(roomJoinEvent, joinHandler)\n socket.on(roomLeaveEvent, leaveHandler)\n if (heartbeatEnabled) {\n socket.on(pingEvent, pingHandler)\n }\n\n const cleanup = (reason: string) => {\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_cleanup',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: { reason },\n })\n socket.off(roomJoinEvent, joinHandler)\n socket.off(roomLeaveEvent, leaveHandler)\n if (heartbeatEnabled) {\n socket.off(pingEvent, pingHandler)\n }\n }\n\n socketTeardowns.set(socket, cleanup)\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_handlers_attached',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: {\n heartbeatEnabled,\n joinEvent: roomJoinEvent,\n leaveEvent: roomLeaveEvent,\n pingEvent: heartbeatEnabled ? pingEvent : undefined,\n },\n })\n\n socket.once('disconnect', (reason) => {\n dbg('sys:disconnect', {\n type: 'lifecycle',\n stage: 'connection_cleanup',\n nsp: socket.nsp.name,\n socketId: socket.id,\n details: { reason },\n })\n const defaultDisconnect = () => {\n cleanup(reason)\n socketTeardowns.delete(socket)\n }\n getSysEvent('sys:disconnect')({\n socket,\n helper,\n reason: String(reason),\n cleanup: defaultDisconnect,\n })\n })\n }\n getSysEvent('sys:connect')({\n socket,\n helper,\n complete: defaultConnect,\n })\n }\n\n return {\n builtInConnectionListener,\n socketTeardowns,\n roomJoinEvent,\n roomLeaveEvent,\n pingEvent,\n }\n}\n","// socket.server.index.ts\nimport type {\n EventMap,\n Payload,\n SocketConnectionConfigOutput,\n} from '@emeryld/rrroutes-contract'\nimport { Server, Socket } from 'socket.io'\nimport type { SocketDebugOptions } from './socket.server.debug'\nimport { createDebugger } from './socket.server.debug'\nimport type {\n HeartbeatServerOptions,\n SocketConnectionHelper,\n SysServerEventMap,\n} from './socket.server.sys'\nimport { createBuiltInConnectionHandlers } from './socket.server.sys'\nimport type { HandlerCtx, HandlerCtxNoAck } from './socket.server.types'\n\nconst createBaseHandlerCtx = (socket: Socket): HandlerCtxNoAck => ({\n sentAt: new Date(),\n socket,\n socketId: socket.id,\n nsp: socket.nsp.name,\n rooms: Array.from(socket.rooms),\n user: socket.data?.user,\n scopes: socket.data?.scopes,\n})\n\nconst normalizeError = (error: unknown, verbose?: boolean) => {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n stack: verbose ? error.stack : undefined,\n }\n }\n if (typeof error === 'string') return { message: error }\n if (typeof error === 'object' && error !== null) {\n return verbose ? error : { message: 'Unknown error' }\n }\n return { message: String(error) }\n}\n\nexport interface SocketConnection<T extends EventMap> {\n on<K extends keyof T & string>(args: {\n eventName: K\n handler: (payload: Payload<T, K>, ctx: HandlerCtx) => void | Promise<void>\n }): () => void\n\n off<K extends keyof T & string>(eventName: K): void\n\n // 1) Strict, typed, autocompleted events\n emit<K extends keyof T & string>(args: {\n eventName: K\n payload: Payload<T, K>\n toRooms?: string[] | string\n metadata?: Record<string, unknown>\n onAck?: (ack: unknown) => void\n }): void\n\n // 2) Arbitrary events (no contract / validation)\n emitAny(args: {\n eventName: string\n payload: unknown\n toRooms?: string[] | string\n metadata?: Record<string, unknown>\n onAck?: (ack: unknown) => void\n }): void\n\n destroy(): void\n}\n\nexport function createSocketConnections<\n T extends EventMap,\n TConfig extends SocketConnectionConfigOutput = SocketConnectionConfigOutput,\n>(\n io: Server,\n events: T,\n opts: {\n debug?: SocketDebugOptions\n heartbeat?: HeartbeatServerOptions\n /** System event customization (connect / disconnect / ping / pong / room join/leave) */\n sys: SysServerEventMap<TConfig, T>\n config: TConfig\n },\n): SocketConnection<T> {\n const dbg = createDebugger(opts?.debug)\n const socketConfig = opts.config\n const heartbeatEnabled = opts?.heartbeat?.enabled !== false\n const eventNames = Object.keys(events)\n dbg(null, {\n type: 'lifecycle',\n stage: 'server_init',\n details: {\n prefinedEvents: eventNames,\n heartbeatEnabled,\n path: io?.path(),\n namespaces: Array.from(io._nsps.keys()),\n transport: io?._opts.transports,\n sysEvents: Object.keys(opts.sys ?? {}),\n },\n })\n\n const getSchema = <K extends keyof T & string>(k: K) => events[k].message\n const toArray = (rooms?: string[] | string): string[] =>\n rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]\n const emitToTargets = <K extends keyof T & string>(\n eventName: K,\n payload: Payload<T, K>,\n targets: string[],\n metadata?: Record<string, unknown>,\n ) => {\n const schema = getSchema(eventName)\n const check = schema.safeParse(payload)\n if (!check.success) {\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n ...(opts?.debug?.verbose ? { attemptedPayload: payload } : {}),\n error: {\n reason: 'invalid_payload',\n message: check.error.message,\n issues: check.error.issues,\n },\n metadata,\n })\n throw new Error(\n `Invalid payload for \"${String(eventName)}\": ${check.error.message}`,\n )\n }\n\n const envelope = {\n eventName,\n sentAt: new Date(),\n sentTo: targets,\n data: check.data as Payload<T, K>,\n metadata: metadata ?? {},\n rooms: targets,\n }\n\n if (targets.length === 0) io.emit(String(eventName), envelope)\n else if (targets.length === 1) {\n const sid = targets[0]!\n const sock = io.sockets.sockets.get(sid as any)\n if (sock) {\n sock.emit(String(eventName), envelope)\n } else {\n io.to(targets).emit(String(eventName), envelope)\n }\n } else {\n io.to(targets).emit(String(eventName), envelope)\n }\n\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n envelope: opts?.debug?.verbose ? envelope : undefined,\n })\n }\n const createSocketHelper = (socket: Socket): SocketConnectionHelper<T> => {\n const helper: SocketConnectionHelper<T> = {\n emit(\n eventName: string,\n payload: unknown,\n metadata?: Record<string, unknown>,\n ) {\n if (Object.prototype.hasOwnProperty.call(events, eventName)) {\n // Known / registered event -> use schema + envelope\n emitToTargets(\n eventName as keyof T & string,\n payload as Payload<T, keyof T & string>,\n [socket.id],\n metadata,\n )\n } else {\n // Unknown / non-registered event -> raw emit, no schema/envelope\n socket.emit(eventName, payload)\n }\n },\n }\n\n return helper\n }\n\n // registrations\n const registrations = new Map<\n string,\n Set<{\n connectionListener: (socket: Socket) => void\n socketListeners: WeakMap<Socket, (raw: unknown) => void>\n }>\n >()\n\n const addRegistration = (\n eventName: string,\n reg: {\n connectionListener: (socket: Socket) => void\n socketListeners: WeakMap<Socket, (raw: unknown) => void>\n },\n ) => {\n let set = registrations.get(eventName)\n if (!set) {\n set = new Set()\n registrations.set(eventName, set)\n }\n set.add(reg)\n }\n\n const removeAllForEvent = (eventName: string) => {\n const set = registrations.get(eventName)\n if (!set) {\n dbg(null, {\n type: 'register',\n event: eventName,\n action: 'unregister',\n msg: 'no handlers registered',\n })\n return\n }\n for (const reg of set) {\n io.off('connection', reg.connectionListener)\n for (const socket of io.sockets.sockets.values()) {\n const wrapped = reg.socketListeners.get(socket)\n if (wrapped) socket.off(String(eventName), wrapped)\n }\n }\n registrations.delete(eventName)\n dbg(eventName, {\n type: 'register',\n action: 'unregister',\n event: eventName,\n msg: 'unregistered',\n })\n }\n\n const {\n builtInConnectionListener,\n socketTeardowns,\n roomJoinEvent,\n roomLeaveEvent,\n pingEvent,\n } = createBuiltInConnectionHandlers<TConfig, T>({\n heartbeat: opts?.heartbeat,\n sys: opts.sys,\n dbg,\n config: socketConfig,\n createCtx: createBaseHandlerCtx,\n debugVerbose: opts?.debug?.verbose === true,\n createHelper: createSocketHelper,\n })\n\n // install built-in connection listener\n io.on('connection', builtInConnectionListener)\n\n const conn = {\n on<K extends keyof T & string>({\n eventName,\n handler,\n }: {\n eventName: K\n handler: (payload: Payload<T, K>, ctx: HandlerCtx) => void | Promise<void>\n }): () => void {\n const socketListeners = new WeakMap<Socket, (raw: unknown) => void>()\n\n const connectionListener = (socket: Socket) => {\n const wrapped = async (raw: unknown) => {\n const schema = getSchema(eventName)\n const parsed = schema.safeParse(raw)\n\n const ctx = createBaseHandlerCtx(socket)\n\n dbg(String(eventName), {\n type: 'handler',\n phase: 'receive',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n rooms: ctx.rooms,\n raw: opts?.debug?.verbose ? raw : undefined,\n })\n\n if (!parsed.success) {\n socket.emit(`${String(eventName)}:error`, {\n eventName,\n sentAt: ctx.sentAt,\n issues: parsed.error.issues,\n })\n dbg(String(eventName), {\n type: 'handler',\n phase: 'validation_error',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n issues: parsed.error.issues,\n })\n return\n }\n\n try {\n await handler(parsed.data as Payload<T, K>, ctx)\n dbg(String(eventName), {\n type: 'handler',\n phase: 'handler_success',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n rooms: ctx.rooms,\n })\n } catch (error) {\n dbg(String(eventName), {\n type: 'handler',\n phase: 'handler_error',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n rooms: ctx.rooms,\n error,\n })\n socket.emit(`${String(eventName)}:error`, {\n eventName,\n sentAt: ctx.sentAt,\n error: normalizeError(error, opts?.debug?.verbose),\n })\n }\n }\n\n socketListeners.set(socket, wrapped)\n socket.on(String(eventName), wrapped)\n socket.once('disconnect', () => {\n const w = socketListeners.get(socket)\n if (w) socket.off(String(eventName), w)\n })\n }\n\n io.on('connection', connectionListener)\n addRegistration(String(eventName), {\n connectionListener,\n socketListeners,\n })\n dbg(String(eventName), {\n type: 'register',\n action: 'register',\n event: String(eventName),\n })\n\n return () => {\n const set = registrations.get(String(eventName))\n if (!set) {\n dbg(null, {\n type: 'register',\n action: 'unregister',\n event: String(eventName),\n msg: `No registration under ${eventName}`,\n })\n return\n }\n for (const reg of Array.from(set)) {\n if (reg.connectionListener === connectionListener) {\n io.off('connection', reg.connectionListener)\n for (const socket of io.sockets.sockets.values()) {\n const wrapped = reg.socketListeners.get(socket)\n if (wrapped) socket.off(String(eventName), wrapped)\n }\n set.delete(reg)\n break\n }\n }\n if (set.size === 0) registrations.delete(String(eventName))\n dbg(String(eventName), {\n type: 'register',\n action: 'unregister',\n event: String(eventName),\n })\n }\n },\n\n off<K extends keyof T & string>(eventName: K): void {\n removeAllForEvent(String(eventName))\n },\n\n emitAny({\n eventName,\n payload,\n rooms,\n metadata,\n }: {\n eventName: string\n payload: unknown\n rooms?: string[] | string\n metadata?: Record<string, unknown>\n }): void {\n const targets = toArray(rooms)\n\n if (Object.prototype.hasOwnProperty.call(events, eventName)) {\n // Known/registered event -> validated path (schema + envelope)\n emitToTargets(\n eventName as keyof T & string,\n payload as Payload<T, keyof T & string>,\n targets,\n metadata,\n )\n return\n }\n\n // Unknown/non-registered event -> raw emit (no zod, no envelope)\n const envelopeOrPayload = payload\n if (targets.length === 0) io.emit(eventName, envelopeOrPayload)\n else if (targets.length === 1) {\n const sid = targets[0]!\n const sock = io.sockets.sockets.get(sid as any)\n if (sock) {\n sock.emit(eventName, envelopeOrPayload)\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n envelope: opts?.debug?.verbose ? envelopeOrPayload : undefined,\n note: 'raw_emit_unregistered_event',\n })\n },\n emit<K extends keyof T & string>({\n eventName,\n payload,\n toRooms: rooms,\n metadata,\n onAck,\n }: {\n eventName: K\n payload: Payload<T, K>\n toRooms?: string[] | string\n metadata?: Record<string, unknown>\n onAck?: (ack: unknown) => void\n }): void {\n const targets = toArray(rooms)\n\n if (Object.prototype.hasOwnProperty.call(events, eventName)) {\n // Known/registered event -> validated path (schema + envelope)\n emitToTargets(\n eventName as keyof T & string,\n payload as Payload<T, keyof T & string>,\n targets,\n metadata,\n )\n return\n }\n\n // Unknown/non-registered event -> raw emit (no zod, no envelope)\n const envelopeOrPayload = payload\n if (targets.length === 0) io.emit(eventName, envelopeOrPayload)\n else if (targets.length === 1) {\n const sid = targets[0]!\n const sock = io.sockets.sockets.get(sid as any)\n if (sock) {\n sock.emit(eventName, envelopeOrPayload)\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n envelope: opts?.debug?.verbose ? envelopeOrPayload : undefined,\n note: 'raw_emit_unregistered_event',\n })\n },\n\n destroy(): void {\n dbg(null, {\n type: 'lifecycle',\n stage: 'destroy_start',\n details: {\n socketCount: io.sockets.sockets.size,\n registrationCount: registrations.size,\n },\n })\n // 1) Remove built-in connection listener so no new sockets get handlers\n io.off('connection', builtInConnectionListener)\n\n // 2) Cleanup built-in handlers for all current sockets and leave rooms\n for (const socket of io.sockets.sockets.values()) {\n const cleanup = socketTeardowns.get(socket)\n if (cleanup) {\n cleanup('destroy')\n socketTeardowns.delete(socket)\n } else {\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_cleanup_fallback',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: { reason: 'teardown_missing' },\n })\n // Fallback if socket was attached before map population\n try {\n socket.removeAllListeners(roomJoinEvent)\n socket.removeAllListeners(roomLeaveEvent)\n socket.removeAllListeners(pingEvent)\n } catch {\n // noop\n }\n }\n }\n\n // 3) Remove all user-registered event listeners and their connection hooks\n for (const eventName of Array.from(registrations.keys())) {\n removeAllForEvent(eventName)\n }\n\n // 4) Defensive: clear any residual maps\n registrations.clear()\n dbg(null, {\n type: 'lifecycle',\n stage: 'destroy_complete',\n details: {\n socketCount: io.sockets.sockets.size,\n registrationCount: registrations.size,\n },\n })\n },\n } as const satisfies SocketConnection<T>\n\n return conn\n}\n\nexport type {\n SocketDebugOptions,\n SocketServerConfigSnapshot,\n SocketServerDebugEvent,\n SocketServerHeartbeatPhase,\n SocketServerLifecycleStage,\n} from './socket.server.debug'\nexport type {\n HeartbeatServerOptions,\n SocketConnectionHelper,\n SysServerEventMap,\n} from './socket.server.sys'\nexport type { HandlerCtx } from './socket.server.types'\nexport type { EventMap, Payload }\n","import type { IncomingHttpHeaders } from 'http'\nimport type { Socket } from 'socket.io'\n\nexport type ConnectionMiddlewareStage = 'incoming'\n\nexport type ConnectionMiddlewareContext = {\n socketId?: string\n nsp?: string\n rooms: string[]\n user?: unknown\n scopes?: string[]\n address?: string\n transport?: string\n protocol?: string\n handshake: {\n url?: string\n issued?: number\n time?: string\n query?: Record<string, unknown>\n auth?: Record<string, unknown>\n headers?: IncomingHttpHeaders\n }\n}\n\nexport type ConnectionMiddlewareEvent = {\n type: 'connection'\n stage: ConnectionMiddlewareStage\n timestamp: Date\n context: ConnectionMiddlewareContext\n}\n\nexport type ConnectionLoggingMiddlewareOptions = {\n /**\n * Custom logger invoked with the structured event.\n * Defaults to console.info.\n */\n logger?: (event: ConnectionMiddlewareEvent) => void\n /**\n * Include raw headers from the handshake. Defaults to false to avoid leaking PII.\n */\n includeHeaders?: boolean\n /**\n * List of auth keys that should be redacted (case-insensitive). Defaults to ['authorization'].\n */\n redactAuthKeys?: string[]\n}\n\nconst defaultRedactedValue = '[REDACTED]'\n\nconst defaultLogger = (event: ConnectionMiddlewareEvent) => {\n const {\n stage,\n context: { socketId, nsp, address, transport, handshake },\n } = event\n // eslint-disable-next-line no-console\n console.info('[socket-connection]', {\n stage,\n socketId,\n nsp,\n address,\n transport,\n url: handshake.url,\n query: handshake.query,\n auth: handshake.auth,\n })\n}\n\nconst redactAuth = (\n auth: Record<string, unknown> | undefined,\n redactKeys: Set<string>,\n): Record<string, unknown> | undefined => {\n if (!auth) return undefined\n if (redactKeys.size === 0) return auth\n\n const clone: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(auth)) {\n const normalizedKey = key.toLowerCase()\n clone[key] = redactKeys.has(normalizedKey) ? defaultRedactedValue : value\n }\n return clone\n}\n\nconst buildContext = (\n socket: Socket,\n includeHeaders: boolean,\n redactKeys: Set<string>,\n): ConnectionMiddlewareContext => {\n const conn = socket.conn as\n | {\n remoteAddress?: string\n transport?: { name?: string }\n protocol?: string | number\n }\n | undefined\n\n const handshake = socket.handshake ?? {}\n\n const protocolValue = conn?.protocol\n\n return {\n socketId: socket.id,\n nsp: socket.nsp?.name,\n rooms: Array.from(socket.rooms ?? []),\n user: (socket.data as any)?.user,\n scopes: (socket.data as any)?.scopes,\n address: conn?.remoteAddress ?? (handshake as any).address,\n transport: conn?.transport?.name,\n protocol: protocolValue != null ? String(protocolValue) : undefined,\n handshake: {\n url: handshake.url,\n issued: handshake.issued,\n time: handshake.time,\n query: handshake.query as Record<string, unknown>,\n auth: redactAuth(handshake.auth as Record<string, unknown>, redactKeys),\n headers: includeHeaders\n ? (handshake.headers as IncomingHttpHeaders)\n : undefined,\n },\n }\n}\n\nexport const createConnectionLoggingMiddleware = (\n options: ConnectionLoggingMiddlewareOptions = {},\n) => {\n const logger = options.logger ?? defaultLogger\n const includeHeaders = options.includeHeaders ?? false\n const redactKeys = new Set(\n (options.redactAuthKeys ?? ['authorization', 'token']).map((key) =>\n key.toLowerCase(),\n ),\n )\n\n return (socket: Socket, next: (err?: Error) => void) => {\n const context = buildContext(socket, includeHeaders, redactKeys)\n logger({\n type: 'connection',\n stage: 'incoming',\n timestamp: new Date(),\n context,\n })\n next()\n }\n}\n\nexport type ConnectionLoggingMiddleware = ReturnType<\n typeof createConnectionLoggingMiddleware\n>\n"],"mappings":"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","names":["import_rrroutes_contract","isPlainObject","multer","normalizeError","toArray"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/routesV3.server.ts","../src/routesV3.server.sanitize.ts","../src/sockets/socket.server.debug.ts","../src/sockets/socket.server.sys.ts","../src/sockets/socket.server.index.ts","../src/sockets/socket.server.middleware.ts"],"sourcesContent":["export { keyOf as contractKeyOf } from '@emeryld/rrroutes-contract'\nexport * from './routesV3.server'\nexport * from './routesV3.server.sanitize'\nexport * from './sockets/socket.server.index'\nexport * from './sockets/socket.server.middleware'\n","/**\n * routesV3.server.ts\n * -----------------------------------------------------------------------------\n * Bind an Express router/app to a `finalize(...)` registry of AnyLeafs.\n * - Fully typed handlers (params/query/body/output)\n * - Zod parsing + optional output validation\n * - Structured middleware stages (sanitizer, preCtx, postCtx, per-route, uploads)\n * - buildCtx runs after payload resolution and before ctx-aware middlewares\n * - Helper to warn about unimplemented routes\n * - DX helpers to use `ctx` in any middleware with proper types\n */\n\nimport {\n AnyLeafLowProfile,\n buildLowProfileLeaf,\n FileField,\n HttpMethod,\n InferBody,\n InferOutput,\n InferParams,\n InferQuery,\n keyOf,\n lowProfileParse,\n} from '@emeryld/rrroutes-contract'\nimport type * as express from 'express'\nimport type { RequestHandler, Router } from 'express'\nimport multer from 'multer'\nimport {\n createRequestSanitizationMiddleware,\n type RequestSanitizationOptions,\n} from './routesV3.server.sanitize'\n\ntype MulterOptions = multer.Options\n/** Shape expected from optional logger implementations. */\nexport type LoggerLike = {\n info?: (...args: any[]) => void\n warn?: (...args: any[]) => void\n error?: (...args: any[]) => void\n debug?: (...args: any[]) => void\n verbose?: (...args: any[]) => void\n system?: (...args: any[]) => void\n log?: (...args: any[]) => void\n}\n\ntype RoutesLoggerCarrier = {\n routesLogger?: LoggerLike\n}\n\ntype CtxWithRoutesLogger<Ctx> = Ctx & RoutesLoggerCarrier\n\n// Debug logging --------------------------------------------------------------\nexport type RouteServerDebugMode = 'minimal' | 'complete'\n\ntype RouteServerDebugEventBase = {\n /** Optional logical name assigned via `RouteDef.debug?.debugName` (or `RouteDef.debugName`). */\n name?: string\n}\n\nexport type RouteServerDebugEvent =\n | (RouteServerDebugEventBase & {\n type: 'request'\n stage: 'start' | 'success' | 'error'\n method: Uppercase<HttpMethod>\n path: string\n url: string\n durationMs?: number\n params?: unknown\n query?: unknown\n body?: unknown\n bodyFiles?: BodyFilesMap | undefined\n output?: unknown\n error?: unknown\n })\n | (RouteServerDebugEventBase & {\n type: 'register'\n method: Uppercase<HttpMethod>\n path: string\n })\n | (RouteServerDebugEventBase & {\n type: 'buildCtx'\n stage: 'start' | 'success' | 'error'\n method: Uppercase<HttpMethod>\n path: string\n url: string\n durationMs?: number\n error?: unknown\n })\n | (RouteServerDebugEventBase & {\n type: 'handler'\n stage: 'start' | 'success' | 'error'\n method: Uppercase<HttpMethod>\n path: string\n durationMs?: number\n params?: unknown\n query?: unknown\n body?: unknown\n bodyFiles?: BodyFilesMap | undefined\n output?: unknown\n error?: unknown\n })\n\nexport type RouteServerDebugLogger = (event: RouteServerDebugEvent) => void\n\n/**\n * Configure server-side debug logging.\n * - Use booleans or `'minimal'/'complete'` for quick toggles.\n * - Pass a custom logger function to redirect structured events.\n * - Provide a map to enable specific event types, opt into verbose payload logging, or restrict logs via `only`.\n */\nexport type RouteServerDebugOptions<Names extends string = string> =\n RouteServerDebugToggleOptions<Names>\n\n/**\n * Fine-grained toggle map for server debug logging.\n * Enable individual event types, opt into verbose payload logging, override the logger, or restrict to named routes.\n * Use `RouteDef.debug?.debugName` (or the deprecated `RouteDef.debugName`) to set the name that `only` will match against.\n */\nexport type RouteServerDebugToggleOptions<Names extends string = string> =\n Partial<Record<RouteServerDebugEvent['type'], boolean>> & {\n verbose?: boolean\n logger?: RouteServerDebugLogger\n only?: Names[]\n }\n\n/**\n * Per-route debug overrides. Same toggles as `RouteServerDebugOptions`, but limited to a single route\n * and therefore replaces the `only` filter with a local `debugName`.\n */\nexport type RouteDefDebugOptions<Names extends string = string> = Omit<\n RouteServerDebugToggleOptions<Names>,\n 'only'\n> & {\n debugName?: Names\n}\n\nconst serverDebugEventTypes: RouteServerDebugEvent['type'][] = [\n 'register',\n 'request',\n 'buildCtx',\n 'handler',\n]\n\ntype ServerDebugEmitter<Names extends string> = {\n emit: (event: RouteServerDebugEvent, name?: Names) => void\n mode: RouteServerDebugMode\n}\n\nconst noopServerEmit = () => {}\n\nfunction createServerDebugEmitter<Names extends string>(\n option?: RouteServerDebugOptions<Names>,\n): ServerDebugEmitter<Names> {\n const disabled: ServerDebugEmitter<Names> = {\n emit: noopServerEmit,\n mode: 'minimal',\n }\n if (!option) return disabled\n\n if (typeof option === 'object') {\n const toggles = option as RouteServerDebugToggleOptions<Names>\n const verbose = Boolean(toggles.verbose)\n const enabledTypes = serverDebugEventTypes.filter((type) => toggles[type])\n if (enabledTypes.length === 0) {\n return { emit: noopServerEmit, mode: verbose ? 'complete' : 'minimal' }\n }\n const whitelist = new Set<RouteServerDebugEvent['type']>(enabledTypes)\n const onlySet =\n toggles.only && toggles.only.length > 0\n ? new Set<Names>(toggles.only)\n : undefined\n const logger = toggles.logger\n const emit: ServerDebugEmitter<Names>['emit'] = (event, name) => {\n if (!whitelist.has(event.type) || !logger) return\n if (onlySet && (!name || !onlySet.has(name))) return\n logger(name ? { ...event, name } : event)\n }\n return { emit, mode: verbose ? 'complete' : 'minimal' }\n }\n\n return disabled\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Keys + leaf helpers (derive keys from byKey to avoid template-literal pitfalls)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/** Keys like \"GET /v1/foo\" that *actually* exist in the registry */\nexport type KeysOfRegistry<\n R extends { byKey: Record<string, AnyLeafLowProfile> },\n> = keyof R['byKey'] & string\n\ntype MethodFromKey<K extends string> = K extends `${infer M} ${string}`\n ? Lowercase<M>\n : never\ntype PathFromKey<K extends string> = K extends `${string} ${infer P}`\n ? P\n : never\n\n/** Given a registry and a key, pick the exact leaf for that method+path */\nexport type LeafFromKey<\n R extends { all: readonly AnyLeafLowProfile[] },\n K extends string,\n> = Extract<\n R['all'][number],\n { method: MethodFromKey<K> & HttpMethod; path: PathFromKey<K> }\n>\n\n/** Optional-ify types if your core returns `never` when a schema isn't defined */\ntype Maybe<T> = [T] extends [never] ? void : T\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst decodeJsonLikeQueryValue = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => decodeJsonLikeQueryValue(entry))\n }\n if (isPlainObject(value)) {\n const next: Record<string, unknown> = {}\n for (const [key, child] of Object.entries(value)) {\n next[key] = decodeJsonLikeQueryValue(child)\n }\n return next\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n return JSON.parse(trimmed)\n } catch {\n return value\n }\n }\n }\n return value\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Context typing & DX helpers (so ctx is usable in *any* middleware)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * Unique symbol used to stash ctx on res.locals.\n * (Symbols are safer than string keys against collisions.)\n */\nexport const CTX_SYMBOL: unique symbol = Symbol.for('typedLeaves.ctx')\n\nconst REQUEST_PAYLOAD_SYMBOL: unique symbol = Symbol.for(\n 'typedLeaves.requestPayload',\n)\n\ntype BodyFilesMap = Record<string, express.Multer.File[] | undefined>\n\ntype BodyFileNamesFromLeaf<Leaf extends AnyLeafLowProfile> =\n Leaf['cfg']['bodyFiles'] extends readonly FileField[]\n ? Leaf['cfg']['bodyFiles'][number]['name']\n : never\ntype BodyFilesMapFromLeaf<Leaf extends AnyLeafLowProfile> =\n BodyFileNamesFromLeaf<Leaf> extends never\n ? undefined\n : Partial<Record<BodyFileNamesFromLeaf<Leaf>, express.Multer.File[]>> &\n BodyFilesMap\n\n/** Parsed params/query/body that are shared between middleware/handler. */\nexport type RouteRequestPayload<Leaf extends AnyLeafLowProfile> = {\n params: Maybe<InferParams<Leaf>>\n query: Maybe<InferQuery<Leaf>>\n body: Maybe<InferBody<Leaf>>\n bodyFiles: BodyFilesMapFromLeaf<Leaf>\n}\n\nfunction isMulterFile(value: unknown): value is express.Multer.File {\n if (!isPlainObject(value)) return false\n const candidate = value as Record<string, unknown>\n return typeof candidate.fieldname === 'string'\n}\n\nfunction collectMulterFiles(req: express.Request): express.Multer.File[] {\n const files: express.Multer.File[] = []\n const pushValue = (value: unknown) => {\n if (value === undefined || value === null) return\n if (Array.isArray(value)) {\n value.forEach(pushValue)\n return\n }\n if (isMulterFile(value)) {\n files.push(value)\n return\n }\n if (isPlainObject(value)) {\n Object.values(value).forEach(pushValue)\n }\n }\n\n pushValue((req as any).files)\n pushValue((req as any).file)\n return files\n}\n\nfunction resolveBodyFilesFromRequest(\n req: express.Request,\n fields: FileField[] | undefined,\n): BodyFilesMap | undefined {\n if (!fields?.length) return undefined\n const allowedNames = new Set(fields.map((field) => field.name))\n const collected = collectMulterFiles(req)\n if (collected.length === 0) return undefined\n\n const result: BodyFilesMap = {}\n for (const file of collected) {\n if (!allowedNames.has(file.fieldname)) continue\n const bucket = result[file.fieldname] ?? []\n bucket.push(file)\n result[file.fieldname] = bucket\n }\n\n return Object.keys(result).length ? result : undefined\n}\n\nfunction getRouteRequestPayload<Leaf extends AnyLeafLowProfile>(\n res: express.Response,\n): RouteRequestPayload<Leaf> {\n const payload = (res.locals as any)[REQUEST_PAYLOAD_SYMBOL]\n if (payload) {\n return payload as RouteRequestPayload<Leaf>\n }\n throw new Error('Request payload was not initialized before middleware')\n}\n\nfunction setRouteRequestPayload<Leaf extends AnyLeafLowProfile>(\n res: express.Response,\n payload: RouteRequestPayload<Leaf>,\n) {\n ;(res.locals as any)[REQUEST_PAYLOAD_SYMBOL] = payload\n}\n\n/** Response type that *has* a ctx on locals for DX in middlewares */\nexport type ResponseWithCtx<Ctx> =\n // Replace locals with an intersection that guarantees CTX_SYMBOL exists\n Omit<express.Response, 'locals'> & {\n locals: express.Response['locals'] & {\n [CTX_SYMBOL]: CtxWithRoutesLogger<Ctx>\n }\n }\n\n/** A middleware signature that can *use* ctx via `res.locals[CTX_SYMBOL]` */\nexport type CtxRequestHandler<Ctx> = (args: {\n req: express.Request\n res: express.Response\n next: express.NextFunction\n ctx: CtxWithRoutesLogger<Ctx>\n}) => any\n\nexport type RouteBeforeHandler<\n Leaf extends AnyLeafLowProfile,\n Ctx = unknown,\n> = (\n args: {\n req: express.Request\n res: express.Response\n next: express.NextFunction\n ctx: CtxWithRoutesLogger<Ctx>\n } & RouteRequestPayload<Leaf>,\n) => any\n\n/**\n * Safely read ctx from any Response.\n * @param res Express response whose locals contain the ctx symbol.\n * @returns Strongly typed context object.\n */\nexport function getCtx<Ctx = unknown>(\n res: express.Response,\n): CtxWithRoutesLogger<Ctx> {\n return (res.locals as any)[CTX_SYMBOL] as CtxWithRoutesLogger<Ctx>\n}\n\n/**\n * Wrap a ctx-typed middleware to a plain RequestHandler (for arrays, etc.).\n * @param mw Middleware that expects a typed response with ctx available.\n * @returns Standard Express request handler.\n */\nfunction adaptCtxMw<Ctx>(mw: CtxRequestHandler<Ctx>): RequestHandler {\n return (req, res, next) => {\n try {\n const result = mw({ req, res, next, ctx: getCtx<Ctx>(res) })\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).catch((err) => next(err))\n }\n return result as any\n } catch (err) {\n next(err as any)\n return undefined\n }\n }\n}\n\nfunction adaptRouteBeforeMw<Leaf extends AnyLeafLowProfile, Ctx = unknown>(\n mw: RouteBeforeHandler<Leaf, Ctx>,\n): RequestHandler {\n return (req, res, next) => {\n try {\n const result = mw({\n req,\n res,\n next,\n ctx: getCtx<Ctx>(res),\n ...getRouteRequestPayload<Leaf>(res),\n })\n if (result && typeof (result as Promise<unknown>).then === 'function') {\n return (result as Promise<unknown>).catch((err) => next(err))\n }\n return result as any\n } catch (err) {\n next(err as any)\n return undefined\n }\n }\n}\n\nfunction logHandlerDebugWithRoutesLogger(\n logger: LoggerLike | undefined,\n event: RouteServerDebugEvent,\n) {\n if (!logger || event.type !== 'handler') return\n const payload: [string, RouteServerDebugEvent] = [\n `[rrroutes-server][handler:${event.stage}] ${event.method} ${event.path}`,\n event,\n ]\n if (event.stage === 'error') {\n ;(\n logger.error ??\n logger.warn ??\n logger.debug ??\n logger.info ??\n logger.log ??\n logger.system\n )?.call(logger, ...payload)\n return\n }\n ;(\n logger.debug ??\n logger.verbose ??\n logger.info ??\n logger.log ??\n logger.system\n )?.call(logger, ...payload)\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Controller types — object form only (simpler, clearer typings)\n// ──────────────────────────────────────────────────────────────────────────────\n\n/** Typed route handler for a specific leaf */\n\nexport type Handler<L extends AnyLeafLowProfile, Ctx = unknown> = (args: {\n req: express.Request\n res: express.Response\n next: express.NextFunction\n ctx: CtxWithRoutesLogger<Ctx>\n params: Maybe<InferParams<L>>\n query: Maybe<InferQuery<L>>\n body: Maybe<InferBody<L>>\n bodyFiles: RouteRequestPayload<L>['bodyFiles']\n}) => Promise<Maybe<InferOutput<L>>> | Maybe<InferOutput<L>>\n\n/** Route definition for one key */\nexport type RouteDef<\n L extends AnyLeafLowProfile,\n Ctx = unknown,\n Names extends string = string,\n> = {\n /** Middlewares before the handler (run after buildCtx/postCtx/derived) */\n before?: Array<RouteBeforeHandler<L, Ctx>>\n /** Your business logic */\n handler: Handler<L, Ctx>\n send?: (ex: express.Response, data: Maybe<InferOutput<L>>) => void\n /**\n * Optional per-route debug overrides. When provided, these replace the global debug options.\n */\n debug?: RouteDefDebugOptions<Names>\n}\n\n/** Map of registry keys -> route defs */\nexport type ControllerMap<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n> = {\n [P in KeysOfRegistry<R>]: RouteDef<LeafFromKey<R, P>, Ctx, Names>\n}\n\nexport type PartialControllerMap<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n> = Partial<ControllerMap<R, Ctx, Names>>\n\n// ──────────────────────────────────────────────────────────────────────────────\n/** Options + derivation helpers */\n// ──────────────────────────────────────────────────────────────────────────────\n\nexport type BuildCtxArgs = {\n req: express.Request\n res: express.Response\n}\n\nexport type BuildCtxHandler<Ctx> = (\n args: BuildCtxArgs,\n) => CtxWithRoutesLogger<Ctx> | Promise<CtxWithRoutesLogger<Ctx>>\n\nexport type RouteServerSanitizer = RequestSanitizationOptions | RequestHandler\n\nexport type RouteServerMiddlewareConfig<Ctx = unknown> = {\n /**\n * Middlewares that run before payload parsing and buildCtx.\n */\n preCtx?: Array<RequestHandler>\n /**\n * Middleware that sanitizes request data before payload parsing.\n * - If a RequestHandler is provided, it's used directly.\n * - If sanitization options are provided, a middleware is created from them.\n */\n sanitizer?: RouteServerSanitizer | undefined\n /**\n * Ctx-aware middlewares that run after buildCtx and before route-level middleware.\n */\n postCtx?: Array<CtxRequestHandler<Ctx>>\n}\n\ntype MulterOptionsResolver = (\n fields: FileField[] | undefined,\n) => MulterOptions | false | undefined\n\nconst defaultMulterOptions: MulterOptions = {\n storage: multer.memoryStorage(),\n}\n\nexport type RouteServerConfig<Ctx = unknown, Names extends string = string> = {\n /**\n * Build a request-scoped context. We wrap this in a middleware that runs\n * after payload resolution and before postCtx/route middlewares, and stash it on\n * `res.locals[CTX_SYMBOL]` so *all* later middlewares can use it.\n * You can optionally include `routesLogger` to override handler debug logging per request.\n */\n buildCtx: BuildCtxHandler<Ctx>\n\n /**\n * Middleware stages for the request pipeline.\n * Order: sanitizer -> preCtx -> resolve -> ctx -> postCtx -> route.before -> handler\n */\n middleware?: RouteServerMiddlewareConfig<Ctx>\n\n /**\n * Multer options used when a route declares `bodyFiles`.\n * - Provide `false` to skip Multer parsing for specific leaves.\n * - Provide a function to compute options per leaf.\n * - When omitted, a shared memory storage is used to parse multipart payloads.\n */\n multerOptions?: MulterOptions | MulterOptionsResolver\n\n /** Validate handler return values with outputSchema (default: true) */\n validateOutput?: boolean\n\n /** Custom responder (default: res.json(data)) */\n send?: (res: express.Response, data: unknown) => void\n\n /**\n * Optional debug logging for the request lifecycle.\n * Supports booleans/modes/loggers, or a toggle map with per-event enabling, verbose payload logging,\n * and `only` filters tied to `RouteDef.debug?.debugName` (or the deprecated `RouteDef.debugName`).\n */\n debug?: RouteServerDebugOptions<Names>\n}\n\n/** Default JSON responder (typed to avoid implicit-any diagnostics) */\nconst defaultSend: (res: express.Response, data: unknown) => void = (\n res,\n data,\n) => {\n res.json(data as any)\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// Core builder\n// ──────────────────────────────────────────────────────────────────────────────\n\nconst REGISTERED_ROUTES_SYMBOL = Symbol.for('routesV3.registeredRoutes')\n\ntype RegisteredRouteStore = Set<string>\n\n/**\n * Retrieve or initialize the shared store of registered route keys.\n * @param router Express router/application that carries previously registered keys.\n * @returns Set of string keys describing registered routes.\n */\nfunction getRegisteredRouteStore(router: Router): RegisteredRouteStore {\n const existing = (router as any)[REGISTERED_ROUTES_SYMBOL] as\n | RegisteredRouteStore\n | undefined\n if (existing) return existing\n const store: RegisteredRouteStore = new Set()\n ;(router as any)[REGISTERED_ROUTES_SYMBOL] = store\n return store\n}\n\n/**\n * Inspect the Express layer stack to discover already-registered routes.\n * @param appOrRouter Express application or router to inspect.\n * @returns All keys in the form `\"METHOD /path\"` found on the stack.\n */\nfunction collectRoutesFromStack(appOrRouter: Router): string[] {\n const result: string[] = []\n const stack: any[] =\n (appOrRouter as any).stack ??\n ((appOrRouter as any)._router\n ? (appOrRouter as any)._router.stack\n : undefined) ??\n []\n\n if (!Array.isArray(stack)) return result\n\n for (const layer of stack) {\n const route = layer && layer.route\n if (!route) continue\n\n const paths = Array.isArray(route.path) ? route.path : [route.path]\n const methodEntries = Object.entries(route.methods ?? {}).filter(\n ([, enabled]) => enabled,\n )\n\n for (const path of paths) {\n for (const [method] of methodEntries) {\n result.push(`${method.toUpperCase()} ${path}`)\n }\n }\n }\n\n return result\n}\n\n/** Runtime helpers returned by `createRRRoute`. */\nexport type RouteServer<Ctx = unknown, Names extends string = string> = {\n router: Router\n register<L extends AnyLeafLowProfile>(\n leaf: L,\n def: RouteDef<L, Ctx, Names>,\n ): void\n registerControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n F extends boolean = false,\n >(\n registry: R,\n controllers: F extends false\n ? PartialControllerMap<R, Ctx, Names>\n : ControllerMap<R, Ctx, Names>,\n all?: F,\n ): void\n warnMissingControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n >(\n registry: R,\n logger: { warn: (...args: any[]) => void },\n ): void\n getRegisteredKeys(): string[]\n}\n\n/**\n * Create an Express binding helper that keeps routes and controllers in sync.\n * @param router Express router or app to register handlers on.\n * @param config Optional configuration controlling ctx building, auth, uploads, etc.\n * Middleware order: sanitizer -> preCtx -> resolve -> ctx -> postCtx -> route.before -> handler.\n * @returns Object with helpers to register controllers and inspect registered keys.\n */\nexport function createRRRoute<Ctx = unknown, Names extends string = string>(\n router: Router,\n config: RouteServerConfig<Ctx, Names>,\n): RouteServer<Ctx, Names> {\n const validateOutput = config.validateOutput ?? true\n const send = config.send ?? defaultSend\n const { emit: defaultEmitDebug, mode: defaultDebugMode } =\n createServerDebugEmitter<Names>(config.debug)\n\n const knownLeaves = new Map<string, AnyLeafLowProfile>()\n\n const decorateDebugEvent = <T extends RouteServerDebugEvent>(\n isVerbose: boolean,\n event: T,\n details?: Partial<RouteServerDebugEvent>,\n ): RouteServerDebugEvent => {\n if (!isVerbose || !details) return event\n return { ...event, ...details } as RouteServerDebugEvent\n }\n\n const middlewareConfig = config.middleware ?? {}\n const postCtxMws = [...(middlewareConfig.postCtx ?? [])].map((mw) =>\n adaptCtxMw<Ctx>(mw),\n )\n const preCtxMws = [...(middlewareConfig.preCtx ?? [])]\n const sanitizerMw =\n middlewareConfig.sanitizer === undefined\n ? undefined\n : typeof middlewareConfig.sanitizer === 'function'\n ? middlewareConfig.sanitizer\n : createRequestSanitizationMiddleware(middlewareConfig.sanitizer)\n const registered = getRegisteredRouteStore(router)\n\n const getMulterOptions = (fields: FileField[] | undefined) => {\n if (!fields || fields.length === 0) return undefined\n const resolved =\n typeof config.multerOptions === 'function'\n ? config.multerOptions(fields)\n : config.multerOptions\n if (resolved === false) return undefined\n return resolved ?? defaultMulterOptions\n }\n\n const runMulterHandler = (\n handler: RequestHandler,\n req: express.Request,\n res: express.Response,\n ) => {\n return new Promise<void>((resolve, reject) => {\n handler(req, res, (err?: any) => {\n if (err) {\n reject(err)\n return\n }\n resolve()\n })\n })\n }\n\n /** Register a single leaf/controller pair on the underlying router. */\n function register<L extends AnyLeafLowProfile>(\n leaf: L,\n def: RouteDef<L, Ctx, Names>,\n ) {\n const method = leaf.method as HttpMethod\n const methodUpper = method.toUpperCase() as Uppercase<HttpMethod>\n const path = leaf.path as string\n const key = keyOf(leaf.method, leaf.path, false)\n const defDebug = def.debug\n let debugName = undefined as Names | undefined\n let routeDebugEmitter: ServerDebugEmitter<Names> | undefined\n if (defDebug) {\n const { debugName: overrideName, ...rest } = defDebug\n const hasOverrides = Object.values(rest).some(\n (value) => value !== undefined,\n )\n if (hasOverrides) {\n routeDebugEmitter = createServerDebugEmitter<Names>({\n ...config.debug,\n ...rest,\n })\n }\n debugName = (overrideName ?? debugName) as Names | undefined\n }\n const activeEmit = routeDebugEmitter?.emit ?? defaultEmitDebug\n const activeDebugMode = routeDebugEmitter?.mode ?? defaultDebugMode\n const emit = (event: RouteServerDebugEvent) => activeEmit(event, debugName)\n const isVerboseDebug = activeDebugMode === 'complete'\n emit({ type: 'register', method: methodUpper, path })\n\n const routeSpecific = (def?.before ?? []).map((mw) =>\n adaptRouteBeforeMw<L, Ctx>(mw),\n )\n const resolvePayloadMw: RequestHandler = async (req, res, next) => {\n const requestUrl = req.originalUrl ?? path\n const startedAt = Date.now()\n let params: Maybe<InferParams<L>> | undefined\n let query: Maybe<InferQuery<L>> | undefined\n let body: Maybe<InferBody<L>> | undefined\n let bodyFiles: BodyFilesMap | undefined\n\n try {\n if (leaf.cfg.bodyFiles && leaf.cfg.bodyFiles.length > 0) {\n const uploadOptions = getMulterOptions(leaf.cfg.bodyFiles)\n if (uploadOptions) {\n const fieldDefs = leaf.cfg.bodyFiles.map(({ name, maxCount }) => ({\n name,\n maxCount,\n }))\n const uploader = multer(uploadOptions).fields(fieldDefs)\n await runMulterHandler(uploader, req, res)\n }\n }\n\n bodyFiles = resolveBodyFilesFromRequest(req, leaf.cfg.bodyFiles)\n params = leaf.cfg.paramsSchema\n ? (lowProfileParse(leaf.cfg.paramsSchema, req.params) as Maybe<\n InferParams<L>\n >)\n : ((Object.keys(req.params || {}).length\n ? (req.params as any)\n : undefined) as Maybe<InferParams<L>>)\n\n const hasQueryKeys =\n req.query && Object.keys(req.query || {}).length > 0\n const parsedQueryInput =\n leaf.cfg.querySchema && hasQueryKeys\n ? (decodeJsonLikeQueryValue(req.query) as Record<string, unknown>)\n : req.query\n if (leaf.cfg.querySchema) {\n try {\n query = lowProfileParse(\n leaf.cfg.querySchema,\n parsedQueryInput as Record<string, unknown>,\n ) as Maybe<InferQuery<L>>\n } catch (err) {\n const parseError = new Error(\n `Query parsing error: ${(err as Error).message ?? String(err)}`,\n )\n ;(parseError as any).raw = JSON.stringify(req.query)\n ;(parseError as any).cause = err\n throw parseError\n }\n } else {\n query = hasQueryKeys ? (req.query as any) : undefined\n }\n\n body = leaf.cfg.bodySchema\n ? (lowProfileParse(leaf.cfg.bodySchema, req.body) as Maybe<\n InferBody<L>\n >)\n : ((req.body !== undefined ? (req.body as any) : undefined) as Maybe<\n InferBody<L>\n >)\n } catch (err) {\n const payloadError = {\n params,\n query,\n body,\n bodyFiles,\n } as RouteRequestPayload<L>\n emit(\n decorateDebugEvent(\n isVerboseDebug,\n {\n type: 'request',\n stage: 'error',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n error: err,\n },\n isVerboseDebug ? payloadError : undefined,\n ),\n )\n next(err as any)\n return\n }\n\n const requestPayload = {\n params,\n query,\n body,\n bodyFiles,\n } as RouteRequestPayload<L>\n setRouteRequestPayload(res, requestPayload)\n next()\n }\n const ctxMw: RequestHandler = async (req, res, next) => {\n const requestUrl = req.originalUrl ?? path\n const startedAt = Date.now()\n emit({\n type: 'buildCtx',\n stage: 'start',\n method: methodUpper,\n path,\n url: requestUrl,\n })\n\n try {\n const ctx = await config.buildCtx({\n req,\n res,\n })\n ;(res.locals as any)[CTX_SYMBOL] = ctx\n emit({\n type: 'buildCtx',\n stage: 'success',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n })\n next()\n } catch (err) {\n emit({\n type: 'buildCtx',\n stage: 'error',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n error: err,\n })\n next(err as any)\n }\n }\n const before: RequestHandler[] = [\n ...(sanitizerMw ? [sanitizerMw] : []),\n ...preCtxMws,\n resolvePayloadMw,\n ctxMw,\n ...postCtxMws,\n ...routeSpecific,\n ]\n\n const wrapped: RequestHandler = async (req, res, next) => {\n const requestUrl = req.originalUrl.split('?')[0] ?? path\n const startedAt = Date.now()\n emit({\n type: 'request',\n stage: 'start',\n method: methodUpper,\n path,\n url: requestUrl,\n })\n const requestPayload = getRouteRequestPayload<L>(res)\n const params = requestPayload.params\n const query = requestPayload.query\n const body = requestPayload.body\n const bodyFiles = requestPayload.bodyFiles\n let responsePayload: InferOutput<L> | undefined\n let hasResponsePayload = false\n const downstreamNext: express.NextFunction = next\n\n const ctx = (res.locals as any)[CTX_SYMBOL] as CtxWithRoutesLogger<Ctx>\n const ctxRoutesLogger = ctx?.routesLogger\n const emitWithCtx = (\n event: RouteServerDebugEvent,\n details?: Partial<RouteServerDebugEvent>,\n ) => {\n const decorated = decorateDebugEvent(isVerboseDebug, event, details)\n if (!config.debug || !config.debug[decorated.type]) {\n return\n }\n if (ctxRoutesLogger) {\n logHandlerDebugWithRoutesLogger(ctxRoutesLogger, decorated)\n } else {\n emit(decorated)\n }\n }\n try {\n const handlerStartedAt = Date.now()\n emitWithCtx(\n {\n type: 'handler',\n stage: 'start',\n method: methodUpper,\n path,\n },\n isVerboseDebug ? { params, query, body, bodyFiles } : undefined,\n )\n\n let result\n try {\n result = await def.handler({\n req,\n res,\n next: downstreamNext,\n ctx,\n params: params as Maybe<InferParams<L>>,\n query: query as Maybe<InferQuery<L>>,\n body: body as Maybe<InferBody<L>>,\n bodyFiles: bodyFiles as RouteRequestPayload<L>['bodyFiles'],\n })\n emitWithCtx(\n {\n type: 'handler',\n stage: 'success',\n method: methodUpper,\n path,\n durationMs: Date.now() - handlerStartedAt,\n },\n isVerboseDebug\n ? {\n params,\n query,\n body,\n bodyFiles,\n ...(result !== undefined ? { output: result } : {}),\n }\n : undefined,\n )\n } catch (e) {\n emitWithCtx(\n {\n type: 'handler',\n stage: 'error',\n method: methodUpper,\n path,\n durationMs: Date.now() - handlerStartedAt,\n error: e,\n },\n isVerboseDebug ? { params, query, body, bodyFiles } : undefined,\n )\n throw e\n }\n\n const out =\n validateOutput && leaf.cfg.outputSchema\n ? lowProfileParse(leaf.cfg.outputSchema, result)\n : result\n responsePayload = out as InferOutput<L>\n hasResponsePayload = true\n def.send ? def.send(res, out as any) : send(res, out)\n\n emitWithCtx(\n {\n type: 'request',\n stage: 'success',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n },\n isVerboseDebug\n ? {\n params,\n query,\n body,\n bodyFiles,\n ...(hasResponsePayload ? { output: responsePayload } : {}),\n }\n : undefined,\n )\n } catch (err) {\n emitWithCtx(\n {\n type: 'request',\n stage: 'error',\n method: methodUpper,\n path,\n url: requestUrl,\n durationMs: Date.now() - startedAt,\n error: err,\n },\n isVerboseDebug ? { params, query, body, bodyFiles } : undefined,\n )\n next(err as any)\n }\n }\n\n ;(router as any)[method](path, ...before, wrapped)\n registered.add(key)\n }\n\n /**\n * Register controller definitions for the provided keys.\n * @param registry Finalized registry of leaves.\n * @param controllers Partial controller map keyed by `\"METHOD /path\"`.\n * @param all Deprecated runtime toggle. Passing any truthy value will throw.\n */\n function registerControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n F extends boolean = false,\n >(registry: R, controllers: PartialControllerMap<R, Ctx, Names>, all?: F) {\n for (const leaf of registry.all) {\n const key = keyOf(leaf.method, leaf.path, false)\n knownLeaves.set(key, leaf)\n }\n\n const missingLeaves: string[] = []\n ;(Object.keys(controllers) as Array<KeysOfRegistry<R>>).forEach((key) => {\n const leaf = registry.byKey[key] as unknown as\n | LeafFromKey<R, typeof key>\n | undefined\n if (!leaf) {\n missingLeaves.push(key)\n return\n }\n const def = controllers[key]\n if (!def) return\n register(leaf as LeafFromKey<R, typeof key>, def)\n })\n if (all && missingLeaves.length > 0) {\n throw new Error(\n `Cannot register controllers: missing definitions for routes: ${missingLeaves.join(\n ', ',\n )}`,\n )\n }\n }\n\n /**\n * Warn about leaves that do not have a registered controller.\n * @param registry Finalized registry of leaves.\n * @param warnLogger Logger used for warning output.\n */\n function warnMissing<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n >(registry: R, warnLogger: { warn: (...args: any[]) => void }) {\n const registeredFromStore = new Set<string>(Array.from(registered))\n if (registeredFromStore.size === 0) {\n collectRoutesFromStack(router).forEach((key) =>\n registeredFromStore.add(key),\n )\n }\n for (const leaf of registry.all) {\n const key = keyOf(leaf.method, leaf.path, false)\n if (!registeredFromStore.has(key)) {\n warnLogger.warn(`No controller registered for route: ${key}`)\n }\n }\n }\n\n return {\n router,\n register,\n registerControllers,\n warnMissingControllers: warnMissing,\n getRegisteredKeys: () => Array.from(registered),\n }\n}\n\n/**\n * Bind only the controllers that are present in the provided map.\n * @param router Express router or app.\n * @param registry Finalized registry produced by `finalize(...)`.\n * @param controllers Partial map of controllers keyed by `\"METHOD /path\"`.\n * @param config Optional route server configuration.\n * @returns The same router instance for chaining.\n */\nexport function bindExpressRoutes<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n>(\n router: Router,\n registry: R,\n controllers: PartialControllerMap<R, Ctx, Names>,\n config: RouteServerConfig<Ctx, Names>,\n) {\n const server = createRRRoute<Ctx, Names>(router, config)\n server.registerControllers(registry, controllers)\n return router\n}\n\n/**\n * Bind controllers for every leaf. Missing entries fail at compile time.\n * @param router Express router or app.\n * @param registry Finalized registry produced by `finalize(...)`.\n * @param controllers Complete map of controllers keyed by `\"METHOD /path\"`.\n * @param config Optional route server configuration.\n * @returns The same router instance for chaining.\n */\nexport function bindAll<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n>(\n router: Router,\n registry: R,\n controllers: {\n [K in KeysOfRegistry<R>]: RouteDef<LeafFromKey<R, K>, Ctx, Names>\n },\n config: RouteServerConfig<Ctx, Names>,\n) {\n const server = createRRRoute<Ctx, Names>(router, config)\n server.registerControllers(registry, controllers)\n return router\n}\n\n// ──────────────────────────────────────────────────────────────────────────────\n// DX helpers\n// ──────────────────────────────────────────────────────────────────────────────\n\n/**\n * Helper for great IntelliSense when authoring controller maps.\n * @returns Function that enforces key names while preserving partial flexibility.\n */\nexport const defineControllers =\n <\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n Ctx = unknown,\n Names extends string = string,\n >() =>\n <M extends PartialControllerMap<R, Ctx, Names>>(m: M) =>\n m\n\n/**\n * Warn about leaves that don't have controllers.\n * Call this during startup to surface missing routes.\n * @param router Express router or app to inspect.\n * @param registry Finalized registry produced by `finalize(...)`.\n * @param logger Logger where warnings are emitted.\n */\nexport function warnMissingControllers<\n R extends {\n all: readonly AnyLeafLowProfile[]\n byKey: Record<string, AnyLeafLowProfile>\n },\n>(router: Router, registry: R, logger: { warn: (...args: any[]) => void }) {\n const registeredStore = (router as any)[REGISTERED_ROUTES_SYMBOL] as\n | Set<string>\n | undefined\n const initial = registeredStore\n ? Array.from(registeredStore)\n : collectRoutesFromStack(router)\n const registeredKeys = new Set<string>(initial)\n\n for (const leaf of registry.all) {\n const k = keyOf(leaf.method, leaf.path, false)\n if (!registeredKeys.has(k)) {\n logger.warn(`No controller registered for route: ${k}`)\n }\n }\n}\n\nexport { buildLowProfileLeaf }\n","import type { Request, RequestHandler } from 'express'\n\nexport type RequestSanitizationTarget = 'params' | 'query' | 'body'\n\nexport type RequestSanitizationCallbackContext = {\n /**\n * Original Express request.\n */\n req: Request\n /**\n * Root request section currently being sanitized.\n */\n target: RequestSanitizationTarget\n /**\n * Path within the selected target.\n * Example: ['profile', 'emails', 0]\n */\n path: ReadonlyArray<string | number>\n /**\n * Current traversal depth for this value.\n */\n depth: number\n}\n\nexport type RequestSanitizationCallback = (\n value: unknown,\n context: RequestSanitizationCallbackContext,\n) => unknown\n\nexport type RequestSanitizationOptions = {\n /**\n * Request sections to sanitize.\n * Defaults to all: params, query, body.\n */\n targets?: RequestSanitizationTarget[]\n /**\n * Remove leading/trailing whitespace from all string values.\n * Defaults to false.\n */\n trimStrings?: boolean\n /**\n * Remove null bytes (`\\u0000`) from strings.\n * Defaults to true.\n */\n stripNullBytes?: boolean\n /**\n * Strip keys used in prototype pollution payloads.\n * Defaults to true.\n */\n stripBlockedKeys?: boolean\n /**\n * Keys to strip when `stripPrototypePollutionKeys` is enabled.\n * Defaults to ['__proto__', 'prototype', 'constructor'].\n */\n blockedKeys?: string[]\n /**\n * Maximum recursion depth while sanitizing nested structures.\n * Defaults to 20.\n */\n maxDepth?: number\n /**\n * Optional callback applied after built-in sanitization.\n * Useful for custom rules (e.g. slug normalization or HTML cleaning).\n */\n customSanitizer?: RequestSanitizationCallback\n /**\n * Log the duration (in ms) of each target sanitization step.\n * Format: [RequestSanitizationProfiler] METHOD URL target=TARGET durationMs=123.456\n * Defaults to false.\n */\n profiler?: boolean\n}\n\ntype NormalizedRequestSanitizationOptions = {\n targets: Set<RequestSanitizationTarget>\n trimStrings: boolean\n stripNullBytes: boolean\n stripBlockedKeys: boolean\n blockedKeys: Set<string>\n maxDepth: number\n customSanitizer?: RequestSanitizationCallback\n profiler: boolean\n}\n\nconst defaultTargets: RequestSanitizationTarget[] = ['params', 'query', 'body']\nconst defaultBlockedKeys = ['__proto__', 'prototype', 'constructor']\nconst defaultMaxDepth = 20\nconst nullBytePattern = /\\u0000/g\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\nconst normalizeOptions = (\n options: RequestSanitizationOptions,\n): NormalizedRequestSanitizationOptions => {\n return {\n targets: new Set(options.targets ?? defaultTargets),\n trimStrings: options.trimStrings ?? false,\n stripNullBytes: options.stripNullBytes ?? true,\n stripBlockedKeys: options.stripBlockedKeys ?? true,\n blockedKeys: new Set(options.blockedKeys ?? defaultBlockedKeys),\n maxDepth: options.maxDepth ?? defaultMaxDepth,\n customSanitizer: options.customSanitizer,\n profiler: options.profiler ?? false,\n }\n}\n\nconst applyCustomSanitizer = (\n value: unknown,\n options: NormalizedRequestSanitizationOptions,\n context: RequestSanitizationCallbackContext,\n): unknown => {\n if (!options.customSanitizer) return value\n return options.customSanitizer(value, context)\n}\n\nconst sanitizeString = (\n value: string,\n options: NormalizedRequestSanitizationOptions,\n) => {\n let next = value\n if (options.stripNullBytes && next.includes('\\u0000')) {\n next = next.replace(nullBytePattern, '')\n }\n if (options.trimStrings) {\n next = next.trim()\n }\n return next\n}\n\nconst sanitizeValue = (\n value: unknown,\n options: NormalizedRequestSanitizationOptions,\n depth: number,\n seen: WeakSet<object>,\n req: Request,\n target: RequestSanitizationTarget,\n path: Array<string | number>,\n): unknown => {\n const context: RequestSanitizationCallbackContext = {\n req,\n target,\n path,\n depth,\n }\n if (depth > options.maxDepth) {\n return applyCustomSanitizer(value, options, context)\n }\n\n if (typeof value === 'string') {\n const sanitized = sanitizeString(value, options)\n return applyCustomSanitizer(sanitized, options, context)\n }\n\n if (value && typeof value === 'object' && seen.has(value as object)) {\n return applyCustomSanitizer(value, options, context)\n }\n\n if (Array.isArray(value)) {\n seen.add(value)\n const next = value.map((entry, index) =>\n sanitizeValue(entry, options, depth + 1, seen, req, target, [\n ...path,\n index,\n ]),\n )\n seen.delete(value)\n return applyCustomSanitizer(next, options, context)\n }\n\n if (!isPlainObject(value)) {\n return applyCustomSanitizer(value, options, context)\n }\n\n seen.add(value)\n\n const source = value as Record<string, unknown>\n const objectTarget =\n Object.getPrototypeOf(source) === null ? Object.create(null) : {}\n for (const [key, entry] of Object.entries(source)) {\n if (options.stripBlockedKeys && options.blockedKeys.has(key)) {\n continue\n }\n ;(objectTarget as Record<string, unknown>)[key] = sanitizeValue(\n entry,\n options,\n depth + 1,\n seen,\n req,\n context.target,\n [...path, key],\n )\n }\n\n seen.delete(value)\n return applyCustomSanitizer(objectTarget, options, context)\n}\n\nconst findPropertyDescriptor = (\n source: object,\n key: PropertyKey,\n): PropertyDescriptor | undefined => {\n let cursor: object | null = source\n while (cursor) {\n const descriptor = Object.getOwnPropertyDescriptor(cursor, key)\n if (descriptor) return descriptor\n cursor = Object.getPrototypeOf(cursor)\n }\n return undefined\n}\n\nconst setRequestQuery = (req: Request, value: unknown): void => {\n const queryDescriptor = findPropertyDescriptor(req as object, 'query')\n if (!queryDescriptor || queryDescriptor.writable || queryDescriptor.set) {\n ;(req as any).query = value\n return\n }\n\n Object.defineProperty(req, 'query', {\n configurable: true,\n enumerable: true,\n writable: true,\n value,\n })\n}\n\nconst profileTargetSanitization = (\n options: NormalizedRequestSanitizationOptions,\n req: Request,\n target: RequestSanitizationTarget,\n sanitize: () => void,\n): void => {\n if (!options.profiler) {\n sanitize()\n return\n }\n\n const startedAt = process.hrtime.bigint()\n try {\n sanitize()\n } finally {\n const durationMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000\n const method = req.method ?? 'UNKNOWN'\n const url = req.originalUrl ?? req.url ?? ''\n console.info(\n `[RequestSanitizationProfiler] ${method} ${url} target=${target} durationMs=${durationMs.toFixed(3)}`,\n )\n }\n}\n\n/**\n * Build a request sanitizer middleware for Express.\n * Can be used in `RouteServerConfig.middleware.sanitizer` or on standalone routers.\n */\nexport const createRequestSanitizationMiddleware = (\n options: RequestSanitizationOptions = {},\n): RequestHandler => {\n const normalized = normalizeOptions(options)\n\n return (req, _res, next) => {\n try {\n if (normalized.targets.has('params') && req.params) {\n profileTargetSanitization(normalized, req, 'params', () => {\n req.params = sanitizeValue(\n req.params,\n normalized,\n 0,\n new WeakSet<object>(),\n req,\n 'params',\n [],\n ) as any\n })\n }\n if (normalized.targets.has('query')) {\n const query = req.query\n if (query) {\n profileTargetSanitization(normalized, req, 'query', () => {\n const sanitizedQuery = sanitizeValue(\n query,\n normalized,\n 0,\n new WeakSet<object>(),\n req,\n 'query',\n [],\n )\n setRequestQuery(req, sanitizedQuery)\n })\n }\n }\n if (normalized.targets.has('body') && req.body !== undefined) {\n profileTargetSanitization(normalized, req, 'body', () => {\n req.body = sanitizeValue(\n req.body,\n normalized,\n 0,\n new WeakSet<object>(),\n req,\n 'body',\n [],\n ) as any\n })\n }\n next()\n } catch (err) {\n next(err as any)\n }\n }\n}\n\n/**\n * Default sanitizer middleware.\n * - strips prototype-pollution keys\n * - strips null bytes from strings\n * - preserves whitespace by default\n */\nexport const requestSanitizationMiddleware: RequestHandler =\n createRequestSanitizationMiddleware()\n","// socket.server.debug.ts\nimport type { IncomingHttpHeaders } from 'http'\n\nexport type SocketServerConfigSnapshot = {\n url?: string\n transport?: string\n protocol?: string\n address?: string\n issued?: number\n time?: string\n query?: Record<string, unknown>\n auth?: Record<string, unknown>\n headers?: IncomingHttpHeaders\n}\n\nexport type SocketServerLifecycleStage =\n | 'server_init'\n | 'connection_listener_installed'\n | 'connection_init'\n | 'connection_handlers_attached'\n | 'connection_cleanup'\n | 'destroy_start'\n | 'destroy_complete'\n | 'connection_cleanup_fallback'\n\nexport type SocketServerHeartbeatPhase = 'ping' | 'pong' | 'skip'\n\nexport type SocketServerDebugEvent =\n | {\n type: 'register'\n action: 'register' | 'unregister'\n event: string\n msg?: string\n }\n | {\n type: 'handler'\n phase:\n | 'receive'\n | 'validation_error'\n | 'handler_success'\n | 'handler_error'\n event: string\n socketId?: string\n nsp?: string\n rooms?: string[]\n raw?: unknown\n issues?: any[]\n error?: unknown\n details?: Record<string, unknown>\n }\n | {\n type: 'emit'\n event: string\n rooms: string[]\n envelope?: unknown\n error?: {\n reason: string\n message?: string\n issues?: unknown\n }\n metadata?: unknown\n note?: string\n }\n | {\n type: 'rooms'\n action: 'join' | 'leave'\n rooms?: string | string[]\n socketId: string\n phase?: string\n payload?: unknown\n issues?: any[]\n }\n | {\n type: 'heartbeat'\n phase: SocketServerHeartbeatPhase\n socketId: string\n payload?: unknown\n issues?: any[]\n error?: boolean\n details?: Record<string, unknown>\n }\n | {\n type: 'config'\n socketId: string\n nsp: string\n snapshot: SocketServerConfigSnapshot\n }\n | {\n type: 'lifecycle'\n stage: SocketServerLifecycleStage\n socketId?: string\n nsp?: string\n details?: Record<string, unknown>\n }\n\nexport type SocketDebugOptions = {\n verbose?: boolean\n /** filters event-based logs (register/handler/emit) by event name */\n only?: string[]\n logger?: (e: SocketServerDebugEvent) => void\n} & {\n [P in SocketServerDebugEvent['type']]?: boolean\n}\n\nexport function createDebugger(options?: SocketDebugOptions) {\n const debug = options ?? {}\n\n return (maybeEvent: string | null, e: SocketServerDebugEvent) => {\n if (!debug.logger) return\n if (!debug[e.type]) return\n\n // only filter applies to event-shaped logs\n if (\n debug.only &&\n maybeEvent &&\n (e.type === 'register' || e.type === 'handler' || e.type === 'emit') &&\n !debug.only.includes(maybeEvent)\n ) {\n return\n }\n\n debug.logger(e)\n }\n}\n","// socket.server.sys.ts\nimport type {\n EventMap,\n Payload,\n SocketConnectionConfigOutput,\n SocketSchemaOutput,\n SysEventName,\n} from '@emeryld/rrroutes-contract'\nimport type { Socket } from 'socket.io'\nimport { z, ZodTypeAny } from 'zod'\nimport type {\n SocketServerConfigSnapshot,\n SocketServerDebugEvent,\n} from './socket.server.debug'\nimport type { HandlerCtxNoAck } from './socket.server.types'\n\nexport type SocketConnectionHelper<Events extends EventMap> = {\n // 1) Strict, typed, autocompleted events\n emit<K extends keyof Events & string>(\n event: K,\n payload: Payload<Events, K>,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n ): void\n\n // 2) Arbitrary events – no type checking on payload\n emit<K extends string>(\n eventName: Exclude<K, keyof Events & string>,\n payload: unknown,\n metadata?: Record<string, unknown>,\n onAck?: (ack: unknown) => void,\n ): void\n}\n\n/** Heartbeat configuration that is not tied to payload shapes (which live in sys event schemas). */\nexport type HeartbeatServerOptions = {\n /** Enable/disable built-in heartbeat handling. Defaults to true. */\n enabled?: boolean\n}\n\nexport type SysServerEventMap<\n Config extends SocketConnectionConfigOutput = SocketConnectionConfigOutput,\n Events extends EventMap = EventMap,\n> = {\n /** Handler for new socket connections. Must call `complete()` to proceed with default connection setup (attaching built-in handlers for heartbeat, room join/leave, disconnect, etc). */\n 'sys:connect': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n /**\n * Call to proceed with the default connection initialization\n * (attaches heartbeat, join, leave and disconnect handlers).\n */\n complete: () => void\n }) => void | Promise<void>\n\n /** Handler for socket disconnections. Must call `cleanup()` to proceed with default disconnect cleanup (removing built-in handlers). */\n 'sys:disconnect': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n /** cleans up all handlers */\n cleanup: () => void\n reason: string\n }) => void | Promise<void>\n\n /** Handler for heartbeat pings. Must return the payload for the corresponding pong response. */\n 'sys:ping': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n ping: SocketSchemaOutput<Config['pingPayload']>\n ctx: HandlerCtxNoAck\n }) =>\n | SocketSchemaOutput<Config['pongPayload']>\n | Promise<SocketSchemaOutput<Config['pongPayload']>>\n\n /** Handler for joining rooms. Must call `join(room)` for each room to be joined. */\n 'sys:room_join': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n rooms: string[]\n meta: SocketSchemaOutput<Config['joinMetaMessage']>\n join: (room: string) => Promise<void>\n }) => void | Promise<void>\n\n /** Handler for leaving rooms. Must call `leave(room)` for each room to be left. */\n 'sys:room_leave': (args: {\n socket: Socket\n helper: SocketConnectionHelper<Events>\n rooms: string[]\n meta: SocketSchemaOutput<Config['leaveMetaMessage']>\n leave: (room: string) => Promise<void>\n }) => void | Promise<void>\n}\n\nconst normalizeError = (error: unknown) => {\n if (error instanceof Error) {\n return { name: error.name, message: error.message }\n }\n if (typeof error === 'string') return { message: error }\n return { message: 'Unknown error' }\n}\n\nconst roomValueSchema = z.union([z.string(), z.array(z.string())])\n\nconst buildRoomPayloadSchema = <Meta extends z.ZodTypeAny>(metaSchema: Meta) =>\n z.object({\n rooms: roomValueSchema,\n meta: metaSchema,\n })\n\ntype DebugFn = (maybeEvent: string | null, e: SocketServerDebugEvent) => void\n\nconst toArray = (rooms?: string[] | string): string[] =>\n rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]\n\nconst snapshotSocketConfig = (socket: Socket): SocketServerConfigSnapshot => {\n const conn = socket.conn as\n | {\n transport?: { name?: string }\n protocol?: string | number\n remoteAddress?: string\n }\n | undefined\n const protocol = conn?.protocol\n return {\n url: socket.handshake.url,\n transport: conn?.transport?.name,\n protocol: protocol != null ? String(protocol) : undefined,\n address: conn?.remoteAddress ?? socket.handshake.address,\n issued: socket.handshake.issued,\n time: socket.handshake.time,\n query: socket.handshake.query as Record<string, unknown>,\n auth: socket.handshake.auth as Record<string, unknown>,\n headers: socket.handshake.headers,\n }\n}\n\nexport function createBuiltInConnectionHandlers<\n C extends SocketConnectionConfigOutput,\n Events extends EventMap,\n>(opts: {\n heartbeat?: HeartbeatServerOptions\n sys: SysServerEventMap<C, Events>\n dbg: DebugFn\n config: C\n createCtx: (socket: Socket) => HandlerCtxNoAck\n debugVerbose?: boolean\n createHelper: (socket: Socket) => SocketConnectionHelper<Events>\n}) {\n const { heartbeat, sys, dbg, config, createCtx, debugVerbose, createHelper } =\n opts\n\n const roomJoinEvent: SysEventName = 'sys:room_join'\n const roomLeaveEvent: SysEventName = 'sys:room_leave'\n const pingEvent: SysEventName = 'sys:ping'\n const pongEvent: SysEventName = 'sys:pong'\n const heartbeatEnabled = heartbeat?.enabled !== false\n\n const joinPayloadSchema = buildRoomPayloadSchema(\n config.joinMetaMessage as any as ZodTypeAny,\n )\n const leavePayloadSchema = buildRoomPayloadSchema(\n config.leaveMetaMessage as any as ZodTypeAny,\n )\n const pingPayloadSchema = config.pingPayload as C['pingPayload']\n const pongPayloadSchema = config.pongPayload as C['pongPayload']\n\n const sysEvents = sys\n const getSysEvent = <\n K extends keyof SysServerEventMap<C, Events> & SysEventName,\n >(\n name: K,\n ) => sysEvents[name]\n\n /** Track per-socket teardown for built-in handlers to ensure explicit cleanup on destroy(). */\n const socketTeardowns = new WeakMap<Socket, (reason: string) => void>()\n\n const builtInConnectionListener = (socket: Socket) => {\n const helper = createHelper(socket)\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_init',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: {\n rooms: Array.from(socket.rooms),\n handshakeIssued: socket.handshake.issued,\n },\n })\n dbg(null, {\n type: 'config',\n socketId: socket.id,\n nsp: socket.nsp.name,\n snapshot: snapshotSocketConfig(socket),\n })\n\n const defaultConnect = () => {\n const includeRaw = debugVerbose === true\n\n // built-in room handlers (wrapped with sys:room_join / sys:room_leave)\n const joinHandler = async (msg: unknown) => {\n dbg(roomJoinEvent, {\n type: 'rooms',\n phase: 'receive',\n action: 'join',\n socketId: socket.id,\n payload: msg,\n })\n const parsed = joinPayloadSchema.safeParse(msg)\n\n if (!parsed.success) {\n socket.emit(`${roomJoinEvent}:error`, {\n eventName: roomJoinEvent,\n issues: parsed.error.issues,\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n action: 'join',\n phase: 'validation_error',\n socketId: socket.id,\n issues: parsed.error.issues,\n payload: msg,\n })\n return\n }\n const list = toArray(parsed.data.rooms)\n\n const join = async (room: string) => {\n await socket.join(room)\n dbg(null, {\n type: 'rooms',\n action: 'join',\n rooms: room,\n socketId: socket.id,\n })\n }\n\n const run = async () => {\n await getSysEvent('sys:room_join')({\n socket,\n helper,\n rooms: list,\n meta: parsed.data.meta as SocketSchemaOutput<C['joinMetaMessage']>,\n join,\n })\n }\n\n try {\n await run()\n } catch (error) {\n socket.emit(`${roomJoinEvent}:error`, {\n error: normalizeError(error),\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n action: 'join',\n phase: 'handler_error',\n payload: includeRaw\n ? { rooms: list, meta: parsed.data.meta }\n : undefined,\n socketId: socket.id,\n issues: [error],\n })\n }\n }\n\n const leaveHandler = async (msg: unknown) => {\n dbg(roomLeaveEvent, {\n type: 'rooms',\n phase: 'receive',\n action: 'leave',\n socketId: socket.id,\n payload: msg,\n })\n const parsed = leavePayloadSchema.safeParse(msg)\n if (!parsed.success) {\n socket.emit(`${roomLeaveEvent}:error`, {\n eventName: roomLeaveEvent,\n issues: parsed.error.issues,\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n action: 'leave',\n phase: 'validation_error',\n socketId: socket.id,\n issues: parsed.error.issues,\n payload: msg,\n })\n return\n }\n\n const list = toArray(parsed.data.rooms)\n\n const leave = async (room: string) => {\n await socket.leave(room)\n dbg(null, {\n type: 'rooms',\n action: 'leave',\n rooms: room,\n socketId: socket.id,\n })\n }\n\n const run = async () => {\n await getSysEvent('sys:room_leave')({\n socket,\n helper,\n rooms: list,\n meta: parsed.data.meta as SocketSchemaOutput<C['leaveMetaMessage']>,\n leave,\n })\n }\n\n try {\n await run()\n } catch (error) {\n socket.emit(`${roomLeaveEvent}:error`, {\n error: normalizeError(error),\n })\n dbg(roomJoinEvent, {\n type: 'rooms',\n phase: 'handler_error',\n payload: { rooms: list, meta: parsed.data.meta },\n socketId: socket.id,\n issues: [error],\n action: 'join',\n })\n }\n }\n\n // heartbeat, wrapped with sys:ping/sys:pong\n const pingHandler = async (msg: unknown) => {\n if (!heartbeatEnabled) {\n dbg(null, {\n type: 'heartbeat',\n phase: 'skip',\n socketId: socket.id,\n details: { reason: 'heartbeat_disabled' },\n error: false,\n })\n return\n }\n\n const parsedPing = pingPayloadSchema.safeParse(msg)\n if (!parsedPing.success) {\n socket.emit(`${pingEvent}:error`, {\n eventName: pingEvent,\n issues: parsedPing.error.issues,\n })\n dbg(null, {\n type: 'heartbeat',\n phase: 'ping',\n socketId: socket.id,\n payload: includeRaw ? msg : undefined,\n issues: parsedPing.error.issues,\n error: true,\n details: { step: 'parse' },\n })\n return\n }\n const ctx = createCtx(socket)\n\n dbg(null, {\n type: 'heartbeat',\n phase: 'ping',\n socketId: socket.id,\n payload: parsedPing.data,\n error: false,\n })\n\n let pongPayload: SocketSchemaOutput<C['pongPayload']>\n try {\n pongPayload = await getSysEvent('sys:ping')({\n ping: parsedPing.data as SocketSchemaOutput<C['pingPayload']>,\n ctx,\n socket,\n helper,\n })\n } catch (error) {\n socket.emit(`${pingEvent}:error`, { error: normalizeError(error) })\n dbg(null, {\n type: 'heartbeat',\n phase: 'ping',\n socketId: socket.id,\n payload: parsedPing.data,\n error: true,\n details: { step: 'sys_handler_error' },\n })\n return\n }\n\n const parsedPong = pongPayloadSchema.safeParse(pongPayload)\n if (!parsedPong.success) {\n socket.emit(`${pongEvent}:error`, {\n eventName: pongEvent,\n issues: parsedPong.error.issues,\n })\n dbg(null, {\n type: 'heartbeat',\n phase: 'pong',\n socketId: socket.id,\n payload: includeRaw ? pongPayload : undefined,\n issues: parsedPong.error.issues,\n error: true,\n details: { step: 'parse' },\n })\n return\n }\n socket.emit(pongEvent, parsedPong.data)\n dbg(null, {\n type: 'heartbeat',\n phase: 'pong',\n socketId: socket.id,\n payload: parsedPong.data,\n error: false,\n })\n }\n\n // attach built-in handlers\n socket.on(roomJoinEvent, joinHandler)\n socket.on(roomLeaveEvent, leaveHandler)\n if (heartbeatEnabled) {\n socket.on(pingEvent, pingHandler)\n }\n\n const cleanup = (reason: string) => {\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_cleanup',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: { reason },\n })\n socket.off(roomJoinEvent, joinHandler)\n socket.off(roomLeaveEvent, leaveHandler)\n if (heartbeatEnabled) {\n socket.off(pingEvent, pingHandler)\n }\n }\n\n socketTeardowns.set(socket, cleanup)\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_handlers_attached',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: {\n heartbeatEnabled,\n joinEvent: roomJoinEvent,\n leaveEvent: roomLeaveEvent,\n pingEvent: heartbeatEnabled ? pingEvent : undefined,\n },\n })\n\n socket.once('disconnect', (reason) => {\n dbg('sys:disconnect', {\n type: 'lifecycle',\n stage: 'connection_cleanup',\n nsp: socket.nsp.name,\n socketId: socket.id,\n details: { reason },\n })\n const defaultDisconnect = () => {\n cleanup(reason)\n socketTeardowns.delete(socket)\n }\n getSysEvent('sys:disconnect')({\n socket,\n helper,\n reason: String(reason),\n cleanup: defaultDisconnect,\n })\n })\n }\n getSysEvent('sys:connect')({\n socket,\n helper,\n complete: defaultConnect,\n })\n }\n\n return {\n builtInConnectionListener,\n socketTeardowns,\n roomJoinEvent,\n roomLeaveEvent,\n pingEvent,\n }\n}\n","// socket.server.index.ts\nimport type {\n EventMap,\n Payload,\n SocketConnectionConfigOutput,\n} from '@emeryld/rrroutes-contract'\nimport { Server, Socket } from 'socket.io'\nimport type { SocketDebugOptions } from './socket.server.debug'\nimport { createDebugger } from './socket.server.debug'\nimport type {\n HeartbeatServerOptions,\n SocketConnectionHelper,\n SysServerEventMap,\n} from './socket.server.sys'\nimport { createBuiltInConnectionHandlers } from './socket.server.sys'\nimport type { HandlerCtx, HandlerCtxNoAck } from './socket.server.types'\n\nconst createBaseHandlerCtx = (socket: Socket): HandlerCtxNoAck => ({\n sentAt: new Date(),\n socket,\n socketId: socket.id,\n nsp: socket.nsp.name,\n rooms: Array.from(socket.rooms),\n user: socket.data?.user,\n scopes: socket.data?.scopes,\n})\n\nconst normalizeError = (error: unknown, verbose?: boolean) => {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n stack: verbose ? error.stack : undefined,\n }\n }\n if (typeof error === 'string') return { message: error }\n if (typeof error === 'object' && error !== null) {\n return verbose ? error : { message: 'Unknown error' }\n }\n return { message: String(error) }\n}\n\nexport interface SocketConnection<T extends EventMap> {\n /** Registers a handler for a specific event. The handler receives the parsed payload and a context object with information about the socket and helper methods. Returns an unregister function to remove the handler. */\n on<K extends keyof T & string>(args: {\n eventName: K\n handler: (payload: Payload<T, K>, ctx: HandlerCtx) => void | Promise<void>\n }): () => void\n\n /** Unregisters all handlers for a specific event. */\n off<K extends keyof T & string>(eventName: K): void\n\n /** Emits an event with a validated payload to specific rooms or sockets. The payload is validated against the schema defined for the event, and an envelope with metadata is sent. If the event is not registered, it falls back to a raw emit without validation or envelope. */\n emit<K extends keyof T & string>(args: {\n eventName: K\n payload: Payload<T, K>\n toRooms?: string[] | string\n metadata?: Record<string, unknown>\n onAck?: (ack: unknown) => void\n }): void\n\n /** Emits an event with an unvalidated payload to specific rooms or sockets. This method does not perform schema validation or envelope wrapping, and is intended for emitting events that are not registered in the events map. */\n emitAny(args: {\n eventName: string\n payload: unknown\n toRooms?: string[] | string\n metadata?: Record<string, unknown>\n onAck?: (ack: unknown) => void\n }): void\n\n /** Destroys the socket connection by removing all event handlers, cleaning up resources, and detaching from the Socket.IO server. After calling this method, the SocketConnection instance should not be used. */\n destroy(): void\n}\n\nexport function createSocketConnections<\n T extends EventMap,\n TConfig extends SocketConnectionConfigOutput = SocketConnectionConfigOutput,\n>(\n /** The Socket.IO server instance to bind to */\n io: Server,\n /** The options for the socket connection, including debug settings, heartbeat configuration, system event handlers, and any custom config values */\n events: T,\n /** The options for the socket connection, including debug settings, heartbeat configuration, system event handlers, and any custom config values */\n opts: {\n /** Optional debug configuration for logging socket events and actions\n * register: when handlers are registered/unregistered\n * handler: when events are received and processed by handlers, including validation results and errors\n * emit: when events are emitted, including payload validation results and errors\n * rooms: when sockets join or leave rooms, including the rooms involved and any issues\n * heartbeat: when heartbeat pings are received and pongs are sent, including any issues or errors\n * config: when a socket connects and receives the initial config snapshot\n * lifecycle: for general lifecycle events like server initialization and destruction\n */\n debug?: SocketDebugOptions\n /** Optional heartbeat configuration to enable connection health checks and automatic disconnections */\n heartbeat?: HeartbeatServerOptions\n /** System event customization (connect / disconnect / ping / pong / room join/leave) */\n sys: SysServerEventMap<TConfig, T>\n /** Custom config values that can be used in system event handlers via the HandlerCtx */\n config: TConfig\n },\n): SocketConnection<T> {\n const dbg = createDebugger(opts?.debug)\n const socketConfig = opts.config\n const heartbeatEnabled = opts?.heartbeat?.enabled !== false\n const eventNames = Object.keys(events)\n dbg(null, {\n type: 'lifecycle',\n stage: 'server_init',\n details: {\n prefinedEvents: eventNames,\n heartbeatEnabled,\n path: io?.path(),\n namespaces: Array.from(io._nsps.keys()),\n transport: io?._opts.transports,\n sysEvents: Object.keys(opts.sys ?? {}),\n },\n })\n\n const getSchema = <K extends keyof T & string>(k: K) => events[k].message\n const toArray = (rooms?: string[] | string): string[] =>\n rooms == null ? [] : Array.isArray(rooms) ? rooms : [rooms]\n const emitToTargets = <K extends keyof T & string>(\n eventName: K,\n payload: Payload<T, K>,\n targets: string[],\n metadata?: Record<string, unknown>,\n ) => {\n const schema = getSchema(eventName)\n const check = schema.safeParse(payload)\n if (!check.success) {\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n ...(opts?.debug?.verbose ? { attemptedPayload: payload } : {}),\n error: {\n reason: 'invalid_payload',\n message: check.error.message,\n issues: check.error.issues,\n },\n metadata,\n })\n throw new Error(\n `Invalid payload for \"${String(eventName)}\": ${check.error.message}`,\n )\n }\n\n const envelope = {\n eventName,\n sentAt: new Date(),\n sentTo: targets,\n data: check.data as Payload<T, K>,\n metadata: metadata ?? {},\n rooms: targets,\n }\n\n if (targets.length === 0) io.emit(String(eventName), envelope)\n else if (targets.length === 1) {\n const sid = targets[0]!\n const sock = io.sockets.sockets.get(sid as any)\n if (sock) {\n sock.emit(String(eventName), envelope)\n } else {\n io.to(targets).emit(String(eventName), envelope)\n }\n } else {\n io.to(targets).emit(String(eventName), envelope)\n }\n\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n envelope: opts?.debug?.verbose ? envelope : undefined,\n })\n }\n const createSocketHelper = (socket: Socket): SocketConnectionHelper<T> => {\n const helper: SocketConnectionHelper<T> = {\n emit(\n eventName: string,\n payload: unknown,\n metadata?: Record<string, unknown>,\n ) {\n if (Object.prototype.hasOwnProperty.call(events, eventName)) {\n // Known / registered event -> use schema + envelope\n emitToTargets(\n eventName as keyof T & string,\n payload as Payload<T, keyof T & string>,\n [socket.id],\n metadata,\n )\n } else {\n // Unknown / non-registered event -> raw emit, no schema/envelope\n socket.emit(eventName, payload)\n }\n },\n }\n\n return helper\n }\n\n // registrations\n const registrations = new Map<\n string,\n Set<{\n connectionListener: (socket: Socket) => void\n socketListeners: WeakMap<Socket, (raw: unknown) => void>\n }>\n >()\n\n const addRegistration = (\n eventName: string,\n reg: {\n connectionListener: (socket: Socket) => void\n socketListeners: WeakMap<Socket, (raw: unknown) => void>\n },\n ) => {\n let set = registrations.get(eventName)\n if (!set) {\n set = new Set()\n registrations.set(eventName, set)\n }\n set.add(reg)\n }\n\n const removeAllForEvent = (eventName: string) => {\n const set = registrations.get(eventName)\n if (!set) {\n dbg(null, {\n type: 'register',\n event: eventName,\n action: 'unregister',\n msg: 'no handlers registered',\n })\n return\n }\n for (const reg of set) {\n io.off('connection', reg.connectionListener)\n for (const socket of io.sockets.sockets.values()) {\n const wrapped = reg.socketListeners.get(socket)\n if (wrapped) socket.off(String(eventName), wrapped)\n }\n }\n registrations.delete(eventName)\n dbg(eventName, {\n type: 'register',\n action: 'unregister',\n event: eventName,\n msg: 'unregistered',\n })\n }\n\n const {\n builtInConnectionListener,\n socketTeardowns,\n roomJoinEvent,\n roomLeaveEvent,\n pingEvent,\n } = createBuiltInConnectionHandlers<TConfig, T>({\n heartbeat: opts?.heartbeat,\n sys: opts.sys,\n dbg,\n config: socketConfig,\n createCtx: createBaseHandlerCtx,\n debugVerbose: opts?.debug?.verbose === true,\n createHelper: createSocketHelper,\n })\n\n // install built-in connection listener\n io.on('connection', builtInConnectionListener)\n\n const conn = {\n on<K extends keyof T & string>({\n eventName,\n handler,\n }: {\n eventName: K\n handler: (payload: Payload<T, K>, ctx: HandlerCtx) => void | Promise<void>\n }): () => void {\n const socketListeners = new WeakMap<Socket, (raw: unknown) => void>()\n\n const connectionListener = (socket: Socket) => {\n const wrapped = async (raw: unknown) => {\n const schema = getSchema(eventName)\n const parsed = schema.safeParse(raw)\n\n const ctx = createBaseHandlerCtx(socket)\n\n dbg(String(eventName), {\n type: 'handler',\n phase: 'receive',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n rooms: ctx.rooms,\n raw: opts?.debug?.verbose ? raw : undefined,\n })\n\n if (!parsed.success) {\n socket.emit(`${String(eventName)}:error`, {\n eventName,\n sentAt: ctx.sentAt,\n issues: parsed.error.issues,\n })\n dbg(String(eventName), {\n type: 'handler',\n phase: 'validation_error',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n issues: parsed.error.issues,\n })\n return\n }\n\n try {\n await handler(parsed.data as Payload<T, K>, ctx)\n dbg(String(eventName), {\n type: 'handler',\n phase: 'handler_success',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n rooms: ctx.rooms,\n })\n } catch (error) {\n dbg(String(eventName), {\n type: 'handler',\n phase: 'handler_error',\n event: String(eventName),\n socketId: ctx.socketId,\n nsp: ctx.nsp,\n rooms: ctx.rooms,\n error,\n })\n socket.emit(`${String(eventName)}:error`, {\n eventName,\n sentAt: ctx.sentAt,\n error: normalizeError(error, opts?.debug?.verbose),\n })\n }\n }\n\n socketListeners.set(socket, wrapped)\n socket.on(String(eventName), wrapped)\n socket.once('disconnect', () => {\n const w = socketListeners.get(socket)\n if (w) socket.off(String(eventName), w)\n })\n }\n\n io.on('connection', connectionListener)\n addRegistration(String(eventName), {\n connectionListener,\n socketListeners,\n })\n dbg(String(eventName), {\n type: 'register',\n action: 'register',\n event: String(eventName),\n })\n\n return () => {\n const set = registrations.get(String(eventName))\n if (!set) {\n dbg(null, {\n type: 'register',\n action: 'unregister',\n event: String(eventName),\n msg: `No registration under ${eventName}`,\n })\n return\n }\n for (const reg of Array.from(set)) {\n if (reg.connectionListener === connectionListener) {\n io.off('connection', reg.connectionListener)\n for (const socket of io.sockets.sockets.values()) {\n const wrapped = reg.socketListeners.get(socket)\n if (wrapped) socket.off(String(eventName), wrapped)\n }\n set.delete(reg)\n break\n }\n }\n if (set.size === 0) registrations.delete(String(eventName))\n dbg(String(eventName), {\n type: 'register',\n action: 'unregister',\n event: String(eventName),\n })\n }\n },\n\n off<K extends keyof T & string>(eventName: K): void {\n removeAllForEvent(String(eventName))\n },\n\n emitAny({\n eventName,\n payload,\n rooms,\n metadata,\n }: {\n eventName: string\n payload: unknown\n rooms?: string[] | string\n metadata?: Record<string, unknown>\n }): void {\n const targets = toArray(rooms)\n\n if (Object.prototype.hasOwnProperty.call(events, eventName)) {\n // Known/registered event -> validated path (schema + envelope)\n emitToTargets(\n eventName as keyof T & string,\n payload as Payload<T, keyof T & string>,\n targets,\n metadata,\n )\n return\n }\n\n // Unknown/non-registered event -> raw emit (no zod, no envelope)\n const envelopeOrPayload = payload\n if (targets.length === 0) io.emit(eventName, envelopeOrPayload)\n else if (targets.length === 1) {\n const sid = targets[0]!\n const sock = io.sockets.sockets.get(sid as any)\n if (sock) {\n sock.emit(eventName, envelopeOrPayload)\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n envelope: opts?.debug?.verbose ? envelopeOrPayload : undefined,\n note: 'raw_emit_unregistered_event',\n })\n },\n emit<K extends keyof T & string>({\n eventName,\n payload,\n toRooms: rooms,\n metadata,\n onAck,\n }: {\n eventName: K\n payload: Payload<T, K>\n toRooms?: string[] | string\n metadata?: Record<string, unknown>\n onAck?: (ack: unknown) => void\n }): void {\n const targets = toArray(rooms)\n\n if (Object.prototype.hasOwnProperty.call(events, eventName)) {\n // Known/registered event -> validated path (schema + envelope)\n emitToTargets(\n eventName as keyof T & string,\n payload as Payload<T, keyof T & string>,\n targets,\n metadata,\n )\n return\n }\n\n // Unknown/non-registered event -> raw emit (no zod, no envelope)\n const envelopeOrPayload = payload\n if (targets.length === 0) io.emit(eventName, envelopeOrPayload)\n else if (targets.length === 1) {\n const sid = targets[0]!\n const sock = io.sockets.sockets.get(sid as any)\n if (sock) {\n sock.emit(eventName, envelopeOrPayload)\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n } else {\n io.to(targets).emit(eventName, envelopeOrPayload)\n }\n\n dbg(String(eventName), {\n type: 'emit',\n event: String(eventName),\n rooms: targets,\n envelope: opts?.debug?.verbose ? envelopeOrPayload : undefined,\n note: 'raw_emit_unregistered_event',\n })\n },\n\n destroy(): void {\n dbg(null, {\n type: 'lifecycle',\n stage: 'destroy_start',\n details: {\n socketCount: io.sockets.sockets.size,\n registrationCount: registrations.size,\n },\n })\n // 1) Remove built-in connection listener so no new sockets get handlers\n io.off('connection', builtInConnectionListener)\n\n // 2) Cleanup built-in handlers for all current sockets and leave rooms\n for (const socket of io.sockets.sockets.values()) {\n const cleanup = socketTeardowns.get(socket)\n if (cleanup) {\n cleanup('destroy')\n socketTeardowns.delete(socket)\n } else {\n dbg(null, {\n type: 'lifecycle',\n stage: 'connection_cleanup_fallback',\n socketId: socket.id,\n nsp: socket.nsp.name,\n details: { reason: 'teardown_missing' },\n })\n // Fallback if socket was attached before map population\n try {\n socket.removeAllListeners(roomJoinEvent)\n socket.removeAllListeners(roomLeaveEvent)\n socket.removeAllListeners(pingEvent)\n } catch {\n // noop\n }\n }\n }\n\n // 3) Remove all user-registered event listeners and their connection hooks\n for (const eventName of Array.from(registrations.keys())) {\n removeAllForEvent(eventName)\n }\n\n // 4) Defensive: clear any residual maps\n registrations.clear()\n dbg(null, {\n type: 'lifecycle',\n stage: 'destroy_complete',\n details: {\n socketCount: io.sockets.sockets.size,\n registrationCount: registrations.size,\n },\n })\n },\n } as const satisfies SocketConnection<T>\n\n return conn\n}\n\nexport type {\n SocketDebugOptions,\n SocketServerConfigSnapshot,\n SocketServerDebugEvent,\n SocketServerHeartbeatPhase,\n SocketServerLifecycleStage,\n} from './socket.server.debug'\nexport type {\n HeartbeatServerOptions,\n SocketConnectionHelper,\n SysServerEventMap,\n} from './socket.server.sys'\nexport type { HandlerCtx } from './socket.server.types'\nexport type { EventMap, Payload }\n","import type { IncomingHttpHeaders } from 'http'\nimport type { Socket } from 'socket.io'\n\nexport type ConnectionMiddlewareStage = 'incoming'\n\nexport type ConnectionMiddlewareContext = {\n socketId?: string\n nsp?: string\n rooms: string[]\n user?: unknown\n scopes?: string[]\n address?: string\n transport?: string\n protocol?: string\n handshake: {\n url?: string\n issued?: number\n time?: string\n query?: Record<string, unknown>\n auth?: Record<string, unknown>\n headers?: IncomingHttpHeaders\n }\n}\n\nexport type ConnectionMiddlewareEvent = {\n type: 'connection'\n stage: ConnectionMiddlewareStage\n timestamp: Date\n context: ConnectionMiddlewareContext\n}\n\nexport type ConnectionLoggingMiddlewareOptions = {\n /**\n * Custom logger invoked with the structured event.\n * Defaults to console.info.\n */\n logger?: (event: ConnectionMiddlewareEvent) => void\n /**\n * Include raw headers from the handshake. Defaults to false to avoid leaking PII.\n */\n includeHeaders?: boolean\n /**\n * List of auth keys that should be redacted (case-insensitive). Defaults to ['authorization'].\n */\n redactAuthKeys?: string[]\n}\n\nconst defaultRedactedValue = '[REDACTED]'\n\nconst defaultLogger = (event: ConnectionMiddlewareEvent) => {\n const {\n stage,\n context: { socketId, nsp, address, transport, handshake },\n } = event\n // eslint-disable-next-line no-console\n console.info('[socket-connection]', {\n stage,\n socketId,\n nsp,\n address,\n transport,\n url: handshake.url,\n query: handshake.query,\n auth: handshake.auth,\n })\n}\n\nconst redactAuth = (\n auth: Record<string, unknown> | undefined,\n redactKeys: Set<string>,\n): Record<string, unknown> | undefined => {\n if (!auth) return undefined\n if (redactKeys.size === 0) return auth\n\n const clone: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(auth)) {\n const normalizedKey = key.toLowerCase()\n clone[key] = redactKeys.has(normalizedKey) ? defaultRedactedValue : value\n }\n return clone\n}\n\nconst buildContext = (\n socket: Socket,\n includeHeaders: boolean,\n redactKeys: Set<string>,\n): ConnectionMiddlewareContext => {\n const conn = socket.conn as\n | {\n remoteAddress?: string\n transport?: { name?: string }\n protocol?: string | number\n }\n | undefined\n\n const handshake = socket.handshake ?? {}\n\n const protocolValue = conn?.protocol\n\n return {\n socketId: socket.id,\n nsp: socket.nsp?.name,\n rooms: Array.from(socket.rooms ?? []),\n user: (socket.data as any)?.user,\n scopes: (socket.data as any)?.scopes,\n address: conn?.remoteAddress ?? (handshake as any).address,\n transport: conn?.transport?.name,\n protocol: protocolValue != null ? String(protocolValue) : undefined,\n handshake: {\n url: handshake.url,\n issued: handshake.issued,\n time: handshake.time,\n query: handshake.query as Record<string, unknown>,\n auth: redactAuth(handshake.auth as Record<string, unknown>, redactKeys),\n headers: includeHeaders\n ? (handshake.headers as IncomingHttpHeaders)\n : undefined,\n },\n }\n}\n\nexport const createConnectionLoggingMiddleware = (\n options: ConnectionLoggingMiddlewareOptions = {},\n) => {\n const logger = options.logger ?? defaultLogger\n const includeHeaders = options.includeHeaders ?? false\n const redactKeys = new Set(\n (options.redactAuthKeys ?? ['authorization', 'token']).map((key) =>\n key.toLowerCase(),\n ),\n )\n\n return (socket: Socket, next: (err?: Error) => void) => {\n const context = buildContext(socket, includeHeaders, redactKeys)\n logger({\n type: 'connection',\n stage: 'incoming',\n timestamp: new Date(),\n context,\n })\n next()\n }\n}\n\nexport type ConnectionLoggingMiddleware = ReturnType<\n typeof createConnectionLoggingMiddleware\n>\n"],"mappings":"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","names":["import_rrroutes_contract","isPlainObject","multer","normalizeError","toArray"]}
|