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
@@ -284,7 +284,7 @@ function initializeClient() {
284
284
  const initialData = (window as any).__HWEB_INITIAL_DATA__;
285
285
 
286
286
  if (!initialData) {
287
- console.error('[hweb] Dados iniciais não encontrados na página.');
287
+ console.error('[hweb] Initial data not found on page.');
288
288
  return;
289
289
  }
290
290
 
@@ -298,7 +298,7 @@ function initializeClient() {
298
298
 
299
299
  const container = document.getElementById('root');
300
300
  if (!container) {
301
- console.error('[hweb] Container #root não encontrado.');
301
+ console.error('[hweb] Container #root not found.');
302
302
  return;
303
303
  }
304
304
 
@@ -316,7 +316,7 @@ function initializeClient() {
316
316
  />
317
317
  );
318
318
  } catch (error) {
319
- console.error('[hweb] Erro ao renderizar aplicação:', error);
319
+ console.error('[hweb] Error rendering application:', error);
320
320
  }
321
321
  }
322
322
 
package/src/helpers.ts CHANGED
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env node
2
+
1
3
  /*
2
4
  * This file is part of the HightJS Project.
3
5
  * Copyright (c) 2025 itsmuzin
@@ -19,9 +21,10 @@
19
21
  import http, {IncomingMessage, Server, ServerResponse} from 'http';
20
22
  import os from 'os';
21
23
  import {URLSearchParams} from 'url'; // API moderna, substitui 'querystring'
24
+ import path from 'path';
22
25
  // Helpers para integração com diferentes frameworks
23
26
  import hweb, {FrameworkAdapterFactory} from './index'; // Importando o tipo
24
- import type {HightJSOptions} from './types';
27
+ import type {HightJSOptions, HightConfig, HightConfigFunction} from './types';
25
28
  import Console, {Colors} from "./api/console";
26
29
  import https, { Server as HttpsServer } from 'https'; // <-- ADICIONAR
27
30
  import fs from 'fs'; // <-- ADICIONAR
@@ -66,7 +69,7 @@ function getLocalExternalIp(): string {
66
69
  }
67
70
 
68
71
  const sendBox = (options: HightJSOptions) => {
69
- const isDev = options.dev ? "Rodando em modo de desenvolvimento" : null;
72
+ const isDev = options.dev ? "Running in development mode" : null;
70
73
 
71
74
  // 1. Verifica se o SSL está ativado (baseado na mesma lógica do initNativeServer)
72
75
  const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
@@ -75,12 +78,12 @@ const sendBox = (options: HightJSOptions) => {
75
78
 
76
79
  // 2. Monta as mensagens com o protocolo correto
77
80
  const messages = [
78
- ` ${Colors.FgGray}┃${Colors.Reset} Local: ${Colors.FgGreen}${protocol}://localhost:${options.port}${Colors.Reset}`,
81
+ ` ${Colors.FgGray}┃${Colors.Reset} Local: ${Colors.FgGreen}${protocol}://localhost:${options.port}${Colors.Reset}`,
79
82
  ];
80
83
 
81
84
  // Só adiciona a rede se o IP local for encontrado
82
85
  if (localIp) {
83
- messages.push(` ${Colors.FgGray}┃${Colors.Reset} Rede: ${Colors.FgGreen}${protocol}://${localIp}:${options.port}${Colors.Reset}`);
86
+ messages.push(` ${Colors.FgGray}┃${Colors.Reset} Network: ${Colors.FgGreen}${protocol}://${localIp}:${options.port}${Colors.Reset}`);
84
87
  }
85
88
 
86
89
  if (isDev) {
@@ -89,10 +92,78 @@ const sendBox = (options: HightJSOptions) => {
89
92
 
90
93
  // Adiciona aviso de redirecionamento se estiver em modo SSL
91
94
  if (isSSL && options.ssl?.redirectPort) {
92
- messages.push(` ${Colors.FgGray}┃${Colors.Reset} HTTP (porta ${options.ssl?.redirectPort}) está redirecionando para HTTPS.`);
95
+ messages.push(` ${Colors.FgGray}┃${Colors.Reset} HTTP (port ${options.ssl?.redirectPort}) is redirecting to HTTPS.`);
93
96
  }
94
97
 
95
- Console.box(messages.join("\n"), { title: "Acesse em:" });
98
+ Console.box(messages.join("\n"), { title: "Access on:" });
99
+ }
100
+
101
+ /**
102
+ * Carrega o arquivo de configuração hightjs.config.ts ou hightjs.config.js do projeto
103
+ * @param projectDir Diretório raiz do projeto
104
+ * @param phase Fase de execução ('development' ou 'production')
105
+ * @returns Configuração mesclada com os valores padrão
106
+ */
107
+ async function loadHightConfig(projectDir: string, phase: string): Promise<HightConfig> {
108
+ const defaultConfig: HightConfig = {
109
+ maxHeadersCount: 100,
110
+ headersTimeout: 60000,
111
+ requestTimeout: 30000,
112
+ serverTimeout: 35000,
113
+ individualRequestTimeout: 30000,
114
+ maxUrlLength: 2048,
115
+ };
116
+
117
+ try {
118
+ // Tenta primeiro .ts, depois .js
119
+ const possiblePaths = [
120
+ path.join(projectDir, 'hightjs.config.ts'),
121
+ path.join(projectDir, 'hightjs.config.js'),
122
+ ];
123
+
124
+ let configPath: string | null = null;
125
+ for (const p of possiblePaths) {
126
+ if (fs.existsSync(p)) {
127
+ configPath = p;
128
+ break;
129
+ }
130
+ }
131
+
132
+ if (!configPath) {
133
+ return defaultConfig;
134
+ }
135
+
136
+ // Remove do cache para permitir hot reload da configuração em dev
137
+ delete require.cache[require.resolve(configPath)];
138
+
139
+ const configModule = require(configPath);
140
+ const configExport = configModule.default || configModule;
141
+
142
+ let userConfig: HightConfig;
143
+
144
+ if (typeof configExport === 'function') {
145
+ // Suporta tanto função síncrona quanto assíncrona
146
+ userConfig = await Promise.resolve(
147
+ (configExport as HightConfigFunction)(phase, { defaultConfig })
148
+ );
149
+ } else {
150
+ userConfig = configExport;
151
+ }
152
+
153
+ // Mescla a configuração do usuário com a padrão
154
+ const mergedConfig = { ...defaultConfig, ...userConfig };
155
+
156
+ const configFileName = path.basename(configPath);
157
+ Console.info(`${Colors.FgCyan}[Config]${Colors.Reset} Loaded ${configFileName}`);
158
+
159
+ return mergedConfig;
160
+ } catch (error) {
161
+ if (error instanceof Error) {
162
+ Console.warn(`${Colors.FgYellow}[Config]${Colors.Reset} Error loading hightjs.config: ${error.message}`);
163
+ Console.warn(`${Colors.FgYellow}[Config]${Colors.Reset} Using default configuration`);
164
+ }
165
+ return defaultConfig;
166
+ }
96
167
  }
97
168
 
98
169
  /**
@@ -181,8 +252,14 @@ async function initNativeServer(hwebApp: HWebApp, options: HightJSOptions, port:
181
252
  const time = Date.now();
182
253
 
183
254
  await hwebApp.prepare();
255
+
256
+ // Carrega a configuração do arquivo hightjs.config.js
257
+ const projectDir = options.dir || process.cwd();
258
+ const phase = options.dev ? 'development' : 'production';
259
+ const hightConfig = await loadHightConfig(projectDir, phase);
260
+
184
261
  const handler = hwebApp.getRequestHandler();
185
- const msg = Console.dynamicLine(` ${Colors.BgYellow} ready ${Colors.Reset} ${Colors.Bright}Iniciando HightJS na porta ${options.port}${Colors.Reset}`);
262
+ const msg = Console.dynamicLine(` ${Colors.BgYellow} ready ${Colors.Reset} ${Colors.Bright}Starting HightJS on port ${options.port}${Colors.Reset}`);
186
263
 
187
264
  // --- LÓGICA DO LISTENER (REUTILIZÁVEL) ---
188
265
  // Extraímos a lógica principal para uma variável
@@ -200,16 +277,17 @@ async function initNativeServer(hwebApp: HWebApp, options: HightJSOptions, port:
200
277
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
201
278
  }
202
279
 
203
- // Timeout por requisição
204
- req.setTimeout(30000, () => {
280
+ // Timeout por requisição (usa configuração personalizada)
281
+ req.setTimeout(hightConfig.individualRequestTimeout || 30000, () => {
205
282
  res.statusCode = 408; // Request Timeout
206
283
  res.end('Request timeout');
207
284
  });
208
285
 
209
286
  try {
210
- // Validação básica de URL
287
+ // Validação básica de URL (usa configuração personalizada)
211
288
  const url = req.url || '/';
212
- if (url.length > 2048) {
289
+ const maxUrlLength = hightConfig.maxUrlLength || 2048;
290
+ if (url.length > maxUrlLength) {
213
291
  res.statusCode = 414; // URI Too Long
214
292
  res.end('URL too long');
215
293
  return;
@@ -227,9 +305,9 @@ async function initNativeServer(hwebApp: HWebApp, options: HightJSOptions, port:
227
305
  } catch (error) {
228
306
  // Log do erro no servidor
229
307
  if (error instanceof Error) {
230
- Console.error(`Erro no servidor nativo: ${error.message}`);
308
+ Console.error(`Native server error: ${error.message}`);
231
309
  } else {
232
- Console.error('Erro desconhecido no servidor nativo:', error);
310
+ Console.error('Unknown native server error:', error);
233
311
  }
234
312
 
235
313
  // Tratamento de erro (idêntico ao seu original)
@@ -297,15 +375,15 @@ async function initNativeServer(hwebApp: HWebApp, options: HightJSOptions, port:
297
375
  server = http.createServer(requestListener as any); // (any para contornar HWebIncomingMessage)
298
376
  }
299
377
 
300
- // Configurações de segurança do servidor (Comum a ambos)
301
- server.setTimeout(35000); // Timeout geral do servidor
302
- server.maxHeadersCount = 100; // Limita número de headers
303
- server.headersTimeout = 60000; // Timeout para headers
304
- server.requestTimeout = 30000; // Timeout para requisições
378
+ // Configurações de segurança do servidor (usa configuração personalizada)
379
+ server.setTimeout(hightConfig.serverTimeout || 35000); // Timeout geral do servidor
380
+ server.maxHeadersCount = hightConfig.maxHeadersCount || 100; // Limita número de headers
381
+ server.headersTimeout = hightConfig.headersTimeout || 60000; // Timeout para headers
382
+ server.requestTimeout = hightConfig.requestTimeout || 30000; // Timeout para requisições
305
383
 
306
384
  server.listen(port, hostname, () => {
307
385
  sendBox({ ...options, port });
308
- msg.end(` ${Colors.BgGreen} ready ${Colors.Reset} ${Colors.Bright}Pronto na porta ${Colors.BgGreen} ${options.port} ${Colors.Reset}${Colors.Bright} em ${Date.now() - time}ms${Colors.Reset}\n`);
386
+ msg.end(` ${Colors.BgGreen} ready ${Colors.Reset} ${Colors.Bright}Ready on port ${Colors.BgGreen} ${options.port} ${Colors.Reset}${Colors.Bright} in ${Date.now() - time}ms${Colors.Reset}\n`);
309
387
  });
310
388
 
311
389
  // Configura WebSocket para hot reload (Comum a ambos)
@@ -344,7 +422,7 @@ export function app(options: HightJSOptions = {}) {
344
422
  const cookieParser = require('cookie-parser');
345
423
  serverApp.use(cookieParser());
346
424
  } catch (e) {
347
- Console.error("Não foi possivel achar cookie-parser");
425
+ Console.error("Could not find cookie-parser");
348
426
  }
349
427
  serverApp.use(express.json());
350
428
  serverApp.use(express.urlencoded({ extended: true }));
@@ -355,12 +433,12 @@ export function app(options: HightJSOptions = {}) {
355
433
  try {
356
434
  await serverApp.register(require('@fastify/cookie'));
357
435
  } catch (e) {
358
- Console.error("Não foi possivel achar @fastify/cookie");
436
+ Console.error("Could not find @fastify/cookie");
359
437
  }
360
438
  try {
361
439
  await serverApp.register(require('@fastify/formbody'));
362
440
  } catch (e) {
363
- Console.error("Não foi possivel achar @fastify/formbody");
441
+ Console.error("Could not find @fastify/formbody");
364
442
  }
365
443
  await serverApp.register(async (fastify: any) => {
366
444
  fastify.all('*', handler);
@@ -390,7 +468,7 @@ export function app(options: HightJSOptions = {}) {
390
468
  const data = await response.json();
391
469
  return data.version;
392
470
  } catch (error) {
393
- Console.error('Não foi possível verificar a versão mais recente do HightJS:', error);
471
+ Console.error('Could not check for the latest HightJS version:', error);
394
472
  return currentVersion; // Retorna a versão atual em caso de erro
395
473
  }
396
474
  }
@@ -398,23 +476,21 @@ export function app(options: HightJSOptions = {}) {
398
476
  const isUpToDate = latestVersion === currentVersion;
399
477
  let message;
400
478
  if (!isUpToDate) {
401
- message = `${Colors.FgGreen} uma nova versão disponível (v${latestVersion})${Colors.FgMagenta}`
479
+ message = `${Colors.FgGreen} A new version is available (v${latestVersion})${Colors.FgMagenta}`
402
480
  } else {
403
- message = `${Colors.FgGreen} Você está na versão mais recente${Colors.FgMagenta}`
481
+ message = `${Colors.FgGreen} You are on the latest version${Colors.FgMagenta}`
404
482
  }
405
483
  console.log(`${Colors.FgMagenta}
406
484
  __ ___ ${Colors.FgGreen} __ ${Colors.FgMagenta}
407
485
  |__| | / _\` |__| | ${Colors.FgGreen} | /__\` ${Colors.FgMagenta} ${Colors.FgMagenta}HightJS ${Colors.FgGray}(v${require('../package.json').version}) - itsmuzin${Colors.FgMagenta}
408
- | | | \\__> | | | ${Colors.FgGreen}\\__/ .__/ ${message}
409
-
410
-
486
+ | | | \\__> | | | ${Colors.FgGreen}\\__/ .__/ ${message}
411
487
  ${Colors.Reset}`);
412
488
 
413
489
  const actualPort = options.port || 3000;
414
490
  const actualHostname = options.hostname || "0.0.0.0";
415
491
 
416
492
  if (framework !== 'native') {
417
- Console.warn(`O framework "${framework}" foi selecionado, mas o método init() funciona com o framework "native". Iniciando servidor nativo...`);
493
+ Console.warn(`The "${framework}" framework was selected, but the init() method only works with the "native" framework. Starting native server...`);
418
494
  }
419
495
 
420
496
 
package/src/hotReload.ts CHANGED
@@ -39,6 +39,8 @@ export class HotReloadManager {
39
39
  private isShuttingDown: boolean = false;
40
40
  private debounceTimers: Map<string, NodeJS.Timeout> = new Map();
41
41
  private customHotReloadListener: ((file: string) => Promise<void> | void) | null = null;
42
+ private isBuilding: boolean = false;
43
+ private buildCompleteResolve: (() => void) | null = null;
42
44
 
43
45
  constructor(projectDir: string) {
44
46
  this.projectDir = projectDir;
@@ -200,33 +202,48 @@ export class HotReloadManager {
200
202
  clearFileCache(filePath);
201
203
  this.clearBackendCache(filePath);
202
204
 
203
- // Checa build se for .ts/.tsx/.js/.jsx
204
- const ext = path.extname(filePath);
205
- if ([".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
206
- const result = await this.checkFrontendBuild(filePath);
207
- if (result.error) {
208
- this.notifyClients('src-error', { file: filePath, error: result.error });
209
- return;
210
- }
211
- }
212
-
213
- // Se for arquivo de frontend, notifica o cliente para recarregar a página
205
+ // Se for arquivo de frontend, aguarda o build terminar antes de recarregar
214
206
  if (isFrontendFile) {
215
- Console.logWithout(Levels.INFO, Colors.BgRed,`📄 Recarregando frontend...`);
216
- this.frontendChangeCallback?.();
217
- this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
207
+ Console.logWithout(Levels.INFO, Colors.BgRed,`📄 Waiting for frontend build...`);
208
+
209
+ // Marca que estamos esperando um build
210
+ this.isBuilding = true;
211
+
212
+ // Cria uma promise que será resolvida quando o build terminar
213
+ const buildPromise = new Promise<void>((resolve) => {
214
+ this.buildCompleteResolve = resolve;
215
+ });
216
+
217
+ // Aguarda o build terminar (com timeout de 30 segundos)
218
+ const timeoutPromise = new Promise<void>((_, reject) => {
219
+ setTimeout(() => reject(new Error('Build timeout')), 30000);
220
+ });
221
+
222
+ try {
223
+ await Promise.race([buildPromise, timeoutPromise]);
224
+ Console.logWithout(Levels.INFO, Colors.BgRed,`✅ Build complete, reloading frontend...`);
225
+ this.frontendChangeCallback?.();
226
+ this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
227
+ } catch (error) {
228
+ Console.logWithout(Levels.ERROR, Colors.BgRed,`⚠️ Timeout in build, reloading anyway...`);
229
+ this.frontendChangeCallback?.();
230
+ this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
231
+ } finally {
232
+ this.isBuilding = false;
233
+ this.buildCompleteResolve = null;
234
+ }
218
235
  }
219
236
 
220
237
  // Se for arquivo de backend, recarrega o módulo e notifica
221
238
  if (isBackendFile) {
222
- Console.logWithout(Levels.INFO, Colors.BgRed,`⚙️ Recarregando backend...`);
239
+ Console.logWithout(Levels.INFO, Colors.BgRed,`⚙️ Reloading backend...`);
223
240
  this.backendApiChangeCallback?.();
224
241
  this.notifyClients('backend-api-reload', { file: filePath, event: 'change' });
225
242
  }
226
243
 
227
244
  // Fallback: se não for nem frontend nem backend detectado, recarrega tudo
228
245
  if (!isFrontendFile && !isBackendFile) {
229
- Console.logWithout(Levels.INFO, Colors.BgRed,`🔄 Recarregando aplicação...`);
246
+ Console.logWithout(Levels.INFO, Colors.BgRed,`🔄 Reloading application...`);
230
247
  this.frontendChangeCallback?.();
231
248
  this.backendApiChangeCallback?.();
232
249
  this.notifyClients('src-reload', { file: filePath, event: 'change' });
@@ -238,7 +255,7 @@ export class HotReloadManager {
238
255
  await this.customHotReloadListener(filePath);
239
256
  } catch (error) {
240
257
  // @ts-ignore
241
- Console.logWithout(Levels.ERROR, `Erro no listener customizado: ${error.message}`);
258
+ Console.logWithout(Levels.ERROR, `Error in custom listener: ${error.message}`);
242
259
  }
243
260
  }
244
261
  }
@@ -256,7 +273,7 @@ export class HotReloadManager {
256
273
  try {
257
274
  ws.send(message);
258
275
  } catch (error) {
259
- Console.logWithout(Levels.ERROR, Colors.BgRed, `Erro ao enviar mensagem WebSocket: ${error}`);
276
+ Console.logWithout(Levels.ERROR, Colors.BgRed, `Error sending WebSocket message: ${error}`);
260
277
  deadClients.push(ws);
261
278
  }
262
279
  } else {
@@ -325,7 +342,7 @@ export class HotReloadManager {
325
342
  ws = new WebSocket('ws://localhost:3000/hweb-hotreload/');
326
343
 
327
344
  ws.onopen = function() {
328
- console.log('🔌 Hot-reload conectado');
345
+ console.log('🔌 Hot-reload connected');
329
346
  isConnected = true;
330
347
  reconnectAttempts = 0;
331
348
  reconnectInterval = 1000;
@@ -345,13 +362,13 @@ export class HotReloadManager {
345
362
  window.location.reload();
346
363
  break;
347
364
  case 'server-restart':
348
- console.log('🔄 Servidor reiniciando...');
365
+ console.log('🔄 Server restarting...');
349
366
  break;
350
367
  case 'server-ready':
351
368
  setTimeout(() => window.location.reload(), 500);
352
369
  break;
353
370
  case 'frontend-error':
354
- console.error('❌ Erro no frontend:', message.data);
371
+ console.error('❌ Frontend error:', message.data);
355
372
  break;
356
373
  }
357
374
  } catch (e) {
@@ -376,7 +393,7 @@ export class HotReloadManager {
376
393
  };
377
394
 
378
395
  } catch (error) {
379
- console.error('Erro ao criar WebSocket:', error);
396
+ console.error('Error creating WebSocket:', error);
380
397
  scheduleReconnect();
381
398
  }
382
399
  }
@@ -446,45 +463,18 @@ export class HotReloadManager {
446
463
 
447
464
  setHotReloadListener(listener: (file: string) => Promise<void> | void) {
448
465
  this.customHotReloadListener = listener;
449
- Console.info('🔌 Hot reload listener customizado registrado');
466
+ Console.info('🔌 Hot reload custom listener registered');
450
467
  }
451
468
 
452
469
  removeHotReloadListener() {
453
470
  this.customHotReloadListener = null;
454
471
  }
455
472
 
456
- private async checkFrontendBuild(filePath: string) {
457
- try {
458
- const tsNodePath = require.resolve('ts-node');
459
- const { spawn } = require('child_process');
460
-
461
- return new Promise<{ error?: string }>((resolve) => {
462
- const proc = spawn(process.execPath, [tsNodePath, '--transpile-only', filePath], {
463
- cwd: this.projectDir,
464
- env: process.env,
465
- timeout: 10000 // Timeout de 10 segundos
466
- });
467
-
468
- let errorMsg = '';
469
-
470
- proc.stderr.on('data', (data: Buffer) => {
471
- errorMsg += data.toString();
472
- });
473
-
474
- proc.on('close', (code: number) => {
475
- if (code !== 0 && errorMsg) {
476
- resolve({ error: errorMsg });
477
- } else {
478
- resolve({});
479
- }
480
- });
481
-
482
- proc.on('error', (error: Error) => {
483
- resolve({ error: error.message });
484
- });
485
- });
486
- } catch (error) {
487
- return { error: `Erro ao verificar build: ${error}` };
473
+ onBuildComplete(success: boolean) {
474
+ if (this.buildCompleteResolve) {
475
+ this.buildCompleteResolve();
476
+ this.buildCompleteResolve = null;
488
477
  }
478
+ this.isBuilding = false;
489
479
  }
490
480
  }
package/src/index.ts CHANGED
@@ -61,6 +61,9 @@ export { app } from './helpers';
61
61
  // Exporta o sistema de WebSocket
62
62
  export type { WebSocketContext, WebSocketHandler } from './types';
63
63
 
64
+ // Exporta os tipos de configuração
65
+ export type { HightConfig, HightConfigFunction } from './types';
66
+
64
67
  // Função para verificar se o projeto é grande o suficiente para se beneficiar de chunks
65
68
  function isLargeProject(projectDir: string): boolean {
66
69
  try {
@@ -254,7 +257,7 @@ export default function hweb(options: HightJSOptions) {
254
257
 
255
258
  // Adiciona callback para recarregar TUDO quando qualquer arquivo mudar
256
259
  hotReloadManager.onBackendApiChange(() => {
257
- Console.info('🔄 Recarregando backend e dependências...');
260
+
258
261
 
259
262
  loadBackendRoutes(userBackendRoutesDir);
260
263
  processWebSocketRoutes(); // Processa rotas WS após recarregar backend
@@ -262,18 +265,16 @@ export default function hweb(options: HightJSOptions) {
262
265
 
263
266
  // Adiciona callback para regenerar entry file quando frontend mudar
264
267
  hotReloadManager.onFrontendChange(() => {
265
- Console.info('🔄 Regenerando frontend...');
266
268
  regenerateEntryFile();
267
269
  });
268
270
  }
269
271
  const now = Date.now();
270
- const timee = Console.dynamicLine(` ${Colors.BgYellow} router ${Colors.Reset} Carregando rotas e componentes do frontend e backend`);
272
+ const timee = Console.dynamicLine(` ${Colors.BgYellow} router ${Colors.Reset} Loading routes and components`);
271
273
  const spinnerFrames1 = ['|', '/', '-', '\\'];
272
274
  let frameIndex1 = 0;
273
275
 
274
276
  const spinner1 = setInterval(() => {
275
- Console.info('aaaa')
276
- timee.update(` ${Colors.FgYellow}${spinnerFrames1[frameIndex1]}${Colors.Reset} Carregando rotas e componentes...`);
277
+ timee.update(` ${Colors.FgYellow}${spinnerFrames1[frameIndex1]}${Colors.Reset} Loading routes and components...`);
277
278
  frameIndex1 = (frameIndex1 + 1) % spinnerFrames1.length;
278
279
  }, 100); // muda a cada 100ms
279
280
  // ORDEM IMPORTANTE: Carrega TUDO antes de criar o arquivo de entrada
@@ -293,18 +294,18 @@ export default function hweb(options: HightJSOptions) {
293
294
 
294
295
  entryPoint = createEntryFile(dir, frontendRoutes);
295
296
  clearInterval(spinner1)
296
- timee.end(` ${Colors.BgGreen} router ${Colors.Reset} Rotas e componentes carregados em ${Date.now() - now}ms`);
297
+ timee.end(` ${Colors.BgGreen} router ${Colors.Reset} Routes and components loaded in ${Date.now() - now}ms`);
297
298
 
298
299
 
299
300
  if (isProduction) {
300
- const time = Console.dynamicLine(` ${Colors.BgYellow} build ${Colors.Reset} Iniciando build do cliente para produção`);
301
+ const time = Console.dynamicLine(` ${Colors.BgYellow} build ${Colors.Reset} Starting client build`);
301
302
 
302
303
  // Spinner
303
304
  const spinnerFrames = ['|', '/', '-', '\\'];
304
305
  let frameIndex = 0;
305
306
 
306
307
  const spinner = setInterval(() => {
307
- time.update(` ${Colors.FgYellow}${spinnerFrames[frameIndex]}${Colors.Reset} Buildando para produção...`);
308
+ time.update(` ${Colors.FgYellow}${spinnerFrames[frameIndex]}${Colors.Reset} Building...`);
308
309
  frameIndex = (frameIndex + 1) % spinnerFrames.length;
309
310
  }, 100); // muda a cada 100ms
310
311
 
@@ -314,14 +315,14 @@ export default function hweb(options: HightJSOptions) {
314
315
 
315
316
  clearInterval(spinner); // para o spinner
316
317
  time.update(""); // limpa a linha
317
- time.end(` ${Colors.BgGreen} build ${Colors.Reset} Build do cliente concluído em ${elapsed}ms`);
318
+ time.end(` ${Colors.BgGreen} build ${Colors.Reset} Client build completed in ${elapsed}ms`);
318
319
 
319
320
  } else {
320
- const time = Console.dynamicLine(` ${Colors.BgYellow} watcher ${Colors.Reset} Iniciando watch do cliente`);
321
+ const time = Console.dynamicLine(` ${Colors.BgYellow} watcher ${Colors.Reset} Starting client watch`);
321
322
  watchWithChunks(entryPoint, outDir, hotReloadManager!).catch(err => {
322
- Console.error(`Erro ao iniciar o watch`, err);
323
+ Console.error(`Error starting watch`, err);
323
324
  });
324
- time.end(` ${Colors.BgGreen} watcher ${Colors.Reset} Watch do cliente iniciado`);
325
+ time.end(` ${Colors.BgGreen} watcher ${Colors.Reset} Client Watch started`);
325
326
  }
326
327
 
327
328
  },
@@ -339,7 +340,6 @@ export default function hweb(options: HightJSOptions) {
339
340
  if (instrumentation.hotReloadListener && typeof instrumentation.hotReloadListener === 'function') {
340
341
  if (hotReloadManager) {
341
342
  hotReloadManager.setHotReloadListener(instrumentation.hotReloadListener);
342
- Console.info('✅ Hot reload listener registrado');
343
343
  }
344
344
  }
345
345
 
@@ -348,7 +348,7 @@ export default function hweb(options: HightJSOptions) {
348
348
  } else if (typeof instrumentation.default === 'function') {
349
349
  instrumentation.default();
350
350
  } else {
351
- Console.warn(`O arquivo de instrumentação ${instrumentationFile} não exporta uma função padrão.`);
351
+ Console.warn(`The instrumentation file ${instrumentationFile} does not export a default function.`);
352
352
  }
353
353
  }
354
354
  },
@@ -470,8 +470,8 @@ export default function hweb(options: HightJSOptions) {
470
470
  return;
471
471
  }
472
472
  } catch (error) {
473
- Console.error(`Erro na rota de API ${pathname}:`, error);
474
- genericRes.status(500).text('Erro interno do servidor na API');
473
+ Console.error(`API route error ${pathname}:`, error);
474
+ genericRes.status(500).text('Internal server error in API');
475
475
  return;
476
476
  }
477
477
  }
@@ -498,8 +498,8 @@ export default function hweb(options: HightJSOptions) {
498
498
  genericRes.status(404).header('Content-Type', 'text/html').send(html);
499
499
  return;
500
500
  } catch (error) {
501
- Console.error(`Erro ao renderizar página 404:`, error);
502
- genericRes.status(404).text('Página não encontrada');
501
+ Console.error(`Error rendering page 404:`, error);
502
+ genericRes.status(404).text('Page not found');
503
503
  return;
504
504
  }
505
505
  }
@@ -513,8 +513,8 @@ export default function hweb(options: HightJSOptions) {
513
513
  });
514
514
  genericRes.status(200).header('Content-Type', 'text/html').send(html);
515
515
  } catch (error) {
516
- Console.error(`Erro ao renderizar a página ${pathname}:`, error);
517
- genericRes.status(500).text('Erro interno do servidor');
516
+ Console.error(`Error rendering page ${pathname}:`, error);
517
+ genericRes.status(500).text('Internal server error');
518
518
  }
519
519
  };
520
520
  },
@@ -529,19 +529,6 @@ export default function hweb(options: HightJSOptions) {
529
529
  setupWebSocketUpgrade(actualServer, hotReloadManager);
530
530
  },
531
531
 
532
- build: async () => {
533
- const msg = Console.dynamicLine(` ${Colors.FgYellow}● ${Colors.Reset}Iniciando build do cliente para produção`);
534
- const outDir = path.join(dir, 'hweb-dist');
535
- fs.mkdirSync(outDir, {recursive: true});
536
-
537
- const routes = loadRoutes(userWebRoutesDir);
538
- const entryPoint = createEntryFile(dir, routes);
539
- const outfile = path.join(outDir, 'main.js');
540
-
541
- await build(entryPoint, outfile, true); // Força produção no build manual
542
-
543
- msg.end(` ${Colors.FgGreen}● ${Colors.Reset}Build do cliente concluído: ${outfile}`);
544
- },
545
532
 
546
533
  stop: () => {
547
534
  if (hotReloadManager) {