vatts 1.0.5 → 1.1.0-alpha.1

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.
@@ -292,6 +292,7 @@ function initializeClient() {
292
292
  const root = (0, client_1.createRoot)(container);
293
293
  // Salva a referência globalmente
294
294
  window.__VATTS_ROOT__ = root;
295
+ console.log(componentMap, initialData);
295
296
  root.render((0, jsx_runtime_1.jsx)(App, { componentMap: componentMap, routes: initialData.routes, initialComponentPath: initialData.initialComponentPath, initialParams: initialData.initialParams, layoutComponent: window.__VATTS_LAYOUT__ }));
296
297
  }
297
298
  catch (error) {
package/dist/helpers.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import http, { Server } from 'http';
3
- import type { VattsOptions } from './types';
3
+ import type { VattsOptions, VattsConfig } from './types';
4
4
  import https from 'https';
5
+ export declare let config: VattsConfig | undefined;
5
6
  export declare function app(options?: VattsOptions): {
6
7
  /**
7
8
  * Integra com uma aplicação de qualquer framework (Express, Fastify, etc)
package/dist/helpers.js CHANGED
@@ -53,6 +53,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
53
53
  return (mod && mod.__esModule) ? mod : { "default": mod };
54
54
  };
55
55
  Object.defineProperty(exports, "__esModule", { value: true });
56
+ exports.config = void 0;
56
57
  exports.app = app;
57
58
  // Imports Nativos do Node.js (movidos para o topo)
58
59
  const http_1 = __importDefault(require("http"));
@@ -133,6 +134,7 @@ async function loadVattsConfig(projectDir, phase) {
133
134
  maxUrlLength: 2048,
134
135
  accessLogging: true,
135
136
  envFiles: [],
137
+ pathRouter: false
136
138
  };
137
139
  try {
138
140
  // Tenta primeiro .ts, depois .js
@@ -321,6 +323,7 @@ async function initNativeServer(vattsApp, options, port, hostname) {
321
323
  const projectDir = options.dir || process.cwd();
322
324
  const phase = options.dev ? 'development' : 'production';
323
325
  const vattsConfig = await loadVattsConfig(projectDir, phase);
326
+ exports.config = vattsConfig;
324
327
  // Passa envFiles da config para as opções do vatts
325
328
  options.envFiles = vattsConfig.envFiles;
326
329
  await vattsApp.prepare();
package/dist/index.js CHANGED
@@ -70,6 +70,7 @@ const env_1 = require("./env/env");
70
70
  // RPC
71
71
  const server_1 = require("./rpc/server");
72
72
  const types_1 = require("./rpc/types");
73
+ const helpers_1 = require("./helpers");
73
74
  // Helpers de segurança para servir arquivos estáticos sem path traversal
74
75
  function isSuspiciousPathname(p) {
75
76
  try {
@@ -97,8 +98,8 @@ Object.defineProperty(exports, "FastifyAdapter", { enumerable: true, get: functi
97
98
  var factory_2 = require("./adapters/factory");
98
99
  Object.defineProperty(exports, "FrameworkAdapterFactory", { enumerable: true, get: function () { return factory_2.FrameworkAdapterFactory; } });
99
100
  // Exporta os helpers para facilitar integração
100
- var helpers_1 = require("./helpers");
101
- Object.defineProperty(exports, "app", { enumerable: true, get: function () { return helpers_1.app; } });
101
+ var helpers_2 = require("./helpers");
102
+ Object.defineProperty(exports, "app", { enumerable: true, get: function () { return helpers_2.app; } });
102
103
  // Função para verificar se o projeto é grande o suficiente para se beneficiar de chunks
103
104
  function isLargeProject(projectDir) {
104
105
  try {
@@ -147,9 +148,17 @@ function createEntryFile(projectDir, routes) {
147
148
  const notFoundImport = notFound
148
149
  ? `import NotFoundComponent from '${path_1.default.relative(tempDir, notFound.componentPath).replace(/\\/g, '/')}';`
149
150
  : '';
150
- const componentRegistration = routes
151
- .map((route, index) => ` '${route.componentPath}': route${index}.component || route${index}.default?.component,`)
152
- .join('\n');
151
+ let componentRegistration;
152
+ if (helpers_1.config?.pathRouter === true) {
153
+ componentRegistration = routes
154
+ .map((route, index) => ` '${route.componentPath}': route${index} || route${index}.default,`)
155
+ .join('\n');
156
+ }
157
+ else {
158
+ componentRegistration = routes
159
+ .map((route, index) => ` '${route.componentPath}': route${index}.component || route${index}.default?.component,`)
160
+ .join('\n');
161
+ }
153
162
  const layoutRegistration = layout
154
163
  ? `window.__VATTS_LAYOUT__ = LayoutComponent.default || LayoutComponent;`
155
164
  : `window.__VATTS_LAYOUT__ = null;`;
@@ -294,7 +303,7 @@ function vatts(options) {
294
303
  }
295
304
  },
296
305
  executeInstrumentation: () => {
297
- const instrumentationFile = fs_1.default.readdirSync(path_1.default.join(dir, 'src')).find(file => /^vattsweb\.(tsx|jsx|js|ts)$/.test(file));
306
+ const instrumentationFile = fs_1.default.readdirSync(path_1.default.join(dir, 'src')).find(file => /^vattsweb\.(js|ts)$/.test(file));
298
307
  if (instrumentationFile) {
299
308
  const instrumentationPath = path_1.default.join(dir, 'src', instrumentationFile);
300
309
  const instrumentation = require(instrumentationPath);
package/dist/router.d.ts CHANGED
@@ -9,6 +9,9 @@ export declare function getLayout(): {
9
9
  componentPath: string;
10
10
  metadata?: any;
11
11
  } | null;
12
+ export declare function loadPathRoutes(routesDir: string): (RouteConfig & {
13
+ componentPath: string;
14
+ })[];
12
15
  export declare function loadRoutes(routesDir: string): (RouteConfig & {
13
16
  componentPath: string;
14
17
  })[];
package/dist/router.js CHANGED
@@ -7,6 +7,7 @@ exports.clearAllRouteCache = clearAllRouteCache;
7
7
  exports.clearFileCache = clearFileCache;
8
8
  exports.loadLayout = loadLayout;
9
9
  exports.getLayout = getLayout;
10
+ exports.loadPathRoutes = loadPathRoutes;
10
11
  exports.loadRoutes = loadRoutes;
11
12
  exports.findMatchingRoute = findMatchingRoute;
12
13
  exports.loadBackendRoutes = loadBackendRoutes;
@@ -39,6 +40,7 @@ const url_1 = require("url");
39
40
  const console_1 = __importDefault(require("./api/console"));
40
41
  const factory_1 = require("./adapters/factory");
41
42
  const http_1 = require("./api/http");
43
+ const helpers_1 = require("./helpers");
42
44
  // --- Estado Global ---
43
45
  let allRoutes = [];
44
46
  let allBackendRoutes = [];
@@ -125,7 +127,7 @@ function requireWithoutStyles(modulePath) {
125
127
  }
126
128
  // --- Carregamento de Layout (Otimizado - Sem I/O de Disco) ---
127
129
  function loadLayout(webDir) {
128
- const extensions = ['layout.tsx', 'layout.ts'];
130
+ const extensions = ['layout.tsx', 'layout.jsx'];
129
131
  let layoutFile = null;
130
132
  for (const ext of extensions) {
131
133
  const fullPath = path_1.default.join(webDir, ext);
@@ -162,9 +164,98 @@ function loadLayout(webDir) {
162
164
  }
163
165
  function getLayout() { return layoutComponent; }
164
166
  // --- Carregamento de Rotas Frontend ---
167
+ // Helper para converter o caminho do arquivo no padrão de URL (Next.js style)
168
+ function convertPathToRoutePattern(absolutePath, routesDir) {
169
+ // 1. Pega o caminho relativo e normaliza as barras
170
+ let relPath = path_1.default.relative(routesDir, absolutePath).replace(/\\/g, '/');
171
+ // 2. Remove o nome do arquivo (page.tsx, page.ts, page.jsx ou page.js) do final
172
+ relPath = relPath.replace(/\/?page\.(?:ts|js)x?$/, '');
173
+ // 3. Remove os "Route Groups" do Next.js, ex: (auth)/login vira /login
174
+ relPath = relPath.replace(/\/\([^)]+\)/g, '').replace(/^\([^)]+\)\/?/, '');
175
+ // 4. Se a string ficou vazia, é a rota raiz
176
+ if (!relPath)
177
+ return '/';
178
+ // 5. Garante que comece com "/"
179
+ return '/' + relPath;
180
+ }
181
+ function loadPathRoutes(routesDir) {
182
+ if (!fs_1.default.existsSync(routesDir)) {
183
+ allRoutes = [];
184
+ return [];
185
+ }
186
+ const loaded = [];
187
+ const cwdPath = process.cwd();
188
+ const scanAndLoad = (dir) => {
189
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
190
+ for (const entry of entries) {
191
+ const name = entry.name;
192
+ // Ignora arquivos/pastas ocultas, de sistema ou de componentes (ex: _components)
193
+ if (name.startsWith('.') || name.startsWith('_'))
194
+ continue;
195
+ const fullPath = path_1.default.join(dir, name);
196
+ if (entry.isDirectory()) {
197
+ if (name === 'backend' || name === 'api')
198
+ continue;
199
+ scanAndLoad(fullPath);
200
+ }
201
+ else if (entry.isFile() && (name === 'page.tsx' || name === 'page.ts' || name === 'page.jsx' || name === 'page.js')) {
202
+ // SÓ carrega se for um arquivo "page"
203
+ try {
204
+ const absolutePath = path_1.default.resolve(fullPath);
205
+ // OTIMIZAÇÃO: Limpa cache apenas se já existia
206
+ if (loadedFiles.has(absolutePath)) {
207
+ safeClearCache(absolutePath);
208
+ }
209
+ // Importa o módulo ignorando estilos
210
+ const routeModule = requireWithoutStyles(absolutePath);
211
+ // O "default" agora é o Componente React em si
212
+ const PageComponent = routeModule.default;
213
+ if (PageComponent) {
214
+ const componentPath = path_1.default.relative(cwdPath, fullPath).replace(/\\/g, '/');
215
+ // Gera o pattern baseado na pasta (ex: /blog/[id])
216
+ const pattern = convertPathToRoutePattern(absolutePath, routesDir);
217
+ // Monta o config dinamicamente
218
+ const generatedConfig = {
219
+ pattern,
220
+ component: PageComponent,
221
+ generateMetadata: routeModule.generateMetadata || (() => ({})),
222
+ };
223
+ // OTIMIZAÇÃO: Pré-compila a regex
224
+ const regex = compileRoutePatternWithGroups(pattern);
225
+ loaded.push({
226
+ config: generatedConfig,
227
+ componentPath,
228
+ regex,
229
+ paramNames: [] // Seus named groups cuidam disso
230
+ });
231
+ loadedFiles.add(absolutePath);
232
+ }
233
+ }
234
+ catch (error) {
235
+ console_1.default.error(`Error loading page ${fullPath}:`, error);
236
+ }
237
+ }
238
+ }
239
+ };
240
+ scanAndLoad(routesDir);
241
+ // Ordena as rotas para que rotas estáticas tenham prioridade sobre rotas dinâmicas [id]
242
+ loaded.sort((a, b) => {
243
+ const aDynamic = a.config.pattern.includes('[');
244
+ const bDynamic = b.config.pattern.includes('[');
245
+ if (aDynamic && !bDynamic)
246
+ return 1;
247
+ if (!aDynamic && bDynamic)
248
+ return -1;
249
+ return b.config.pattern.length - a.config.pattern.length; // Mais específicas primeiro
250
+ });
251
+ allRoutes = loaded;
252
+ return allRoutes.map(r => ({ ...r.config, componentPath: r.componentPath }));
253
+ }
165
254
  function loadRoutes(routesDir) {
255
+ if (helpers_1.config?.pathRouter == true) {
256
+ return loadPathRoutes(path_1.default.join(routesDir, "../"));
257
+ }
166
258
  if (!fs_1.default.existsSync(routesDir)) {
167
- console_1.default.warn(`Frontend routes directory not found at ${routesDir}.`);
168
259
  allRoutes = [];
169
260
  return [];
170
261
  }
@@ -184,7 +275,7 @@ function loadRoutes(routesDir) {
184
275
  continue;
185
276
  scanAndLoad(fullPath);
186
277
  }
187
- else if (entry.isFile() && (name.endsWith('.tsx') || name.endsWith('.ts'))) {
278
+ else if (entry.isFile() && (name.endsWith('.tsx') || name.endsWith('.ts') || name.endsWith(".jsx") || name.endsWith(".js"))) {
188
279
  try {
189
280
  const absolutePath = path_1.default.resolve(fullPath);
190
281
  // OTIMIZAÇÃO CRÍTICA: Só limpa cache se o arquivo já foi carregado antes.
@@ -239,7 +330,7 @@ const middlewareCache = new Map();
239
330
  function getMiddlewaresForDir(dir) {
240
331
  if (middlewareCache.has(dir))
241
332
  return middlewareCache.get(dir);
242
- const files = ['middleware.ts', 'middleware.tsx'];
333
+ const files = ['middleware.ts', 'middleware.js'];
243
334
  let middlewares = [];
244
335
  for (const file of files) {
245
336
  const fullPath = path_1.default.join(dir, file);
@@ -293,7 +384,7 @@ function loadBackendRoutes(backendRoutesDir) {
293
384
  if (entry.isDirectory()) {
294
385
  scanAndLoadAPI(fullPath);
295
386
  }
296
- else if (entry.isFile() && (name.endsWith('.ts') || name.endsWith('.tsx'))) {
387
+ else if (entry.isFile() && (name.endsWith('.ts') || name.endsWith(".js"))) {
297
388
  if (name.startsWith('middleware'))
298
389
  continue;
299
390
  try {
@@ -334,7 +425,6 @@ function loadBackendRoutes(backendRoutesDir) {
334
425
  function findMatchingBackendRoute(pathname, method) {
335
426
  const methodUpper = method.toUpperCase();
336
427
  for (const route of allBackendRoutes) {
337
- // Verifica método antes de rodar regex (otimização barata)
338
428
  // @ts-ignore
339
429
  if (!route.config[methodUpper])
340
430
  continue;
@@ -350,7 +440,7 @@ function findMatchingBackendRoute(pathname, method) {
350
440
  }
351
441
  // --- 404 Not Found ---
352
442
  function loadNotFound(webDir) {
353
- const files = ['notFound.tsx', 'notFound.ts'];
443
+ const files = ['notFound.tsx', 'notFound.jsx'];
354
444
  for (const file of files) {
355
445
  const fullPath = path_1.default.join(webDir, file);
356
446
  if (fs_1.default.existsSync(fullPath)) {
package/dist/types.d.ts CHANGED
@@ -33,6 +33,11 @@ export interface VattsOptions {
33
33
  * Essas configurações podem ser definidas no arquivo vatts.config.js
34
34
  */
35
35
  export interface VattsConfig {
36
+ /**
37
+ * Prefere utilizar rotas por path, sem precisar registrar?
38
+ * Padrão: false
39
+ */
40
+ pathRouter?: boolean;
36
41
  /**
37
42
  * Limita o número máximo de headers HTTP permitidos por requisição.
38
43
  * Padrão: 100
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vatts",
3
- "version": "1.0.5",
3
+ "version": "1.1.0-alpha.1",
4
4
  "description": "Vatts.js is a high-level framework for building web applications with ease and speed. It provides a robust set of tools and features to streamline development and enhance productivity.",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "itsmuzin",