@ressjs/vite-router 0.5.0 → 0.6.0-experimental.0

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.
Files changed (110) hide show
  1. package/README.md +41 -31
  2. package/dist/client/entry.d.mts +2 -0
  3. package/dist/client/entry.mjs +1 -0
  4. package/dist/client/index.d.ts +2 -0
  5. package/dist/client/index.js +8 -0
  6. package/dist/config/base-path.d.ts +44 -0
  7. package/dist/config/base-path.js +100 -0
  8. package/dist/config/codegen.d.ts +23 -0
  9. package/dist/config/codegen.js +118 -0
  10. package/dist/config/define.d.ts +8 -0
  11. package/dist/config/define.js +12 -0
  12. package/dist/config/env.d.ts +19 -0
  13. package/dist/config/env.js +40 -0
  14. package/dist/config/index.d.ts +18 -0
  15. package/dist/config/index.js +44 -0
  16. package/dist/config/load.d.ts +26 -0
  17. package/dist/config/load.js +73 -0
  18. package/dist/config/middleware.d.ts +18 -0
  19. package/dist/config/middleware.js +79 -0
  20. package/dist/config/rules.d.ts +48 -0
  21. package/dist/config/rules.js +149 -0
  22. package/dist/config/types.d.ts +164 -0
  23. package/dist/config/types.js +2 -0
  24. package/dist/config/validate.d.ts +19 -0
  25. package/dist/config/validate.js +105 -0
  26. package/dist/config/watch.d.ts +41 -0
  27. package/dist/config/watch.js +132 -0
  28. package/dist/fs/module-extensions.d.ts +82 -0
  29. package/dist/fs/module-extensions.js +196 -0
  30. package/dist/helpers/html-generator.d.ts +22 -5
  31. package/dist/helpers/html-generator.js +89 -120
  32. package/dist/helpers/middlewares.d.ts +7 -7
  33. package/dist/helpers/middlewares.js +51 -103
  34. package/dist/helpers/request-handler.d.ts +2 -2
  35. package/dist/helpers/request-handler.js +118 -25
  36. package/dist/index.d.ts +30 -3
  37. package/dist/index.js +70 -8
  38. package/dist/pages.d.ts +10 -9
  39. package/dist/pages.js +42 -261
  40. package/dist/platform.d.ts +11 -14
  41. package/dist/platform.js +18 -102
  42. package/dist/plugin/environments.d.ts +66 -0
  43. package/dist/plugin/environments.js +72 -0
  44. package/dist/plugin/index.d.ts +54 -0
  45. package/dist/plugin/index.js +178 -0
  46. package/dist/plugin/virtual-entries.d.ts +26 -0
  47. package/dist/plugin/virtual-entries.js +80 -0
  48. package/dist/render.d.ts +23 -2
  49. package/dist/render.js +40 -53
  50. package/dist/router.d.ts +32 -13
  51. package/dist/router.js +147 -146
  52. package/dist/routes/dispatcher.d.ts +37 -0
  53. package/dist/routes/dispatcher.js +69 -0
  54. package/dist/routes/manifest.d.ts +17 -0
  55. package/dist/routes/manifest.js +56 -0
  56. package/dist/routes/match.d.ts +20 -0
  57. package/dist/routes/match.js +75 -0
  58. package/dist/routes/parse.d.ts +31 -0
  59. package/dist/routes/parse.js +114 -0
  60. package/dist/routes/rank.d.ts +12 -0
  61. package/dist/routes/rank.js +49 -0
  62. package/dist/routes/router.d.ts +44 -0
  63. package/dist/routes/router.js +81 -0
  64. package/dist/routes/scan.d.ts +16 -0
  65. package/dist/routes/scan.js +82 -0
  66. package/dist/routes/types.d.ts +85 -0
  67. package/dist/routes/types.js +13 -0
  68. package/dist/runtime/dev-server.d.ts +62 -0
  69. package/dist/runtime/dev-server.js +94 -0
  70. package/dist/runtime/module-loader.d.ts +55 -0
  71. package/dist/runtime/module-loader.js +122 -0
  72. package/dist/runtime/prod-server.d.ts +42 -0
  73. package/dist/runtime/prod-server.js +142 -0
  74. package/dist/runtime/template.d.ts +10 -0
  75. package/dist/runtime/template.js +33 -0
  76. package/dist/security/client-props.d.ts +25 -0
  77. package/dist/security/client-props.js +50 -0
  78. package/dist/security/config.d.ts +130 -0
  79. package/dist/security/config.js +73 -0
  80. package/dist/security/csp.d.ts +53 -0
  81. package/dist/security/csp.js +118 -0
  82. package/dist/security/dev-hardening.d.ts +46 -0
  83. package/dist/security/dev-hardening.js +65 -0
  84. package/dist/security/errors.d.ts +37 -0
  85. package/dist/security/errors.js +84 -0
  86. package/dist/security/escape.d.ts +40 -0
  87. package/dist/security/escape.js +90 -0
  88. package/dist/security/head-tags.d.ts +32 -0
  89. package/dist/security/head-tags.js +111 -0
  90. package/dist/security/headers.d.ts +62 -0
  91. package/dist/security/headers.js +187 -0
  92. package/dist/security/index.d.ts +24 -0
  93. package/dist/security/index.js +47 -0
  94. package/dist/security/serialize.d.ts +48 -0
  95. package/dist/security/serialize.js +146 -0
  96. package/dist/variants/assets.d.ts +23 -0
  97. package/dist/variants/assets.js +78 -0
  98. package/dist/variants/catalog.d.ts +33 -0
  99. package/dist/variants/catalog.js +79 -0
  100. package/dist/variants/platform-tokens.d.ts +9 -0
  101. package/dist/variants/platform-tokens.js +15 -0
  102. package/dist/variants/resolve.d.ts +40 -0
  103. package/dist/variants/resolve.js +90 -0
  104. package/dist/variants/suffix.d.ts +8 -0
  105. package/dist/variants/suffix.js +12 -0
  106. package/dist/variants/types.d.ts +69 -0
  107. package/dist/variants/types.js +2 -0
  108. package/package.json +22 -10
  109. package/dist/helpers/vite-config.d.ts +0 -10
  110. package/dist/helpers/vite-config.js +0 -90
@@ -1,130 +1,93 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateClientScript = generateClientScript;
7
- exports.generateClientCSS = generateClientCSS;
3
+ exports.resolvePageAssets = void 0;
8
4
  exports.generateCompleteHTML = generateCompleteHTML;
9
- const promises_1 = __importDefault(require("node:fs/promises"));
10
- async function generateClientScript(pageFile, platformInfo, manifest, isProduction) {
11
- // Sanitizar nombre: convertir [id] a _id_ para nombres de archivo (igual que en pages.ts)
12
- const rel = pageFile
13
- .replace(/^app\/pages\//, '')
14
- .replace(/\.tsx$|\.jsx$/, '')
15
- .replace(/\//g, '__')
16
- .replace(/\[([^\]]+)\]/g, '_$1_');
17
- let entryKey = `${rel}__entry-client.tsx`;
18
- if (platformInfo && platformInfo.device !== 'desktop') {
19
- // Priority order (from highest to lowest):
20
- const priorities = [
21
- // 1. Specific: device.os.tsx
22
- `${rel}__entry-client.${platformInfo.device}.${platformInfo.os}.tsx`,
23
- // 2. DeviceType: device.tsx
24
- `${rel}__entry-client.${platformInfo.device}.tsx`,
25
- // 3. Mobile Fallback: mobile.tsx (only for phone/tablet)
26
- ...(platformInfo.device === 'phone' || platformInfo.device === 'tablet'
27
- ? [`${rel}__entry-client.mobile.tsx`]
28
- : []),
29
- // 4. OS General: os.tsx
30
- `${rel}__entry-client.${platformInfo.os}.tsx`
31
- ];
32
- // Find first existing entry following priority order
33
- for (const candidate of priorities) {
34
- if (isProduction) {
35
- // In production, check manifest
36
- const manifestKey = `dist/.entries/${candidate}`;
37
- if (manifest[manifestKey]) {
38
- entryKey = candidate;
39
- break;
40
- }
41
- }
42
- else {
43
- // In development, check if physical file exists
44
- try {
45
- await promises_1.default.access(`dist/.entries/${candidate}`);
46
- entryKey = candidate;
47
- break;
48
- }
49
- catch {
50
- // File doesn't exist, continue to next priority
51
- }
52
- }
53
- }
54
- }
55
- if (!isProduction) {
56
- return `/dist/.entries/${entryKey}`;
57
- }
58
- else {
59
- const chunk = manifest[`dist/.entries/${entryKey}`];
60
- return chunk ? `/${chunk.file}` : null;
61
- }
5
+ const platform_1 = require("../platform");
6
+ const security_1 = require("../security");
7
+ const assets_1 = require("@ressjs/assets");
8
+ var assets_2 = require("@ressjs/assets");
9
+ Object.defineProperty(exports, "resolvePageAssets", { enumerable: true, get: function () { return assets_2.resolvePageAssets; } });
10
+ /**
11
+ * Plataforma que se asume cuando la detección está desactivada.
12
+ *
13
+ * Es la misma que produce el pipeline cuando nadie declaró nada, de modo que
14
+ * apagar la detección y recibir una petición anónima den el mismo resultado.
15
+ */
16
+ function fallbackPlatform() {
17
+ return platform_1.DEFAULT_PLATFORM;
62
18
  }
63
- function generateClientCSS(pageFile, platformInfo, manifest, isProduction) {
64
- if (!isProduction || !pageFile) {
65
- return '';
66
- }
67
- // Sanitizar nombre: convertir [id] a _id_ para nombres de archivo (igual que en pages.ts)
68
- const rel = pageFile
69
- .replace(/^app\/pages\//, '')
70
- .replace(/\.tsx$|\.jsx$/, '')
71
- .replace(/\//g, '__')
72
- .replace(/\[([^\]]+)\]/g, '_$1_');
73
- let entryKey = `dist/.entries/${rel}__entry-client.tsx`;
74
- if (platformInfo && platformInfo.device !== 'desktop') {
75
- // Priority order (from highest to lowest):
76
- const priorities = [
77
- // 1. Specific: device.os.tsx
78
- `dist/.entries/${rel}__entry-client.${platformInfo.device}.${platformInfo.os}.tsx`,
79
- // 2. DeviceType: device.tsx
80
- `dist/.entries/${rel}__entry-client.${platformInfo.device}.tsx`,
81
- // 3. Mobile Fallback: mobile.tsx (only for phone/tablet)
82
- ...(platformInfo.device === 'phone' || platformInfo.device === 'tablet'
83
- ? [`dist/.entries/${rel}__entry-client.mobile.tsx`]
84
- : []),
85
- // 4. OS General: os.tsx
86
- `dist/.entries/${rel}__entry-client.${platformInfo.os}.tsx`
87
- ];
88
- // Find first existing entry following priority order
89
- for (const candidate of priorities) {
90
- if (manifest[candidate]) {
91
- entryKey = candidate;
92
- break;
93
- }
94
- }
95
- }
96
- const entryChunk = manifest[entryKey];
97
- if (entryChunk && entryChunk.css) {
98
- return entryChunk.css.map((cssFile) => `<link rel="stylesheet" href="/${cssFile}">`).join('');
99
- }
100
- return '';
101
- }
102
- async function generateCompleteHTML(context) {
103
- const { template, rendered, page, manifest, isProduction, platformInfo, serverSideResult } = context;
104
- const scriptSrc = await generateClientScript(page.file, platformInfo, manifest, isProduction);
105
- const scriptTag = scriptSrc ? `<script type="module" src="${scriptSrc}"></script>` : '';
106
- const cssLinks = page?.file ? generateClientCSS(page.file, platformInfo, manifest, isProduction) : '';
107
- // Construir contenido HEAD extra y atributos desde serverSideResult
19
+ async function generateCompleteHTML(context, security) {
20
+ const { template, rendered, page, platformInfo, serverSideResult, catalog, assets } = context;
21
+ const ctx = security ?? {
22
+ isProduction: context.isProduction,
23
+ options: (0, security_1.resolveSecurityOptions)(),
24
+ route: page?.route ?? '',
25
+ };
26
+ const escapeCtx = { where: '', isProduction: ctx.isProduction, route: ctx.route };
27
+ const nonce = ctx.nonce;
28
+ const platform = platformInfo ?? fallbackPlatform();
29
+ const resolved = context.styles ?? (catalog && assets && page?.pageId
30
+ ? (0, assets_1.resolvePageAssets)(page.pageId, platform, catalog, assets)
31
+ : { js: '', css: [] });
32
+ const scriptTag = resolved.js
33
+ ? `<script type="module"${nonceAttr(nonce)} src="${(0, security_1.escapeAttrValue)(resolved.js)}"></script>`
34
+ : '';
35
+ const cssLinks = resolved.css
36
+ .map((href) => `<link rel="stylesheet" href="${(0, security_1.escapeAttrValue)(href)}">`)
37
+ .join('');
108
38
  let headContent = cssLinks;
109
39
  let htmlAttributes = '';
110
40
  let bodyAttributes = '';
111
41
  let pageTitle = '';
112
42
  if (serverSideResult?.html) {
113
43
  if (serverSideResult.html.head?.attributes) {
114
- htmlAttributes = Object.entries(serverSideResult.html.head.attributes)
115
- .map(([k, v]) => `${k}="${v}"`).join(' ');
44
+ htmlAttributes = (0, security_1.renderAttrs)(serverSideResult.html.head.attributes, {
45
+ ...escapeCtx,
46
+ where: '<html>',
47
+ });
116
48
  }
117
49
  if (serverSideResult.html.body?.attributes) {
118
- bodyAttributes = Object.entries(serverSideResult.html.body.attributes)
119
- .map(([k, v]) => `${k}="${v}"`).join(' ');
50
+ bodyAttributes = (0, security_1.renderAttrs)(serverSideResult.html.body.attributes, {
51
+ ...escapeCtx,
52
+ where: '<body>',
53
+ });
120
54
  }
121
55
  if (serverSideResult.html.head?.extraTags) {
122
- headContent += '\n' + serverSideResult.html.head.extraTags.join('\n');
123
- }
124
- if (serverSideResult.title || serverSideResult.html.head?.title) {
125
- pageTitle = `<title>${serverSideResult.title || serverSideResult.html.head?.title}</title>`;
56
+ headContent +=
57
+ '\n' +
58
+ (0, security_1.renderHeadTags)(normalizeHeadTags(serverSideResult.html.head.extraTags), escapeCtx, {
59
+ allowScriptTags: ctx.options.head.allowScriptTags,
60
+ extraAllowlist: ctx.options.head.extraTagAllowlist,
61
+ nonce,
62
+ });
126
63
  }
64
+ const title = serverSideResult.title || serverSideResult.html.head?.title;
65
+ if (title)
66
+ pageTitle = `<title>${(0, security_1.escapeHtmlText)(title)}</title>`;
127
67
  }
68
+ // La plataforma sólo se escribe si la página varía por algo. Si no varía, el
69
+ // documento tiene que ser idéntico para todos —es lo que lo hace cacheable— y
70
+ // el cliente la detecta por su cuenta.
71
+ const varies = (ctx.varyBy?.length ?? 0) > 0;
72
+ const platformTravels = ctx.options.serializePlatform === 'always' ||
73
+ (ctx.options.serializePlatform === 'auto' && varies);
74
+ // El estado que viaja. `__RESS_PAGE__` sólo en desarrollo: es una ruta del
75
+ // sistema de archivos del proyecto y no le aporta nada al cliente.
76
+ const blocks = [
77
+ ...(platformTravels ? [{ varName: '__RESS_PLATFORM__', value: platform }] : []),
78
+ { varName: '__RESS_PROPS__', value: rendered.props || {} },
79
+ { varName: '__RESS_ROUTE__', value: page?.route ?? '' },
80
+ // Alias del modelo anterior. Se emiten una versión más para no romper a
81
+ // quien los lea hoy.
82
+ { varName: '__INITIAL_PROPS__', value: rendered.props || {} },
83
+ { varName: '__PAGE_ROUTE__', value: page?.route ?? '' },
84
+ ...(ctx.isProduction
85
+ ? []
86
+ : [
87
+ { varName: '__RESS_PAGE__', value: page?.file ?? '' },
88
+ { varName: '__PAGE_FILE__', value: page?.file ?? '' },
89
+ ]),
90
+ ];
128
91
  let html = template;
129
92
  if (htmlAttributes)
130
93
  html = html.replace('<html', `<html ${htmlAttributes}`);
@@ -132,15 +95,21 @@ async function generateCompleteHTML(context) {
132
95
  html = html.replace('<body', `<body ${bodyAttributes}`);
133
96
  if (pageTitle)
134
97
  html = html.replace(/<title>.*?<\/title>/i, pageTitle);
135
- html = html
98
+ return html
136
99
  .replace('<!--app-head-->', headContent)
137
100
  .replace('<!--app-html-->', rendered.html)
138
- .replace('</body>', `<script>
139
- window.__INITIAL_PROPS__=${JSON.stringify(rendered.props || {})};
140
- window.__PAGE_ROUTE__=${JSON.stringify(page.route)};
141
- window.__PAGE_FILE__=${JSON.stringify(page.file)};
142
- </script>
143
- ${scriptTag}
144
- </body>`);
145
- return html;
101
+ .replace('</body>', `${(0, security_1.renderStateScript)(blocks, nonce)}${scriptTag}</body>`);
102
+ }
103
+ const nonceAttr = (nonce) => (nonce ? ` nonce="${(0, security_1.escapeAttrValue)(nonce)}"` : '');
104
+ /**
105
+ * Acepta la forma estructurada y descarta el string de HTML crudo.
106
+ *
107
+ * Un array de strings no se puede filtrar sin analizar HTML, y analizarlo para
108
+ * decidir si es seguro es exactamente el problema que la lista de etiquetas
109
+ * admitidas evita. F-004 ya produce la forma estructurada.
110
+ */
111
+ function normalizeHeadTags(tags) {
112
+ if (!Array.isArray(tags))
113
+ return [];
114
+ return tags.filter((t) => typeof t === 'object' && t !== null && typeof t.tag === 'string');
146
115
  }
@@ -1,4 +1,5 @@
1
1
  import { Request, RequestHandler, Response } from 'express';
2
+ import type { ModuleLoader } from '../runtime/module-loader';
2
3
  export interface MiddlewareInfo {
3
4
  route: string;
4
5
  file: string;
@@ -32,11 +33,11 @@ export declare function getMiddlewares(): MiddlewareInfo[];
32
33
  /**
33
34
  * Carga middlewares para una página específica y los convierte en middlewares de Express
34
35
  */
35
- export declare function loadPageMiddlewares(pageRoute: string, vite?: any): Promise<RequestHandler[]>;
36
+ export declare function loadPageMiddlewares(pageRoute: string, loader?: ModuleLoader): Promise<RequestHandler[]>;
36
37
  /**
37
38
  * Carga el módulo completo de una página
38
39
  */
39
- export declare function loadPageModule(pageFile: string, vite?: any): Promise<PageModule | null>;
40
+ export declare function loadPageModule(pageFile: string, loader?: ModuleLoader): Promise<PageModule | null>;
40
41
  /**
41
42
  * Convierte getServerSideProps en un middleware de Express
42
43
  */
@@ -45,21 +46,20 @@ export declare function createGetServerSidePropsMiddleware(pageModule: PageModul
45
46
  * Creates a unified error handler for a specific page route
46
47
  * This replaces the old createPageErrorMiddleware with a more useful approach
47
48
  */
48
- export declare function createPageErrorHandler(pageFile: string, vite?: any): (err: any, req: any, res: any, next: any) => Promise<void>;
49
+ export declare function createPageErrorHandler(pageFile: string, loader?: ModuleLoader): (err: any, req: any, res: any, next: any) => Promise<void>;
49
50
  /**
50
51
  * Creates a dynamic middleware handler that reloads middlewares on each request in development
51
52
  * This enables HMR for middlewares
52
53
  * I FUCKING HATE THIS FUNCTION BUT IT SEEMS TO WORK
53
54
  */
54
- export declare function createDynamicPageMiddlewares(pageRoute: string, pageFile: string, vite?: any): RequestHandler;
55
55
  /**
56
56
  * 1. Resuelve middlewares previos al getServerSideProps
57
57
  */
58
- export declare function getPagePrevMiddlewares(pageRoute: string, vite?: any): Promise<RequestHandler[]>;
58
+ export declare function getPagePrevMiddlewares(pageRoute: string, loader?: ModuleLoader): Promise<RequestHandler[]>;
59
59
  /**
60
60
  * 2. Convierte getServerSideProps a middleware
61
61
  */
62
- export declare function getServerSidePropsAsMiddleware(pageFile: string, vite?: any): Promise<RequestHandler>;
62
+ export declare function getServerSidePropsAsMiddleware(pageFile: string, loader?: ModuleLoader): Promise<RequestHandler>;
63
63
  /**
64
64
  * 3. Error middleware con fallback automático y jerarquía
65
65
  * Orden de prioridad (el más específico gana):
@@ -69,4 +69,4 @@ export declare function getServerSidePropsAsMiddleware(pageFile: string, vite?:
69
69
  * 4. errorMiddleware en root middlewares.ts (más general)
70
70
  * 5. defaultErrorMiddleware (fallback)
71
71
  */
72
- export declare function getErrorMiddleware(pageFile: string, vite?: any): Promise<any>;
72
+ export declare function getErrorMiddleware(pageFile: string, loader?: ModuleLoader): Promise<any>;
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
4
  };
@@ -41,25 +8,29 @@ exports.loadPageMiddlewares = loadPageMiddlewares;
41
8
  exports.loadPageModule = loadPageModule;
42
9
  exports.createGetServerSidePropsMiddleware = createGetServerSidePropsMiddleware;
43
10
  exports.createPageErrorHandler = createPageErrorHandler;
44
- exports.createDynamicPageMiddlewares = createDynamicPageMiddlewares;
45
11
  exports.getPagePrevMiddlewares = getPagePrevMiddlewares;
46
12
  exports.getServerSidePropsAsMiddleware = getServerSidePropsAsMiddleware;
47
13
  exports.getErrorMiddleware = getErrorMiddleware;
48
14
  const node_path_1 = __importDefault(require("node:path"));
49
15
  const fast_glob_1 = __importDefault(require("fast-glob"));
50
- const pages_1 = require("../pages");
16
+ const prod_server_1 = require("../runtime/prod-server");
17
+ const module_extensions_1 = require("../fs/module-extensions");
51
18
  /**
52
19
  * Busca archivos de middlewares tanto específicos por página como globales por carpeta
53
20
  */
54
21
  function getMiddlewares() {
55
- // Busca archivos .middlewares.ts y middlewares.ts
56
- const files = fast_glob_1.default.sync('app/pages/**/*.middlewares.{ts,js}');
57
- const globalFiles = fast_glob_1.default.sync('app/pages/**/middlewares.{ts,js}');
22
+ // Las dos formas: `algo.middlewares.<ext>` para una página, `middlewares.<ext>`
23
+ // para una carpeta. Qué extensiones cuentan lo declara la política, no este archivo.
24
+ const [globalGlob, pageGlobPattern] = (0, module_extensions_1.middlewareGlobs)((0, module_extensions_1.getExtensionPolicy)());
25
+ const files = fast_glob_1.default.sync(pageGlobPattern);
26
+ const globalFiles = fast_glob_1.default.sync(globalGlob);
58
27
  const middlewares = [];
59
28
  // Procesar archivos específicos de página: page.middlewares.ts
60
29
  for (const file of files) {
61
- let route = file.replace(/^app\/pages/, '').replace(/\.middlewares\.(ts|js)$/, '');
62
- route = route.replace(/\/index$/, '') || '/';
30
+ // La derivación recorta cualquier extensión reconocida: antes sólo quitaba
31
+ // `.ts` y `.js`, así que un `.middlewares.tsx` producía una ruta con la
32
+ // extensión adentro, no coincidía con ninguna página y no corría nunca.
33
+ let route = (0, module_extensions_1.middlewareRoute)(file).replace(/\/index$/, '') || '/';
63
34
  // Calcular depth: contar slashes en la ruta del archivo
64
35
  const depth = (file.match(/\//g) || []).length;
65
36
  middlewares.push({
@@ -72,8 +43,7 @@ function getMiddlewares() {
72
43
  }
73
44
  // Procesar archivos globales: middlewares.ts
74
45
  for (const file of globalFiles) {
75
- let route = file.replace(/^app\/pages/, '').replace(/\/middlewares\.(ts|js)$/, '');
76
- route = route || '/';
46
+ let route = (0, module_extensions_1.middlewareRoute)(file) || '/';
77
47
  // Calcular depth: contar slashes en la ruta del archivo
78
48
  const depth = (file.match(/\//g) || []).length;
79
49
  middlewares.push({
@@ -89,7 +59,7 @@ function getMiddlewares() {
89
59
  /**
90
60
  * Carga middlewares para una página específica y los convierte en middlewares de Express
91
61
  */
92
- async function loadPageMiddlewares(pageRoute, vite) {
62
+ async function loadPageMiddlewares(pageRoute, loader) {
93
63
  const allMiddlewares = getMiddlewares();
94
64
  // Filtrar middlewares relevantes para esta página usando jerarquía
95
65
  const relevantMiddlewares = allMiddlewares.filter(middleware => {
@@ -121,7 +91,7 @@ async function loadPageMiddlewares(pageRoute, vite) {
121
91
  // Cargar middlewares de archivos .middlewares.ts
122
92
  for (const middlewareFile of relevantMiddlewares) {
123
93
  try {
124
- const moduleToLoad = await loadMiddlewareModule(middlewareFile, vite);
94
+ const moduleToLoad = await loadMiddlewareModule(middlewareFile, loader);
125
95
  const handlers = moduleToLoad.default || [];
126
96
  for (const handler of handlers) {
127
97
  if (typeof handler === 'function') {
@@ -138,7 +108,7 @@ async function loadPageMiddlewares(pageRoute, vite) {
138
108
  /**
139
109
  * Carga el módulo completo de una página
140
110
  */
141
- async function loadPageModule(pageFile, vite) {
111
+ async function loadPageModule(pageFile, loader) {
142
112
  const isProduction = process.env.NODE_ENV === 'production';
143
113
  const cacheKey = `${pageFile}-${process.env.NODE_ENV || 'development'}`;
144
114
  // Only use cache in production mode to allow HMR in development
@@ -147,19 +117,12 @@ async function loadPageModule(pageFile, vite) {
147
117
  }
148
118
  try {
149
119
  let pageModule;
150
- if (vite) {
151
- const modulePath = `/${pageFile}`;
152
- pageModule = await vite.ssrLoadModule(modulePath);
120
+ if (loader) {
121
+ pageModule = await loader.load(`/${pageFile}`);
153
122
  }
154
123
  else {
155
- if (pageFile.endsWith('.tsx')) {
156
- const moduleUrl = (0, pages_1.getCompiledProdPage)(pageFile);
157
- pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
158
- }
159
- else {
160
- const moduleUrl = node_path_1.default.resolve(pageFile);
161
- pageModule = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
162
- }
124
+ const moduleUrl = (0, prod_server_1.resolveServerModulePath)(pageFile);
125
+ pageModule = await import(/* @vite-ignore */ moduleUrl);
163
126
  }
164
127
  const result = pageModule;
165
128
  // Only cache in production mode
@@ -217,9 +180,9 @@ function createGetServerSidePropsMiddleware(pageModule) {
217
180
  * Creates a unified error handler for a specific page route
218
181
  * This replaces the old createPageErrorMiddleware with a more useful approach
219
182
  */
220
- function createPageErrorHandler(pageFile, vite) {
183
+ function createPageErrorHandler(pageFile, loader) {
221
184
  return async (err, req, res, next) => {
222
- const errorMiddleware = await getErrorMiddleware(pageFile, vite);
185
+ const errorMiddleware = await getErrorMiddleware(pageFile, loader);
223
186
  errorMiddleware(err, req, res, next);
224
187
  };
225
188
  }
@@ -238,41 +201,17 @@ const defaultErrorMiddleware = (err, _req, res, _next) => {
238
201
  * This enables HMR for middlewares
239
202
  * I FUCKING HATE THIS FUNCTION BUT IT SEEMS TO WORK
240
203
  */
241
- function createDynamicPageMiddlewares(pageRoute, pageFile, vite) {
242
- return async (req, res, next) => {
243
- try {
244
- const middlewares = [
245
- ...(await loadPageMiddlewares(pageRoute, vite)),
246
- await getServerSidePropsAsMiddleware(pageFile, vite)
247
- ];
248
- // Execute middlewares sequentially
249
- let currentIndex = 0;
250
- const executeNext = (err) => {
251
- if (err)
252
- return next(err);
253
- const currentMiddleware = middlewares[currentIndex++];
254
- if (!currentMiddleware)
255
- return next();
256
- currentMiddleware(req, res, executeNext);
257
- };
258
- executeNext();
259
- }
260
- catch (error) {
261
- next(error);
262
- }
263
- };
264
- }
265
204
  /**
266
205
  * 1. Resuelve middlewares previos al getServerSideProps
267
206
  */
268
- async function getPagePrevMiddlewares(pageRoute, vite) {
269
- return await loadPageMiddlewares(pageRoute, vite);
207
+ async function getPagePrevMiddlewares(pageRoute, loader) {
208
+ return await loadPageMiddlewares(pageRoute, loader);
270
209
  }
271
210
  /**
272
211
  * 2. Convierte getServerSideProps a middleware
273
212
  */
274
- async function getServerSidePropsAsMiddleware(pageFile, vite) {
275
- const pageModule = await loadPageModule(pageFile, vite);
213
+ async function getServerSidePropsAsMiddleware(pageFile, loader) {
214
+ const pageModule = await loadPageModule(pageFile, loader);
276
215
  return pageModule ? createGetServerSidePropsMiddleware(pageModule) : (_req, _res, next) => next();
277
216
  }
278
217
  /**
@@ -284,14 +223,14 @@ async function getServerSidePropsAsMiddleware(pageFile, vite) {
284
223
  * 4. errorMiddleware en root middlewares.ts (más general)
285
224
  * 5. defaultErrorMiddleware (fallback)
286
225
  */
287
- async function getErrorMiddleware(pageFile, vite) {
288
- const pageModule = await loadPageModule(pageFile, vite);
226
+ async function getErrorMiddleware(pageFile, loader) {
227
+ const pageModule = await loadPageModule(pageFile, loader);
289
228
  // 1. Prioridad máxima: errorMiddleware en la página
290
229
  if (pageModule?.errorMiddleware) {
291
230
  return pageModule.errorMiddleware;
292
231
  }
293
232
  // 2-4. Buscar errorMiddleware en middlewares siguiendo jerarquía
294
- const errorMiddleware = await findErrorMiddlewareInHierarchy(pageFile, vite);
233
+ const errorMiddleware = await findErrorMiddlewareInHierarchy(pageFile, loader);
295
234
  if (errorMiddleware) {
296
235
  return errorMiddleware;
297
236
  }
@@ -302,11 +241,20 @@ async function getErrorMiddleware(pageFile, vite) {
302
241
  * Busca errorMiddleware en la jerarquía de middlewares
303
242
  * Desde el más específico (página) hasta el más general (root)
304
243
  */
305
- async function findErrorMiddlewareInHierarchy(pageFile, vite) {
244
+ async function findErrorMiddlewareInHierarchy(pageFile, loader) {
306
245
  // Obtener todos los middlewares que podrían aplicar a esta página
307
246
  const allMiddlewares = getMiddlewares();
308
247
  // Convertir pageFile a route para matching
309
- let pageRoute = pageFile.replace(/^app\/pages/, '').replace(/\.(tsx|ts|jsx|js)$/, '');
248
+ // Sin `try` esto lanzaría desde el camino de error —el que atiende cuando algo
249
+ // ya falló—, y una página que no se pudo renderizar terminaría en una
250
+ // excepción sin manejar en vez de en la página de error.
251
+ let pageRoute;
252
+ try {
253
+ pageRoute = '/' + (0, module_extensions_1.pageIdOf)(pageFile);
254
+ }
255
+ catch {
256
+ pageRoute = '/' + pageFile.replace(/^app\/pages\//, '').replace(/\.[^./]+$/, '');
257
+ }
310
258
  pageRoute = pageRoute.replace(/\/index$/, '') || '/';
311
259
  // Filtrar middlewares relevantes para esta página
312
260
  const relevantMiddlewares = allMiddlewares
@@ -336,7 +284,7 @@ async function findErrorMiddlewareInHierarchy(pageFile, vite) {
336
284
  // Buscar errorMiddleware en orden de especificidad
337
285
  for (const middlewareInfo of relevantMiddlewares) {
338
286
  try {
339
- const middlewareModule = await loadMiddlewareModule(middlewareInfo, vite);
287
+ const middlewareModule = await loadMiddlewareModule(middlewareInfo, loader);
340
288
  if (middlewareModule?.errorMiddleware) {
341
289
  return middlewareModule.errorMiddleware;
342
290
  }
@@ -347,14 +295,15 @@ async function findErrorMiddlewareInHierarchy(pageFile, vite) {
347
295
  }
348
296
  return null;
349
297
  }
350
- // Cache for loaded middleware modules to avoid multiple ssrLoadModule calls
298
+ // Caché de módulos de middleware. Sólo activa en producción: en desarrollo
299
+ // cada rearmado del router debe volver a leerlos para reflejar los cambios.
351
300
  const middlewareModuleCache = new Map();
352
- // Cache for loaded page modules to avoid multiple ssrLoadModule calls
301
+ // Caché de módulos de página. Sólo activa en producción, por el mismo motivo.
353
302
  const pageModuleCache = new Map();
354
303
  /**
355
304
  * Cargar un módulo de middleware específico
356
305
  */
357
- async function loadMiddlewareModule(middlewareInfo, vite) {
306
+ async function loadMiddlewareModule(middlewareInfo, loader) {
358
307
  const isProduction = process.env.NODE_ENV === 'production';
359
308
  const cacheKey = `${middlewareInfo.file}-${process.env.NODE_ENV || 'development'}`;
360
309
  // Only use cache in production mode to allow HMR in development
@@ -362,16 +311,15 @@ async function loadMiddlewareModule(middlewareInfo, vite) {
362
311
  return middlewareModuleCache.get(cacheKey);
363
312
  }
364
313
  let moduleToLoad;
365
- if (!isProduction && vite) {
366
- moduleToLoad = await vite.ssrLoadModule(middlewareInfo.file);
314
+ if (!isProduction && loader) {
315
+ moduleToLoad = await loader.load(middlewareInfo.file);
367
316
  }
368
317
  else {
369
- // En producción, usar archivos compilados
370
- const compiledPath = middlewareInfo.file
371
- .replace(/^app\/pages\//, 'dist/server/')
372
- .replace(/\.ts$/, '.js');
373
- const moduleUrl = node_path_1.default.resolve(compiledPath);
374
- moduleToLoad = await Promise.resolve(`${moduleUrl}`).then(s => __importStar(require(s)));
318
+ // En producción se importa el artefacto compilado. La traducción del nombre
319
+ // es la misma que usa el resto del framework: antes esta copia sólo recortaba
320
+ // `.ts`, así que un middleware `.js` cargaba un archivo inexistente.
321
+ const moduleUrl = (0, prod_server_1.resolveServerModulePath)(middlewareInfo.file);
322
+ moduleToLoad = await import(/* @vite-ignore */ moduleUrl);
375
323
  }
376
324
  // Only cache in production mode
377
325
  if (isProduction) {
@@ -1,4 +1,4 @@
1
- import { ViteConfig } from './vite-config';
1
+ import type { RessRuntime } from '../runtime/dev-server';
2
2
  export interface RequestContext {
3
3
  req: any;
4
4
  res: any;
@@ -12,6 +12,6 @@ export interface RouterConfig {
12
12
  platform: string;
13
13
  req: any;
14
14
  }) => Promise<string>;
15
- viteConfig: ViteConfig;
15
+ viteConfig: RessRuntime;
16
16
  }
17
17
  export declare function processRequest(context: RequestContext, config: RouterConfig, renderServer?: any): Promise<void>;