webspresso 0.0.69 → 0.0.70

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/index.d.ts CHANGED
@@ -90,7 +90,10 @@ export function setAppContext(partial: { db?: DatabaseInstance | null }): void;
90
90
  export function mountPages(
91
91
  app: Application,
92
92
  options: Record<string, unknown>
93
- ): unknown;
93
+ ): {
94
+ routeMetadata: unknown[];
95
+ registerDynamicFileRoutes: () => void;
96
+ };
94
97
 
95
98
  export function filePathToRoute(filePath: string, pagesDir: string): string;
96
99
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.69",
3
+ "version": "0.0.70",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -506,9 +506,17 @@ function mountPages(app, options) {
506
506
 
507
507
  // Sort routes: static before dynamic before catch-all; then more literal segments, then deeper paths
508
508
  const sortRoutes = (routes) => routes.sort(compareRouteRegistrationOrder);
509
-
510
- // Register API routes
511
- for (const route of sortRoutes(apiRoutes)) {
509
+ sortRoutes(apiRoutes);
510
+ sortRoutes(ssrRoutes);
511
+
512
+ const apiStatic = apiRoutes.filter((r) => routeRegistrationMeta(r.routePath).tier === 0);
513
+ const apiDynamic = apiRoutes.filter((r) => routeRegistrationMeta(r.routePath).tier !== 0);
514
+ const ssrStatic = ssrRoutes.filter((r) => routeRegistrationMeta(r.routePath).tier === 0);
515
+ const ssrDynamic = ssrRoutes.filter((r) => routeRegistrationMeta(r.routePath).tier !== 0);
516
+
517
+ /** Register API routes (shared by static phase and dynamic phase). */
518
+ const registerApiRoutes = (routes) => {
519
+ for (const route of routes) {
512
520
  const handler = require(route.fullPath);
513
521
  const handlerFn = typeof handler === 'function' ? handler : handler.default || handler.handler;
514
522
  const routeMiddleware = handler.middleware;
@@ -582,10 +590,12 @@ function mountPages(app, options) {
582
590
  });
583
591
 
584
592
  log(` ${route.method.toUpperCase()} ${route.routePath} -> ${route.file}`);
585
- }
586
-
587
- // Register SSR routes
588
- for (const route of sortRoutes(ssrRoutes)) {
593
+ }
594
+ };
595
+
596
+ /** Register SSR GET routes (shared by static phase and dynamic phase). */
597
+ const registerSsrRoutes = (routes) => {
598
+ for (const route of routes) {
589
599
  app.get(route.routePath, async (req, res, next) => {
590
600
  try {
591
601
  // Detect locale
@@ -714,8 +724,19 @@ function mountPages(app, options) {
714
724
  });
715
725
 
716
726
  log(` GET ${route.routePath} -> ${route.file}`);
717
- }
718
-
727
+ }
728
+ };
729
+
730
+ // Static / literal file routes first so plugins can register reserved paths (e.g. /_admin)
731
+ // before catch-all dynamics like /:slug shadow them.
732
+ registerApiRoutes(apiStatic);
733
+ registerSsrRoutes(ssrStatic);
734
+
735
+ const registerDynamicFileRoutes = () => {
736
+ registerApiRoutes(apiDynamic);
737
+ registerSsrRoutes(ssrDynamic);
738
+ };
739
+
719
740
  // Return route metadata for plugins
720
741
  const routeMetadata = [
721
742
  ...ssrRoutes.map(r => ({
@@ -733,8 +754,8 @@ function mountPages(app, options) {
733
754
  isDynamic: r.routePath.includes(':') || r.routePath.includes('*')
734
755
  }))
735
756
  ];
736
-
737
- return routeMetadata;
757
+
758
+ return { routeMetadata, registerDynamicFileRoutes };
738
759
  }
739
760
 
740
761
  module.exports = {
package/src/server.js CHANGED
@@ -440,7 +440,7 @@ function createApp(options = {}) {
440
440
  if (!isTest) {
441
441
  console.log('\nMounting routes:');
442
442
  }
443
- const routeMetadata = mountPages(app, {
443
+ const { routeMetadata, registerDynamicFileRoutes } = mountPages(app, {
444
444
  pagesDir,
445
445
  nunjucks: nunjucksEnv,
446
446
  middlewares,
@@ -449,7 +449,7 @@ function createApp(options = {}) {
449
449
  db: options.db ?? null,
450
450
  clientRuntime,
451
451
  });
452
-
452
+
453
453
  // Set route metadata in plugin manager
454
454
  pluginManager.setRoutes(routeMetadata);
455
455
 
@@ -491,7 +491,11 @@ function createApp(options = {}) {
491
491
  clientRuntime,
492
492
  });
493
493
  }
494
-
494
+
495
+ // Dynamic / catch-all file routes after plugins and setupRoutes so paths like /_admin
496
+ // or custom /login are not shadowed by pages/[slug].njk (/:slug).
497
+ registerDynamicFileRoutes();
498
+
495
499
  // Helper to create error page context with fsy
496
500
  function createErrorContext(req, extraData = {}) {
497
501
  const baseUrl = process.env.BASE_URL || `http://localhost:${process.env.PORT || 3000}`;