@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/README.md +19 -0
- package/dist/index.cjs +115 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +115 -43
- package/dist/index.js.map +1 -1
- package/dist/routesV3.server.d.ts +19 -2
- package/dist/sockets/socket.server.sys.d.ts +1 -1
- package/package.json +6 -5
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(
|
|
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
|
-
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
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(
|
|
483
|
-
|
|
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;
|