@emeryld/rrroutes-server 2.6.4 → 2.6.6
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 +94 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -456,6 +456,9 @@ var defaultSend = (res, data) => {
|
|
|
456
456
|
res.json(data);
|
|
457
457
|
};
|
|
458
458
|
var REGISTERED_ROUTES_SYMBOL = /* @__PURE__ */ Symbol.for("routesV3.registeredRoutes");
|
|
459
|
+
var REGISTERED_ROUTE_ENTRIES_SYMBOL = /* @__PURE__ */ Symbol.for(
|
|
460
|
+
"routesV3.registeredRouteEntries"
|
|
461
|
+
);
|
|
459
462
|
function getRegisteredRouteStore(router) {
|
|
460
463
|
const existing = router[REGISTERED_ROUTES_SYMBOL];
|
|
461
464
|
if (existing) return existing;
|
|
@@ -463,6 +466,88 @@ function getRegisteredRouteStore(router) {
|
|
|
463
466
|
router[REGISTERED_ROUTES_SYMBOL] = store;
|
|
464
467
|
return store;
|
|
465
468
|
}
|
|
469
|
+
function parseRegisteredRouteKey(key) {
|
|
470
|
+
const firstSpace = key.indexOf(" ");
|
|
471
|
+
if (firstSpace <= 0) return void 0;
|
|
472
|
+
const method = key.slice(0, firstSpace).toUpperCase();
|
|
473
|
+
const path = key.slice(firstSpace + 1);
|
|
474
|
+
if (!path) return void 0;
|
|
475
|
+
return { method, path, key, origin: "unknown (pre-existing router stack)" };
|
|
476
|
+
}
|
|
477
|
+
function getRegistrationOrigin() {
|
|
478
|
+
const stack = new Error().stack;
|
|
479
|
+
if (!stack) return "unknown";
|
|
480
|
+
const lines = stack.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
481
|
+
for (const line of lines) {
|
|
482
|
+
if (/^Error:?$/.test(line)) continue;
|
|
483
|
+
if (line.includes("getRegistrationOrigin") || line.includes("findShadowingPriorRoute") || line.includes("createRRRoute") || line.includes("register (") || line.includes("routesV3.server.ts") || line.includes("<anonymous>") || line.includes("node_modules") || line.includes("internal/")) {
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
return line.replace(/^at\s+/, "");
|
|
487
|
+
}
|
|
488
|
+
return lines.find((line) => !/^Error:?$/.test(line))?.replace(/^at\s+/, "") ?? "unknown";
|
|
489
|
+
}
|
|
490
|
+
function getRegisteredRouteEntriesStore(router) {
|
|
491
|
+
const existing = router[REGISTERED_ROUTE_ENTRIES_SYMBOL];
|
|
492
|
+
if (existing) return existing;
|
|
493
|
+
const seeded = collectRoutesFromStack(router).map(parseRegisteredRouteKey).filter((entry) => Boolean(entry));
|
|
494
|
+
router[REGISTERED_ROUTE_ENTRIES_SYMBOL] = seeded;
|
|
495
|
+
return seeded;
|
|
496
|
+
}
|
|
497
|
+
function toParsedRouteSegments(path) {
|
|
498
|
+
const segments = path.split("/").filter(Boolean);
|
|
499
|
+
return segments.map((segment) => {
|
|
500
|
+
if (segment.startsWith("*") && segment.length > 1) return { kind: "wildcard" };
|
|
501
|
+
if (segment.startsWith(":") && segment.length > 1) return { kind: "param" };
|
|
502
|
+
return { kind: "static", value: segment };
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
function buildProbePathForRoute(path) {
|
|
506
|
+
const parsed = toParsedRouteSegments(path);
|
|
507
|
+
const segments = [];
|
|
508
|
+
for (const segment of parsed) {
|
|
509
|
+
if (segment.kind === "static") {
|
|
510
|
+
segments.push(segment.value);
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
if (segment.kind === "param") {
|
|
514
|
+
segments.push("__rrroutes_param__");
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
segments.push("__rrroutes_splat__", "__rrroutes_tail__");
|
|
518
|
+
}
|
|
519
|
+
return `/${segments.join("/")}`.replace(/\/+/g, "/");
|
|
520
|
+
}
|
|
521
|
+
function routePatternMatchesConcretePath(routePattern, concretePath) {
|
|
522
|
+
const patternSegments = toParsedRouteSegments(routePattern);
|
|
523
|
+
const pathSegments = concretePath.split("/").filter(Boolean);
|
|
524
|
+
let i = 0;
|
|
525
|
+
let j = 0;
|
|
526
|
+
while (i < patternSegments.length) {
|
|
527
|
+
const pattern = patternSegments[i];
|
|
528
|
+
if (pattern.kind === "wildcard") {
|
|
529
|
+
return j < pathSegments.length;
|
|
530
|
+
}
|
|
531
|
+
if (j >= pathSegments.length) return false;
|
|
532
|
+
if (pattern.kind === "param") {
|
|
533
|
+
i += 1;
|
|
534
|
+
j += 1;
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
if (pattern.value !== pathSegments[j]) return false;
|
|
538
|
+
i += 1;
|
|
539
|
+
j += 1;
|
|
540
|
+
}
|
|
541
|
+
return j === pathSegments.length;
|
|
542
|
+
}
|
|
543
|
+
function findShadowingPriorRoute(entries, method, path) {
|
|
544
|
+
const probePath = buildProbePathForRoute(path);
|
|
545
|
+
return entries.find((entry) => {
|
|
546
|
+
if (entry.method !== method) return false;
|
|
547
|
+
if (entry.path === path) return true;
|
|
548
|
+
return routePatternMatchesConcretePath(entry.path, probePath);
|
|
549
|
+
});
|
|
550
|
+
}
|
|
466
551
|
function collectRoutesFromStack(appOrRouter) {
|
|
467
552
|
const result = [];
|
|
468
553
|
const stack = appOrRouter.stack ?? (appOrRouter._router ? appOrRouter._router.stack : void 0) ?? [];
|
|
@@ -499,6 +584,7 @@ function createRRRoute(router, config) {
|
|
|
499
584
|
const preCtxMws = [...middlewareConfig.preCtx ?? []];
|
|
500
585
|
const sanitizerMw = middlewareConfig.sanitizer === void 0 ? void 0 : typeof middlewareConfig.sanitizer === "function" ? middlewareConfig.sanitizer : createRequestSanitizationMiddleware(middlewareConfig.sanitizer);
|
|
501
586
|
const registered = getRegisteredRouteStore(router);
|
|
587
|
+
const registeredEntries = getRegisteredRouteEntriesStore(router);
|
|
502
588
|
const getMulterOptions = (fields) => {
|
|
503
589
|
if (!fields || fields.length === 0) return void 0;
|
|
504
590
|
const resolved = typeof config.multerOptions === "function" ? config.multerOptions(fields) : config.multerOptions;
|
|
@@ -541,6 +627,13 @@ function createRRRoute(router, config) {
|
|
|
541
627
|
const activeDebugMode = routeDebugEmitter?.mode ?? defaultDebugMode;
|
|
542
628
|
const emit = (event) => activeEmit(event, debugName);
|
|
543
629
|
const isVerboseDebug = activeDebugMode === "complete";
|
|
630
|
+
const origin = getRegistrationOrigin();
|
|
631
|
+
const shadowingEntry = findShadowingPriorRoute(registeredEntries, methodUpper, path);
|
|
632
|
+
if (shadowingEntry) {
|
|
633
|
+
console.warn(
|
|
634
|
+
`[rrroutes-server] Registering ${methodUpper} ${path} may be shadowed by previously registered ${shadowingEntry.method} ${shadowingEntry.path}. Precedence: ${shadowingEntry.method} ${shadowingEntry.path} takes precedence (registered first). Current declaration origin: ${origin}. Prior declaration origin: ${shadowingEntry.origin}.`
|
|
635
|
+
);
|
|
636
|
+
}
|
|
544
637
|
emit({ type: "register", method: methodUpper, path });
|
|
545
638
|
const routeSpecific = (def?.before ?? []).map(
|
|
546
639
|
(mw) => adaptRouteBeforeMw(mw)
|
|
@@ -789,6 +882,7 @@ function createRRRoute(router, config) {
|
|
|
789
882
|
};
|
|
790
883
|
router[method](path, ...before, wrapped);
|
|
791
884
|
registered.add(key);
|
|
885
|
+
registeredEntries.push({ method: methodUpper, path, key, origin });
|
|
792
886
|
registeredDefs.set(key, {
|
|
793
887
|
leaf,
|
|
794
888
|
def
|