hightjs 0.2.52 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/adapters/express.js +1 -1
  2. package/dist/api/console.d.ts +6 -4
  3. package/dist/api/console.js +27 -9
  4. package/dist/auth/components.js +16 -0
  5. package/dist/auth/core.js +16 -0
  6. package/dist/auth/index.js +16 -0
  7. package/dist/auth/jwt.js +16 -0
  8. package/dist/auth/providers/index.js +16 -0
  9. package/dist/auth/providers.js +16 -0
  10. package/dist/auth/react/index.js +16 -0
  11. package/dist/auth/react.js +16 -0
  12. package/dist/auth/routes.js +16 -0
  13. package/dist/auth/types.js +16 -0
  14. package/dist/bin/hightjs.js +68 -11
  15. package/dist/builder.js +16 -0
  16. package/dist/client/clientRouter.js +16 -0
  17. package/dist/client/entry.client.js +16 -0
  18. package/dist/client.js +16 -0
  19. package/dist/helpers.d.ts +7 -6
  20. package/dist/helpers.js +284 -198
  21. package/dist/hotReload.js +23 -7
  22. package/dist/index.js +49 -25
  23. package/dist/router.js +16 -0
  24. package/dist/types.d.ts +6 -0
  25. package/docs/cli.md +4 -5
  26. package/package.json +1 -1
  27. package/src/adapters/express.ts +18 -1
  28. package/src/adapters/factory.ts +16 -0
  29. package/src/adapters/fastify.ts +16 -0
  30. package/src/adapters/native.ts +16 -0
  31. package/src/api/console.ts +28 -10
  32. package/src/api/http.ts +16 -0
  33. package/src/auth/client.ts +16 -0
  34. package/src/auth/components.tsx +16 -0
  35. package/src/auth/core.ts +16 -0
  36. package/src/auth/index.ts +16 -0
  37. package/src/auth/jwt.ts +16 -0
  38. package/src/auth/providers/credentials.ts +16 -0
  39. package/src/auth/providers/discord.ts +16 -0
  40. package/src/auth/providers/google.ts +16 -0
  41. package/src/auth/providers/index.ts +16 -0
  42. package/src/auth/providers.ts +16 -0
  43. package/src/auth/react/index.ts +16 -0
  44. package/src/auth/react.tsx +16 -0
  45. package/src/auth/routes.ts +17 -0
  46. package/src/auth/types.ts +17 -0
  47. package/src/bin/hightjs.js +79 -11
  48. package/src/builder.js +16 -0
  49. package/src/client/DefaultNotFound.tsx +16 -0
  50. package/src/client/clientRouter.ts +16 -0
  51. package/src/client/entry.client.tsx +16 -0
  52. package/src/client.ts +16 -0
  53. package/src/components/Link.tsx +16 -0
  54. package/src/helpers.ts +327 -215
  55. package/src/hotReload.ts +24 -8
  56. package/src/index.ts +54 -25
  57. package/src/renderer.tsx +16 -0
  58. package/src/router.ts +16 -0
  59. package/src/types/framework.ts +16 -0
  60. package/src/types.ts +22 -0
package/dist/helpers.js CHANGED
@@ -1,4 +1,20 @@
1
1
  "use strict";
2
+ /*
3
+ * This file is part of the HightJS Project.
4
+ * Copyright (c) 2025 itsmuzin
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
2
18
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
19
  if (k2 === undefined) k2 = k;
4
20
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -37,234 +53,157 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
53
  };
38
54
  Object.defineProperty(exports, "__esModule", { value: true });
39
55
  exports.app = app;
40
- // Helpers para integração com diferentes frameworks
41
- const index_1 = __importStar(require("./index"));
56
+ // Imports Nativos do Node.js (movidos para o topo)
57
+ const http_1 = __importDefault(require("http"));
42
58
  const os_1 = __importDefault(require("os"));
59
+ const url_1 = require("url"); // API moderna, substitui 'querystring'
60
+ // Helpers para integração com diferentes frameworks
61
+ const index_1 = __importStar(require("./index")); // Importando o tipo
43
62
  const console_1 = __importStar(require("./api/console"));
63
+ const https_1 = __importDefault(require("https")); // <-- ADICIONAR
64
+ const fs_1 = __importDefault(require("fs")); // <-- ADICIONAR
65
+ // --- Helpers ---
66
+ /**
67
+ * Encontra o IP externo local (rede)
68
+ */
44
69
  function getLocalExternalIp() {
45
70
  const interfaces = os_1.default.networkInterfaces();
46
71
  for (const name of Object.keys(interfaces)) {
47
- for (const iface of interfaces[name]) {
48
- if (iface.family === 'IPv4' && !iface.internal) {
49
- return iface.address;
72
+ const ifaceList = interfaces[name];
73
+ if (ifaceList) {
74
+ for (const iface of ifaceList) {
75
+ if (iface.family === 'IPv4' && !iface.internal) {
76
+ return iface.address;
77
+ }
50
78
  }
51
79
  }
52
80
  }
53
- return 'localhost';
81
+ return 'localhost'; // Fallback
54
82
  }
55
83
  const sendBox = (options) => {
56
84
  const isDev = options.dev ? "Rodando em modo de desenvolvimento" : null;
85
+ // 1. Verifica se o SSL está ativado (baseado na mesma lógica do initNativeServer)
86
+ const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
87
+ const protocol = isSSL ? 'https' : 'http';
88
+ const localIp = getLocalExternalIp(); // Assume que getLocalExternalIp() existe
89
+ // 2. Monta as mensagens com o protocolo correto
57
90
  const messages = [
58
- ` ${console_1.Colors.FgMagenta}● ${console_1.Colors.Reset}Local: ${console_1.Colors.FgGreen}http://localhost:${options.port}${console_1.Colors.Reset}`,
59
- ` ${console_1.Colors.FgMagenta}● ${console_1.Colors.Reset}Rede: ${console_1.Colors.FgGreen}http://${getLocalExternalIp()}:${options.port}${console_1.Colors.Reset}`,
91
+ ` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Local: ${console_1.Colors.FgGreen}${protocol}://localhost:${options.port}${console_1.Colors.Reset}`,
60
92
  ];
61
- if (isDev) {
62
- messages.push(` ${console_1.Colors.FgMagenta}● ${console_1.Colors.Reset}${isDev}`);
63
- }
64
- console_1.default.box(messages.join("\n"), { title: "Acesse o HightJS em:" });
65
- };
66
- exports.default = app;
67
- function app(options = {}) {
68
- const framework = options.framework || 'native'; // Mudando o padrão para 'native'
69
- index_1.FrameworkAdapterFactory.setFramework(framework);
70
- const hwebApp = (0, index_1.default)(options);
71
- return {
72
- ...hwebApp,
73
- /**
74
- * Integra com uma aplicação de qualquer framework (Express, Fastify, etc)
75
- */
76
- integrate: async (serverApp) => {
77
- await hwebApp.prepare();
78
- const handler = hwebApp.getRequestHandler();
79
- if (framework === 'express') {
80
- // Express integration
81
- serverApp.use(handler);
82
- hwebApp.setupWebSocket(serverApp);
83
- }
84
- else if (framework === 'fastify') {
85
- // Fastify integration
86
- await serverApp.register(async (fastify) => {
87
- fastify.all('*', handler);
88
- });
89
- hwebApp.setupWebSocket(serverApp);
90
- }
91
- else {
92
- // Generic integration - assume Express-like
93
- serverApp.use(handler);
94
- hwebApp.setupWebSocket(serverApp);
95
- }
96
- hwebApp.executeInstrumentation();
97
- return serverApp;
98
- },
99
- /**
100
- * Inicia um servidor HightJS fechado (o usuário não tem acesso ao framework)
101
- */
102
- init: async () => {
103
- console.log(`${console_1.Colors.FgMagenta}
104
- _ _ _ _ _ _ _____
105
- | | | (_) | | | | | |/ ____|
106
- | |__| |_ __ _| |__ | |_ | | (___
107
- | __ | |/ _\` | '_ \\| __| _ | |\\___ \\
108
- | | | | | (_| | | | | |_ | |__| |____) |
109
- |_| |_|_|\\__, |_| |_|\\__| \\____/|_____/
110
- __/ |
111
- |___/ ${console_1.Colors.Reset}`);
112
- const actualPort = options.port || 3000;
113
- const actualHostname = options.hostname || "0.0.0.0";
114
- if (framework === 'express') {
115
- return await initExpressServer(hwebApp, options, actualPort, actualHostname);
116
- }
117
- else if (framework === 'fastify') {
118
- return await initFastifyServer(hwebApp, options, actualPort, actualHostname);
119
- }
120
- else {
121
- // Default to Native
122
- return await initNativeServer(hwebApp, options, actualPort, actualHostname);
123
- }
124
- }
125
- };
126
- }
127
- /**
128
- * Inicializa servidor Express fechado
129
- */
130
- async function initExpressServer(hwebApp, options, port, hostname) {
131
- const msg = console_1.default.dynamicLine(` ${console_1.Colors.FgCyan}● ${console_1.Colors.Reset}Iniciando HightJS com Express...`);
132
- const express = require('express');
133
- const app = express();
134
- // Middlewares básicos para Express
135
- app.use(express.json());
136
- app.use(express.urlencoded({ extended: true }));
137
- // Cookie parser se disponível
138
- try {
139
- const cookieParser = require('cookie-parser');
140
- app.use(cookieParser());
141
- }
142
- catch (e) {
143
- console_1.default.error("Não foi possivel achar cookie-parser");
144
- }
145
- await hwebApp.prepare();
146
- const handler = hwebApp.getRequestHandler();
147
- app.use(handler);
148
- const server = app.listen(port, hostname, () => {
149
- sendBox({ ...options, port });
150
- msg.end(` ${console_1.Colors.FgCyan}● ${console_1.Colors.Reset}Servidor Express iniciado (compatibilidade)`);
151
- });
152
- // Configura WebSocket para hot reload
153
- hwebApp.setupWebSocket(server);
154
- hwebApp.executeInstrumentation();
155
- return server;
156
- }
157
- /**
158
- * Inicializa servidor Fastify fechado
159
- */
160
- async function initFastifyServer(hwebApp, options, port, hostname) {
161
- const msg = console_1.default.dynamicLine(` ${console_1.Colors.FgCyan}● ${console_1.Colors.Reset}Iniciando HightJS com Fastify...`);
162
- const fastify = require('fastify')({ logger: false });
163
- // Registra plugins básicos para Fastify
164
- try {
165
- await fastify.register(require('@fastify/cookie'));
166
- }
167
- catch (e) {
168
- console_1.default.error("Não foi possivel achar @fastify/cookie");
93
+ // adiciona a rede se o IP local for encontrado
94
+ 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}`);
169
96
  }
170
- try {
171
- await fastify.register(require('@fastify/formbody'));
97
+ if (isDev) {
98
+ messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} ${isDev}`);
172
99
  }
173
- catch (e) {
174
- console_1.default.error("Não foi possivel achar @fastify/formbody");
100
+ // Adiciona aviso de redirecionamento se estiver em modo SSL
101
+ 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.`);
175
103
  }
176
- await hwebApp.prepare();
177
- const handler = hwebApp.getRequestHandler();
178
- // Registra o handler do hweb
179
- await fastify.register(async (fastify) => {
180
- fastify.all('*', handler);
181
- });
182
- hwebApp.setupWebSocket(fastify);
183
- const address = await fastify.listen({ port, host: hostname });
184
- sendBox({ ...options, port });
185
- msg.end(` ${console_1.Colors.FgCyan}● ${console_1.Colors.Reset}Servidor Fastify iniciado (compatibilidade)`);
186
- hwebApp.executeInstrumentation();
187
- return fastify;
188
- }
104
+ console_1.default.box(messages.join("\n"), { title: "Acesse em:" });
105
+ };
189
106
  /**
190
- * Inicializa servidor nativo do HightJS usando HTTP puro
107
+ * Middleware para parsing do body com proteções de segurança (versão melhorada).
108
+ * Rejeita a promise em caso de erro de parsing ou estouro de limite.
191
109
  */
192
- async function initNativeServer(hwebApp, options, port, hostname) {
193
- const msg = console_1.default.dynamicLine(` ${console_1.Colors.FgMagenta}⚡ ${console_1.Colors.Reset}${console_1.Colors.Bright}Iniciando HightJS em modo NATIVO${console_1.Colors.Reset}`);
194
- const http = require('http');
195
- const { parse: parseUrl } = require('url');
196
- const { parse: parseQuery } = require('querystring');
197
- await hwebApp.prepare();
198
- const handler = hwebApp.getRequestHandler();
199
- // Middleware para parsing do body com proteções de segurança
200
- const parseBody = (req) => {
201
- return new Promise((resolve, reject) => {
202
- if (req.method === 'GET' || req.method === 'HEAD') {
110
+ const parseBody = (req) => {
111
+ // Constantes para limites de segurança
112
+ const MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB limite total
113
+ const MAX_JSON_SIZE = 1 * 1024 * 1024; // 1MB limite para JSON
114
+ const BODY_TIMEOUT = 30000; // 30 segundos
115
+ return new Promise((resolve, reject) => {
116
+ if (req.method === 'GET' || req.method === 'HEAD') {
117
+ resolve(null);
118
+ return;
119
+ }
120
+ let body = '';
121
+ let totalSize = 0;
122
+ // Timeout para requisições lentas
123
+ const timeout = setTimeout(() => {
124
+ req.destroy();
125
+ reject(new Error('Request body timeout'));
126
+ }, BODY_TIMEOUT);
127
+ req.on('data', (chunk) => {
128
+ totalSize += chunk.length;
129
+ // Proteção contra DoS (Payload Too Large)
130
+ if (totalSize > MAX_BODY_SIZE) {
131
+ clearTimeout(timeout);
132
+ req.destroy();
133
+ reject(new Error('Request body too large'));
134
+ return;
135
+ }
136
+ body += chunk.toString();
137
+ });
138
+ req.on('end', () => {
139
+ clearTimeout(timeout);
140
+ if (!body) {
203
141
  resolve(null);
204
142
  return;
205
143
  }
206
- let body = '';
207
- let totalSize = 0;
208
- const maxBodySize = 10 * 1024 * 1024; // 10MB limite
209
- // Timeout para requisições que demoram muito
210
- const timeout = setTimeout(() => {
211
- req.destroy();
212
- reject(new Error('Request timeout'));
213
- }, 30000); // 30 segundos
214
- req.on('data', (chunk) => {
215
- totalSize += chunk.length;
216
- // Proteção contra ataques de DoS por body muito grande
217
- if (totalSize > maxBodySize) {
218
- clearTimeout(timeout);
219
- req.destroy();
220
- reject(new Error('Request body too large'));
221
- return;
222
- }
223
- body += chunk.toString();
224
- });
225
- req.on('end', () => {
226
- clearTimeout(timeout);
227
- try {
228
- const contentType = req.headers['content-type'] || '';
229
- if (contentType.includes('application/json')) {
230
- // Validação adicional para JSON
231
- if (body.length > 1024 * 1024) { // 1MB limite para JSON
232
- reject(new Error('JSON body too large'));
233
- return;
234
- }
235
- resolve(JSON.parse(body));
144
+ try {
145
+ const contentType = req.headers['content-type'] || '';
146
+ if (contentType.includes('application/json')) {
147
+ if (body.length > MAX_JSON_SIZE) {
148
+ reject(new Error('JSON body too large'));
149
+ return;
236
150
  }
237
- else if (contentType.includes('application/x-www-form-urlencoded')) {
238
- resolve(parseQuery(body));
151
+ // Rejeita promise se o JSON for inválido
152
+ try {
153
+ resolve(JSON.parse(body));
239
154
  }
240
- else {
241
- resolve(body);
155
+ catch (e) {
156
+ reject(new Error('Invalid JSON body'));
242
157
  }
243
158
  }
244
- catch (error) {
245
- resolve(body); // Fallback para string se parsing falhar
159
+ else if (contentType.includes('application/x-www-form-urlencoded')) {
160
+ // Usa API moderna URLSearchParams (segura contra prototype pollution)
161
+ resolve(Object.fromEntries(new url_1.URLSearchParams(body)));
246
162
  }
247
- });
248
- req.on('error', (error) => {
249
- clearTimeout(timeout);
163
+ else {
164
+ resolve(body); // Fallback para texto plano
165
+ }
166
+ }
167
+ catch (error) {
168
+ // Pega qualquer outro erro síncrono
250
169
  reject(error);
251
- });
170
+ }
252
171
  });
253
- };
254
- // Cria o servidor HTTP nativo com configurações de segurança
255
- const server = http.createServer(async (req, res) => {
172
+ req.on('error', (error) => {
173
+ clearTimeout(timeout);
174
+ reject(error);
175
+ });
176
+ });
177
+ };
178
+ /**
179
+ * Inicializa servidor nativo do HightJS usando HTTP ou HTTPS
180
+ */
181
+ async function initNativeServer(hwebApp, options, port, hostname) {
182
+ const time = Date.now();
183
+ await hwebApp.prepare();
184
+ 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}`);
186
+ // --- LÓGICA DO LISTENER (REUTILIZÁVEL) ---
187
+ // Extraímos a lógica principal para uma variável
188
+ // para que possa ser usada tanto pelo servidor HTTP quanto HTTPS.
189
+ const requestListener = async (req, res) => {
256
190
  // Configurações de segurança básicas
257
191
  res.setHeader('X-Content-Type-Options', 'nosniff');
258
192
  res.setHeader('X-Frame-Options', 'DENY');
259
193
  res.setHeader('X-XSS-Protection', '1; mode=block');
260
194
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
261
- // Timeout para requisições
195
+ // IMPORTANTE: Adiciona HSTS (Strict-Transport-Security) se estiver em modo SSL
196
+ // Isso força o navegador a usar HTTPS no futuro.
197
+ if (options.ssl) {
198
+ res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
199
+ }
200
+ // Timeout por requisição
262
201
  req.setTimeout(30000, () => {
263
202
  res.statusCode = 408; // Request Timeout
264
203
  res.end('Request timeout');
265
204
  });
266
205
  try {
267
- // Validação básica de URL para prevenir ataques
206
+ // Validação básica de URL
268
207
  const url = req.url || '/';
269
208
  if (url.length > 2048) {
270
209
  res.statusCode = 414; // URI Too Long
@@ -272,16 +211,22 @@ async function initNativeServer(hwebApp, options, port, hostname) {
272
211
  return;
273
212
  }
274
213
  // Parse do body com proteções
275
- req.body = await parseBody(req);
276
- // Adiciona host se não existir
214
+ req.body = await parseBody(req); // Assumindo que parseBody existe
215
+ // Adiciona host se não existir (necessário para `new URL`)
277
216
  req.headers.host = req.headers.host || `localhost:${port}`;
278
217
  // Chama o handler do HightJS
279
218
  await handler(req, res);
280
219
  }
281
220
  catch (error) {
282
- console_1.default.error('Erro no servidor nativo:', error);
221
+ // Log do erro no servidor
222
+ if (error instanceof Error) {
223
+ console_1.default.error(`Erro no servidor nativo: ${error.message}`);
224
+ }
225
+ else {
226
+ console_1.default.error('Erro desconhecido no servidor nativo:', error);
227
+ }
228
+ // Tratamento de erro (idêntico ao seu original)
283
229
  if (!res.headersSent) {
284
- res.statusCode = 500;
285
230
  res.setHeader('Content-Type', 'text/plain');
286
231
  if (error instanceof Error) {
287
232
  if (error.message.includes('too large')) {
@@ -292,27 +237,168 @@ async function initNativeServer(hwebApp, options, port, hostname) {
292
237
  res.statusCode = 408; // Request Timeout
293
238
  res.end('Request timeout');
294
239
  }
240
+ else if (error.message.includes('Invalid JSON')) {
241
+ res.statusCode = 400; // Bad Request
242
+ res.end('Invalid JSON body');
243
+ }
295
244
  else {
245
+ res.statusCode = 500;
296
246
  res.end('Internal server error');
297
247
  }
298
248
  }
299
249
  else {
250
+ res.statusCode = 500;
300
251
  res.end('Internal server error');
301
252
  }
302
253
  }
303
254
  }
304
- });
305
- // Configurações de segurança do servidor
255
+ };
256
+ // --- FIM DO LISTENER ---
257
+ let server; // O tipo do servidor pode variar
258
+ const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
259
+ if (isSSL && options.ssl) {
260
+ const sslOptions = {
261
+ key: fs_1.default.readFileSync(options.ssl.key),
262
+ cert: fs_1.default.readFileSync(options.ssl.cert),
263
+ ca: options.ssl.ca ? fs_1.default.readFileSync(options.ssl.ca) : undefined
264
+ };
265
+ // 1. Cria o servidor HTTPS principal
266
+ server = https_1.default.createServer(sslOptions, requestListener); // (any para contornar HWebIncomingMessage)
267
+ // 2. Cria o servidor de REDIRECIONAMENTO (HTTP -> HTTPS)
268
+ const httpRedirectPort = options.ssl.redirectPort;
269
+ http_1.default.createServer((req, res) => {
270
+ const host = req.headers['host'] || hostname;
271
+ // Remove a porta do host (ex: meusite.com:80)
272
+ const hostWithoutPort = host.split(':')[0];
273
+ // Monta a URL de redirecionamento
274
+ let redirectUrl = `https://${hostWithoutPort}`;
275
+ // Adiciona a porta HTTPS apenas se não for a padrão (443)
276
+ if (port !== 443) {
277
+ redirectUrl += `:${port}`;
278
+ }
279
+ redirectUrl += req.url || '/';
280
+ res.writeHead(301, { 'Location': redirectUrl });
281
+ res.end();
282
+ }).listen(httpRedirectPort, hostname, () => { });
283
+ }
284
+ else {
285
+ // --- MODO HTTP (Original) ---
286
+ // Cria o servidor HTTP nativo
287
+ server = http_1.default.createServer(requestListener); // (any para contornar HWebIncomingMessage)
288
+ }
289
+ // Configurações de segurança do servidor (Comum a ambos)
306
290
  server.setTimeout(35000); // Timeout geral do servidor
307
291
  server.maxHeadersCount = 100; // Limita número de headers
308
292
  server.headersTimeout = 60000; // Timeout para headers
309
293
  server.requestTimeout = 30000; // Timeout para requisições
310
294
  server.listen(port, hostname, () => {
311
295
  sendBox({ ...options, port });
312
- msg.end(` ${console_1.Colors.FgGreen}${console_1.Colors.Reset}${console_1.Colors.Bright}Servidor HightJS NATIVO ativo!${console_1.Colors.Reset}`);
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`);
313
297
  });
314
- // Configura WebSocket para hot reload
298
+ // Configura WebSocket para hot reload (Comum a ambos)
315
299
  hwebApp.setupWebSocket(server);
316
300
  hwebApp.executeInstrumentation();
317
301
  return server;
318
302
  }
303
+ // --- Função Principal ---
304
+ function app(options = {}) {
305
+ const framework = options.framework || 'native';
306
+ index_1.FrameworkAdapterFactory.setFramework(framework);
307
+ // Tipando a app principal do hweb
308
+ const hwebApp = (0, index_1.default)(options);
309
+ return {
310
+ ...hwebApp,
311
+ /**
312
+ * Integra com uma aplicação de qualquer framework (Express, Fastify, etc)
313
+ * O 'serverApp: any' é mantido para flexibilidade, já que pode ser de tipos diferentes.
314
+ */
315
+ integrate: async (serverApp) => {
316
+ await hwebApp.prepare();
317
+ const handler = hwebApp.getRequestHandler();
318
+ // O framework é setado nas opções do hweb, que deve
319
+ // retornar o handler correto em getRequestHandler()
320
+ // A lógica de integração original parece correta.
321
+ if (framework === 'express') {
322
+ const express = require('express');
323
+ try {
324
+ const cookieParser = require('cookie-parser');
325
+ serverApp.use(cookieParser());
326
+ }
327
+ catch (e) {
328
+ console_1.default.error("Não foi possivel achar cookie-parser");
329
+ }
330
+ serverApp.use(express.json());
331
+ serverApp.use(express.urlencoded({ extended: true }));
332
+ serverApp.use(handler);
333
+ hwebApp.setupWebSocket(serverApp);
334
+ }
335
+ else if (framework === 'fastify') {
336
+ try {
337
+ await serverApp.register(require('@fastify/cookie'));
338
+ }
339
+ catch (e) {
340
+ console_1.default.error("Não foi possivel achar @fastify/cookie");
341
+ }
342
+ try {
343
+ await serverApp.register(require('@fastify/formbody'));
344
+ }
345
+ catch (e) {
346
+ console_1.default.error("Não foi possivel achar @fastify/formbody");
347
+ }
348
+ await serverApp.register(async (fastify) => {
349
+ fastify.all('*', handler);
350
+ });
351
+ hwebApp.setupWebSocket(serverApp);
352
+ }
353
+ else {
354
+ // Generic integration (assume Express-like)
355
+ serverApp.use(handler);
356
+ hwebApp.setupWebSocket(serverApp);
357
+ }
358
+ hwebApp.executeInstrumentation();
359
+ return serverApp;
360
+ },
361
+ /**
362
+ * Inicia um servidor HightJS fechado (o usuário não tem acesso ao framework)
363
+ */
364
+ init: async () => {
365
+ const currentVersion = require('../package.json').version;
366
+ async function verifyVersion() {
367
+ // node fetch
368
+ try {
369
+ const response = await fetch('https://registry.npmjs.org/hightjs/latest');
370
+ const data = await response.json();
371
+ return data.version;
372
+ }
373
+ catch (error) {
374
+ console_1.default.error('Não foi possível verificar a versão mais recente do HightJS:', error);
375
+ return currentVersion; // Retorna a versão atual em caso de erro
376
+ }
377
+ }
378
+ const latestVersion = await verifyVersion();
379
+ const isUpToDate = latestVersion === currentVersion;
380
+ let message;
381
+ if (!isUpToDate) {
382
+ message = `${console_1.Colors.FgGreen} Há uma nova versão disponível (v${latestVersion})${console_1.Colors.FgMagenta}`;
383
+ }
384
+ else {
385
+ message = `${console_1.Colors.FgGreen} Você está na versão mais recente${console_1.Colors.FgMagenta}`;
386
+ }
387
+ console.log(`${console_1.Colors.FgMagenta}
388
+ __ ___ ${console_1.Colors.FgGreen} __ ${console_1.Colors.FgMagenta}
389
+ |__| | / _\` |__| | ${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
+
393
+ ${console_1.Colors.Reset}`);
394
+ const actualPort = options.port || 3000;
395
+ const actualHostname = options.hostname || "0.0.0.0";
396
+ if (framework !== 'native') {
397
+ console_1.default.warn(`O framework "${framework}" foi selecionado, mas o método init() só funciona com o framework "native". Iniciando servidor nativo...`);
398
+ }
399
+ return await initNativeServer(hwebApp, options, actualPort, actualHostname);
400
+ }
401
+ };
402
+ }
403
+ // Exporta a função 'app' como nomeada e também como padrão
404
+ exports.default = app;
package/dist/hotReload.js CHANGED
@@ -34,6 +34,22 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.HotReloadManager = void 0;
37
+ /*
38
+ * This file is part of the HightJS Project.
39
+ * Copyright (c) 2025 itsmuzin
40
+ *
41
+ * Licensed under the Apache License, Version 2.0 (the "License");
42
+ * you may not use this file except in compliance with the License.
43
+ * You may obtain a copy of the License at
44
+ *
45
+ * http://www.apache.org/licenses/LICENSE-2.0
46
+ *
47
+ * Unless required by applicable law or agreed to in writing, software
48
+ * distributed under the License is distributed on an "AS IS" BASIS,
49
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
50
+ * See the License for the specific language governing permissions and
51
+ * limitations under the License.
52
+ */
37
53
  const ws_1 = require("ws");
38
54
  const chokidar = __importStar(require("chokidar"));
39
55
  const path = __importStar(require("path"));
@@ -108,10 +124,10 @@ class HotReloadManager {
108
124
  this.cleanupClient(ws);
109
125
  });
110
126
  ws.on('error', (error) => {
111
- console_1.default.logWithout(console_1.Levels.ERROR, `WebSocket error: ${error.message}`);
127
+ console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `WebSocket error: ${error.message}`);
112
128
  this.cleanupClient(ws);
113
129
  });
114
- console_1.default.logWithout(console_1.Levels.INFO, '🔌 Hot-reload cliente conectado');
130
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, '🔌 Hot-reload cliente conectado');
115
131
  });
116
132
  }
117
133
  cleanupClient(ws) {
@@ -170,7 +186,7 @@ class HotReloadManager {
170
186
  };
171
187
  }
172
188
  async handleAnySrcChange(filePath) {
173
- console_1.default.logWithout(console_1.Levels.INFO, `🔄 Arquivo alterado: ${path.basename(filePath)}`);
189
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `🔄 Arquivo alterado: ${path.basename(filePath)}`);
174
190
  // Detecta se é arquivo de frontend ou backend
175
191
  const isFrontendFile = filePath.includes(path.join('src', 'web', 'routes')) ||
176
192
  filePath.includes(path.join('src', 'web', 'components')) ||
@@ -194,19 +210,19 @@ class HotReloadManager {
194
210
  }
195
211
  // Se for arquivo de frontend, notifica o cliente para recarregar a página
196
212
  if (isFrontendFile) {
197
- console_1.default.logWithout(console_1.Levels.INFO, `📄 Recarregando frontend...`);
213
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `📄 Recarregando frontend...`);
198
214
  this.frontendChangeCallback?.();
199
215
  this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
200
216
  }
201
217
  // Se for arquivo de backend, recarrega o módulo e notifica
202
218
  if (isBackendFile) {
203
- console_1.default.logWithout(console_1.Levels.INFO, `⚙️ Recarregando backend...`);
219
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `⚙️ Recarregando backend...`);
204
220
  this.backendApiChangeCallback?.();
205
221
  this.notifyClients('backend-api-reload', { file: filePath, event: 'change' });
206
222
  }
207
223
  // Fallback: se não for nem frontend nem backend detectado, recarrega tudo
208
224
  if (!isFrontendFile && !isBackendFile) {
209
- console_1.default.logWithout(console_1.Levels.INFO, `🔄 Recarregando aplicação...`);
225
+ console_1.default.logWithout(console_1.Levels.INFO, console_1.Colors.BgRed, `🔄 Recarregando aplicação...`);
210
226
  this.frontendChangeCallback?.();
211
227
  this.backendApiChangeCallback?.();
212
228
  this.notifyClients('src-reload', { file: filePath, event: 'change' });
@@ -234,7 +250,7 @@ class HotReloadManager {
234
250
  ws.send(message);
235
251
  }
236
252
  catch (error) {
237
- console_1.default.logWithout(console_1.Levels.ERROR, `Erro ao enviar mensagem WebSocket: ${error}`);
253
+ console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `Erro ao enviar mensagem WebSocket: ${error}`);
238
254
  deadClients.push(ws);
239
255
  }
240
256
  }