@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.cjs
CHANGED
|
@@ -499,6 +499,9 @@ var defaultSend = (res, data) => {
|
|
|
499
499
|
res.json(data);
|
|
500
500
|
};
|
|
501
501
|
var REGISTERED_ROUTES_SYMBOL = /* @__PURE__ */ Symbol.for("routesV3.registeredRoutes");
|
|
502
|
+
var REGISTERED_ROUTE_ENTRIES_SYMBOL = /* @__PURE__ */ Symbol.for(
|
|
503
|
+
"routesV3.registeredRouteEntries"
|
|
504
|
+
);
|
|
502
505
|
function getRegisteredRouteStore(router) {
|
|
503
506
|
const existing = router[REGISTERED_ROUTES_SYMBOL];
|
|
504
507
|
if (existing) return existing;
|
|
@@ -506,6 +509,88 @@ function getRegisteredRouteStore(router) {
|
|
|
506
509
|
router[REGISTERED_ROUTES_SYMBOL] = store;
|
|
507
510
|
return store;
|
|
508
511
|
}
|
|
512
|
+
function parseRegisteredRouteKey(key) {
|
|
513
|
+
const firstSpace = key.indexOf(" ");
|
|
514
|
+
if (firstSpace <= 0) return void 0;
|
|
515
|
+
const method = key.slice(0, firstSpace).toUpperCase();
|
|
516
|
+
const path = key.slice(firstSpace + 1);
|
|
517
|
+
if (!path) return void 0;
|
|
518
|
+
return { method, path, key, origin: "unknown (pre-existing router stack)" };
|
|
519
|
+
}
|
|
520
|
+
function getRegistrationOrigin() {
|
|
521
|
+
const stack = new Error().stack;
|
|
522
|
+
if (!stack) return "unknown";
|
|
523
|
+
const lines = stack.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
524
|
+
for (const line of lines) {
|
|
525
|
+
if (/^Error:?$/.test(line)) continue;
|
|
526
|
+
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/")) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
return line.replace(/^at\s+/, "");
|
|
530
|
+
}
|
|
531
|
+
return lines.find((line) => !/^Error:?$/.test(line))?.replace(/^at\s+/, "") ?? "unknown";
|
|
532
|
+
}
|
|
533
|
+
function getRegisteredRouteEntriesStore(router) {
|
|
534
|
+
const existing = router[REGISTERED_ROUTE_ENTRIES_SYMBOL];
|
|
535
|
+
if (existing) return existing;
|
|
536
|
+
const seeded = collectRoutesFromStack(router).map(parseRegisteredRouteKey).filter((entry) => Boolean(entry));
|
|
537
|
+
router[REGISTERED_ROUTE_ENTRIES_SYMBOL] = seeded;
|
|
538
|
+
return seeded;
|
|
539
|
+
}
|
|
540
|
+
function toParsedRouteSegments(path) {
|
|
541
|
+
const segments = path.split("/").filter(Boolean);
|
|
542
|
+
return segments.map((segment) => {
|
|
543
|
+
if (segment.startsWith("*") && segment.length > 1) return { kind: "wildcard" };
|
|
544
|
+
if (segment.startsWith(":") && segment.length > 1) return { kind: "param" };
|
|
545
|
+
return { kind: "static", value: segment };
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
function buildProbePathForRoute(path) {
|
|
549
|
+
const parsed = toParsedRouteSegments(path);
|
|
550
|
+
const segments = [];
|
|
551
|
+
for (const segment of parsed) {
|
|
552
|
+
if (segment.kind === "static") {
|
|
553
|
+
segments.push(segment.value);
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (segment.kind === "param") {
|
|
557
|
+
segments.push("__rrroutes_param__");
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
segments.push("__rrroutes_splat__", "__rrroutes_tail__");
|
|
561
|
+
}
|
|
562
|
+
return `/${segments.join("/")}`.replace(/\/+/g, "/");
|
|
563
|
+
}
|
|
564
|
+
function routePatternMatchesConcretePath(routePattern, concretePath) {
|
|
565
|
+
const patternSegments = toParsedRouteSegments(routePattern);
|
|
566
|
+
const pathSegments = concretePath.split("/").filter(Boolean);
|
|
567
|
+
let i = 0;
|
|
568
|
+
let j = 0;
|
|
569
|
+
while (i < patternSegments.length) {
|
|
570
|
+
const pattern = patternSegments[i];
|
|
571
|
+
if (pattern.kind === "wildcard") {
|
|
572
|
+
return j < pathSegments.length;
|
|
573
|
+
}
|
|
574
|
+
if (j >= pathSegments.length) return false;
|
|
575
|
+
if (pattern.kind === "param") {
|
|
576
|
+
i += 1;
|
|
577
|
+
j += 1;
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
if (pattern.value !== pathSegments[j]) return false;
|
|
581
|
+
i += 1;
|
|
582
|
+
j += 1;
|
|
583
|
+
}
|
|
584
|
+
return j === pathSegments.length;
|
|
585
|
+
}
|
|
586
|
+
function findShadowingPriorRoute(entries, method, path) {
|
|
587
|
+
const probePath = buildProbePathForRoute(path);
|
|
588
|
+
return entries.find((entry) => {
|
|
589
|
+
if (entry.method !== method) return false;
|
|
590
|
+
if (entry.path === path) return true;
|
|
591
|
+
return routePatternMatchesConcretePath(entry.path, probePath);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
509
594
|
function collectRoutesFromStack(appOrRouter) {
|
|
510
595
|
const result = [];
|
|
511
596
|
const stack = appOrRouter.stack ?? (appOrRouter._router ? appOrRouter._router.stack : void 0) ?? [];
|
|
@@ -542,6 +627,7 @@ function createRRRoute(router, config) {
|
|
|
542
627
|
const preCtxMws = [...middlewareConfig.preCtx ?? []];
|
|
543
628
|
const sanitizerMw = middlewareConfig.sanitizer === void 0 ? void 0 : typeof middlewareConfig.sanitizer === "function" ? middlewareConfig.sanitizer : createRequestSanitizationMiddleware(middlewareConfig.sanitizer);
|
|
544
629
|
const registered = getRegisteredRouteStore(router);
|
|
630
|
+
const registeredEntries = getRegisteredRouteEntriesStore(router);
|
|
545
631
|
const getMulterOptions = (fields) => {
|
|
546
632
|
if (!fields || fields.length === 0) return void 0;
|
|
547
633
|
const resolved = typeof config.multerOptions === "function" ? config.multerOptions(fields) : config.multerOptions;
|
|
@@ -584,6 +670,13 @@ function createRRRoute(router, config) {
|
|
|
584
670
|
const activeDebugMode = routeDebugEmitter?.mode ?? defaultDebugMode;
|
|
585
671
|
const emit = (event) => activeEmit(event, debugName);
|
|
586
672
|
const isVerboseDebug = activeDebugMode === "complete";
|
|
673
|
+
const origin = getRegistrationOrigin();
|
|
674
|
+
const shadowingEntry = findShadowingPriorRoute(registeredEntries, methodUpper, path);
|
|
675
|
+
if (shadowingEntry) {
|
|
676
|
+
console.warn(
|
|
677
|
+
`[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}.`
|
|
678
|
+
);
|
|
679
|
+
}
|
|
587
680
|
emit({ type: "register", method: methodUpper, path });
|
|
588
681
|
const routeSpecific = (def?.before ?? []).map(
|
|
589
682
|
(mw) => adaptRouteBeforeMw(mw)
|
|
@@ -832,6 +925,7 @@ function createRRRoute(router, config) {
|
|
|
832
925
|
};
|
|
833
926
|
router[method](path, ...before, wrapped);
|
|
834
927
|
registered.add(key);
|
|
928
|
+
registeredEntries.push({ method: methodUpper, path, key, origin });
|
|
835
929
|
registeredDefs.set(key, {
|
|
836
930
|
leaf,
|
|
837
931
|
def
|