@emeryld/rrroutes-server 2.4.1 → 2.4.3

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.js CHANGED
@@ -64,6 +64,20 @@ var decodeJsonLikeQueryValue = (value) => {
64
64
  return value;
65
65
  };
66
66
  var CTX_SYMBOL = /* @__PURE__ */ Symbol.for("typedLeaves.ctx");
67
+ var REQUEST_PAYLOAD_SYMBOL = /* @__PURE__ */ Symbol.for(
68
+ "typedLeaves.requestPayload"
69
+ );
70
+ function getRouteRequestPayload(res) {
71
+ const payload = res.locals[REQUEST_PAYLOAD_SYMBOL];
72
+ if (payload) {
73
+ return payload;
74
+ }
75
+ throw new Error("Request payload was not initialized before middleware");
76
+ }
77
+ function setRouteRequestPayload(res, payload) {
78
+ ;
79
+ res.locals[REQUEST_PAYLOAD_SYMBOL] = payload;
80
+ }
67
81
  function getCtx(res) {
68
82
  return res.locals[CTX_SYMBOL];
69
83
  }
@@ -81,6 +95,26 @@ function adaptCtxMw(mw) {
81
95
  }
82
96
  };
83
97
  }
98
+ function adaptRouteBeforeMw(mw) {
99
+ return (req, res, next) => {
100
+ try {
101
+ const result = mw({
102
+ req,
103
+ res,
104
+ next,
105
+ ctx: getCtx(res),
106
+ ...getRouteRequestPayload(res)
107
+ });
108
+ if (result && typeof result.then === "function") {
109
+ return result.catch((err) => next(err));
110
+ }
111
+ return result;
112
+ } catch (err) {
113
+ next(err);
114
+ return void 0;
115
+ }
116
+ };
117
+ }
84
118
  function logHandlerDebugWithRoutesLogger(logger, event) {
85
119
  if (!logger || event.type !== "handler") return;
86
120
  const payload = [
@@ -171,7 +205,9 @@ function createRRRoute(router, config) {
171
205
  const emit = (event) => activeEmit(event, debugName);
172
206
  const isVerboseDebug = activeDebugMode === "complete";
173
207
  emit({ type: "register", method: methodUpper, path });
174
- const routeSpecific = (def?.before ?? []).map((mw) => adaptCtxMw(mw));
208
+ const routeSpecific = (def?.before ?? []).map(
209
+ (mw) => adaptRouteBeforeMw(mw)
210
+ );
175
211
  const derived = buildDerived(leaf);
176
212
  const ctxMw = async (req, res, next) => {
177
213
  const requestUrl = req.originalUrl ?? path;
@@ -183,8 +219,66 @@ function createRRRoute(router, config) {
183
219
  path,
184
220
  url: requestUrl
185
221
  });
222
+ let params;
223
+ let query;
224
+ let body;
186
225
  try {
187
- const ctx = await config.buildCtx(req, res);
226
+ params = leaf.cfg.paramsSchema ? lowProfileParse(leaf.cfg.paramsSchema, req.params) : Object.keys(req.params || {}).length ? req.params : void 0;
227
+ const hasQueryKeys = req.query && Object.keys(req.query || {}).length > 0;
228
+ const parsedQueryInput = leaf.cfg.querySchema && hasQueryKeys ? decodeJsonLikeQueryValue(req.query) : req.query;
229
+ if (leaf.cfg.querySchema) {
230
+ try {
231
+ query = lowProfileParse(
232
+ leaf.cfg.querySchema,
233
+ parsedQueryInput
234
+ );
235
+ } catch (err) {
236
+ const parseError = new Error(
237
+ `Query parsing error: ${err.message ?? String(err)}`
238
+ );
239
+ parseError.raw = JSON.stringify(req.query);
240
+ parseError.cause = err;
241
+ throw parseError;
242
+ }
243
+ } else {
244
+ query = hasQueryKeys ? req.query : void 0;
245
+ }
246
+ body = leaf.cfg.bodySchema ? lowProfileParse(leaf.cfg.bodySchema, req.body) : req.body !== void 0 ? req.body : void 0;
247
+ } catch (err) {
248
+ const payloadError = {
249
+ params,
250
+ query,
251
+ body
252
+ };
253
+ emit(
254
+ decorateDebugEvent(
255
+ isVerboseDebug,
256
+ {
257
+ type: "request",
258
+ stage: "error",
259
+ method: methodUpper,
260
+ path,
261
+ url: requestUrl,
262
+ durationMs: Date.now() - startedAt,
263
+ error: err
264
+ },
265
+ isVerboseDebug ? payloadError : void 0
266
+ )
267
+ );
268
+ next(err);
269
+ return;
270
+ }
271
+ const requestPayload = {
272
+ params,
273
+ query,
274
+ body
275
+ };
276
+ setRouteRequestPayload(res, requestPayload);
277
+ try {
278
+ const ctx = await config.buildCtx({
279
+ req,
280
+ res
281
+ });
188
282
  res.locals[CTX_SYMBOL] = ctx;
189
283
  emit({
190
284
  type: "buildCtx",
@@ -224,21 +318,16 @@ function createRRRoute(router, config) {
224
318
  path,
225
319
  url: requestUrl
226
320
  });
227
- let params;
228
- let query;
229
- let body;
321
+ const requestPayload = getRouteRequestPayload(res);
322
+ const params = requestPayload.params;
323
+ const query = requestPayload.query;
324
+ const body = requestPayload.body;
230
325
  let responsePayload;
231
326
  let hasResponsePayload = false;
232
327
  const downstreamNext = next;
233
328
  const ctx = res.locals[CTX_SYMBOL];
234
329
  const ctxRoutesLogger = ctx?.routesLogger;
235
330
  const emitWithCtx = (event, details) => {
236
- if (event.type == "request" && event.stage == "error") {
237
- console.log("Request error event emitted:", {
238
- event,
239
- ctxRoutesLogger: !!ctxRoutesLogger
240
- });
241
- }
242
331
  const decorated = decorateDebugEvent(isVerboseDebug, event, details);
243
332
  if (!config.debug || !config.debug[decorated.type]) {
244
333
  return;
@@ -250,26 +339,6 @@ function createRRRoute(router, config) {
250
339
  }
251
340
  };
252
341
  try {
253
- params = leaf.cfg.paramsSchema ? lowProfileParse(leaf.cfg.paramsSchema, req.params) : Object.keys(req.params || {}).length ? req.params : void 0;
254
- try {
255
- const parsedQueryInput = leaf.cfg.querySchema && req.query ? decodeJsonLikeQueryValue(req.query) : req.query;
256
- query = leaf.cfg.querySchema ? lowProfileParse(leaf.cfg.querySchema, parsedQueryInput) : Object.keys(req.query || {}).length ? req.query : void 0;
257
- } catch (e) {
258
- emitWithCtx({
259
- type: "request",
260
- stage: "error",
261
- method: methodUpper,
262
- path,
263
- url: requestUrl,
264
- error: {
265
- ...e,
266
- raw: JSON.stringify(req.query),
267
- message: `Query parsing error: ${e.message}`
268
- }
269
- });
270
- throw e;
271
- }
272
- body = leaf.cfg.bodySchema ? lowProfileParse(leaf.cfg.bodySchema, req.body) : req.body !== void 0 ? req.body : void 0;
273
342
  const handlerStartedAt = Date.now();
274
343
  emitWithCtx(
275
344
  {
@@ -360,29 +429,28 @@ function createRRRoute(router, config) {
360
429
  registered.add(key);
361
430
  }
362
431
  function registerControllers(registry, controllers, all) {
363
- if (all !== void 0 && all !== false) {
364
- const label = typeof all === "string" ? all : all === true ? "true" : String(all);
365
- throw new Error(
366
- `registerControllers: "${label}" is not allowed at runtime. Use bindAll(...) for compile-time coverage or warnMissingControllers(...) to surface missing routes.`
367
- );
368
- }
369
432
  for (const leaf of registry.all) {
370
433
  const key = keyOf(leaf.method, leaf.path, false);
371
434
  knownLeaves.set(key, leaf);
372
435
  }
373
- ;
436
+ const missingLeaves = [];
374
437
  Object.keys(controllers).forEach((key) => {
375
438
  const leaf = registry.byKey[key];
376
439
  if (!leaf) {
377
- console.warn(
378
- `No leaf found for controller key: ${key}. Not registering route.`
379
- );
440
+ missingLeaves.push(key);
380
441
  return;
381
442
  }
382
443
  const def = controllers[key];
383
444
  if (!def) return;
384
445
  register(leaf, def);
385
446
  });
447
+ if (all && missingLeaves.length > 0) {
448
+ throw new Error(
449
+ `Cannot register controllers: missing definitions for routes: ${missingLeaves.join(
450
+ ", "
451
+ )}`
452
+ );
453
+ }
386
454
  }
387
455
  function warnMissing(registry, warnLogger) {
388
456
  const registeredFromStore = new Set(Array.from(registered));
@@ -479,8 +547,12 @@ function createBuiltInConnectionHandlers(opts) {
479
547
  const pingEvent = "sys:ping";
480
548
  const pongEvent = "sys:pong";
481
549
  const heartbeatEnabled = heartbeat?.enabled !== false;
482
- const joinPayloadSchema = buildRoomPayloadSchema(config.joinMetaMessage);
483
- const leavePayloadSchema = buildRoomPayloadSchema(config.leaveMetaMessage);
550
+ const joinPayloadSchema = buildRoomPayloadSchema(
551
+ config.joinMetaMessage
552
+ );
553
+ const leavePayloadSchema = buildRoomPayloadSchema(
554
+ config.leaveMetaMessage
555
+ );
484
556
  const pingPayloadSchema = config.pingPayload;
485
557
  const pongPayloadSchema = config.pongPayload;
486
558
  const sysEvents = sys;