hightjs 0.3.2 → 0.3.4

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 (42) hide show
  1. package/dist/adapters/factory.js +8 -8
  2. package/dist/adapters/native.js +3 -3
  3. package/dist/auth/client.js +5 -5
  4. package/dist/auth/components.js +2 -2
  5. package/dist/auth/core.js +2 -2
  6. package/dist/auth/react.js +4 -4
  7. package/dist/auth/routes.js +1 -1
  8. package/dist/bin/hightjs.js +29 -328
  9. package/dist/builder.js +47 -21
  10. package/dist/client/DefaultNotFound.js +1 -1
  11. package/dist/client/entry.client.js +3 -3
  12. package/dist/helpers.d.ts +1 -0
  13. package/dist/helpers.js +90 -28
  14. package/dist/hotReload.d.ts +3 -1
  15. package/dist/hotReload.js +43 -51
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +16 -30
  18. package/dist/router.js +133 -62
  19. package/dist/types.d.ts +42 -0
  20. package/docs/config.md +201 -0
  21. package/example/hightjs.config.ts +81 -0
  22. package/example/package-lock.json +633 -3054
  23. package/example/package.json +1 -1
  24. package/package.json +1 -1
  25. package/src/adapters/factory.ts +8 -8
  26. package/src/adapters/native.ts +3 -3
  27. package/src/auth/client.ts +5 -5
  28. package/src/auth/components.tsx +2 -2
  29. package/src/auth/core.ts +2 -2
  30. package/src/auth/react.tsx +4 -4
  31. package/src/auth/routes.ts +1 -1
  32. package/src/bin/hightjs.js +30 -391
  33. package/src/builder.js +47 -22
  34. package/src/client/DefaultNotFound.tsx +1 -1
  35. package/src/client/entry.client.tsx +3 -3
  36. package/src/helpers.ts +105 -29
  37. package/src/hotReload.ts +45 -55
  38. package/src/index.ts +20 -33
  39. package/src/router.ts +140 -63
  40. package/src/types.ts +52 -0
  41. package/example/.hweb/entry.client.js +0 -24
  42. package/example/hweb-dist/main-5KKAYNUU.js +0 -1137
package/dist/builder.js CHANGED
@@ -82,7 +82,7 @@ const postcssPlugin = {
82
82
  plugins.push(pluginModule(pluginOptions || {}));
83
83
  }
84
84
  catch (error) {
85
- Console.warn(`Não foi possível carregar plugin ${pluginName}:`, error.message);
85
+ Console.warn(`Unable to load plugin ${pluginName}:`, error.message);
86
86
  }
87
87
  }
88
88
  }
@@ -96,8 +96,8 @@ const postcssPlugin = {
96
96
  processedCss = result.css;
97
97
  }
98
98
  catch (postcssError) {
99
- Console.warn(`Erro ao processar CSS com PostCSS:`, postcssError.message);
100
- Console.warn(`Usando CSS original sem processamento.`);
99
+ Console.warn(`Error processing CSS with PostCSS:`, postcssError.message);
100
+ Console.warn(`Using raw CSS without processing.`);
101
101
  }
102
102
  }
103
103
  return {
@@ -185,9 +185,6 @@ const reactResolvePlugin = {
185
185
  async function buildWithChunks(entryPoint, outdir, isProduction = false) {
186
186
  // limpar diretorio
187
187
  fs.rmSync(outdir, { recursive: true, force: true });
188
- if (!isProduction) {
189
- console.log(`Iniciando o build com chunks de \"${entryPoint}\"...`);
190
- }
191
188
  try {
192
189
  await esbuild.build({
193
190
  entryPoints: [entryPoint],
@@ -214,12 +211,9 @@ async function buildWithChunks(entryPoint, outdir, isProduction = false) {
214
211
  keepNames: true,
215
212
  treeShaking: true,
216
213
  });
217
- if (!isProduction) {
218
- console.log(`Build com chunks finalizado! Saída: \"${outdir}\".`);
219
- }
220
214
  }
221
215
  catch (error) {
222
- console.error('Ocorreu um erro durante o build com chunks:', error);
216
+ console.error('An error occurred while building:', error);
223
217
  process.exit(1);
224
218
  }
225
219
  }
@@ -234,6 +228,25 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
234
228
  // limpar diretorio
235
229
  fs.rmSync(outdir, { recursive: true, force: true });
236
230
  try {
231
+ // Plugin para notificar quando o build termina
232
+ const buildCompletePlugin = {
233
+ name: 'build-complete',
234
+ setup(build) {
235
+ let isFirstBuild = true;
236
+ build.onEnd((result) => {
237
+ if (hotReloadManager) {
238
+ if (isFirstBuild) {
239
+ isFirstBuild = false;
240
+ hotReloadManager.onBuildComplete(true);
241
+ }
242
+ else {
243
+ // Notifica o hot reload manager que o build foi concluído
244
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
245
+ }
246
+ }
247
+ });
248
+ }
249
+ };
237
250
  const context = await esbuild.context({
238
251
  entryPoints: [entryPoint],
239
252
  bundle: true,
@@ -243,7 +256,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
243
256
  outdir: outdir,
244
257
  loader: { '.js': 'jsx', '.ts': 'tsx' },
245
258
  external: nodeBuiltIns,
246
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
259
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
247
260
  format: 'esm',
248
261
  jsx: 'automatic',
249
262
  define: {
@@ -262,7 +275,7 @@ async function watchWithChunks(entryPoint, outdir, hotReloadManager = null) {
262
275
  }
263
276
  catch (error) {
264
277
  console.error(error);
265
- Console.error('Erro ao iniciar o modo watch com chunks:', error);
278
+ Console.error('Error starting watch mode with chunks:', error);
266
279
  throw error;
267
280
  }
268
281
  }
@@ -277,9 +290,6 @@ async function build(entryPoint, outfile, isProduction = false) {
277
290
  // limpar diretorio do outfile
278
291
  const outdir = path.dirname(outfile);
279
292
  fs.rmSync(outdir, { recursive: true, force: true });
280
- if (!isProduction) {
281
- console.log(`Iniciando o build de \"${entryPoint}\"...`);
282
- }
283
293
  try {
284
294
  await esbuild.build({
285
295
  entryPoints: [entryPoint],
@@ -309,12 +319,9 @@ async function build(entryPoint, outfile, isProduction = false) {
309
319
  treeShaking: true,
310
320
  drop: [], // Não remove nada automaticamente
311
321
  });
312
- if (!isProduction) {
313
- console.log(`Build finalizado com sucesso! Saída: \"${outfile}\".`);
314
- }
315
322
  }
316
323
  catch (error) {
317
- console.error('Ocorreu um erro durante o build:', error);
324
+ console.error('An error occurred during build:', error);
318
325
  process.exit(1);
319
326
  }
320
327
  }
@@ -327,6 +334,25 @@ async function build(entryPoint, outfile, isProduction = false) {
327
334
  */
328
335
  async function watch(entryPoint, outfile, hotReloadManager = null) {
329
336
  try {
337
+ // Plugin para notificar quando o build termina
338
+ const buildCompletePlugin = {
339
+ name: 'build-complete',
340
+ setup(build) {
341
+ let isFirstBuild = true;
342
+ build.onEnd((result) => {
343
+ if (hotReloadManager) {
344
+ if (isFirstBuild) {
345
+ isFirstBuild = false;
346
+ hotReloadManager.onBuildComplete(true);
347
+ }
348
+ else {
349
+ // Notifica o hot reload manager que o build foi concluído
350
+ hotReloadManager.onBuildComplete(result.errors.length === 0);
351
+ }
352
+ }
353
+ });
354
+ }
355
+ };
330
356
  const context = await esbuild.context({
331
357
  entryPoints: [entryPoint],
332
358
  bundle: true,
@@ -336,7 +362,7 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
336
362
  outfile: outfile,
337
363
  loader: { '.js': 'jsx', '.ts': 'tsx' },
338
364
  external: nodeBuiltIns,
339
- plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin],
365
+ plugins: [postcssPlugin, npmDependenciesPlugin, reactResolvePlugin, buildCompletePlugin],
340
366
  format: 'iife',
341
367
  globalName: 'HwebApp',
342
368
  jsx: 'automatic',
@@ -358,7 +384,7 @@ async function watch(entryPoint, outfile, hotReloadManager = null) {
358
384
  await context.watch();
359
385
  }
360
386
  catch (error) {
361
- Console.error('Erro ao iniciar o modo watch:', error);
387
+ Console.error('Error starting watch mode:', error);
362
388
  throw error;
363
389
  }
364
390
  }
@@ -49,5 +49,5 @@ function DefaultNotFound() {
49
49
  fontWeight: '400',
50
50
  lineHeight: '49px',
51
51
  margin: '0px'
52
- }, children: "Esta p\u00E1gina n\u00E3o pode ser achada." }) })] }) }));
52
+ }, children: "This page cannot be found." }) })] }) }));
53
53
  }
@@ -265,7 +265,7 @@ function DevIndicator() {
265
265
  function initializeClient() {
266
266
  const initialData = window.__HWEB_INITIAL_DATA__;
267
267
  if (!initialData) {
268
- console.error('[hweb] Dados iniciais não encontrados na página.');
268
+ console.error('[hweb] Initial data not found on page.');
269
269
  return;
270
270
  }
271
271
  // Cria o mapa de componentes dinamicamente a partir dos módulos carregados
@@ -276,7 +276,7 @@ function initializeClient() {
276
276
  }
277
277
  const container = document.getElementById('root');
278
278
  if (!container) {
279
- console.error('[hweb] Container #root não encontrado.');
279
+ console.error('[hweb] Container #root not found.');
280
280
  return;
281
281
  }
282
282
  try {
@@ -285,7 +285,7 @@ function initializeClient() {
285
285
  root.render((0, jsx_runtime_1.jsx)(App, { componentMap: componentMap, routes: initialData.routes, initialComponentPath: initialData.initialComponentPath, initialParams: initialData.initialParams, layoutComponent: window.__HWEB_LAYOUT__ }));
286
286
  }
287
287
  catch (error) {
288
- console.error('[hweb] Erro ao renderizar aplicação:', error);
288
+ console.error('[hweb] Error rendering application:', error);
289
289
  }
290
290
  }
291
291
  // Executa quando o DOM estiver pronto
package/dist/helpers.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  import http, { Server } from 'http';
2
3
  import type { HightJSOptions } from './types';
3
4
  import https from 'https';
package/dist/helpers.js CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  "use strict";
2
3
  /*
3
4
  * This file is part of the HightJS Project.
@@ -57,6 +58,7 @@ exports.app = app;
57
58
  const http_1 = __importDefault(require("http"));
58
59
  const os_1 = __importDefault(require("os"));
59
60
  const url_1 = require("url"); // API moderna, substitui 'querystring'
61
+ const path_1 = __importDefault(require("path"));
60
62
  // Helpers para integração com diferentes frameworks
61
63
  const index_1 = __importStar(require("./index")); // Importando o tipo
62
64
  const console_1 = __importStar(require("./api/console"));
@@ -81,28 +83,85 @@ function getLocalExternalIp() {
81
83
  return 'localhost'; // Fallback
82
84
  }
83
85
  const sendBox = (options) => {
84
- const isDev = options.dev ? "Rodando em modo de desenvolvimento" : null;
86
+ const isDev = options.dev ? "Running in development mode" : null;
85
87
  // 1. Verifica se o SSL está ativado (baseado na mesma lógica do initNativeServer)
86
88
  const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
87
89
  const protocol = isSSL ? 'https' : 'http';
88
90
  const localIp = getLocalExternalIp(); // Assume que getLocalExternalIp() existe
89
91
  // 2. Monta as mensagens com o protocolo correto
90
92
  const messages = [
91
- ` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Local: ${console_1.Colors.FgGreen}${protocol}://localhost:${options.port}${console_1.Colors.Reset}`,
93
+ ` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Local: ${console_1.Colors.FgGreen}${protocol}://localhost:${options.port}${console_1.Colors.Reset}`,
92
94
  ];
93
95
  // Só adiciona a rede se o IP local for encontrado
94
96
  if (localIp) {
95
- messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Rede: ${console_1.Colors.FgGreen}${protocol}://${localIp}:${options.port}${console_1.Colors.Reset}`);
97
+ messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Network: ${console_1.Colors.FgGreen}${protocol}://${localIp}:${options.port}${console_1.Colors.Reset}`);
96
98
  }
97
99
  if (isDev) {
98
100
  messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} ${isDev}`);
99
101
  }
100
102
  // Adiciona aviso de redirecionamento se estiver em modo SSL
101
103
  if (isSSL && options.ssl?.redirectPort) {
102
- messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} HTTP (porta ${options.ssl?.redirectPort}) está redirecionando para HTTPS.`);
104
+ messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} HTTP (port ${options.ssl?.redirectPort}) is redirecting to HTTPS.`);
103
105
  }
104
- console_1.default.box(messages.join("\n"), { title: "Acesse em:" });
106
+ console_1.default.box(messages.join("\n"), { title: "Access on:" });
105
107
  };
108
+ /**
109
+ * Carrega o arquivo de configuração hightjs.config.ts ou hightjs.config.js do projeto
110
+ * @param projectDir Diretório raiz do projeto
111
+ * @param phase Fase de execução ('development' ou 'production')
112
+ * @returns Configuração mesclada com os valores padrão
113
+ */
114
+ async function loadHightConfig(projectDir, phase) {
115
+ const defaultConfig = {
116
+ maxHeadersCount: 100,
117
+ headersTimeout: 60000,
118
+ requestTimeout: 30000,
119
+ serverTimeout: 35000,
120
+ individualRequestTimeout: 30000,
121
+ maxUrlLength: 2048,
122
+ };
123
+ try {
124
+ // Tenta primeiro .ts, depois .js
125
+ const possiblePaths = [
126
+ path_1.default.join(projectDir, 'hightjs.config.ts'),
127
+ path_1.default.join(projectDir, 'hightjs.config.js'),
128
+ ];
129
+ let configPath = null;
130
+ for (const p of possiblePaths) {
131
+ if (fs_1.default.existsSync(p)) {
132
+ configPath = p;
133
+ break;
134
+ }
135
+ }
136
+ if (!configPath) {
137
+ return defaultConfig;
138
+ }
139
+ // Remove do cache para permitir hot reload da configuração em dev
140
+ delete require.cache[require.resolve(configPath)];
141
+ const configModule = require(configPath);
142
+ const configExport = configModule.default || configModule;
143
+ let userConfig;
144
+ if (typeof configExport === 'function') {
145
+ // Suporta tanto função síncrona quanto assíncrona
146
+ userConfig = await Promise.resolve(configExport(phase, { defaultConfig }));
147
+ }
148
+ else {
149
+ userConfig = configExport;
150
+ }
151
+ // Mescla a configuração do usuário com a padrão
152
+ const mergedConfig = { ...defaultConfig, ...userConfig };
153
+ const configFileName = path_1.default.basename(configPath);
154
+ console_1.default.info(`${console_1.Colors.FgCyan}[Config]${console_1.Colors.Reset} Loaded ${configFileName}`);
155
+ return mergedConfig;
156
+ }
157
+ catch (error) {
158
+ if (error instanceof Error) {
159
+ console_1.default.warn(`${console_1.Colors.FgYellow}[Config]${console_1.Colors.Reset} Error loading hightjs.config: ${error.message}`);
160
+ console_1.default.warn(`${console_1.Colors.FgYellow}[Config]${console_1.Colors.Reset} Using default configuration`);
161
+ }
162
+ return defaultConfig;
163
+ }
164
+ }
106
165
  /**
107
166
  * Middleware para parsing do body com proteções de segurança (versão melhorada).
108
167
  * Rejeita a promise em caso de erro de parsing ou estouro de limite.
@@ -181,8 +240,12 @@ const parseBody = (req) => {
181
240
  async function initNativeServer(hwebApp, options, port, hostname) {
182
241
  const time = Date.now();
183
242
  await hwebApp.prepare();
243
+ // Carrega a configuração do arquivo hightjs.config.js
244
+ const projectDir = options.dir || process.cwd();
245
+ const phase = options.dev ? 'development' : 'production';
246
+ const hightConfig = await loadHightConfig(projectDir, phase);
184
247
  const handler = hwebApp.getRequestHandler();
185
- const msg = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}Iniciando HightJS na porta ${options.port}${console_1.Colors.Reset}`);
248
+ const msg = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}Starting HightJS on port ${options.port}${console_1.Colors.Reset}`);
186
249
  // --- LÓGICA DO LISTENER (REUTILIZÁVEL) ---
187
250
  // Extraímos a lógica principal para uma variável
188
251
  // para que possa ser usada tanto pelo servidor HTTP quanto HTTPS.
@@ -197,15 +260,16 @@ async function initNativeServer(hwebApp, options, port, hostname) {
197
260
  if (options.ssl) {
198
261
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
199
262
  }
200
- // Timeout por requisição
201
- req.setTimeout(30000, () => {
263
+ // Timeout por requisição (usa configuração personalizada)
264
+ req.setTimeout(hightConfig.individualRequestTimeout || 30000, () => {
202
265
  res.statusCode = 408; // Request Timeout
203
266
  res.end('Request timeout');
204
267
  });
205
268
  try {
206
- // Validação básica de URL
269
+ // Validação básica de URL (usa configuração personalizada)
207
270
  const url = req.url || '/';
208
- if (url.length > 2048) {
271
+ const maxUrlLength = hightConfig.maxUrlLength || 2048;
272
+ if (url.length > maxUrlLength) {
209
273
  res.statusCode = 414; // URI Too Long
210
274
  res.end('URL too long');
211
275
  return;
@@ -220,10 +284,10 @@ async function initNativeServer(hwebApp, options, port, hostname) {
220
284
  catch (error) {
221
285
  // Log do erro no servidor
222
286
  if (error instanceof Error) {
223
- console_1.default.error(`Erro no servidor nativo: ${error.message}`);
287
+ console_1.default.error(`Native server error: ${error.message}`);
224
288
  }
225
289
  else {
226
- console_1.default.error('Erro desconhecido no servidor nativo:', error);
290
+ console_1.default.error('Unknown native server error:', error);
227
291
  }
228
292
  // Tratamento de erro (idêntico ao seu original)
229
293
  if (!res.headersSent) {
@@ -286,14 +350,14 @@ async function initNativeServer(hwebApp, options, port, hostname) {
286
350
  // Cria o servidor HTTP nativo
287
351
  server = http_1.default.createServer(requestListener); // (any para contornar HWebIncomingMessage)
288
352
  }
289
- // Configurações de segurança do servidor (Comum a ambos)
290
- server.setTimeout(35000); // Timeout geral do servidor
291
- server.maxHeadersCount = 100; // Limita número de headers
292
- server.headersTimeout = 60000; // Timeout para headers
293
- server.requestTimeout = 30000; // Timeout para requisições
353
+ // Configurações de segurança do servidor (usa configuração personalizada)
354
+ server.setTimeout(hightConfig.serverTimeout || 35000); // Timeout geral do servidor
355
+ server.maxHeadersCount = hightConfig.maxHeadersCount || 100; // Limita número de headers
356
+ server.headersTimeout = hightConfig.headersTimeout || 60000; // Timeout para headers
357
+ server.requestTimeout = hightConfig.requestTimeout || 30000; // Timeout para requisições
294
358
  server.listen(port, hostname, () => {
295
359
  sendBox({ ...options, port });
296
- msg.end(` ${console_1.Colors.BgGreen} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}Pronto na porta ${console_1.Colors.BgGreen} ${options.port} ${console_1.Colors.Reset}${console_1.Colors.Bright} em ${Date.now() - time}ms${console_1.Colors.Reset}\n`);
360
+ msg.end(` ${console_1.Colors.BgGreen} ready ${console_1.Colors.Reset} ${console_1.Colors.Bright}Ready on port ${console_1.Colors.BgGreen} ${options.port} ${console_1.Colors.Reset}${console_1.Colors.Bright} in ${Date.now() - time}ms${console_1.Colors.Reset}\n`);
297
361
  });
298
362
  // Configura WebSocket para hot reload (Comum a ambos)
299
363
  hwebApp.setupWebSocket(server);
@@ -325,7 +389,7 @@ function app(options = {}) {
325
389
  serverApp.use(cookieParser());
326
390
  }
327
391
  catch (e) {
328
- console_1.default.error("Não foi possivel achar cookie-parser");
392
+ console_1.default.error("Could not find cookie-parser");
329
393
  }
330
394
  serverApp.use(express.json());
331
395
  serverApp.use(express.urlencoded({ extended: true }));
@@ -337,13 +401,13 @@ function app(options = {}) {
337
401
  await serverApp.register(require('@fastify/cookie'));
338
402
  }
339
403
  catch (e) {
340
- console_1.default.error("Não foi possivel achar @fastify/cookie");
404
+ console_1.default.error("Could not find @fastify/cookie");
341
405
  }
342
406
  try {
343
407
  await serverApp.register(require('@fastify/formbody'));
344
408
  }
345
409
  catch (e) {
346
- console_1.default.error("Não foi possivel achar @fastify/formbody");
410
+ console_1.default.error("Could not find @fastify/formbody");
347
411
  }
348
412
  await serverApp.register(async (fastify) => {
349
413
  fastify.all('*', handler);
@@ -371,7 +435,7 @@ function app(options = {}) {
371
435
  return data.version;
372
436
  }
373
437
  catch (error) {
374
- console_1.default.error('Não foi possível verificar a versão mais recente do HightJS:', error);
438
+ console_1.default.error('Could not check for the latest HightJS version:', error);
375
439
  return currentVersion; // Retorna a versão atual em caso de erro
376
440
  }
377
441
  }
@@ -379,22 +443,20 @@ function app(options = {}) {
379
443
  const isUpToDate = latestVersion === currentVersion;
380
444
  let message;
381
445
  if (!isUpToDate) {
382
- message = `${console_1.Colors.FgGreen} uma nova versão disponível (v${latestVersion})${console_1.Colors.FgMagenta}`;
446
+ message = `${console_1.Colors.FgGreen} A new version is available (v${latestVersion})${console_1.Colors.FgMagenta}`;
383
447
  }
384
448
  else {
385
- message = `${console_1.Colors.FgGreen} Você está na versão mais recente${console_1.Colors.FgMagenta}`;
449
+ message = `${console_1.Colors.FgGreen} You are on the latest version${console_1.Colors.FgMagenta}`;
386
450
  }
387
451
  console.log(`${console_1.Colors.FgMagenta}
388
452
  __ ___ ${console_1.Colors.FgGreen} __ ${console_1.Colors.FgMagenta}
389
453
  |__| | / _\` |__| | ${console_1.Colors.FgGreen} | /__\` ${console_1.Colors.FgMagenta} ${console_1.Colors.FgMagenta}HightJS ${console_1.Colors.FgGray}(v${require('../package.json').version}) - itsmuzin${console_1.Colors.FgMagenta}
390
- | | | \\__> | | | ${console_1.Colors.FgGreen}\\__/ .__/ ${message}
391
-
392
-
454
+ | | | \\__> | | | ${console_1.Colors.FgGreen}\\__/ .__/ ${message}
393
455
  ${console_1.Colors.Reset}`);
394
456
  const actualPort = options.port || 3000;
395
457
  const actualHostname = options.hostname || "0.0.0.0";
396
458
  if (framework !== 'native') {
397
- console_1.default.warn(`O framework "${framework}" foi selecionado, mas o método init() funciona com o framework "native". Iniciando servidor nativo...`);
459
+ console_1.default.warn(`The "${framework}" framework was selected, but the init() method only works with the "native" framework. Starting native server...`);
398
460
  }
399
461
  return await initNativeServer(hwebApp, options, actualPort, actualHostname);
400
462
  }
@@ -9,6 +9,8 @@ export declare class HotReloadManager {
9
9
  private isShuttingDown;
10
10
  private debounceTimers;
11
11
  private customHotReloadListener;
12
+ private isBuilding;
13
+ private buildCompleteResolve;
12
14
  constructor(projectDir: string);
13
15
  start(): Promise<void>;
14
16
  handleUpgrade(request: IncomingMessage, socket: any, head: Buffer): void;
@@ -26,5 +28,5 @@ export declare class HotReloadManager {
26
28
  onFrontendChange(callback: () => void): void;
27
29
  setHotReloadListener(listener: (file: string) => Promise<void> | void): void;
28
30
  removeHotReloadListener(): void;
29
- private checkFrontendBuild;
31
+ onBuildComplete(success: boolean): void;
30
32
  }
package/dist/hotReload.js CHANGED
@@ -65,6 +65,8 @@ class HotReloadManager {
65
65
  this.isShuttingDown = false;
66
66
  this.debounceTimers = new Map();
67
67
  this.customHotReloadListener = null;
68
+ this.isBuilding = false;
69
+ this.buildCompleteResolve = null;
68
70
  this.projectDir = projectDir;
69
71
  }
70
72
  async start() {
@@ -198,30 +200,44 @@ class HotReloadManager {
198
200
  // Limpa o cache do arquivo alterado
199
201
  (0, router_1.clearFileCache)(filePath);
200
202
  this.clearBackendCache(filePath);
201
- // Checa build se for .ts/.tsx/.js/.jsx
202
- const ext = path.extname(filePath);
203
- if ([".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
204
- const result = await this.checkFrontendBuild(filePath);
205
- if (result.error) {
206
- this.notifyClients('src-error', { file: filePath, error: result.error });
207
- return;
208
- }
209
- }
210
- // Se for arquivo de frontend, notifica o cliente para recarregar a página
203
+ // Se for arquivo de frontend, aguarda o build terminar antes de recarregar
211
204
  if (isFrontendFile) {
212
- console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `📄 Recarregando frontend...`);
213
- this.frontendChangeCallback?.();
214
- this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
205
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `📄 Waiting for frontend build...`);
206
+ // Marca que estamos esperando um build
207
+ this.isBuilding = true;
208
+ // Cria uma promise que será resolvida quando o build terminar
209
+ const buildPromise = new Promise((resolve) => {
210
+ this.buildCompleteResolve = resolve;
211
+ });
212
+ // Aguarda o build terminar (com timeout de 30 segundos)
213
+ const timeoutPromise = new Promise((_, reject) => {
214
+ setTimeout(() => reject(new Error('Build timeout')), 30000);
215
+ });
216
+ try {
217
+ await Promise.race([buildPromise, timeoutPromise]);
218
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `✅ Build complete, reloading frontend...`);
219
+ this.frontendChangeCallback?.();
220
+ this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
221
+ }
222
+ catch (error) {
223
+ console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `⚠️ Timeout in build, reloading anyway...`);
224
+ this.frontendChangeCallback?.();
225
+ this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
226
+ }
227
+ finally {
228
+ this.isBuilding = false;
229
+ this.buildCompleteResolve = null;
230
+ }
215
231
  }
216
232
  // Se for arquivo de backend, recarrega o módulo e notifica
217
233
  if (isBackendFile) {
218
- console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `⚙️ Recarregando backend...`);
234
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `⚙️ Reloading backend...`);
219
235
  this.backendApiChangeCallback?.();
220
236
  this.notifyClients('backend-api-reload', { file: filePath, event: 'change' });
221
237
  }
222
238
  // Fallback: se não for nem frontend nem backend detectado, recarrega tudo
223
239
  if (!isFrontendFile && !isBackendFile) {
224
- console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `🔄 Recarregando aplicação...`);
240
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `🔄 Reloading application...`);
225
241
  this.frontendChangeCallback?.();
226
242
  this.backendApiChangeCallback?.();
227
243
  this.notifyClients('src-reload', { file: filePath, event: 'change' });
@@ -233,7 +249,7 @@ class HotReloadManager {
233
249
  }
234
250
  catch (error) {
235
251
  // @ts-ignore
236
- console_1.default.logWithout(console_1.Levels.ERROR, `Erro no listener customizado: ${error.message}`);
252
+ console_1.default.logWithout(console_1.Levels.ERROR, `Error in custom listener: ${error.message}`);
237
253
  }
238
254
  }
239
255
  }
@@ -249,7 +265,7 @@ class HotReloadManager {
249
265
  ws.send(message);
250
266
  }
251
267
  catch (error) {
252
- console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `Erro ao enviar mensagem WebSocket: ${error}`);
268
+ console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `Error sending WebSocket message: ${error}`);
253
269
  deadClients.push(ws);
254
270
  }
255
271
  }
@@ -311,7 +327,7 @@ class HotReloadManager {
311
327
  ws = new WebSocket('ws://localhost:3000/hweb-hotreload/');
312
328
 
313
329
  ws.onopen = function() {
314
- console.log('🔌 Hot-reload conectado');
330
+ console.log('🔌 Hot-reload connected');
315
331
  isConnected = true;
316
332
  reconnectAttempts = 0;
317
333
  reconnectInterval = 1000;
@@ -331,13 +347,13 @@ class HotReloadManager {
331
347
  window.location.reload();
332
348
  break;
333
349
  case 'server-restart':
334
- console.log('🔄 Servidor reiniciando...');
350
+ console.log('🔄 Server restarting...');
335
351
  break;
336
352
  case 'server-ready':
337
353
  setTimeout(() => window.location.reload(), 500);
338
354
  break;
339
355
  case 'frontend-error':
340
- console.error('❌ Erro no frontend:', message.data);
356
+ console.error('❌ Frontend error:', message.data);
341
357
  break;
342
358
  }
343
359
  } catch (e) {
@@ -362,7 +378,7 @@ class HotReloadManager {
362
378
  };
363
379
 
364
380
  } catch (error) {
365
- console.error('Erro ao criar WebSocket:', error);
381
+ console.error('Error creating WebSocket:', error);
366
382
  scheduleReconnect();
367
383
  }
368
384
  }
@@ -427,41 +443,17 @@ class HotReloadManager {
427
443
  }
428
444
  setHotReloadListener(listener) {
429
445
  this.customHotReloadListener = listener;
430
- console_1.default.info('🔌 Hot reload listener customizado registrado');
446
+ console_1.default.info('🔌 Hot reload custom listener registered');
431
447
  }
432
448
  removeHotReloadListener() {
433
449
  this.customHotReloadListener = null;
434
450
  }
435
- async checkFrontendBuild(filePath) {
436
- try {
437
- const tsNodePath = require.resolve('ts-node');
438
- const { spawn } = require('child_process');
439
- return new Promise((resolve) => {
440
- const proc = spawn(process.execPath, [tsNodePath, '--transpile-only', filePath], {
441
- cwd: this.projectDir,
442
- env: process.env,
443
- timeout: 10000 // Timeout de 10 segundos
444
- });
445
- let errorMsg = '';
446
- proc.stderr.on('data', (data) => {
447
- errorMsg += data.toString();
448
- });
449
- proc.on('close', (code) => {
450
- if (code !== 0 && errorMsg) {
451
- resolve({ error: errorMsg });
452
- }
453
- else {
454
- resolve({});
455
- }
456
- });
457
- proc.on('error', (error) => {
458
- resolve({ error: error.message });
459
- });
460
- });
461
- }
462
- catch (error) {
463
- return { error: `Erro ao verificar build: ${error}` };
451
+ onBuildComplete(success) {
452
+ if (this.buildCompleteResolve) {
453
+ this.buildCompleteResolve();
454
+ this.buildCompleteResolve = null;
464
455
  }
456
+ this.isBuilding = false;
465
457
  }
466
458
  }
467
459
  exports.HotReloadManager = HotReloadManager;
package/dist/index.d.ts CHANGED
@@ -8,11 +8,11 @@ export { FrameworkAdapterFactory } from './adapters/factory';
8
8
  export type { GenericRequest, GenericResponse, CookieOptions } from './types/framework';
9
9
  export { app } from './helpers';
10
10
  export type { WebSocketContext, WebSocketHandler } from './types';
11
+ export type { HightConfig, HightConfigFunction } from './types';
11
12
  export default function hweb(options: HightJSOptions): {
12
13
  prepare: () => Promise<void>;
13
14
  executeInstrumentation: () => void;
14
15
  getRequestHandler: () => RequestHandler;
15
16
  setupWebSocket: (server: any) => void;
16
- build: () => Promise<void>;
17
17
  stop: () => void;
18
18
  };