@emeryld/rrroutes-server 2.2.16 → 2.3.0

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/README.md CHANGED
@@ -22,18 +22,20 @@ This package peers with `@emeryld/rrroutes-contract` and bundles `zod`.
22
22
  ## Quick start: HTTP routes
23
23
 
24
24
  ```ts
25
- import express from 'express';
26
- import { finalize, resource } from '@emeryld/rrroutes-contract';
27
- import { createRRRoute, defineControllers } from '@emeryld/rrroutes-server';
28
- import multer from 'multer';
29
- import { z } from 'zod';
25
+ import express from 'express'
26
+ import { finalize, resource } from '@emeryld/rrroutes-contract'
27
+ import { createRRRoute, defineControllers } from '@emeryld/rrroutes-server'
28
+ import multer from 'multer'
29
+ import { z } from 'zod'
30
30
 
31
31
  // 1) Build & finalize contracts (usually elsewhere in your app)
32
32
  const leaves = resource('/api')
33
33
  .sub('profiles', (r) =>
34
34
  r
35
35
  .get({
36
- outputSchema: z.array(z.object({ id: z.string().uuid(), name: z.string() })),
36
+ outputSchema: z.array(
37
+ z.object({ id: z.string().uuid(), name: z.string() }),
38
+ ),
37
39
  description: 'List profiles',
38
40
  })
39
41
  .routeParameter('profileId', z.string().uuid(), (p) =>
@@ -55,56 +57,73 @@ const leaves = resource('/api')
55
57
  )
56
58
  .done(),
57
59
  )
58
- .done();
60
+ .done()
59
61
 
60
- const registry = finalize(leaves);
62
+ const registry = finalize(leaves)
61
63
 
62
64
  // 2) Wire Express with ctx + derived upload middleware
63
- const upload = multer({ storage: multer.memoryStorage() });
64
- const app = express();
65
+ const upload = multer({ storage: multer.memoryStorage() })
66
+ const app = express()
65
67
  const server = createRRRoute(app, {
66
- buildCtx: async (req) => ({ user: await loadUser(req), routesLogger: console }), // ctx lives on res.locals[CTX_SYMBOL]
68
+ buildCtx: async (req) => ({
69
+ user: await loadUser(req),
70
+ routesLogger: console,
71
+ }), // ctx lives on res.locals[CTX_SYMBOL]
67
72
  globalMiddleware: {
68
73
  before: [
69
74
  ({ ctx, next }) => {
70
- if (!ctx.user) throw new Error('unauthorized');
71
- next();
75
+ if (!ctx.user) throw new Error('unauthorized')
76
+ next()
72
77
  },
73
78
  ],
74
79
  },
75
80
  fromCfg: {
76
- upload: (files) => (files && files.length > 0 ? [upload.fields(files)] : []),
81
+ upload: (files) =>
82
+ files && files.length > 0 ? [upload.fields(files)] : [],
77
83
  },
78
84
  validateOutput: true, // parse handler returns with outputSchema (default true)
79
- debug: { request: true, handler: true, verbose: true, logger: (e) => console.debug(e) },
80
- });
85
+ debug: {
86
+ request: true,
87
+ handler: true,
88
+ verbose: true,
89
+ logger: (e) => console.debug(e),
90
+ },
91
+ })
81
92
 
82
93
  // 3) Author controllers with enforced keys/types
83
- const controllers = defineControllers<typeof registry, { user: { id: string } }>()({
94
+ const controllers = defineControllers<
95
+ typeof registry,
96
+ { user: { id: string } }
97
+ >()({
84
98
  'GET /api/profiles': {
85
99
  handler: async ({ ctx }) => {
86
- return fetchProfilesFor(ctx.user.id);
100
+ return fetchProfilesFor(ctx.user.id)
87
101
  },
88
102
  },
89
103
  'PATCH /api/profiles/:profileId': {
90
- before: [({ ctx, params, next }) => (params.profileId === ctx.user.id ? next() : next(new Error('Forbidden')))],
104
+ before: [
105
+ ({ ctx, params, next }) =>
106
+ params.profileId === ctx.user.id
107
+ ? next()
108
+ : next(new Error('Forbidden')),
109
+ ],
91
110
  handler: async ({ params, body }) => {
92
- return updateProfile(params.profileId, body);
111
+ return updateProfile(params.profileId, body)
93
112
  },
94
113
  },
95
114
  'PUT /api/profiles/:profileId/avatar': {
96
115
  handler: async ({ req, params }) => {
97
- const avatar = (req.files as any)?.avatar?.[0];
98
- await storeAvatar(params.profileId, avatar?.buffer);
99
- return { ok: true };
116
+ const avatar = (req.files as any)?.avatar?.[0]
117
+ await storeAvatar(params.profileId, avatar?.buffer)
118
+ return { ok: true }
100
119
  },
101
120
  },
102
- });
121
+ })
103
122
 
104
- server.registerControllers(registry, controllers);
105
- server.warnMissingControllers(registry, console); // warns in dev about unhandled leaves
123
+ server.registerControllers(registry, controllers)
124
+ server.warnMissingControllers(registry, console) // warns in dev about unhandled leaves
106
125
 
107
- app.listen(3000);
126
+ app.listen(3000)
108
127
  ```
109
128
 
110
129
  ## Detailed usage (HTTP)
@@ -112,19 +131,26 @@ app.listen(3000);
112
131
  ### Controller maps and typing
113
132
 
114
133
  ```ts
115
- import { defineControllers, bindExpressRoutes } from '@emeryld/rrroutes-server';
134
+ import { defineControllers, bindExpressRoutes } from '@emeryld/rrroutes-server'
116
135
 
117
136
  const controllers = defineControllers<typeof registry, Ctx>()({
118
- 'POST /v1/articles': { handler: async ({ body, ctx }) => createArticle(ctx.user.id, body) },
119
- });
137
+ 'POST /v1/articles': {
138
+ handler: async ({ body, ctx }) => createArticle(ctx.user.id, body),
139
+ },
140
+ })
120
141
 
121
142
  // register only the controllers provided (missing keys are ignored)
122
143
  bindExpressRoutes(app, registry, controllers, {
123
144
  buildCtx: () => ({ user: { id: '123' } }),
124
- });
145
+ })
125
146
 
126
147
  // or enforce every key is present at compile time
127
- bindExpressRoutes(app, registry, controllers as { [K in keyof typeof registry.byKey]: any }, { buildCtx });
148
+ bindExpressRoutes(
149
+ app,
150
+ registry,
151
+ controllers as { [K in keyof typeof registry.byKey]: any },
152
+ { buildCtx },
153
+ )
128
154
  ```
129
155
 
130
156
  - `defineControllers<Registry, Ctx>()(map)` keeps literal `"METHOD /path"` keys accurate and infers params/query/body/output types per leaf.
@@ -136,24 +162,24 @@ bindExpressRoutes(app, registry, controllers as { [K in keyof typeof registry.by
136
162
  Order: `buildCtx` → `global.before` → `fromCfg` (derived) → `route.before` → handler → `route.after` → `global.after`.
137
163
 
138
164
  ```ts
139
- import { getCtx, CtxRequestHandler } from '@emeryld/rrroutes-server';
165
+ import { getCtx, CtxRequestHandler } from '@emeryld/rrroutes-server'
140
166
 
141
167
  const audit: CtxRequestHandler<Ctx> = ({ ctx, req, next }) => {
142
- ctx.routesLogger?.info?.('audit', { user: ctx.user?.id, path: req.path });
143
- next();
144
- };
168
+ ctx.routesLogger?.info?.('audit', { user: ctx.user?.id, path: req.path })
169
+ next()
170
+ }
145
171
 
146
172
  const server = createRRRoute(app, {
147
173
  buildCtx: (req, res) => ({ user: res.locals.user, routesLogger: console }),
148
174
  globalMiddleware: { before: [audit] },
149
- });
175
+ })
150
176
 
151
177
  // Inside any Express middleware (even outside route.before/after), use getCtx to retrieve typed ctx:
152
178
  app.use((req, res, next) => {
153
- const ctx = getCtx<Ctx>(res);
154
- ctx?.routesLogger?.debug?.('in arbitrary middleware');
155
- next();
156
- });
179
+ const ctx = getCtx<Ctx>(res)
180
+ ctx?.routesLogger?.debug?.('in arbitrary middleware')
181
+ next()
182
+ })
157
183
  ```
158
184
 
159
185
  - `CtxRequestHandler` receives `{ req, res, next, ctx }` with your typed ctx.
@@ -164,17 +190,18 @@ app.use((req, res, next) => {
164
190
  Use `fromCfg.upload` to attach middleware when a leaf declares `bodyFiles`.
165
191
 
166
192
  ```ts
167
- import multer from 'multer';
168
- import { FileField } from '@emeryld/rrroutes-contract';
193
+ import multer from 'multer'
194
+ import { FileField } from '@emeryld/rrroutes-contract'
169
195
 
170
- const upload = multer({ storage: multer.memoryStorage() });
196
+ const upload = multer({ storage: multer.memoryStorage() })
171
197
 
172
198
  const server = createRRRoute(app, {
173
199
  buildCtx,
174
200
  fromCfg: {
175
- upload: (files: FileField[] | undefined) => (files?.length ? [upload.fields(files)] : []),
201
+ upload: (files: FileField[] | undefined) =>
202
+ files?.length ? [upload.fields(files)] : [],
176
203
  },
177
- });
204
+ })
178
205
  ```
179
206
 
180
207
  ### Output validation and custom responders
@@ -186,7 +213,7 @@ const server = createRRRoute(app, {
186
213
  const server = createRRRoute(app, {
187
214
  buildCtx,
188
215
  send: (res, data) => res.status(201).json({ data }),
189
- });
216
+ })
190
217
  ```
191
218
 
192
219
  ### Debug logging
@@ -203,7 +230,7 @@ const server = createRRRoute(app, {
203
230
  only: ['users:list'], // filter by RouteDef.debug?.debugName
204
231
  logger: (event) => console.log('[route-debug]', event),
205
232
  },
206
- });
233
+ })
207
234
  ```
208
235
 
209
236
  Per-route overrides:
@@ -212,7 +239,7 @@ Per-route overrides:
212
239
  server.register(registry.byKey['GET /api/profiles'], {
213
240
  debug: { handler: true, debugName: 'profiles:list' },
214
241
  handler: async () => [],
215
- });
242
+ })
216
243
  ```
217
244
 
218
245
  Context logger passthrough: if `buildCtx` provides `routesLogger`, handler debug events also flow to that logger (useful for request-scoped loggers).
@@ -228,33 +255,45 @@ Context logger passthrough: if `buildCtx` provides `routesLogger`, handler debug
228
255
  `@emeryld/rrroutes-server` also ships a typed Socket.IO wrapper that pairs with `defineSocketEvents` from the contract package.
229
256
 
230
257
  ```ts
231
- import { Server } from 'socket.io';
232
- import { defineSocketEvents } from '@emeryld/rrroutes-contract';
233
- import { createSocketConnections, createConnectionLoggingMiddleware } from '@emeryld/rrroutes-server';
234
- import { z } from 'zod';
258
+ import { Server } from 'socket.io'
259
+ import { defineSocketEvents } from '@emeryld/rrroutes-contract'
260
+ import {
261
+ createSocketConnections,
262
+ createConnectionLoggingMiddleware,
263
+ } from '@emeryld/rrroutes-server'
264
+ import { z } from 'zod'
235
265
 
236
266
  const { config, events } = defineSocketEvents(
237
267
  {
238
268
  joinMetaMessage: z.object({ room: z.string() }),
239
269
  leaveMetaMessage: z.object({ room: z.string() }),
240
270
  pingPayload: z.object({ sentAt: z.string() }),
241
- pongPayload: z.object({ sentAt: z.string(), sinceMs: z.number().optional() }),
271
+ pongPayload: z.object({
272
+ sentAt: z.string(),
273
+ sinceMs: z.number().optional(),
274
+ }),
242
275
  },
243
276
  {
244
- 'chat:message': { message: z.object({ roomId: z.string(), text: z.string(), userId: z.string() }) },
277
+ 'chat:message': {
278
+ message: z.object({
279
+ roomId: z.string(),
280
+ text: z.string(),
281
+ userId: z.string(),
282
+ }),
283
+ },
245
284
  },
246
- );
285
+ )
247
286
 
248
- const io = new Server(3000, { cors: { origin: '*', credentials: true } });
249
- io.use(createConnectionLoggingMiddleware({ includeHeaders: false }));
287
+ const io = new Server(3000, { cors: { origin: '*', credentials: true } })
288
+ io.use(createConnectionLoggingMiddleware({ includeHeaders: false }))
250
289
 
251
290
  const sockets = createSocketConnections(io, events, {
252
291
  config,
253
292
  heartbeat: { enabled: true }, // enables sys:ping/sys:pong using config schemas
254
293
  sys: {
255
294
  'sys:connect': async ({ socket, complete }) => {
256
- socket.data.user = await loadUserFromHandshake(socket.handshake);
257
- await complete(); // attach built-ins (ping/pong, join/leave)
295
+ socket.data.user = await loadUserFromHandshake(socket.handshake)
296
+ await complete() // attach built-ins (ping/pong, join/leave)
258
297
  },
259
298
  'sys:ping': async ({ socket, ping }) => ({
260
299
  sentAt: ping.sentAt,
@@ -268,17 +307,17 @@ const sockets = createSocketConnections(io, events, {
268
307
  verbose: true,
269
308
  logger: (e) => console.debug('[socket-debug]', e),
270
309
  },
271
- });
310
+ })
272
311
 
273
312
  // Validate inbound payloads + emit envelopes
274
313
  sockets.on('chat:message', async (payload, ctx) => {
275
- await saveMessage(payload, ctx.user);
314
+ await saveMessage(payload, ctx.user)
276
315
  // broadcast to room participants
277
- sockets.emit('chat:message', payload, payload.roomId);
278
- });
316
+ sockets.emit('chat:message', payload, payload.roomId)
317
+ })
279
318
 
280
319
  // Graceful shutdown
281
- process.on('SIGTERM', () => sockets.destroy());
320
+ process.on('SIGTERM', () => sockets.destroy())
282
321
  ```
283
322
 
284
323
  - Payloads are validated on both emit and receive; invalid payloads trigger `<event>:error` with Zod issues.
package/dist/index.cjs CHANGED
@@ -43,7 +43,10 @@ var serverDebugEventTypes = [
43
43
  var noopServerEmit = () => {
44
44
  };
45
45
  function createServerDebugEmitter(option) {
46
- const disabled = { emit: noopServerEmit, mode: "minimal" };
46
+ const disabled = {
47
+ emit: noopServerEmit,
48
+ mode: "minimal"
49
+ };
47
50
  if (!option) return disabled;
48
51
  if (typeof option === "object") {
49
52
  const toggles = option;
@@ -66,8 +69,11 @@ function createServerDebugEmitter(option) {
66
69
  }
67
70
  var keyOf = (leaf) => `${leaf.method.toUpperCase()} ${leaf.path}`;
68
71
  var CTX_SYMBOL = Symbol.for("typedLeaves.ctx");
69
- var AFTER_HANDLER_NEXT_SYMBOL = Symbol.for("typedLeaves.afterHandlerNext");
72
+ var AFTER_HANDLER_NEXT_SYMBOL = Symbol.for(
73
+ "typedLeaves.afterHandlerNext"
74
+ );
70
75
  function setAfterHandlerNext(res, value) {
76
+ ;
71
77
  res.locals[AFTER_HANDLER_NEXT_SYMBOL] = value;
72
78
  }
73
79
  function handlerInvokedNext(res) {
@@ -110,9 +116,11 @@ function logHandlerDebugWithRoutesLogger(logger, event) {
110
116
  event
111
117
  ];
112
118
  if (event.stage === "error") {
119
+ ;
113
120
  (logger.error ?? logger.warn ?? logger.debug ?? logger.info ?? logger.log ?? logger.system)?.call(logger, ...payload);
114
121
  return;
115
122
  }
123
+ ;
116
124
  (logger.debug ?? logger.verbose ?? logger.info ?? logger.log ?? logger.system)?.call(logger, ...payload);
117
125
  }
118
126
  var defaultSend = (res, data) => {
@@ -134,7 +142,9 @@ function collectRoutesFromStack(appOrRouter) {
134
142
  const route = layer && layer.route;
135
143
  if (!route) continue;
136
144
  const paths = Array.isArray(route.path) ? route.path : [route.path];
137
- const methodEntries = Object.entries(route.methods ?? {}).filter(([, enabled]) => enabled);
145
+ const methodEntries = Object.entries(route.methods ?? {}).filter(
146
+ ([, enabled]) => enabled
147
+ );
138
148
  for (const path of paths) {
139
149
  for (const [method] of methodEntries) {
140
150
  result.push(`${method.toUpperCase()} ${path}`);
@@ -175,11 +185,14 @@ function createRRRoute(router, config) {
175
185
  let routeDebugEmitter;
176
186
  if (defDebug) {
177
187
  const { debugName: overrideName, ...rest } = defDebug;
178
- const hasOverrides = Object.values(rest).some((value) => value !== void 0);
188
+ const hasOverrides = Object.values(rest).some(
189
+ (value) => value !== void 0
190
+ );
179
191
  if (hasOverrides) {
180
- routeDebugEmitter = createServerDebugEmitter(
181
- { ...config.debug, ...rest }
182
- );
192
+ routeDebugEmitter = createServerDebugEmitter({
193
+ ...config.debug,
194
+ ...rest
195
+ });
183
196
  }
184
197
  debugName = overrideName ?? debugName;
185
198
  }
@@ -193,7 +206,13 @@ function createRRRoute(router, config) {
193
206
  const ctxMw = async (req, res, next) => {
194
207
  const requestUrl = req.originalUrl ?? path;
195
208
  const startedAt = Date.now();
196
- emit({ type: "buildCtx", stage: "start", method: methodUpper, path, url: requestUrl });
209
+ emit({
210
+ type: "buildCtx",
211
+ stage: "start",
212
+ method: methodUpper,
213
+ path,
214
+ url: requestUrl
215
+ });
197
216
  try {
198
217
  const ctx = await config.buildCtx(req, res);
199
218
  res.locals[CTX_SYMBOL] = ctx;
@@ -220,11 +239,22 @@ function createRRRoute(router, config) {
220
239
  next(err);
221
240
  }
222
241
  };
223
- const before = [ctxMw, ...globalBeforeMws, ...derived, ...routeSpecific];
242
+ const before = [
243
+ ctxMw,
244
+ ...globalBeforeMws,
245
+ ...derived,
246
+ ...routeSpecific
247
+ ];
224
248
  const wrapped = async (req, res, next) => {
225
249
  const requestUrl = req.originalUrl.split("?")[0] ?? path;
226
250
  const startedAt = Date.now();
227
- emit({ type: "request", stage: "start", method: methodUpper, path, url: requestUrl });
251
+ emit({
252
+ type: "request",
253
+ stage: "start",
254
+ method: methodUpper,
255
+ path,
256
+ url: requestUrl
257
+ });
228
258
  let params;
229
259
  let query;
230
260
  let body;
@@ -371,10 +401,13 @@ function createRRRoute(router, config) {
371
401
  const key = keyOf(leaf);
372
402
  knownLeaves.set(key, leaf);
373
403
  }
404
+ ;
374
405
  Object.keys(controllers).forEach((key) => {
375
406
  const leaf = registry.byKey[key];
376
407
  if (!leaf) {
377
- logger?.warn?.(`No leaf found for controller key: ${key}. Not registering route.`);
408
+ logger?.warn?.(
409
+ `No leaf found for controller key: ${key}. Not registering route.`
410
+ );
378
411
  return;
379
412
  }
380
413
  const def = controllers[key];
@@ -399,7 +432,9 @@ function createRRRoute(router, config) {
399
432
  function warnMissing(registry, warnLogger) {
400
433
  const registeredFromStore = new Set(Array.from(registered));
401
434
  if (registeredFromStore.size === 0) {
402
- collectRoutesFromStack(router).forEach((key) => registeredFromStore.add(key));
435
+ collectRoutesFromStack(router).forEach(
436
+ (key) => registeredFromStore.add(key)
437
+ );
403
438
  }
404
439
  for (const leaf of registry.all) {
405
440
  const key = keyOf(leaf);
@@ -543,7 +578,12 @@ function createBuiltInConnectionHandlers(opts) {
543
578
  const list = toArray(parsed.data.rooms);
544
579
  const join = async (room) => {
545
580
  await socket.join(room);
546
- dbg(null, { type: "rooms", action: "join", rooms: room, socketId: socket.id });
581
+ dbg(null, {
582
+ type: "rooms",
583
+ action: "join",
584
+ rooms: room,
585
+ socketId: socket.id
586
+ });
547
587
  };
548
588
  const run = async () => {
549
589
  await getSysEvent("sys:room_join")({
@@ -557,7 +597,9 @@ function createBuiltInConnectionHandlers(opts) {
557
597
  try {
558
598
  await run();
559
599
  } catch (error) {
560
- socket.emit(`${roomJoinEvent}:error`, { error: normalizeError(error) });
600
+ socket.emit(`${roomJoinEvent}:error`, {
601
+ error: normalizeError(error)
602
+ });
561
603
  dbg(roomJoinEvent, {
562
604
  type: "rooms",
563
605
  action: "join",
@@ -595,7 +637,12 @@ function createBuiltInConnectionHandlers(opts) {
595
637
  const list = toArray(parsed.data.rooms);
596
638
  const leave = async (room) => {
597
639
  await socket.leave(room);
598
- dbg(null, { type: "rooms", action: "leave", rooms: room, socketId: socket.id });
640
+ dbg(null, {
641
+ type: "rooms",
642
+ action: "leave",
643
+ rooms: room,
644
+ socketId: socket.id
645
+ });
599
646
  };
600
647
  const run = async () => {
601
648
  await getSysEvent("sys:room_leave")({
@@ -609,7 +656,9 @@ function createBuiltInConnectionHandlers(opts) {
609
656
  try {
610
657
  await run();
611
658
  } catch (error) {
612
- socket.emit(`${roomLeaveEvent}:error`, { error: normalizeError(error) });
659
+ socket.emit(`${roomLeaveEvent}:error`, {
660
+ error: normalizeError(error)
661
+ });
613
662
  dbg(roomJoinEvent, {
614
663
  type: "rooms",
615
664
  phase: "handler_error",
@@ -658,7 +707,12 @@ function createBuiltInConnectionHandlers(opts) {
658
707
  });
659
708
  let pongPayload;
660
709
  try {
661
- pongPayload = await getSysEvent("sys:ping")({ ping: parsedPing.data, ctx, socket, helper });
710
+ pongPayload = await getSysEvent("sys:ping")({
711
+ ping: parsedPing.data,
712
+ ctx,
713
+ socket,
714
+ helper
715
+ });
662
716
  } catch (error) {
663
717
  socket.emit(`${pingEvent}:error`, { error: normalizeError(error) });
664
718
  dbg(null, {
@@ -823,7 +877,9 @@ function createSocketConnections(io, events, opts) {
823
877
  },
824
878
  metadata
825
879
  });
826
- throw new Error(`Invalid payload for "${String(eventName)}": ${check.error.message}`);
880
+ throw new Error(
881
+ `Invalid payload for "${String(eventName)}": ${check.error.message}`
882
+ );
827
883
  }
828
884
  const envelope = {
829
885
  eventName,
@@ -884,7 +940,12 @@ function createSocketConnections(io, events, opts) {
884
940
  }
885
941
  }
886
942
  registrations.delete(eventName);
887
- dbg(eventName, { type: "register", action: "unregister", event: eventName, msg: "unregistered" });
943
+ dbg(eventName, {
944
+ type: "register",
945
+ action: "unregister",
946
+ event: eventName,
947
+ msg: "unregistered"
948
+ });
888
949
  };
889
950
  const {
890
951
  builtInConnectionListener,
@@ -970,7 +1031,10 @@ function createSocketConnections(io, events, opts) {
970
1031
  });
971
1032
  };
972
1033
  io.on("connection", connectionListener);
973
- addRegistration(String(eventName), { connectionListener, socketListeners });
1034
+ addRegistration(String(eventName), {
1035
+ connectionListener,
1036
+ socketListeners
1037
+ });
974
1038
  dbg(String(eventName), {
975
1039
  type: "register",
976
1040
  action: "register",
@@ -1116,7 +1180,9 @@ var createConnectionLoggingMiddleware = (options = {}) => {
1116
1180
  const logger = options.logger ?? defaultLogger;
1117
1181
  const includeHeaders = options.includeHeaders ?? false;
1118
1182
  const redactKeys = new Set(
1119
- (options.redactAuthKeys ?? ["authorization", "token"]).map((key) => key.toLowerCase())
1183
+ (options.redactAuthKeys ?? ["authorization", "token"]).map(
1184
+ (key) => key.toLowerCase()
1185
+ )
1120
1186
  );
1121
1187
  return (socket, next) => {
1122
1188
  const context = buildContext(socket, includeHeaders, redactKeys);