@ressjs/vite-router 0.5.2 → 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 +42 -32
  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 -105
  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
package/dist/pages.js CHANGED
@@ -1,54 +1,15 @@
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
  };
38
5
  Object.defineProperty(exports, "__esModule", { value: true });
39
6
  exports.convertRouteToExpress = convertRouteToExpress;
40
7
  exports.getPages = getPages;
41
- exports.getViteInput = getViteInput;
42
8
  exports.getViteSSRInput = getViteSSRInput;
43
- exports.loadManifest = loadManifest;
44
- exports.getCompiledProdPage = getCompiledProdPage;
45
- exports.resolvePlatformCSS = resolvePlatformCSS;
46
- exports.generateTempEntries = generateTempEntries;
47
- exports.generateSingleEntry = generateSingleEntry;
48
- exports.getClientEntriesInput = getClientEntriesInput;
49
- const promises_1 = __importDefault(require("node:fs/promises"));
50
9
  const node_path_1 = __importDefault(require("node:path"));
51
10
  const fast_glob_1 = __importDefault(require("fast-glob"));
11
+ const catalog_1 = require("./variants/catalog");
12
+ const module_extensions_1 = require("./fs/module-extensions");
52
13
  /**
53
14
  * Convierte rutas estilo Next.js con parámetros dinámicos a formato Express
54
15
  * Ejemplos:
@@ -59,241 +20,61 @@ const fast_glob_1 = __importDefault(require("fast-glob"));
59
20
  function convertRouteToExpress(route) {
60
21
  return route.replace(/\[([^\]]+)\]/g, ':$1');
61
22
  }
62
- function getPages() {
63
- // Busca tanto page.tsx como page/index.tsx y prioriza el más corto
64
- const files = fast_glob_1.default.sync('app/pages/**/*.{tsx,jsx}');
23
+ function getPages(policy = (0, module_extensions_1.getExtensionPolicy)()) {
24
+ const files = fast_glob_1.default
25
+ .sync((0, module_extensions_1.pageGlob)(policy))
26
+ .filter((file) => (0, module_extensions_1.isPageFile)(file, policy))
27
+ .sort();
28
+ // Dos archivos que definen la misma página son ambiguos: cuál gana dependería
29
+ // del orden del sistema de archivos, que cambia entre sistemas operativos.
30
+ //
31
+ // En desarrollo se avisa y se sigue con el primero, para no dejar el servidor
32
+ // caído mientras alguien renombra un archivo; al construir se falla.
33
+ (0, module_extensions_1.assertNoModuleCollision)(files, 'app/pages', {
34
+ strict: process.env.NODE_ENV === 'production',
35
+ });
65
36
  const seen = new Set();
66
37
  const pages = [];
67
38
  for (const file of files) {
68
- let route = file.replace(/^app\/pages/, '').replace(/\.tsx$|\.jsx$/, '');
69
- route = route.replace(/\/index$/, '') || '/';
70
- // Prioriza page.tsx sobre page/index.tsx
71
- if (!seen.has(route)) {
72
- seen.add(route);
73
- const expressRoute = convertRouteToExpress(route);
74
- pages.push({ route, expressRoute, file, abs: node_path_1.default.resolve(file) });
75
- }
39
+ // `page1.tsx` y `page1/index.tsx` describen la misma URL. Gana el primero
40
+ // por orden alfabético, que es estable.
41
+ const route = ('/' + (0, module_extensions_1.pageIdOf)(file)).replace(/\/index$/, '') || '/';
42
+ if (seen.has(route))
43
+ continue;
44
+ seen.add(route);
45
+ pages.push({
46
+ route,
47
+ expressRoute: convertRouteToExpress(route),
48
+ file,
49
+ abs: node_path_1.default.resolve(file),
50
+ pageId: (0, catalog_1.pageIdFromFile)(file),
51
+ });
76
52
  }
77
53
  return pages;
78
54
  }
79
- // Para Vite: input { [route]: absPath }
80
- function getViteInput() {
81
- const pages = getPages();
55
+ /**
56
+ * Entradas del entorno de servidor: las páginas más sus middlewares.
57
+ *
58
+ * El entorno de cliente no aparece acá: sus entradas salen del catálogo de
59
+ * variantes, porque una página produce una por cada plataforma que atiende.
60
+ */
61
+ function getViteSSRInput() {
82
62
  const input = {};
83
- for (const page of pages) {
84
- input[page.file.replace(/^app\/pages\//, '').replace(/\.tsx$|\.jsx$/, '')] = page.abs;
63
+ for (const page of getPages()) {
64
+ input[(0, module_extensions_1.pageIdOf)(page.file)] = page.abs;
85
65
  }
86
- return input;
87
- }
88
- // Para Vite SSR: input incluyendo páginas + middlewares
89
- function getViteSSRInput() {
90
- const input = getViteInput(); // Empezar con las páginas
91
- // Agregar TODOS los middlewares: .middlewares.ts y middlewares.ts
92
- const middlewareFiles = fast_glob_1.default.sync('app/pages/**/{middlewares,*.middlewares}.{ts,js}');
66
+ const middlewareFiles = (0, module_extensions_1.middlewareGlobs)((0, module_extensions_1.getExtensionPolicy)()).flatMap((g) => fast_glob_1.default.sync(g));
93
67
  for (const middlewareFile of middlewareFiles) {
94
- const key = middlewareFile.replace(/^app\/pages\//, '').replace(/\.(ts|js)$/, '');
95
- input[key] = node_path_1.default.resolve(middlewareFile);
68
+ // La clave define dónde queda el artefacto, así que tiene que coincidir con
69
+ // lo que `toCompiledPath` busca al importarlo en producción. Con la
70
+ // extensión adentro se emitía `algo.middlewares.tsx.js` y la carga fallaba.
71
+ input[(0, module_extensions_1.pageIdOf)(middlewareFile)] = node_path_1.default.resolve(middlewareFile);
96
72
  }
97
73
  return input;
98
74
  }
99
- async function loadManifest(distPath = 'dist') {
100
- const assetsDir = node_path_1.default.join(distPath, 'server/.vite');
101
- const files = await promises_1.default.readdir(assetsDir);
102
- const manifestFile = files.find(f => /^manifest-.*\.js$/.test(f));
103
- if (!manifestFile)
104
- throw new Error('No manifest file found in dist/server/assets');
105
- // Import dinámico del manifest
106
- const manifest = (await Promise.resolve(`${node_path_1.default.join(assetsDir, manifestFile)}`).then(s => __importStar(require(s)))).default;
107
- return manifest;
108
- }
109
75
  /**
110
76
  * Convierte una ruta de página TypeScript a su equivalente compilado en producción
111
77
  *
112
78
  * @param pageFile - Ruta del archivo de página (relativa: "app/pages/pokedex/index.tsx" o absoluta: "/path/to/app/pages/pokedex/index.tsx")
113
79
  * @returns Ruta absoluta del archivo compilado (ej: "/path/to/project/dist/server/pokedex/index.js")
114
80
  */
115
- function getCompiledProdPage(pageFile) {
116
- if (!pageFile.endsWith('.tsx')) {
117
- throw new Error(`getCompiledProdPage expects a .tsx file, got: ${pageFile}`);
118
- }
119
- // Si es una ruta absoluta, extraer solo la parte relativa
120
- let relativePath;
121
- if (node_path_1.default.isAbsolute(pageFile)) {
122
- // Buscar la parte después de "app/pages/" or "app\pages\" (Windows-compatible)
123
- const normalizedPath = pageFile.replace(/\\/g, '/');
124
- const appPagesIndex = normalizedPath.indexOf('app/pages/');
125
- if (appPagesIndex === -1) {
126
- throw new Error(`Absolute path must contain "app/pages/", got: ${pageFile}`);
127
- }
128
- relativePath = normalizedPath.substring(appPagesIndex);
129
- }
130
- else {
131
- relativePath = pageFile;
132
- }
133
- // Convertir app/pages/pokedex/index.tsx a dist/server/pokedex/index.js
134
- // También convierte [id] a _id_ para rutas dinámicas
135
- const compiledRelativePath = relativePath
136
- .replace(/^app\/pages\//, '') // Quitar prefijo app/pages/
137
- .replace(/\.tsx$/, '.js') // Cambiar extensión .tsx a .js
138
- .replace(/\[([^\]]+)\]/g, '_$1_'); // Convertir [id] a _id_
139
- return node_path_1.default.resolve(process.cwd(), 'dist', 'server', compiledRelativePath);
140
- }
141
- async function fileExists(file) {
142
- try {
143
- await promises_1.default.access(file);
144
- return true;
145
- }
146
- catch {
147
- return false;
148
- }
149
- }
150
- /**
151
- * Platform-aware CSS resolution
152
- * Busca CSS files con prioridades basadas en platform detection
153
- */
154
- // Función helper para determinar si es probablemente un dispositivo móvil
155
- function isProbablyMobile(platform) {
156
- // Mobile si es phone/tablet, o webview (que suele ser mobile), o category native (React Native)
157
- return platform.device === 'phone' ||
158
- platform.device === 'tablet' ||
159
- platform.category === 'webview' ||
160
- platform.category === 'native';
161
- }
162
- async function resolvePlatformCSS(basePath, platform) {
163
- // Orden de prioridad corregido: OS first → device+OS → device → mobile condicional
164
- const priorities = [];
165
- // 1. OS específico primero: android.scss, ios.scss
166
- priorities.push(`${basePath}.${platform.os}.scss`);
167
- // Para webview, agregar combinaciones específicas después del OS
168
- if (platform.category === 'webview') {
169
- // 2. webview.os.scss (ej: webview.android.scss, webview.ios.scss)
170
- priorities.push(`${basePath}.webview.${platform.os}.scss`);
171
- // 3. webview.scss general
172
- priorities.push(`${basePath}.webview.scss`);
173
- }
174
- // Para native o web, agregar combinaciones device.os
175
- if (platform.category === 'native' || platform.category === 'web') {
176
- // 2. device.os.scss (ej: phone.android.scss, tablet.ios.scss)
177
- priorities.push(`${basePath}.${platform.device}.${platform.os}.scss`);
178
- }
179
- // 3. Device específico: phone.scss, tablet.scss, desktop.scss
180
- priorities.push(`${basePath}.${platform.device}.scss`);
181
- // 4. Mobile fallback SOLO si es probablemente móvil
182
- if (isProbablyMobile(platform)) {
183
- priorities.push(`${basePath}.mobile.scss`);
184
- }
185
- // 5. Fallback final
186
- priorities.push(`${basePath}.scss`);
187
- // Retorna el primer archivo que exista
188
- for (const file of priorities) {
189
- if (await fileExists(file)) {
190
- return file;
191
- }
192
- }
193
- // Si ninguno existe, retorna el CSS base
194
- return `${basePath}.scss`;
195
- }
196
- async function generateTempEntries(distPath = 'dist', platformInfo) {
197
- const pages = getPages();
198
- const entriesDir = node_path_1.default.resolve(distPath, '.entries');
199
- // Solo crea el directorio si no existe, no lo borra
200
- await promises_1.default.mkdir(entriesDir, { recursive: true });
201
- const promises = pages.map(async (page) => {
202
- // Sanitizar nombre: convertir [id] a _id_ para nombres de archivo
203
- const rel = page.file
204
- .replace(/^app\/pages\//, '')
205
- .replace(/\.tsx$|\.jsx$/, '')
206
- .replace(/\//g, '__')
207
- .replace(/\[([^\]]+)\]/g, '_$1_');
208
- if (platformInfo && platformInfo.device !== 'desktop') {
209
- // Solo genera entry específico para mobile devices (phone, tablet)
210
- const basePath = page.file.replace(/\.(tsx|jsx)$/, '');
211
- const platformCSS = await resolvePlatformCSS(basePath, platformInfo);
212
- // Generar entry específico con el CSS resuelto (puede ser base o específico)
213
- const platformSuffix = `${platformInfo.device}.${platformInfo.os}`;
214
- const entryPath = node_path_1.default.join(entriesDir, rel + `__entry-client.${platformSuffix}.tsx`);
215
- await generateSingleEntry(page, entryPath, platformCSS);
216
- return [entryPath];
217
- }
218
- else {
219
- // Lógica mejorada: busca dinámicamente todos los archivos CSS específicos
220
- const basePath = page.file.replace(/\.(tsx|jsx)$/, '');
221
- const baseScss = basePath + '.scss';
222
- const results = [];
223
- // Genera entry-client base (desktop) - solo CSS base
224
- const entryPath = node_path_1.default.join(entriesDir, rel + '__entry-client.tsx');
225
- await generateSingleEntry(page, entryPath, baseScss);
226
- results.push(entryPath);
227
- // Buscar dinámicamente todos los archivos CSS específicos de plataforma
228
- const glob = await Promise.resolve().then(() => __importStar(require('fast-glob')));
229
- const cssFiles = await glob.default(`${basePath}.*.scss`);
230
- for (const cssFile of cssFiles) {
231
- // Extraer el sufijo del archivo CSS (ej: mobile, webview.android, desktop.linux)
232
- const suffix = cssFile
233
- .replace(basePath + '.', '')
234
- .replace('.scss', '');
235
- // Generar entry-client específico
236
- const specificEntryPath = node_path_1.default.join(entriesDir, rel + `__entry-client.${suffix}.tsx`);
237
- await generateSingleEntry(page, specificEntryPath, cssFile);
238
- results.push(specificEntryPath);
239
- }
240
- return results;
241
- }
242
- });
243
- const entryFiles = await Promise.all(promises);
244
- return entryFiles.flat().filter(Boolean);
245
- }
246
- async function generateSingleEntry(page, entryPath, preferredScssFile) {
247
- // Verifica si el archivo ya existe y es más reciente que el archivo fuente
248
- try {
249
- const entryStat = await promises_1.default.stat(entryPath);
250
- const pageStat = await promises_1.default.stat(page.abs);
251
- if (entryStat.mtime > pageStat.mtime) {
252
- return; // El entry ya existe y está actualizado
253
- }
254
- }
255
- catch {
256
- // El archivo no existe, continúa con la generación
257
- }
258
- const importPath = node_path_1.default.relative(node_path_1.default.dirname(entryPath), page.abs).replace(/\\/g, '/');
259
- // Lógica de fallback: intenta cargar el CSS preferido, si no existe carga el base
260
- let scssToImport = '';
261
- let scssImport = '';
262
- if (await fileExists(preferredScssFile)) {
263
- // Existe el CSS específico, usarlo
264
- scssToImport = preferredScssFile;
265
- }
266
- else {
267
- // No existe el CSS específico, usar el CSS base como fallback
268
- const baseScss = page.file.replace(/\.(tsx|jsx)$/, '.scss');
269
- if (await fileExists(baseScss)) {
270
- scssToImport = baseScss;
271
- }
272
- }
273
- if (scssToImport) {
274
- const scssImportPath = node_path_1.default.relative(node_path_1.default.dirname(entryPath), scssToImport).replace(/\\/g, '/');
275
- scssImport = `import "${scssImportPath.startsWith('.') ? scssImportPath : './' + scssImportPath}";`;
276
- }
277
- const template = `
278
- ${scssImport}
279
- import { StrictMode } from "react";
280
- import { hydrateRoot } from "react-dom/client";
281
- import Page from "${importPath.startsWith('.') ? importPath : './' + importPath}";
282
- const props = window.__INITIAL_PROPS__ || {};
283
- hydrateRoot(document.getElementById("root"), <StrictMode><Page {...props} /></StrictMode>);
284
- `.trim();
285
- await promises_1.default.mkdir(node_path_1.default.dirname(entryPath), { recursive: true });
286
- await promises_1.default.writeFile(entryPath, template);
287
- }
288
- async function getClientEntriesInput(distPath = 'dist') {
289
- await generateTempEntries(distPath);
290
- // Incluir todos los entry-clients: base, mobile, desktop.linux
291
- const entryFiles = fast_glob_1.default.sync(`${distPath}/.entries/**/*__entry-client*.tsx`);
292
- const input = {};
293
- for (const file of entryFiles) {
294
- // Mantener el nombre completo del archivo como key para diferenciar las plataformas
295
- const key = file.replace(new RegExp(`^${distPath}/\\.entries/`), '');
296
- input[key] = node_path_1.default.resolve(file);
297
- }
298
- return input;
299
- }
@@ -1,16 +1,13 @@
1
1
  /**
2
- * Platform detection for ress.js
3
- * Combina headers custom de React Native con User-Agent parsing
2
+ * Detección de plataforma.
3
+ *
4
+ * La implementación vive en `@ressjs/platform`, que no depende del router ni de
5
+ * Vite: así el puente del WebView, el cliente y cualquier consumidor externo
6
+ * pueden preguntarle lo mismo sin arrastrar el framework entero.
7
+ *
8
+ * Este archivo existe para que `import { detectPlatform } from '@ressjs/vite-router'`
9
+ * siga funcionando.
4
10
  */
5
- export interface PlatformInfo {
6
- category: 'web' | 'webview' | 'native';
7
- os: 'ios' | 'android' | 'windows' | 'macos' | 'linux' | 'unknown';
8
- device: 'phone' | 'tablet' | 'desktop';
9
- version?: string;
10
- appVersion?: string;
11
- source: 'headers' | 'user-agent';
12
- }
13
- /**
14
- * Detecta plataforma usando headers custom + User-Agent fallback
15
- */
16
- export declare function detectPlatform(userAgent: string, headers?: any): PlatformInfo;
11
+ export { detect, detectPlatform, DEFAULT_PLATFORM } from '@ressjs/platform';
12
+ export { hasCapability, isHandheld, isTV, isWebView } from '@ressjs/platform';
13
+ export type { NativeAppInfo, PlatformDevice, PlatformInfo, PlatformOS } from '@ressjs/platform';
package/dist/platform.js CHANGED
@@ -1,106 +1,22 @@
1
1
  "use strict";
2
2
  /**
3
- * Platform detection for ress.js
4
- * Combina headers custom de React Native con User-Agent parsing
3
+ * Detección de plataforma.
4
+ *
5
+ * La implementación vive en `@ressjs/platform`, que no depende del router ni de
6
+ * Vite: así el puente del WebView, el cliente y cualquier consumidor externo
7
+ * pueden preguntarle lo mismo sin arrastrar el framework entero.
8
+ *
9
+ * Este archivo existe para que `import { detectPlatform } from '@ressjs/vite-router'`
10
+ * siga funcionando.
5
11
  */
6
12
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.detectPlatform = detectPlatform;
8
- /**
9
- * Detecta plataforma usando headers custom + User-Agent fallback
10
- */
11
- function detectPlatform(userAgent, headers = {}) {
12
- const ressHeaders = headers;
13
- // 1. React Native headers detection
14
- if (ressHeaders['x-rn-platform']) {
15
- return {
16
- category: 'native',
17
- os: ressHeaders['x-rn-platform'] || 'android',
18
- device: 'phone', // React Native es típicamente mobile
19
- version: ressHeaders['x-rn-version'],
20
- source: 'headers'
21
- };
22
- }
23
- // 2. WebView headers detection
24
- if (ressHeaders['x-webview'] === 'true' || ressHeaders['x-ressjs-platform'] === 'webview') {
25
- const os = ressHeaders['x-platform'] || ressHeaders['x-ressjs-os'] || 'android';
26
- return {
27
- category: 'webview',
28
- os: os,
29
- device: ressHeaders['x-ressjs-device'] || 'phone',
30
- version: ressHeaders['x-ressjs-version'],
31
- appVersion: ressHeaders['x-ressjs-app-version'],
32
- source: 'headers'
33
- };
34
- }
35
- // 3. Ress.js specific headers (original logic)
36
- if (ressHeaders['x-ressjs-platform'] === 'webview') {
37
- return {
38
- category: 'webview',
39
- os: ressHeaders['x-ressjs-os'] || 'android',
40
- device: ressHeaders['x-ressjs-device'] || 'phone',
41
- version: ressHeaders['x-ressjs-version'],
42
- appVersion: ressHeaders['x-ressjs-app-version'],
43
- source: 'headers'
44
- };
45
- }
46
- // 4. User-Agent fallback detection
47
- return detectFromUserAgent(userAgent);
48
- }
49
- /**
50
- * Detección por User-Agent (navegadores estándar)
51
- */
52
- function detectFromUserAgent(userAgent) {
53
- const ua = userAgent.toLowerCase();
54
- // SPECIAL CASE: React Native
55
- if (ua.includes('reactnative')) {
56
- let os = 'android';
57
- if (ua.includes('ios')) {
58
- os = 'ios';
59
- }
60
- else if (ua.includes('android')) {
61
- os = 'android';
62
- }
63
- return {
64
- category: 'native',
65
- os,
66
- device: 'phone', // React Native siempre mobile
67
- source: 'user-agent'
68
- };
69
- }
70
- // Detectar OS
71
- let os = 'unknown';
72
- if (ua.includes('iphone') || ua.includes('ipad') || ua.includes('ios')) {
73
- os = 'ios';
74
- }
75
- else if (ua.includes('android')) {
76
- os = 'android';
77
- }
78
- else if (ua.includes('windows')) {
79
- os = 'windows';
80
- }
81
- else if (ua.includes('macintosh') || ua.includes('mac os x')) {
82
- os = 'macos';
83
- }
84
- else if (ua.includes('linux')) {
85
- os = 'linux';
86
- }
87
- // Detectar device type
88
- let device = 'desktop';
89
- if (ua.includes('ipad')) {
90
- device = 'tablet';
91
- }
92
- else if (ua.includes('mobile') || ua.includes('phone')) {
93
- device = 'phone';
94
- }
95
- else if (ua.includes('tablet')) {
96
- device = 'tablet';
97
- }
98
- // Detectar category (web vs webview)
99
- let category = 'web';
100
- return {
101
- category,
102
- os,
103
- device,
104
- source: 'user-agent'
105
- };
106
- }
13
+ exports.isWebView = exports.isTV = exports.isHandheld = exports.hasCapability = exports.DEFAULT_PLATFORM = exports.detectPlatform = exports.detect = void 0;
14
+ var platform_1 = require("@ressjs/platform");
15
+ Object.defineProperty(exports, "detect", { enumerable: true, get: function () { return platform_1.detect; } });
16
+ Object.defineProperty(exports, "detectPlatform", { enumerable: true, get: function () { return platform_1.detectPlatform; } });
17
+ Object.defineProperty(exports, "DEFAULT_PLATFORM", { enumerable: true, get: function () { return platform_1.DEFAULT_PLATFORM; } });
18
+ var platform_2 = require("@ressjs/platform");
19
+ Object.defineProperty(exports, "hasCapability", { enumerable: true, get: function () { return platform_2.hasCapability; } });
20
+ Object.defineProperty(exports, "isHandheld", { enumerable: true, get: function () { return platform_2.isHandheld; } });
21
+ Object.defineProperty(exports, "isTV", { enumerable: true, get: function () { return platform_2.isTV; } });
22
+ Object.defineProperty(exports, "isWebView", { enumerable: true, get: function () { return platform_2.isWebView; } });
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Declaración de los entornos de build de ress.js.
3
+ *
4
+ * Cliente y servidor se describen como entornos de Vite, de modo que una sola
5
+ * invocación de build produzca ambos.
6
+ */
7
+ /**
8
+ * Directorios de salida.
9
+ *
10
+ * Es la única declaración: la comparten el build y el runtime de producción, que
11
+ * es lo que garantiza que el servidor busque donde el build escribió.
12
+ */
13
+ export declare const OUT_DIR: {
14
+ /** Raíz de salida. El manifest de rutas vive acá, junto a los dos entornos. */
15
+ readonly base: "dist";
16
+ readonly client: "dist/client";
17
+ readonly ssr: "dist/server";
18
+ };
19
+ export interface EnvironmentInputs {
20
+ client: Record<string, string>;
21
+ ssr: Record<string, string>;
22
+ }
23
+ /**
24
+ * Construye la porción de configuración de Vite que aporta el framework.
25
+ *
26
+ * Se devuelve desde el hook `config` del plugin, de modo que Vite la fusione con
27
+ * la configuración del usuario según sus reglas normales: lo que el usuario
28
+ * declare se aplica encima sin que el framework lo pise.
29
+ *
30
+ * Las entradas llegan resueltas desde afuera. Quién las enumera es un detalle
31
+ * interno del framework, no algo que el proyecto consumidor deba declarar en su
32
+ * `vite.config.ts`.
33
+ */
34
+ export declare function defineEnvironments(inputs?: EnvironmentInputs): {
35
+ environments: {
36
+ client: {
37
+ build: {
38
+ outDir: "dist/client";
39
+ manifest: boolean;
40
+ rolldownOptions: {
41
+ input: Record<string, string>;
42
+ };
43
+ };
44
+ };
45
+ ssr: {
46
+ build: {
47
+ outDir: "dist/server";
48
+ ssr: boolean;
49
+ rolldownOptions: {
50
+ input: Record<string, string>;
51
+ };
52
+ };
53
+ };
54
+ };
55
+ builder: {
56
+ /**
57
+ * Secuencial, y en este orden: el build de servidor necesita el manifest
58
+ * que produce el de cliente para poder resolver assets por página. En
59
+ * paralelo, el servidor podría leer un manifest incompleto o inexistente.
60
+ */
61
+ buildApp: (builder: {
62
+ environments: Record<string, unknown>;
63
+ build: (env: unknown) => Promise<unknown>;
64
+ }) => Promise<void>;
65
+ };
66
+ };
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * Declaración de los entornos de build de ress.js.
4
+ *
5
+ * Cliente y servidor se describen como entornos de Vite, de modo que una sola
6
+ * invocación de build produzca ambos.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.OUT_DIR = void 0;
10
+ exports.defineEnvironments = defineEnvironments;
11
+ /**
12
+ * Directorios de salida.
13
+ *
14
+ * Es la única declaración: la comparten el build y el runtime de producción, que
15
+ * es lo que garantiza que el servidor busque donde el build escribió.
16
+ */
17
+ exports.OUT_DIR = {
18
+ /** Raíz de salida. El manifest de rutas vive acá, junto a los dos entornos. */
19
+ base: 'dist',
20
+ client: 'dist/client',
21
+ ssr: 'dist/server',
22
+ };
23
+ /**
24
+ * Construye la porción de configuración de Vite que aporta el framework.
25
+ *
26
+ * Se devuelve desde el hook `config` del plugin, de modo que Vite la fusione con
27
+ * la configuración del usuario según sus reglas normales: lo que el usuario
28
+ * declare se aplica encima sin que el framework lo pise.
29
+ *
30
+ * Las entradas llegan resueltas desde afuera. Quién las enumera es un detalle
31
+ * interno del framework, no algo que el proyecto consumidor deba declarar en su
32
+ * `vite.config.ts`.
33
+ */
34
+ function defineEnvironments(inputs = { client: {}, ssr: {} }) {
35
+ const clientOutDir = exports.OUT_DIR.client;
36
+ const ssrOutDir = exports.OUT_DIR.ssr;
37
+ return {
38
+ environments: {
39
+ client: {
40
+ build: {
41
+ outDir: clientOutDir,
42
+ // El manifest del cliente es lo que permite al servidor resolver, en
43
+ // producción, qué artefacto corresponde a cada página y variante.
44
+ manifest: true,
45
+ rolldownOptions: {
46
+ input: inputs.client,
47
+ },
48
+ },
49
+ },
50
+ ssr: {
51
+ build: {
52
+ outDir: ssrOutDir,
53
+ ssr: true,
54
+ rolldownOptions: {
55
+ input: inputs.ssr,
56
+ },
57
+ },
58
+ },
59
+ },
60
+ builder: {
61
+ /**
62
+ * Secuencial, y en este orden: el build de servidor necesita el manifest
63
+ * que produce el de cliente para poder resolver assets por página. En
64
+ * paralelo, el servidor podría leer un manifest incompleto o inexistente.
65
+ */
66
+ buildApp: async (builder) => {
67
+ await builder.build(builder.environments.client);
68
+ await builder.build(builder.environments.ssr);
69
+ },
70
+ },
71
+ };
72
+ }