hightjs 0.5.2 → 0.5.3

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 (48) hide show
  1. package/package.json +1 -1
  2. package/src/builder.js +8 -8
  3. package/src/hotReload.ts +4 -7
  4. package/src/router.ts +14 -26
  5. package/dist/adapters/express.d.ts +0 -7
  6. package/dist/adapters/express.js +0 -63
  7. package/dist/adapters/factory.d.ts +0 -23
  8. package/dist/adapters/factory.js +0 -122
  9. package/dist/adapters/fastify.d.ts +0 -25
  10. package/dist/adapters/fastify.js +0 -61
  11. package/dist/adapters/native.d.ts +0 -8
  12. package/dist/adapters/native.js +0 -198
  13. package/dist/api/console.d.ts +0 -94
  14. package/dist/api/console.js +0 -294
  15. package/dist/api/http.d.ts +0 -180
  16. package/dist/api/http.js +0 -469
  17. package/dist/bin/hightjs.d.ts +0 -2
  18. package/dist/bin/hightjs.js +0 -214
  19. package/dist/builder.d.ts +0 -32
  20. package/dist/builder.js +0 -581
  21. package/dist/client/DefaultNotFound.d.ts +0 -1
  22. package/dist/client/DefaultNotFound.js +0 -79
  23. package/dist/client/client.d.ts +0 -3
  24. package/dist/client/client.js +0 -24
  25. package/dist/client/clientRouter.d.ts +0 -58
  26. package/dist/client/clientRouter.js +0 -132
  27. package/dist/client/entry.client.d.ts +0 -1
  28. package/dist/client/entry.client.js +0 -455
  29. package/dist/components/Link.d.ts +0 -7
  30. package/dist/components/Link.js +0 -13
  31. package/dist/global/global.d.ts +0 -117
  32. package/dist/global/global.js +0 -17
  33. package/dist/helpers.d.ts +0 -20
  34. package/dist/helpers.js +0 -583
  35. package/dist/hotReload.d.ts +0 -32
  36. package/dist/hotReload.js +0 -548
  37. package/dist/index.d.ts +0 -18
  38. package/dist/index.js +0 -494
  39. package/dist/loaders.d.ts +0 -1
  40. package/dist/loaders.js +0 -46
  41. package/dist/renderer.d.ts +0 -14
  42. package/dist/renderer.js +0 -380
  43. package/dist/router.d.ts +0 -101
  44. package/dist/router.js +0 -667
  45. package/dist/types/framework.d.ts +0 -37
  46. package/dist/types/framework.js +0 -2
  47. package/dist/types.d.ts +0 -192
  48. package/dist/types.js +0 -2
package/dist/router.js DELETED
@@ -1,667 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.clearAllRouteCache = clearAllRouteCache;
7
- exports.clearFileCache = clearFileCache;
8
- exports.loadLayout = loadLayout;
9
- exports.getLayout = getLayout;
10
- exports.loadRoutes = loadRoutes;
11
- exports.findMatchingRoute = findMatchingRoute;
12
- exports.loadBackendRoutes = loadBackendRoutes;
13
- exports.findMatchingBackendRoute = findMatchingBackendRoute;
14
- exports.loadNotFound = loadNotFound;
15
- exports.getNotFound = getNotFound;
16
- exports.processWebSocketRoutes = processWebSocketRoutes;
17
- exports.findMatchingWebSocketRoute = findMatchingWebSocketRoute;
18
- exports.setupWebSocketUpgrade = setupWebSocketUpgrade;
19
- /*
20
- * This file is part of the HightJS Project.
21
- * Copyright (c) 2025 itsmuzin
22
- *
23
- * Licensed under the Apache License, Version 2.0 (the "License");
24
- * you may not use this file except in compliance with the License.
25
- * You may obtain a copy of the License at
26
- *
27
- * http://www.apache.org/licenses/LICENSE-2.0
28
- *
29
- * Unless required by applicable law or agreed to in writing, software
30
- * distributed under the License is distributed on an "AS IS" BASIS,
31
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32
- * See the License for the specific language governing permissions and
33
- * limitations under the License.
34
- */
35
- const fs_1 = __importDefault(require("fs"));
36
- const path_1 = __importDefault(require("path"));
37
- const ws_1 = require("ws");
38
- const url_1 = require("url");
39
- const console_1 = __importDefault(require("./api/console"));
40
- const factory_1 = require("./adapters/factory");
41
- const http_1 = require("./api/http");
42
- // --- Roteamento do Frontend ---
43
- // Guarda todas as rotas de PÁGINA (React) encontradas
44
- // A rota agora também armazena o caminho do arquivo para ser usado como um ID único no cliente
45
- let allRoutes = [];
46
- // Guarda o layout se existir
47
- let layoutComponent = null;
48
- // Guarda o componente 404 personalizado se existir
49
- let notFoundComponent = null;
50
- // Cache de arquivos carregados para limpeza
51
- let loadedRouteFiles = new Set();
52
- let loadedLayoutFiles = new Set();
53
- let loadedNotFoundFiles = new Set();
54
- /**
55
- * Limpa o cache do require para um arquivo específico
56
- * @param filePath Caminho do arquivo para limpar
57
- */
58
- function clearRequireCache(filePath) {
59
- try {
60
- const resolvedPath = require.resolve(filePath);
61
- delete require.cache[resolvedPath];
62
- // Também limpa arquivos temporários relacionados (apenas se existir no cache)
63
- const tempFile = filePath.replace(/\.(tsx|ts|jsx|js)$/, '.temp.$1');
64
- const tempResolvedPath = require.cache[require.resolve(tempFile)];
65
- if (tempResolvedPath) {
66
- delete require.cache[require.resolve(tempFile)];
67
- }
68
- }
69
- catch {
70
- // Arquivo pode não estar no cache ou não ser resolvível
71
- }
72
- }
73
- /**
74
- * Limpa todo o cache de rotas carregadas
75
- */
76
- function clearAllRouteCache() {
77
- // Limpa cache das rotas
78
- loadedRouteFiles.forEach(filePath => {
79
- clearRequireCache(filePath);
80
- });
81
- loadedRouteFiles.clear();
82
- // Limpa cache do layout
83
- loadedLayoutFiles.forEach(filePath => {
84
- clearRequireCache(filePath);
85
- });
86
- loadedLayoutFiles.clear();
87
- // Limpa cache do notFound
88
- loadedNotFoundFiles.forEach(filePath => {
89
- clearRequireCache(filePath);
90
- });
91
- loadedNotFoundFiles.clear();
92
- }
93
- /**
94
- * Limpa o cache de um arquivo específico e recarrega as rotas se necessário
95
- * @param changedFilePath Caminho do arquivo que foi alterado
96
- */
97
- function clearFileCache(changedFilePath) {
98
- const absolutePath = path_1.default.isAbsolute(changedFilePath) ? changedFilePath : path_1.default.resolve(changedFilePath);
99
- // Limpa o cache do arquivo específico
100
- clearRequireCache(absolutePath);
101
- // Remove das listas de arquivos carregados
102
- loadedRouteFiles.delete(absolutePath);
103
- loadedLayoutFiles.delete(absolutePath);
104
- loadedNotFoundFiles.delete(absolutePath);
105
- }
106
- /**
107
- * Carrega o layout.tsx se existir no diretório web
108
- * @param webDir O diretório web onde procurar o layout
109
- * @returns O layout carregado ou null se não existir
110
- */
111
- function loadLayout(webDir) {
112
- const layoutPath = path_1.default.join(webDir, 'layout.tsx');
113
- const layoutPathTs = path_1.default.join(webDir, 'layout.ts');
114
- const layoutPathJsx = path_1.default.join(webDir, 'layout.jsx');
115
- const layoutPathJs = path_1.default.join(webDir, 'layout.js');
116
- const layoutFile = fs_1.default.existsSync(layoutPath) ? layoutPath :
117
- fs_1.default.existsSync(layoutPathTs) ? layoutPathTs :
118
- fs_1.default.existsSync(layoutPathJsx) ? layoutPathJsx :
119
- fs_1.default.existsSync(layoutPathJs) ? layoutPathJs : null;
120
- if (layoutFile) {
121
- const absolutePath = path_1.default.resolve(layoutFile);
122
- const componentPath = path_1.default.relative(process.cwd(), layoutFile).replace(/\\/g, '/');
123
- try {
124
- // HACK: Cria uma versão temporária do layout SEM imports de CSS para carregar no servidor
125
- const layoutContent = fs_1.default.readFileSync(layoutFile, 'utf8');
126
- const tempContent = layoutContent
127
- .replace(/import\s+['"][^'"]*\.css['"];?/g, '// CSS import removido para servidor')
128
- .replace(/import\s+['"][^'"]*\.scss['"];?/g, '// SCSS import removido para servidor')
129
- .replace(/import\s+['"][^'"]*\.sass['"];?/g, '// SASS import removido para servidor');
130
- const tempFile = layoutFile.replace(/\.(tsx|ts|jsx|js)$/, '.temp.$1');
131
- fs_1.default.writeFileSync(tempFile, tempContent);
132
- // Otimização: limpa cache apenas se existir
133
- try {
134
- const resolvedPath = require.resolve(tempFile);
135
- if (require.cache[resolvedPath]) {
136
- delete require.cache[resolvedPath];
137
- }
138
- }
139
- catch { }
140
- const layoutModule = require(tempFile);
141
- // Remove o arquivo temporário
142
- fs_1.default.unlinkSync(tempFile);
143
- const metadata = layoutModule.metadata || null;
144
- // Registra o arquivo como carregado
145
- loadedLayoutFiles.add(absolutePath);
146
- layoutComponent = { componentPath, metadata };
147
- return layoutComponent;
148
- }
149
- catch (error) {
150
- console_1.default.error(`Error loading layout ${layoutFile}:`, error);
151
- layoutComponent = { componentPath };
152
- return layoutComponent;
153
- }
154
- }
155
- layoutComponent = null;
156
- return null;
157
- }
158
- /**
159
- * Retorna o layout atual se carregado
160
- */
161
- function getLayout() {
162
- return layoutComponent;
163
- }
164
- /**
165
- * Carrega dinamicamente todas as rotas de frontend do diretório do usuário.
166
- * @param routesDir O diretório onde as rotas de página estão localizadas.
167
- * @returns A lista de rotas de página que foram carregadas.
168
- */
169
- function loadRoutes(routesDir) {
170
- if (!fs_1.default.existsSync(routesDir)) {
171
- console_1.default.warn(`Frontend routes directory not found at ${routesDir}. No page will be loaded.`);
172
- allRoutes = [];
173
- return allRoutes;
174
- }
175
- // Otimização: usa função recursiva manual para evitar overhead do recursive: true
176
- const routeFiles = [];
177
- const scanDirectory = (dir, baseDir = '') => {
178
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
179
- for (const entry of entries) {
180
- const relativePath = baseDir ? path_1.default.join(baseDir, entry.name) : entry.name;
181
- if (entry.isDirectory()) {
182
- // Pula diretório backend inteiro
183
- if (entry.name === 'backend')
184
- continue;
185
- scanDirectory(path_1.default.join(dir, entry.name), relativePath);
186
- }
187
- else if (entry.isFile()) {
188
- // Filtra apenas arquivos .ts/.tsx/.js/.jsx
189
- if (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx') ||
190
- entry.name.endsWith('.js') || entry.name.endsWith('.jsx')) {
191
- routeFiles.push(relativePath);
192
- }
193
- }
194
- }
195
- };
196
- scanDirectory(routesDir);
197
- const loaded = [];
198
- const cwdPath = process.cwd();
199
- // Otimização: processa arquivos em lote
200
- for (const file of routeFiles) {
201
- const filePath = path_1.default.join(routesDir, file);
202
- const absolutePath = path_1.default.resolve(filePath);
203
- try {
204
- // Otimização: limpa cache apenas se já existir
205
- const resolvedPath = require.resolve(filePath);
206
- if (require.cache[resolvedPath]) {
207
- delete require.cache[resolvedPath];
208
- }
209
- const routeModule = require(filePath);
210
- if (routeModule.default?.pattern && routeModule.default?.component) {
211
- // Otimização: calcula componentPath apenas uma vez
212
- const componentPath = path_1.default.relative(cwdPath, filePath).replace(/\\/g, '/');
213
- loaded.push({ ...routeModule.default, componentPath });
214
- loadedRouteFiles.add(absolutePath);
215
- }
216
- }
217
- catch (error) {
218
- console_1.default.error(`Error loading page route ${filePath}:`, error);
219
- }
220
- }
221
- allRoutes = loaded;
222
- return allRoutes;
223
- }
224
- /**
225
- * Encontra a rota de página correspondente para uma URL.
226
- * @param pathname O caminho da URL (ex: "/users/123").
227
- * @returns Um objeto com a rota e os parâmetros, ou null se não encontrar.
228
- */
229
- function findMatchingRoute(pathname) {
230
- for (const route of allRoutes) {
231
- if (!route.pattern)
232
- continue;
233
- const regexPattern = route.pattern
234
- // [[...param]] → opcional catch-all
235
- .replace(/\[\[\.\.\.(\w+)\]\]/g, '(?<$1>.+)?')
236
- // [...param] → obrigatório catch-all
237
- .replace(/\[\.\.\.(\w+)\]/g, '(?<$1>.+)')
238
- // /[[param]] → opcional com barra também opcional
239
- .replace(/\/\[\[(\w+)\]\]/g, '(?:/(?<$1>[^/]+))?')
240
- // [[param]] → segmento opcional (sem barra anterior)
241
- .replace(/\[\[(\w+)\]\]/g, '(?<$1>[^/]+)?')
242
- // [param] → segmento obrigatório
243
- .replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
244
- // permite / opcional no final
245
- const regex = new RegExp(`^${regexPattern}/?$`);
246
- const match = pathname.match(regex);
247
- if (match) {
248
- return {
249
- route,
250
- params: match.groups || {}
251
- };
252
- }
253
- }
254
- return null;
255
- }
256
- // --- Roteamento do Backend ---
257
- // Guarda todas as rotas de API encontradas
258
- let allBackendRoutes = [];
259
- // Cache de middlewares carregados por diretório
260
- let loadedMiddlewares = new Map();
261
- /**
262
- * Carrega middlewares de um diretório específico
263
- * @param dir O diretório onde procurar por middleware.ts
264
- * @returns Array de middlewares encontrados
265
- */
266
- function loadMiddlewareFromDirectory(dir) {
267
- const middlewares = [];
268
- // Procura por middleware.ts, middleware.tsx, middleware.js ou middleware.jsx
269
- const middlewarePath = path_1.default.join(dir, 'middleware.ts');
270
- const middlewarePathTsx = path_1.default.join(dir, 'middleware.tsx');
271
- const middlewarePathJs = path_1.default.join(dir, 'middleware.js');
272
- const middlewarePathJsx = path_1.default.join(dir, 'middleware.jsx');
273
- const middlewareFile = fs_1.default.existsSync(middlewarePath) ? middlewarePath :
274
- fs_1.default.existsSync(middlewarePathTsx) ? middlewarePathTsx :
275
- fs_1.default.existsSync(middlewarePathJs) ? middlewarePathJs :
276
- fs_1.default.existsSync(middlewarePathJsx) ? middlewarePathJsx : null;
277
- if (middlewareFile) {
278
- try {
279
- const absolutePath = path_1.default.resolve(middlewareFile);
280
- clearRequireCache(absolutePath);
281
- const middlewareModule = require(middlewareFile);
282
- // Suporte para export default (função única) ou export { middleware1, middleware2 }
283
- if (typeof middlewareModule.default === 'function') {
284
- middlewares.push(middlewareModule.default);
285
- }
286
- else if (middlewareModule.default && Array.isArray(middlewareModule.default)) {
287
- middlewares.push(...middlewareModule.default);
288
- }
289
- else {
290
- // Procura por exports nomeados que sejam funções
291
- Object.keys(middlewareModule).forEach(key => {
292
- if (key !== 'default' && typeof middlewareModule[key] === 'function') {
293
- middlewares.push(middlewareModule[key]);
294
- }
295
- });
296
- }
297
- }
298
- catch (error) {
299
- console_1.default.error(`Error loading middleware ${middlewareFile}:`, error);
300
- }
301
- }
302
- return middlewares;
303
- }
304
- /**
305
- * Coleta middlewares do diretório específico da rota (não herda dos pais)
306
- * @param routeFilePath Caminho completo do arquivo de rota
307
- * @param backendRoutesDir Diretório raiz das rotas de backend
308
- * @returns Array com middlewares apenas do diretório da rota
309
- */
310
- function collectMiddlewaresForRoute(routeFilePath, backendRoutesDir) {
311
- const relativePath = path_1.default.relative(backendRoutesDir, routeFilePath);
312
- const routeDir = path_1.default.dirname(path_1.default.join(backendRoutesDir, relativePath));
313
- // Carrega middlewares APENAS do diretório específico da rota (não herda dos pais)
314
- if (!loadedMiddlewares.has(routeDir)) {
315
- const middlewares = loadMiddlewareFromDirectory(routeDir);
316
- loadedMiddlewares.set(routeDir, middlewares);
317
- }
318
- return loadedMiddlewares.get(routeDir) || [];
319
- }
320
- /**
321
- * Carrega dinamicamente todas as rotas de API do diretório de backend.
322
- * @param backendRoutesDir O diretório onde as rotas de API estão localizadas.
323
- */
324
- function loadBackendRoutes(backendRoutesDir) {
325
- if (!fs_1.default.existsSync(backendRoutesDir)) {
326
- // É opcional ter uma API, então não mostramos um aviso se a pasta não existir.
327
- allBackendRoutes = [];
328
- return;
329
- }
330
- // Limpa cache de middlewares para recarregar
331
- loadedMiddlewares.clear();
332
- // Otimização: usa função recursiva manual e coleta middlewares durante o scan
333
- const routeFiles = [];
334
- const middlewareFiles = new Map(); // dir -> filepath
335
- const scanDirectory = (dir, baseDir = '') => {
336
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
337
- for (const entry of entries) {
338
- const relativePath = baseDir ? path_1.default.join(baseDir, entry.name) : entry.name;
339
- if (entry.isDirectory()) {
340
- scanDirectory(path_1.default.join(dir, entry.name), relativePath);
341
- }
342
- else if (entry.isFile()) {
343
- const isSupported = entry.name.endsWith('.ts') || entry.name.endsWith('.tsx') ||
344
- entry.name.endsWith('.js') || entry.name.endsWith('.jsx');
345
- if (!isSupported)
346
- continue;
347
- // Identifica middlewares durante o scan
348
- if (entry.name.startsWith('middleware')) {
349
- const dirPath = path_1.default.dirname(path_1.default.join(backendRoutesDir, relativePath));
350
- middlewareFiles.set(dirPath, path_1.default.join(backendRoutesDir, relativePath));
351
- }
352
- else {
353
- routeFiles.push(relativePath);
354
- }
355
- }
356
- }
357
- };
358
- scanDirectory(backendRoutesDir);
359
- // Otimização: pré-carrega todos os middlewares em um único passe
360
- for (const [dirPath, middlewarePath] of middlewareFiles) {
361
- try {
362
- const resolvedPath = require.resolve(middlewarePath);
363
- if (require.cache[resolvedPath]) {
364
- delete require.cache[resolvedPath];
365
- }
366
- const middlewareModule = require(middlewarePath);
367
- const middlewares = [];
368
- if (typeof middlewareModule.default === 'function') {
369
- middlewares.push(middlewareModule.default);
370
- }
371
- else if (Array.isArray(middlewareModule.default)) {
372
- middlewares.push(...middlewareModule.default);
373
- }
374
- else {
375
- // Exports nomeados
376
- for (const key in middlewareModule) {
377
- if (key !== 'default' && typeof middlewareModule[key] === 'function') {
378
- middlewares.push(middlewareModule[key]);
379
- }
380
- }
381
- }
382
- if (middlewares.length > 0) {
383
- loadedMiddlewares.set(dirPath, middlewares);
384
- }
385
- }
386
- catch (error) {
387
- console_1.default.error(`Error loading middleware ${middlewarePath}:`, error);
388
- }
389
- }
390
- // Otimização: processa rotas com cache já limpo
391
- const loaded = [];
392
- for (const file of routeFiles) {
393
- const filePath = path_1.default.join(backendRoutesDir, file);
394
- try {
395
- // Otimização: limpa cache apenas se existir
396
- const resolvedPath = require.resolve(filePath);
397
- if (require.cache[resolvedPath]) {
398
- delete require.cache[resolvedPath];
399
- }
400
- const routeModule = require(filePath);
401
- if (routeModule.default?.pattern) {
402
- const routeConfig = { ...routeModule.default };
403
- // Se a rota NÃO tem middleware definido, usa os da pasta
404
- if (!routeConfig.hasOwnProperty('middleware')) {
405
- const routeDir = path_1.default.dirname(path_1.default.resolve(filePath));
406
- const folderMiddlewares = loadedMiddlewares.get(routeDir);
407
- if (folderMiddlewares && folderMiddlewares.length > 0) {
408
- routeConfig.middleware = folderMiddlewares;
409
- }
410
- }
411
- loaded.push(routeConfig);
412
- }
413
- }
414
- catch (error) {
415
- console_1.default.error(`Error loading API route ${filePath}:`, error);
416
- }
417
- }
418
- allBackendRoutes = loaded;
419
- }
420
- /**
421
- * Encontra a rota de API correspondente para uma URL e método HTTP.
422
- * @param pathname O caminho da URL (ex: "/api/users/123").
423
- * @param method O método HTTP da requisição (GET, POST, etc.).
424
- * @returns Um objeto com a rota e os parâmetros, ou null se não encontrar.
425
- */
426
- function findMatchingBackendRoute(pathname, method) {
427
- for (const route of allBackendRoutes) {
428
- // Verifica se a rota tem um handler para o método HTTP atual
429
- if (!route.pattern || !route[method.toUpperCase()])
430
- continue;
431
- const regexPattern = route.pattern
432
- // [[...param]] → opcional catch-all
433
- .replace(/\[\[\.\.\.(\w+)\]\]/g, '(?<$1>.+)?')
434
- // [...param] → obrigatório catch-all
435
- .replace(/\[\.\.\.(\w+)\]/g, '(?<$1>.+)')
436
- // [[param]] → segmento opcional
437
- .replace(/\[\[(\w+)\]\]/g, '(?<$1>[^/]+)?')
438
- // [param] → segmento obrigatório
439
- .replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
440
- const regex = new RegExp(`^${regexPattern}/?$`);
441
- const match = pathname.match(regex);
442
- if (match) {
443
- return {
444
- route,
445
- params: match.groups || {}
446
- };
447
- }
448
- }
449
- return null;
450
- }
451
- /**
452
- * Carrega o notFound.tsx se existir no diretório web
453
- * @param webDir O diretório web onde procurar o notFound
454
- * @returns O notFound carregado ou null se não existir
455
- */
456
- function loadNotFound(webDir) {
457
- const notFoundPath = path_1.default.join(webDir, 'notFound.tsx');
458
- const notFoundPathTs = path_1.default.join(webDir, 'notFound.ts');
459
- const notFoundPathJsx = path_1.default.join(webDir, 'notFound.jsx');
460
- const notFoundPathJs = path_1.default.join(webDir, 'notFound.js');
461
- const notFoundFile = fs_1.default.existsSync(notFoundPath) ? notFoundPath :
462
- fs_1.default.existsSync(notFoundPathTs) ? notFoundPathTs :
463
- fs_1.default.existsSync(notFoundPathJsx) ? notFoundPathJsx :
464
- fs_1.default.existsSync(notFoundPathJs) ? notFoundPathJs : null;
465
- if (notFoundFile) {
466
- const absolutePath = path_1.default.resolve(notFoundFile);
467
- const componentPath = path_1.default.relative(process.cwd(), notFoundFile).replace(/\\/g, '/');
468
- try {
469
- // Otimização: limpa cache apenas se existir
470
- try {
471
- const resolvedPath = require.resolve(notFoundFile);
472
- if (require.cache[resolvedPath]) {
473
- delete require.cache[resolvedPath];
474
- }
475
- }
476
- catch { }
477
- // Registra o arquivo como carregado
478
- loadedNotFoundFiles.add(absolutePath);
479
- notFoundComponent = { componentPath };
480
- return notFoundComponent;
481
- }
482
- catch (error) {
483
- console_1.default.error(`Error loading notFound ${notFoundFile}:`, error);
484
- notFoundComponent = { componentPath };
485
- return notFoundComponent;
486
- }
487
- }
488
- notFoundComponent = null;
489
- return null;
490
- }
491
- /**
492
- * Retorna o componente 404 atual se carregado
493
- */
494
- function getNotFound() {
495
- return notFoundComponent;
496
- }
497
- // --- WebSocket Functions ---
498
- // Guarda todas as rotas WebSocket encontradas
499
- let allWebSocketRoutes = [];
500
- // Conexões WebSocket ativas
501
- let wsConnections = new Set();
502
- /**
503
- * Processa e registra rotas WebSocket encontradas nas rotas backend
504
- */
505
- function processWebSocketRoutes() {
506
- allWebSocketRoutes = [];
507
- for (const route of allBackendRoutes) {
508
- if (route.WS) {
509
- const wsRoute = {
510
- pattern: route.pattern,
511
- handler: route.WS,
512
- middleware: route.middleware
513
- };
514
- allWebSocketRoutes.push(wsRoute);
515
- }
516
- }
517
- }
518
- /**
519
- * Encontra a rota WebSocket correspondente para uma URL
520
- */
521
- function findMatchingWebSocketRoute(pathname) {
522
- for (const route of allWebSocketRoutes) {
523
- if (!route.pattern)
524
- continue;
525
- const regexPattern = route.pattern
526
- .replace(/\[\[\.\.\.(\w+)\]\]/g, '(?<$1>.+)?')
527
- .replace(/\[\.\.\.(\w+)\]/g, '(?<$1>.+)')
528
- .replace(/\[\[(\w+)\]\]/g, '(?<$1>[^/]+)?')
529
- .replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
530
- const regex = new RegExp(`^${regexPattern}/?$`);
531
- const match = pathname.match(regex);
532
- if (match) {
533
- return {
534
- route,
535
- params: match.groups || {}
536
- };
537
- }
538
- }
539
- return null;
540
- }
541
- /**
542
- * Trata uma nova conexão WebSocket
543
- */
544
- function handleWebSocketConnection(ws, req, hwebReq) {
545
- if (!req.url)
546
- return;
547
- const url = new url_1.URL(req.url, `http://${req.headers.host}`);
548
- const pathname = url.pathname;
549
- const matchedRoute = findMatchingWebSocketRoute(pathname);
550
- if (!matchedRoute) {
551
- ws.close(1000, 'Route not found');
552
- return;
553
- }
554
- const params = extractWebSocketParams(pathname, matchedRoute.route.pattern);
555
- const query = Object.fromEntries(url.searchParams.entries());
556
- const context = {
557
- hightReq: hwebReq,
558
- ws,
559
- req,
560
- url,
561
- params,
562
- query,
563
- send: (data) => {
564
- if (ws.readyState === ws_1.WebSocket.OPEN) {
565
- const message = typeof data === 'string' ? data : JSON.stringify(data);
566
- ws.send(message);
567
- }
568
- },
569
- close: (code, reason) => {
570
- ws.close(code || 1000, reason);
571
- },
572
- broadcast: (data, exclude) => {
573
- const message = typeof data === 'string' ? data : JSON.stringify(data);
574
- const excludeSet = new Set(exclude || []);
575
- wsConnections.forEach(connection => {
576
- if (connection.readyState === ws_1.WebSocket.OPEN && !excludeSet.has(connection)) {
577
- connection.send(message);
578
- }
579
- });
580
- }
581
- };
582
- try {
583
- matchedRoute.route.handler(context);
584
- }
585
- catch (error) {
586
- console.error('Error in WebSocket handler:', error);
587
- ws.close(1011, 'Internal server error');
588
- }
589
- }
590
- /**
591
- * Extrai parâmetros da URL para WebSocket
592
- */
593
- function extractWebSocketParams(pathname, pattern) {
594
- const params = {};
595
- const regexPattern = pattern
596
- .replace(/\[\[\.\.\.(\w+)\]\]/g, '(?<$1>.+)?')
597
- .replace(/\[\.\.\.(\w+)\]/g, '(?<$1>.+)')
598
- .replace(/\[\[(\w+)\]\]/g, '(?<$1>[^/]+)?')
599
- .replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
600
- const regex = new RegExp(`^${regexPattern}/?$`);
601
- const match = pathname.match(regex);
602
- if (match && match.groups) {
603
- Object.assign(params, match.groups);
604
- }
605
- return params;
606
- }
607
- /**
608
- * Configura WebSocket upgrade no servidor HTTP existente
609
- * @param server Servidor HTTP (Express, Fastify ou Native)
610
- * @param hotReloadManager Instância do gerenciador de hot-reload para coordenação
611
- */
612
- function setupWebSocketUpgrade(server, hotReloadManager) {
613
- // NÃO remove listeners existentes para preservar hot-reload
614
- // Em vez disso, coordena com o sistema existente
615
- // Verifica se já existe um listener de upgrade
616
- const existingListeners = server.listeners('upgrade');
617
- // Se não há listeners, ou se o hot-reload ainda não foi configurado, adiciona o nosso
618
- if (existingListeners.length === 0) {
619
- server.on('upgrade', (request, socket, head) => {
620
- handleWebSocketUpgrade(request, socket, head, hotReloadManager);
621
- });
622
- }
623
- }
624
- function handleWebSocketUpgrade(request, socket, head, hotReloadManager) {
625
- const adapter = factory_1.FrameworkAdapterFactory.getCurrentAdapter();
626
- if (!adapter) {
627
- console.error('❌ Framework adapter not detected. Unable to process WebSocket upgrade.');
628
- socket.destroy();
629
- return;
630
- }
631
- const genericReq = adapter.parseRequest(request);
632
- const hwebReq = new http_1.HightJSRequest(genericReq);
633
- const { pathname } = new url_1.URL(request.url, `http://${request.headers.host}`);
634
- // Prioridade 1: Hot reload (sistema interno)
635
- if (pathname === '/hweb-hotreload/') {
636
- if (hotReloadManager) {
637
- hotReloadManager.handleUpgrade(request, socket, head);
638
- }
639
- else {
640
- socket.destroy();
641
- }
642
- return;
643
- }
644
- // Prioridade 2: Rotas WebSocket do usuário
645
- const matchedRoute = findMatchingWebSocketRoute(pathname);
646
- if (matchedRoute) {
647
- // Faz upgrade para WebSocket usando noServer
648
- const wss = new ws_1.WebSocketServer({
649
- noServer: true,
650
- perMessageDeflate: false, // Melhor performance
651
- maxPayload: 1024 * 1024 // Limite de 1MB
652
- });
653
- wss.handleUpgrade(request, socket, head, (ws) => {
654
- wsConnections.add(ws);
655
- ws.on('close', () => {
656
- wsConnections.delete(ws);
657
- });
658
- ws.on('error', (error) => {
659
- wsConnections.delete(ws);
660
- });
661
- // Processa a conexão
662
- handleWebSocketConnection(ws, request, hwebReq);
663
- });
664
- return;
665
- }
666
- socket.destroy();
667
- }