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