hightjs 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/builder.js +8 -8
- package/src/hotReload.ts +4 -7
- package/src/router.ts +14 -26
- package/dist/adapters/express.d.ts +0 -7
- package/dist/adapters/express.js +0 -63
- package/dist/adapters/factory.d.ts +0 -23
- package/dist/adapters/factory.js +0 -122
- package/dist/adapters/fastify.d.ts +0 -25
- package/dist/adapters/fastify.js +0 -61
- package/dist/adapters/native.d.ts +0 -8
- package/dist/adapters/native.js +0 -198
- package/dist/api/console.d.ts +0 -94
- package/dist/api/console.js +0 -294
- package/dist/api/http.d.ts +0 -180
- package/dist/api/http.js +0 -469
- package/dist/bin/hightjs.d.ts +0 -2
- package/dist/bin/hightjs.js +0 -214
- package/dist/builder.d.ts +0 -32
- package/dist/builder.js +0 -581
- package/dist/client/DefaultNotFound.d.ts +0 -1
- package/dist/client/DefaultNotFound.js +0 -79
- package/dist/client/client.d.ts +0 -3
- package/dist/client/client.js +0 -24
- package/dist/client/clientRouter.d.ts +0 -58
- package/dist/client/clientRouter.js +0 -132
- package/dist/client/entry.client.d.ts +0 -1
- package/dist/client/entry.client.js +0 -455
- package/dist/components/Link.d.ts +0 -7
- package/dist/components/Link.js +0 -13
- package/dist/global/global.d.ts +0 -117
- package/dist/global/global.js +0 -17
- package/dist/helpers.d.ts +0 -20
- package/dist/helpers.js +0 -583
- package/dist/hotReload.d.ts +0 -32
- package/dist/hotReload.js +0 -548
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -494
- package/dist/loaders.d.ts +0 -1
- package/dist/loaders.js +0 -46
- package/dist/renderer.d.ts +0 -14
- package/dist/renderer.js +0 -380
- package/dist/router.d.ts +0 -101
- package/dist/router.js +0 -667
- package/dist/types/framework.d.ts +0 -37
- package/dist/types/framework.js +0 -2
- package/dist/types.d.ts +0 -192
- package/dist/types.js +0 -2
package/dist/helpers.js
DELETED
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/*
|
|
4
|
-
* This file is part of the HightJS Project.
|
|
5
|
-
* Copyright (c) 2025 itsmuzin
|
|
6
|
-
*
|
|
7
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
-
* you may not use this file except in compliance with the License.
|
|
9
|
-
* You may obtain a copy of the License at
|
|
10
|
-
*
|
|
11
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
*
|
|
13
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
* See the License for the specific language governing permissions and
|
|
17
|
-
* limitations under the License.
|
|
18
|
-
*/
|
|
19
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
-
if (k2 === undefined) k2 = k;
|
|
21
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
-
}
|
|
25
|
-
Object.defineProperty(o, k2, desc);
|
|
26
|
-
}) : (function(o, m, k, k2) {
|
|
27
|
-
if (k2 === undefined) k2 = k;
|
|
28
|
-
o[k2] = m[k];
|
|
29
|
-
}));
|
|
30
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
-
}) : function(o, v) {
|
|
33
|
-
o["default"] = v;
|
|
34
|
-
});
|
|
35
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
-
var ownKeys = function(o) {
|
|
37
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
-
var ar = [];
|
|
39
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
-
return ar;
|
|
41
|
-
};
|
|
42
|
-
return ownKeys(o);
|
|
43
|
-
};
|
|
44
|
-
return function (mod) {
|
|
45
|
-
if (mod && mod.__esModule) return mod;
|
|
46
|
-
var result = {};
|
|
47
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
-
__setModuleDefault(result, mod);
|
|
49
|
-
return result;
|
|
50
|
-
};
|
|
51
|
-
})();
|
|
52
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
53
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
54
|
-
};
|
|
55
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
-
exports.app = app;
|
|
57
|
-
// Imports Nativos do Node.js (movidos para o topo)
|
|
58
|
-
const http_1 = __importDefault(require("http"));
|
|
59
|
-
const os_1 = __importDefault(require("os"));
|
|
60
|
-
const url_1 = require("url"); // API moderna, substitui 'querystring'
|
|
61
|
-
const path_1 = __importDefault(require("path"));
|
|
62
|
-
// Helpers para integração com diferentes frameworks
|
|
63
|
-
const index_1 = __importStar(require("./index")); // Importando o tipo
|
|
64
|
-
const console_1 = __importStar(require("./api/console"));
|
|
65
|
-
const https_1 = __importDefault(require("https")); // <-- ADICIONAR
|
|
66
|
-
const fs_1 = __importDefault(require("fs")); // <-- ADICIONAR
|
|
67
|
-
// Registra loaders customizados para importar arquivos não-JS
|
|
68
|
-
const { registerLoaders } = require('./loaders');
|
|
69
|
-
registerLoaders();
|
|
70
|
-
// --- Helpers ---
|
|
71
|
-
/**
|
|
72
|
-
* Encontra o IP externo local (rede)
|
|
73
|
-
*/
|
|
74
|
-
function getLocalExternalIp() {
|
|
75
|
-
const interfaces = os_1.default.networkInterfaces();
|
|
76
|
-
for (const name of Object.keys(interfaces)) {
|
|
77
|
-
const ifaceList = interfaces[name];
|
|
78
|
-
if (ifaceList) {
|
|
79
|
-
for (const iface of ifaceList) {
|
|
80
|
-
if (iface.family === 'IPv4' && !iface.internal) {
|
|
81
|
-
return iface.address;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return 'localhost'; // Fallback
|
|
87
|
-
}
|
|
88
|
-
const sendBox = (options) => {
|
|
89
|
-
const isDev = options.dev ? "Running in development mode" : null;
|
|
90
|
-
// 1. Verifica se o SSL está ativado (baseado na mesma lógica do initNativeServer)
|
|
91
|
-
const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
|
|
92
|
-
const protocol = isSSL ? 'https' : 'http';
|
|
93
|
-
const localIp = getLocalExternalIp(); // Assume que getLocalExternalIp() existe
|
|
94
|
-
// 2. Monta as mensagens com o protocolo correto
|
|
95
|
-
const messages = [
|
|
96
|
-
` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Local: ${console_1.Colors.FgGreen}${protocol}://localhost:${options.port}${console_1.Colors.Reset}`,
|
|
97
|
-
];
|
|
98
|
-
// Só adiciona a rede se o IP local for encontrado
|
|
99
|
-
if (localIp) {
|
|
100
|
-
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} Network: ${console_1.Colors.FgGreen}${protocol}://${localIp}:${options.port}${console_1.Colors.Reset}`);
|
|
101
|
-
}
|
|
102
|
-
if (isDev) {
|
|
103
|
-
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} ${isDev}`);
|
|
104
|
-
}
|
|
105
|
-
// Adiciona aviso de redirecionamento se estiver em modo SSL
|
|
106
|
-
if (isSSL && options.ssl?.redirectPort) {
|
|
107
|
-
messages.push(` ${console_1.Colors.FgGray}┃${console_1.Colors.Reset} HTTP (port ${options.ssl?.redirectPort}) is redirecting to HTTPS.`);
|
|
108
|
-
}
|
|
109
|
-
console_1.default.box(messages.join("\n"), { title: "Access on:" });
|
|
110
|
-
};
|
|
111
|
-
/**
|
|
112
|
-
* Carrega o arquivo de configuração hightjs.config.ts ou hightjs.config.js do projeto
|
|
113
|
-
* @param projectDir Diretório raiz do projeto
|
|
114
|
-
* @param phase Fase de execução ('development' ou 'production')
|
|
115
|
-
* @returns Configuração mesclada com os valores padrão
|
|
116
|
-
*/
|
|
117
|
-
async function loadHightConfig(projectDir, phase) {
|
|
118
|
-
const defaultConfig = {
|
|
119
|
-
maxHeadersCount: 100,
|
|
120
|
-
headersTimeout: 60000,
|
|
121
|
-
requestTimeout: 30000,
|
|
122
|
-
serverTimeout: 35000,
|
|
123
|
-
individualRequestTimeout: 30000,
|
|
124
|
-
maxUrlLength: 2048,
|
|
125
|
-
accessLogging: true,
|
|
126
|
-
};
|
|
127
|
-
try {
|
|
128
|
-
// Tenta primeiro .ts, depois .js
|
|
129
|
-
const possiblePaths = [
|
|
130
|
-
path_1.default.join(projectDir, 'hightjs.config.ts'),
|
|
131
|
-
path_1.default.join(projectDir, 'hightjs.config.js'),
|
|
132
|
-
];
|
|
133
|
-
let configPath = null;
|
|
134
|
-
for (const p of possiblePaths) {
|
|
135
|
-
if (fs_1.default.existsSync(p)) {
|
|
136
|
-
configPath = p;
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (!configPath) {
|
|
141
|
-
return defaultConfig;
|
|
142
|
-
}
|
|
143
|
-
// Remove do cache para permitir hot reload da configuração em dev
|
|
144
|
-
delete require.cache[require.resolve(configPath)];
|
|
145
|
-
const configModule = require(configPath);
|
|
146
|
-
const configExport = configModule.default || configModule;
|
|
147
|
-
let userConfig;
|
|
148
|
-
if (typeof configExport === 'function') {
|
|
149
|
-
// Suporta tanto função síncrona quanto assíncrona
|
|
150
|
-
userConfig = await Promise.resolve(configExport(phase, { defaultConfig }));
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
userConfig = configExport;
|
|
154
|
-
}
|
|
155
|
-
// Mescla a configuração do usuário com a padrão
|
|
156
|
-
const mergedConfig = { ...defaultConfig, ...userConfig };
|
|
157
|
-
const configFileName = path_1.default.basename(configPath);
|
|
158
|
-
console_1.default.info(`${console_1.Colors.FgCyan}[Config]${console_1.Colors.Reset} Loaded ${configFileName}`);
|
|
159
|
-
return mergedConfig;
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
if (error instanceof Error) {
|
|
163
|
-
console_1.default.warn(`${console_1.Colors.FgYellow}[Config]${console_1.Colors.Reset} Error loading hightjs.config: ${error.message}`);
|
|
164
|
-
console_1.default.warn(`${console_1.Colors.FgYellow}[Config]${console_1.Colors.Reset} Using default configuration`);
|
|
165
|
-
}
|
|
166
|
-
return defaultConfig;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Aplica headers CORS na resposta baseado na configuração.
|
|
171
|
-
* @param req Requisição HTTP
|
|
172
|
-
* @param res Resposta HTTP
|
|
173
|
-
* @param corsConfig Configuração de CORS
|
|
174
|
-
* @returns true se a requisição foi finalizada (OPTIONS), false caso contrário
|
|
175
|
-
*/
|
|
176
|
-
function applyCors(req, res, corsConfig) {
|
|
177
|
-
if (!corsConfig || !corsConfig.enabled) {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
const origin = req.headers.origin || req.headers.referer;
|
|
181
|
-
// Verifica se a origem é permitida
|
|
182
|
-
let allowOrigin = false;
|
|
183
|
-
if (corsConfig.origin === '*') {
|
|
184
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
185
|
-
allowOrigin = true;
|
|
186
|
-
}
|
|
187
|
-
else if (typeof corsConfig.origin === 'string' && origin === corsConfig.origin) {
|
|
188
|
-
res.setHeader('Access-Control-Allow-Origin', corsConfig.origin);
|
|
189
|
-
allowOrigin = true;
|
|
190
|
-
}
|
|
191
|
-
else if (Array.isArray(corsConfig.origin) && origin && corsConfig.origin.includes(origin)) {
|
|
192
|
-
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
193
|
-
allowOrigin = true;
|
|
194
|
-
}
|
|
195
|
-
else if (typeof corsConfig.origin === 'function' && origin) {
|
|
196
|
-
try {
|
|
197
|
-
if (corsConfig.origin(origin)) {
|
|
198
|
-
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
199
|
-
allowOrigin = true;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
console_1.default.warn(`${console_1.Colors.FgYellow}[CORS]${console_1.Colors.Reset} Error validating origin: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Se a origem não for permitida e não for wildcard, não aplica outros headers
|
|
207
|
-
if (!allowOrigin && corsConfig.origin !== '*') {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
// Credenciais (não pode ser usado com origin: '*')
|
|
211
|
-
if (corsConfig.credentials && corsConfig.origin !== '*') {
|
|
212
|
-
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
213
|
-
}
|
|
214
|
-
// Métodos permitidos
|
|
215
|
-
const methods = corsConfig.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
|
|
216
|
-
res.setHeader('Access-Control-Allow-Methods', methods.join(', '));
|
|
217
|
-
// Headers permitidos
|
|
218
|
-
const allowedHeaders = corsConfig.allowedHeaders || ['Content-Type', 'Authorization'];
|
|
219
|
-
res.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '));
|
|
220
|
-
// Headers expostos
|
|
221
|
-
if (corsConfig.exposedHeaders && corsConfig.exposedHeaders.length > 0) {
|
|
222
|
-
res.setHeader('Access-Control-Expose-Headers', corsConfig.exposedHeaders.join(', '));
|
|
223
|
-
}
|
|
224
|
-
// Max age para cache de preflight
|
|
225
|
-
const maxAge = corsConfig.maxAge !== undefined ? corsConfig.maxAge : 86400;
|
|
226
|
-
res.setHeader('Access-Control-Max-Age', maxAge.toString());
|
|
227
|
-
// Responde requisições OPTIONS (preflight)
|
|
228
|
-
if (req.method === 'OPTIONS') {
|
|
229
|
-
res.statusCode = 204; // No Content
|
|
230
|
-
res.end();
|
|
231
|
-
return true;
|
|
232
|
-
}
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Middleware para parsing do body com proteções de segurança (versão melhorada).
|
|
237
|
-
*/
|
|
238
|
-
const parseBody = (req) => {
|
|
239
|
-
// Constantes para limites de segurança
|
|
240
|
-
const MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB limite total
|
|
241
|
-
const MAX_JSON_SIZE = 1 * 1024 * 1024; // 1MB limite para JSON
|
|
242
|
-
const BODY_TIMEOUT = 30000; // 30 segundos
|
|
243
|
-
return new Promise((resolve, reject) => {
|
|
244
|
-
if (req.method === 'GET' || req.method === 'HEAD') {
|
|
245
|
-
resolve(null);
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
let body = '';
|
|
249
|
-
let totalSize = 0;
|
|
250
|
-
// Timeout para requisições lentas
|
|
251
|
-
const timeout = setTimeout(() => {
|
|
252
|
-
req.destroy();
|
|
253
|
-
reject(new Error('Request body timeout'));
|
|
254
|
-
}, BODY_TIMEOUT);
|
|
255
|
-
req.on('data', (chunk) => {
|
|
256
|
-
totalSize += chunk.length;
|
|
257
|
-
// Proteção contra DoS (Payload Too Large)
|
|
258
|
-
if (totalSize > MAX_BODY_SIZE) {
|
|
259
|
-
clearTimeout(timeout);
|
|
260
|
-
req.destroy();
|
|
261
|
-
reject(new Error('Request body too large'));
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
body += chunk.toString();
|
|
265
|
-
});
|
|
266
|
-
req.on('end', () => {
|
|
267
|
-
clearTimeout(timeout);
|
|
268
|
-
if (!body) {
|
|
269
|
-
resolve(null);
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
try {
|
|
273
|
-
const contentType = req.headers['content-type'] || '';
|
|
274
|
-
if (contentType.includes('application/json')) {
|
|
275
|
-
if (body.length > MAX_JSON_SIZE) {
|
|
276
|
-
reject(new Error('JSON body too large'));
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
// Rejeita promise se o JSON for inválido
|
|
280
|
-
try {
|
|
281
|
-
resolve(JSON.parse(body));
|
|
282
|
-
}
|
|
283
|
-
catch (e) {
|
|
284
|
-
reject(new Error('Invalid JSON body'));
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
288
|
-
// Usa API moderna URLSearchParams (segura contra prototype pollution)
|
|
289
|
-
resolve(Object.fromEntries(new url_1.URLSearchParams(body)));
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
resolve(body); // Fallback para texto plano
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
catch (error) {
|
|
296
|
-
// Pega qualquer outro erro síncrono
|
|
297
|
-
reject(error);
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
req.on('error', (error) => {
|
|
301
|
-
clearTimeout(timeout);
|
|
302
|
-
reject(error);
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
/**
|
|
307
|
-
* Inicializa servidor nativo do HightJS usando HTTP ou HTTPS
|
|
308
|
-
*/
|
|
309
|
-
async function initNativeServer(hwebApp, options, port, hostname) {
|
|
310
|
-
const time = Date.now();
|
|
311
|
-
await hwebApp.prepare();
|
|
312
|
-
// Carrega a configuração do arquivo hightjs.config.js
|
|
313
|
-
const projectDir = options.dir || process.cwd();
|
|
314
|
-
const phase = options.dev ? 'development' : 'production';
|
|
315
|
-
const hightConfig = await loadHightConfig(projectDir, phase);
|
|
316
|
-
const handler = hwebApp.getRequestHandler();
|
|
317
|
-
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}`);
|
|
318
|
-
// --- LÓGICA DO LISTENER (REUTILIZÁVEL) ---
|
|
319
|
-
// Extraímos a lógica principal para uma variável
|
|
320
|
-
// para que possa ser usada tanto pelo servidor HTTP quanto HTTPS.
|
|
321
|
-
const requestListener = async (req, res) => {
|
|
322
|
-
const requestStartTime = Date.now();
|
|
323
|
-
const method = req.method || 'GET';
|
|
324
|
-
const url = req.url || '/';
|
|
325
|
-
// Aplica CORS se configurado
|
|
326
|
-
const corsHandled = applyCors(req, res, hightConfig.cors);
|
|
327
|
-
if (corsHandled) {
|
|
328
|
-
// Requisição OPTIONS foi respondida pelo CORS
|
|
329
|
-
if (hightConfig.accessLogging) {
|
|
330
|
-
const duration = Date.now() - requestStartTime;
|
|
331
|
-
console_1.default.logCustomLevel('OPTIONS', true, console_1.Colors.BgMagenta, `${url} ${console_1.Colors.FgGreen}204${console_1.Colors.Reset} ${console_1.Colors.FgGray}${duration}ms${console_1.Colors.Reset} ${console_1.Colors.FgCyan}[CORS]${console_1.Colors.Reset}`);
|
|
332
|
-
}
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
// Configurações de segurança básicas
|
|
336
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
337
|
-
res.setHeader('X-Frame-Options', 'DENY');
|
|
338
|
-
res.setHeader('X-XSS-Protection', '1; mode=block');
|
|
339
|
-
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
340
|
-
// IMPORTANTE: Adiciona HSTS (Strict-Transport-Security) se estiver em modo SSL
|
|
341
|
-
// Isso força o navegador a usar HTTPS no futuro.
|
|
342
|
-
if (options.ssl) {
|
|
343
|
-
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
|
344
|
-
}
|
|
345
|
-
// Timeout por requisição (usa configuração personalizada)
|
|
346
|
-
req.setTimeout(hightConfig.individualRequestTimeout || 30000, () => {
|
|
347
|
-
res.statusCode = 408; // Request Timeout
|
|
348
|
-
res.end('Request timeout');
|
|
349
|
-
// Log de timeout
|
|
350
|
-
if (hightConfig.accessLogging) {
|
|
351
|
-
const duration = Date.now() - requestStartTime;
|
|
352
|
-
console_1.default.info(`${console_1.Colors.FgYellow}${method}${console_1.Colors.Reset} ${url} ${console_1.Colors.FgRed}408${console_1.Colors.Reset} ${console_1.Colors.FgGray}${duration}ms${console_1.Colors.Reset}`);
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
// Intercepta o método end() para logar quando a resposta for enviada
|
|
356
|
-
const originalEnd = res.end.bind(res);
|
|
357
|
-
let hasEnded = false;
|
|
358
|
-
res.end = function (...args) {
|
|
359
|
-
if (!hasEnded && hightConfig.accessLogging) {
|
|
360
|
-
hasEnded = true;
|
|
361
|
-
const duration = Date.now() - requestStartTime;
|
|
362
|
-
const statusCode = res.statusCode || 200;
|
|
363
|
-
// Define cor baseada no status code
|
|
364
|
-
let statusColor = console_1.Colors.FgGreen; // 2xx
|
|
365
|
-
if (statusCode >= 500)
|
|
366
|
-
statusColor = console_1.Colors.FgRed; // 5xx
|
|
367
|
-
else if (statusCode >= 400)
|
|
368
|
-
statusColor = console_1.Colors.FgYellow; // 4xx
|
|
369
|
-
else if (statusCode >= 300)
|
|
370
|
-
statusColor = console_1.Colors.FgCyan; // 3xx
|
|
371
|
-
// Formata o método com cor
|
|
372
|
-
let methodColor = console_1.Colors.BgCyan;
|
|
373
|
-
if (method === 'POST')
|
|
374
|
-
methodColor = console_1.Colors.BgGreen;
|
|
375
|
-
else if (method === 'PUT')
|
|
376
|
-
methodColor = console_1.Colors.BgYellow;
|
|
377
|
-
else if (method === 'DELETE')
|
|
378
|
-
methodColor = console_1.Colors.BgRed;
|
|
379
|
-
else if (method === 'PATCH')
|
|
380
|
-
methodColor = console_1.Colors.BgMagenta;
|
|
381
|
-
console_1.default.logCustomLevel(method, true, methodColor, `${url} ${statusColor}${statusCode}${console_1.Colors.Reset} ${console_1.Colors.FgGray}${duration}ms${console_1.Colors.Reset}`);
|
|
382
|
-
}
|
|
383
|
-
// @ts-ignore
|
|
384
|
-
return originalEnd.apply(this, args);
|
|
385
|
-
};
|
|
386
|
-
try {
|
|
387
|
-
// Validação básica de URL (usa configuração personalizada)
|
|
388
|
-
const maxUrlLength = hightConfig.maxUrlLength || 2048;
|
|
389
|
-
if (url.length > maxUrlLength) {
|
|
390
|
-
res.statusCode = 414; // URI Too Long
|
|
391
|
-
res.end('URL too long');
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
// Parse do body com proteções
|
|
395
|
-
req.body = await parseBody(req); // Assumindo que parseBody existe
|
|
396
|
-
// Adiciona host se não existir (necessário para `new URL`)
|
|
397
|
-
req.headers.host = req.headers.host || `localhost:${port}`;
|
|
398
|
-
// Chama o handler do HightJS
|
|
399
|
-
await handler(req, res);
|
|
400
|
-
}
|
|
401
|
-
catch (error) {
|
|
402
|
-
// Log do erro no servidor
|
|
403
|
-
if (error instanceof Error) {
|
|
404
|
-
console_1.default.error(`Native server error: ${error.message}`);
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
console_1.default.error('Unknown native server error:', error);
|
|
408
|
-
}
|
|
409
|
-
// Tratamento de erro (idêntico ao seu original)
|
|
410
|
-
if (!res.headersSent) {
|
|
411
|
-
res.setHeader('Content-Type', 'text/plain');
|
|
412
|
-
if (error instanceof Error) {
|
|
413
|
-
if (error.message.includes('too large')) {
|
|
414
|
-
res.statusCode = 413; // Payload Too Large
|
|
415
|
-
res.end('Request too large');
|
|
416
|
-
}
|
|
417
|
-
else if (error.message.includes('timeout')) {
|
|
418
|
-
res.statusCode = 408; // Request Timeout
|
|
419
|
-
res.end('Request timeout');
|
|
420
|
-
}
|
|
421
|
-
else if (error.message.includes('Invalid JSON')) {
|
|
422
|
-
res.statusCode = 400; // Bad Request
|
|
423
|
-
res.end('Invalid JSON body');
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
res.statusCode = 500;
|
|
427
|
-
res.end('Internal server error');
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
else {
|
|
431
|
-
res.statusCode = 500;
|
|
432
|
-
res.end('Internal server error');
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
// --- FIM DO LISTENER ---
|
|
438
|
-
let server; // O tipo do servidor pode variar
|
|
439
|
-
const isSSL = options.ssl && options.ssl.key && options.ssl.cert;
|
|
440
|
-
if (isSSL && options.ssl) {
|
|
441
|
-
const sslOptions = {
|
|
442
|
-
key: fs_1.default.readFileSync(options.ssl.key),
|
|
443
|
-
cert: fs_1.default.readFileSync(options.ssl.cert),
|
|
444
|
-
ca: options.ssl.ca ? fs_1.default.readFileSync(options.ssl.ca) : undefined
|
|
445
|
-
};
|
|
446
|
-
// 1. Cria o servidor HTTPS principal
|
|
447
|
-
server = https_1.default.createServer(sslOptions, requestListener); // (any para contornar HWebIncomingMessage)
|
|
448
|
-
// 2. Cria o servidor de REDIRECIONAMENTO (HTTP -> HTTPS)
|
|
449
|
-
const httpRedirectPort = options.ssl.redirectPort;
|
|
450
|
-
http_1.default.createServer((req, res) => {
|
|
451
|
-
const host = req.headers['host'] || hostname;
|
|
452
|
-
// Remove a porta do host (ex: meusite.com:80)
|
|
453
|
-
const hostWithoutPort = host.split(':')[0];
|
|
454
|
-
// Monta a URL de redirecionamento
|
|
455
|
-
let redirectUrl = `https://${hostWithoutPort}`;
|
|
456
|
-
// Adiciona a porta HTTPS apenas se não for a padrão (443)
|
|
457
|
-
if (port !== 443) {
|
|
458
|
-
redirectUrl += `:${port}`;
|
|
459
|
-
}
|
|
460
|
-
redirectUrl += req.url || '/';
|
|
461
|
-
res.writeHead(301, { 'Location': redirectUrl });
|
|
462
|
-
res.end();
|
|
463
|
-
}).listen(httpRedirectPort, hostname, () => { });
|
|
464
|
-
}
|
|
465
|
-
else {
|
|
466
|
-
// --- MODO HTTP (Original) ---
|
|
467
|
-
// Cria o servidor HTTP nativo
|
|
468
|
-
server = http_1.default.createServer(requestListener); // (any para contornar HWebIncomingMessage)
|
|
469
|
-
}
|
|
470
|
-
// Configurações de segurança do servidor (usa configuração personalizada)
|
|
471
|
-
server.setTimeout(hightConfig.serverTimeout || 35000); // Timeout geral do servidor
|
|
472
|
-
server.maxHeadersCount = hightConfig.maxHeadersCount || 100; // Limita número de headers
|
|
473
|
-
server.headersTimeout = hightConfig.headersTimeout || 60000; // Timeout para headers
|
|
474
|
-
server.requestTimeout = hightConfig.requestTimeout || 30000; // Timeout para requisições
|
|
475
|
-
server.listen(port, hostname, () => {
|
|
476
|
-
sendBox({ ...options, port });
|
|
477
|
-
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`);
|
|
478
|
-
});
|
|
479
|
-
// Configura WebSocket para hot reload (Comum a ambos)
|
|
480
|
-
hwebApp.setupWebSocket(server);
|
|
481
|
-
hwebApp.executeInstrumentation();
|
|
482
|
-
return server;
|
|
483
|
-
}
|
|
484
|
-
// --- Função Principal ---
|
|
485
|
-
function app(options = {}) {
|
|
486
|
-
const framework = options.framework || 'native';
|
|
487
|
-
index_1.FrameworkAdapterFactory.setFramework(framework);
|
|
488
|
-
// Tipando a app principal do hweb
|
|
489
|
-
const hwebApp = (0, index_1.default)(options);
|
|
490
|
-
return {
|
|
491
|
-
...hwebApp,
|
|
492
|
-
/**
|
|
493
|
-
* Integra com uma aplicação de qualquer framework (Express, Fastify, etc)
|
|
494
|
-
* O 'serverApp: any' é mantido para flexibilidade, já que pode ser de tipos diferentes.
|
|
495
|
-
*/
|
|
496
|
-
integrate: async (serverApp) => {
|
|
497
|
-
await hwebApp.prepare();
|
|
498
|
-
const handler = hwebApp.getRequestHandler();
|
|
499
|
-
// O framework é setado nas opções do hweb, que deve
|
|
500
|
-
// retornar o handler correto em getRequestHandler()
|
|
501
|
-
// A lógica de integração original parece correta.
|
|
502
|
-
if (framework === 'express') {
|
|
503
|
-
const express = require('express');
|
|
504
|
-
try {
|
|
505
|
-
const cookieParser = require('cookie-parser');
|
|
506
|
-
serverApp.use(cookieParser());
|
|
507
|
-
}
|
|
508
|
-
catch (e) {
|
|
509
|
-
console_1.default.error("Could not find cookie-parser");
|
|
510
|
-
}
|
|
511
|
-
serverApp.use(express.json());
|
|
512
|
-
serverApp.use(express.urlencoded({ extended: true }));
|
|
513
|
-
serverApp.use(handler);
|
|
514
|
-
hwebApp.setupWebSocket(serverApp);
|
|
515
|
-
}
|
|
516
|
-
else if (framework === 'fastify') {
|
|
517
|
-
try {
|
|
518
|
-
await serverApp.register(require('@fastify/cookie'));
|
|
519
|
-
}
|
|
520
|
-
catch (e) {
|
|
521
|
-
console_1.default.error("Could not find @fastify/cookie");
|
|
522
|
-
}
|
|
523
|
-
try {
|
|
524
|
-
await serverApp.register(require('@fastify/formbody'));
|
|
525
|
-
}
|
|
526
|
-
catch (e) {
|
|
527
|
-
console_1.default.error("Could not find @fastify/formbody");
|
|
528
|
-
}
|
|
529
|
-
await serverApp.register(async (fastify) => {
|
|
530
|
-
fastify.all('*', handler);
|
|
531
|
-
});
|
|
532
|
-
hwebApp.setupWebSocket(serverApp);
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
// Generic integration (assume Express-like)
|
|
536
|
-
serverApp.use(handler);
|
|
537
|
-
hwebApp.setupWebSocket(serverApp);
|
|
538
|
-
}
|
|
539
|
-
hwebApp.executeInstrumentation();
|
|
540
|
-
return serverApp;
|
|
541
|
-
},
|
|
542
|
-
/**
|
|
543
|
-
* Inicia um servidor HightJS fechado (o usuário não tem acesso ao framework)
|
|
544
|
-
*/
|
|
545
|
-
init: async () => {
|
|
546
|
-
const currentVersion = require('../package.json').version;
|
|
547
|
-
async function verifyVersion() {
|
|
548
|
-
// node fetch
|
|
549
|
-
try {
|
|
550
|
-
const response = await fetch('https://registry.npmjs.org/hightjs/latest');
|
|
551
|
-
const data = await response.json();
|
|
552
|
-
return data.version;
|
|
553
|
-
}
|
|
554
|
-
catch (error) {
|
|
555
|
-
console_1.default.error('Could not check for the latest HightJS version:', error);
|
|
556
|
-
return currentVersion; // Retorna a versão atual em caso de erro
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
const latestVersion = await verifyVersion();
|
|
560
|
-
const isUpToDate = latestVersion === currentVersion;
|
|
561
|
-
let message;
|
|
562
|
-
if (!isUpToDate) {
|
|
563
|
-
message = `${console_1.Colors.FgGreen} A new version is available (v${latestVersion})${console_1.Colors.FgMagenta}`;
|
|
564
|
-
}
|
|
565
|
-
else {
|
|
566
|
-
message = `${console_1.Colors.FgGreen} You are on the latest version${console_1.Colors.FgMagenta}`;
|
|
567
|
-
}
|
|
568
|
-
console.log(`${console_1.Colors.FgMagenta}
|
|
569
|
-
__ ___ ${console_1.Colors.FgGreen} __ ${console_1.Colors.FgMagenta}
|
|
570
|
-
|__| | / _\` |__| | ${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}
|
|
571
|
-
| | | \\__> | | | ${console_1.Colors.FgGreen}\\__/ .__/ ${message}
|
|
572
|
-
${console_1.Colors.Reset}`);
|
|
573
|
-
const actualPort = options.port || 3000;
|
|
574
|
-
const actualHostname = options.hostname || "0.0.0.0";
|
|
575
|
-
if (framework !== 'native') {
|
|
576
|
-
console_1.default.warn(`The "${framework}" framework was selected, but the init() method only works with the "native" framework. Starting native server...`);
|
|
577
|
-
}
|
|
578
|
-
return await initNativeServer(hwebApp, options, actualPort, actualHostname);
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
// Exporta a função 'app' como nomeada e também como padrão
|
|
583
|
-
exports.default = app;
|
package/dist/hotReload.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { IncomingMessage } from 'http';
|
|
2
|
-
export declare class HotReloadManager {
|
|
3
|
-
private wss;
|
|
4
|
-
private watchers;
|
|
5
|
-
private projectDir;
|
|
6
|
-
private clients;
|
|
7
|
-
private backendApiChangeCallback;
|
|
8
|
-
private frontendChangeCallback;
|
|
9
|
-
private isShuttingDown;
|
|
10
|
-
private debounceTimers;
|
|
11
|
-
private customHotReloadListener;
|
|
12
|
-
private isBuilding;
|
|
13
|
-
private buildCompleteResolve;
|
|
14
|
-
constructor(projectDir: string);
|
|
15
|
-
start(): Promise<void>;
|
|
16
|
-
handleUpgrade(request: IncomingMessage, socket: any, head: Buffer): void;
|
|
17
|
-
private setupWebSocketServer;
|
|
18
|
-
private cleanupClient;
|
|
19
|
-
private setupWatchers;
|
|
20
|
-
private debounce;
|
|
21
|
-
private handleAnySrcChange;
|
|
22
|
-
private notifyClients;
|
|
23
|
-
private restartServer;
|
|
24
|
-
stop(): void;
|
|
25
|
-
getClientScript(): string;
|
|
26
|
-
private clearBackendCache;
|
|
27
|
-
onBackendApiChange(callback: () => void): void;
|
|
28
|
-
onFrontendChange(callback: () => void): void;
|
|
29
|
-
setHotReloadListener(listener: (file: string) => Promise<void> | void): void;
|
|
30
|
-
removeHotReloadListener(): void;
|
|
31
|
-
onBuildComplete(success: boolean): void;
|
|
32
|
-
}
|