hightjs 0.3.3 → 0.3.5

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 (47) hide show
  1. package/dist/adapters/factory.js +8 -8
  2. package/dist/adapters/native.js +3 -3
  3. package/dist/api/console.js +1 -1
  4. package/dist/auth/client.js +5 -5
  5. package/dist/auth/components.js +2 -2
  6. package/dist/auth/core.js +2 -2
  7. package/dist/auth/react.js +4 -4
  8. package/dist/auth/routes.js +1 -1
  9. package/dist/bin/hightjs.js +32 -331
  10. package/dist/builder.js +7 -19
  11. package/dist/client/DefaultNotFound.js +1 -1
  12. package/dist/client/entry.client.js +98 -8
  13. package/dist/helpers.d.ts +1 -0
  14. package/dist/helpers.js +130 -29
  15. package/dist/hotReload.js +25 -16
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +26 -36
  18. package/dist/renderer.js +137 -18
  19. package/dist/router.js +133 -62
  20. package/dist/types.d.ts +81 -0
  21. package/docs/config.md +216 -0
  22. package/example/hightjs.config.ts +87 -0
  23. package/example/package-lock.json +633 -3054
  24. package/example/package.json +3 -3
  25. package/example/src/web/layout.tsx +57 -3
  26. package/example/src/web/routes/index.tsx +1 -1
  27. package/package.json +1 -1
  28. package/src/adapters/factory.ts +8 -8
  29. package/src/adapters/native.ts +3 -3
  30. package/src/api/console.ts +3 -1
  31. package/src/auth/client.ts +5 -5
  32. package/src/auth/components.tsx +2 -2
  33. package/src/auth/core.ts +2 -2
  34. package/src/auth/react.tsx +4 -4
  35. package/src/auth/routes.ts +1 -1
  36. package/src/bin/hightjs.js +33 -394
  37. package/src/builder.js +7 -20
  38. package/src/client/DefaultNotFound.tsx +1 -1
  39. package/src/client/entry.client.tsx +125 -10
  40. package/src/helpers.ts +144 -30
  41. package/src/hotReload.ts +25 -16
  42. package/src/index.ts +33 -39
  43. package/src/renderer.tsx +142 -18
  44. package/src/router.ts +142 -63
  45. package/src/types.ts +108 -0
  46. package/example/.hweb/entry.client.js +0 -24
  47. package/example/hweb-dist/main-5KKAYNUU.js +0 -1137
package/dist/index.js CHANGED
@@ -236,23 +236,20 @@ function hweb(options) {
236
236
  await hotReloadManager.start();
237
237
  // Adiciona callback para recarregar TUDO quando qualquer arquivo mudar
238
238
  hotReloadManager.onBackendApiChange(() => {
239
- console_1.default.info('🔄 Recarregando backend e dependências...');
240
239
  (0, router_1.loadBackendRoutes)(userBackendRoutesDir);
241
240
  (0, router_1.processWebSocketRoutes)(); // Processa rotas WS após recarregar backend
242
241
  });
243
242
  // Adiciona callback para regenerar entry file quando frontend mudar
244
243
  hotReloadManager.onFrontendChange(() => {
245
- console_1.default.info('🔄 Regenerando frontend...');
246
244
  regenerateEntryFile();
247
245
  });
248
246
  }
249
247
  const now = Date.now();
250
- const timee = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} router ${console_1.Colors.Reset} Carregando rotas e componentes do frontend e backend`);
248
+ const timee = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} router ${console_1.Colors.Reset} Loading routes and components`);
251
249
  const spinnerFrames1 = ['|', '/', '-', '\\'];
252
250
  let frameIndex1 = 0;
253
251
  const spinner1 = setInterval(() => {
254
- console_1.default.info('aaaa');
255
- timee.update(` ${console_1.Colors.FgYellow}${spinnerFrames1[frameIndex1]}${console_1.Colors.Reset} Carregando rotas e componentes...`);
252
+ timee.update(` ${console_1.Colors.FgYellow}${spinnerFrames1[frameIndex1]}${console_1.Colors.Reset} Loading routes and components...`);
256
253
  frameIndex1 = (frameIndex1 + 1) % spinnerFrames1.length;
257
254
  }, 100); // muda a cada 100ms
258
255
  // ORDEM IMPORTANTE: Carrega TUDO antes de criar o arquivo de entrada
@@ -263,18 +260,18 @@ function hweb(options) {
263
260
  // Carrega layout.tsx ANTES de criar o entry file
264
261
  const layout = (0, router_1.loadLayout)(userWebDir);
265
262
  const notFound = (0, router_1.loadNotFound)(userWebDir);
266
- const outDir = path_1.default.join(dir, 'hweb-dist');
263
+ const outDir = path_1.default.join(dir, '.hight');
267
264
  fs_1.default.mkdirSync(outDir, { recursive: true });
268
265
  entryPoint = createEntryFile(dir, frontendRoutes);
269
266
  clearInterval(spinner1);
270
- timee.end(` ${console_1.Colors.BgGreen} router ${console_1.Colors.Reset} Rotas e componentes carregados em ${Date.now() - now}ms`);
267
+ timee.end(` ${console_1.Colors.BgGreen} router ${console_1.Colors.Reset} Routes and components loaded in ${Date.now() - now}ms`);
271
268
  if (isProduction) {
272
- const time = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} build ${console_1.Colors.Reset} Iniciando build do cliente para produção`);
269
+ const time = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} build ${console_1.Colors.Reset} Starting client build`);
273
270
  // Spinner
274
271
  const spinnerFrames = ['|', '/', '-', '\\'];
275
272
  let frameIndex = 0;
276
273
  const spinner = setInterval(() => {
277
- time.update(` ${console_1.Colors.FgYellow}${spinnerFrames[frameIndex]}${console_1.Colors.Reset} Buildando para produção...`);
274
+ time.update(` ${console_1.Colors.FgYellow}${spinnerFrames[frameIndex]}${console_1.Colors.Reset} Building...`);
278
275
  frameIndex = (frameIndex + 1) % spinnerFrames.length;
279
276
  }, 100); // muda a cada 100ms
280
277
  const now = Date.now();
@@ -282,14 +279,18 @@ function hweb(options) {
282
279
  const elapsed = Date.now() - now;
283
280
  clearInterval(spinner); // para o spinner
284
281
  time.update(""); // limpa a linha
285
- time.end(` ${console_1.Colors.BgGreen} build ${console_1.Colors.Reset} Build do cliente concluído em ${elapsed}ms`);
282
+ time.end(` ${console_1.Colors.BgGreen} build ${console_1.Colors.Reset} Client build completed in ${elapsed}ms`);
283
+ // Notifica o hot reload manager que o build foi concluído
284
+ if (hotReloadManager) {
285
+ hotReloadManager.onBuildComplete(true);
286
+ }
286
287
  }
287
288
  else {
288
- const time = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} watcher ${console_1.Colors.Reset} Iniciando watch do cliente`);
289
+ const time = console_1.default.dynamicLine(` ${console_1.Colors.BgYellow} watcher ${console_1.Colors.Reset} Starting client watch`);
289
290
  (0, builder_1.watchWithChunks)(entryPoint, outDir, hotReloadManager).catch(err => {
290
- console_1.default.error(`Erro ao iniciar o watch`, err);
291
+ console_1.default.error(`Error starting watch`, err);
291
292
  });
292
- time.end(` ${console_1.Colors.BgGreen} watcher ${console_1.Colors.Reset} Watch do cliente iniciado`);
293
+ time.end(` ${console_1.Colors.BgGreen} watcher ${console_1.Colors.Reset} Client Watch started`);
293
294
  }
294
295
  },
295
296
  executeInstrumentation: () => {
@@ -303,7 +304,6 @@ function hweb(options) {
303
304
  if (instrumentation.hotReloadListener && typeof instrumentation.hotReloadListener === 'function') {
304
305
  if (hotReloadManager) {
305
306
  hotReloadManager.setHotReloadListener(instrumentation.hotReloadListener);
306
- console_1.default.info('✅ Hot reload listener registrado');
307
307
  }
308
308
  }
309
309
  if (typeof instrumentation === 'function') {
@@ -313,7 +313,7 @@ function hweb(options) {
313
313
  instrumentation.default();
314
314
  }
315
315
  else {
316
- console_1.default.warn(`O arquivo de instrumentação ${instrumentationFile} não exporta uma função padrão.`);
316
+ console_1.default.warn(`The instrumentation file ${instrumentationFile} does not export a default function.`);
317
317
  }
318
318
  }
319
319
  },
@@ -334,7 +334,7 @@ function hweb(options) {
334
334
  return;
335
335
  }
336
336
  // 2. Primeiro verifica se é um arquivo estático da pasta public
337
- if (pathname !== '/' && !pathname.startsWith('/api/') && !pathname.startsWith('/hweb-')) {
337
+ if (pathname !== '/' && !pathname.startsWith('/api/') && !pathname.startsWith('/.hight')) {
338
338
  const publicDir = path_1.default.join(dir, 'public');
339
339
  const filePath = path_1.default.join(publicDir, pathname);
340
340
  if (fs_1.default.existsSync(filePath) && fs_1.default.statSync(filePath).isFile()) {
@@ -376,10 +376,10 @@ function hweb(options) {
376
376
  return;
377
377
  }
378
378
  }
379
- // 3. Verifica se é um arquivo estático do hweb-dist
380
- if (pathname.startsWith('/hweb-dist/')) {
381
- const staticPath = path_1.default.join(dir, 'hweb-dist');
382
- const filePath = path_1.default.join(staticPath, pathname.replace('/hweb-dist/', ''));
379
+ // 3. Verifica se é um arquivo estático do .hight
380
+ if (pathname.startsWith('/_hight/')) {
381
+ const staticPath = path_1.default.join(dir, '.hight');
382
+ const filePath = path_1.default.join(staticPath, pathname.replace('/_hight/', ''));
383
383
  if (fs_1.default.existsSync(filePath)) {
384
384
  const ext = path_1.default.extname(filePath).toLowerCase();
385
385
  const contentTypes = {
@@ -420,8 +420,8 @@ function hweb(options) {
420
420
  }
421
421
  }
422
422
  catch (error) {
423
- console_1.default.error(`Erro na rota de API ${pathname}:`, error);
424
- genericRes.status(500).text('Erro interno do servidor na API');
423
+ console_1.default.error(`API route error ${pathname}:`, error);
424
+ genericRes.status(500).text('Internal server error in API');
425
425
  return;
426
426
  }
427
427
  }
@@ -446,8 +446,8 @@ function hweb(options) {
446
446
  return;
447
447
  }
448
448
  catch (error) {
449
- console_1.default.error(`Erro ao renderizar página 404:`, error);
450
- genericRes.status(404).text('Página não encontrada');
449
+ console_1.default.error(`Error rendering page 404:`, error);
450
+ genericRes.status(404).text('Page not found');
451
451
  return;
452
452
  }
453
453
  }
@@ -461,8 +461,8 @@ function hweb(options) {
461
461
  genericRes.status(200).header('Content-Type', 'text/html').send(html);
462
462
  }
463
463
  catch (error) {
464
- console_1.default.error(`Erro ao renderizar a página ${pathname}:`, error);
465
- genericRes.status(500).text('Erro interno do servidor');
464
+ console_1.default.error(`Error rendering page ${pathname}:`, error);
465
+ genericRes.status(500).text('Internal server error');
466
466
  }
467
467
  };
468
468
  },
@@ -474,16 +474,6 @@ function hweb(options) {
474
474
  // Usa o sistema coordenado de WebSocket upgrade que integra hot-reload e rotas de usuário
475
475
  (0, router_1.setupWebSocketUpgrade)(actualServer, hotReloadManager);
476
476
  },
477
- build: async () => {
478
- const msg = console_1.default.dynamicLine(` ${console_1.Colors.FgYellow}● ${console_1.Colors.Reset}Iniciando build do cliente para produção`);
479
- const outDir = path_1.default.join(dir, 'hweb-dist');
480
- fs_1.default.mkdirSync(outDir, { recursive: true });
481
- const routes = (0, router_1.loadRoutes)(userWebRoutesDir);
482
- const entryPoint = createEntryFile(dir, routes);
483
- const outfile = path_1.default.join(outDir, 'main.js');
484
- await (0, builder_1.build)(entryPoint, outfile, true); // Força produção no build manual
485
- msg.end(` ${console_1.Colors.FgGreen}● ${console_1.Colors.Reset}Build do cliente concluído: ${outfile}`);
486
- },
487
477
  stop: () => {
488
478
  if (hotReloadManager) {
489
479
  hotReloadManager.stop();
package/dist/renderer.js CHANGED
@@ -7,18 +7,123 @@ exports.render = render;
7
7
  const router_1 = require("./router");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
- // Funções para codificar/decodificar dados (disfarça o JSON no HTML)
11
- function encodeInitialData(data) {
12
- // Converte para JSON, depois para base64, e adiciona um prefixo fake
10
+ // Função para gerar todas as meta tags
11
+ function generateMetaTags(metadata) {
12
+ const tags = [];
13
+ // Charset
14
+ tags.push(`<meta charset="${metadata.charset || 'UTF-8'}">`);
15
+ // Viewport
16
+ tags.push(`<meta name="viewport" content="${metadata.viewport || 'width=device-width, initial-scale=1.0'}">`);
17
+ // Description
18
+ if (metadata.description) {
19
+ tags.push(`<meta name="description" content="${metadata.description}">`);
20
+ }
21
+ // Keywords
22
+ if (metadata.keywords) {
23
+ const keywordsStr = Array.isArray(metadata.keywords)
24
+ ? metadata.keywords.join(', ')
25
+ : metadata.keywords;
26
+ tags.push(`<meta name="keywords" content="${keywordsStr}">`);
27
+ }
28
+ // Author
29
+ if (metadata.author) {
30
+ tags.push(`<meta name="author" content="${metadata.author}">`);
31
+ }
32
+ // Theme color
33
+ if (metadata.themeColor) {
34
+ tags.push(`<meta name="theme-color" content="${metadata.themeColor}">`);
35
+ }
36
+ // Robots
37
+ if (metadata.robots) {
38
+ tags.push(`<meta name="robots" content="${metadata.robots}">`);
39
+ }
40
+ // Canonical
41
+ if (metadata.canonical) {
42
+ tags.push(`<link rel="canonical" href="${metadata.canonical}">`);
43
+ }
44
+ // Favicon
45
+ if (metadata.favicon) {
46
+ tags.push(`<link rel="icon" href="${metadata.favicon}">`);
47
+ }
48
+ // Apple Touch Icon
49
+ if (metadata.appleTouchIcon) {
50
+ tags.push(`<link rel="apple-touch-icon" href="${metadata.appleTouchIcon}">`);
51
+ }
52
+ // Manifest
53
+ if (metadata.manifest) {
54
+ tags.push(`<link rel="manifest" href="${metadata.manifest}">`);
55
+ }
56
+ // Open Graph
57
+ if (metadata.openGraph) {
58
+ const og = metadata.openGraph;
59
+ if (og.title)
60
+ tags.push(`<meta property="og:title" content="${og.title}">`);
61
+ if (og.description)
62
+ tags.push(`<meta property="og:description" content="${og.description}">`);
63
+ if (og.type)
64
+ tags.push(`<meta property="og:type" content="${og.type}">`);
65
+ if (og.url)
66
+ tags.push(`<meta property="og:url" content="${og.url}">`);
67
+ if (og.siteName)
68
+ tags.push(`<meta property="og:site_name" content="${og.siteName}">`);
69
+ if (og.locale)
70
+ tags.push(`<meta property="og:locale" content="${og.locale}">`);
71
+ if (og.image) {
72
+ if (typeof og.image === 'string') {
73
+ tags.push(`<meta property="og:image" content="${og.image}">`);
74
+ }
75
+ else {
76
+ tags.push(`<meta property="og:image" content="${og.image.url}">`);
77
+ if (og.image.width)
78
+ tags.push(`<meta property="og:image:width" content="${og.image.width}">`);
79
+ if (og.image.height)
80
+ tags.push(`<meta property="og:image:height" content="${og.image.height}">`);
81
+ if (og.image.alt)
82
+ tags.push(`<meta property="og:image:alt" content="${og.image.alt}">`);
83
+ }
84
+ }
85
+ }
86
+ // Twitter Card
87
+ if (metadata.twitter) {
88
+ const tw = metadata.twitter;
89
+ if (tw.card)
90
+ tags.push(`<meta name="twitter:card" content="${tw.card}">`);
91
+ if (tw.site)
92
+ tags.push(`<meta name="twitter:site" content="${tw.site}">`);
93
+ if (tw.creator)
94
+ tags.push(`<meta name="twitter:creator" content="${tw.creator}">`);
95
+ if (tw.title)
96
+ tags.push(`<meta name="twitter:title" content="${tw.title}">`);
97
+ if (tw.description)
98
+ tags.push(`<meta name="twitter:description" content="${tw.description}">`);
99
+ if (tw.image)
100
+ tags.push(`<meta name="twitter:image" content="${tw.image}">`);
101
+ if (tw.imageAlt)
102
+ tags.push(`<meta name="twitter:image:alt" content="${tw.imageAlt}">`);
103
+ }
104
+ // Custom meta tags
105
+ if (metadata.other) {
106
+ for (const [key, value] of Object.entries(metadata.other)) {
107
+ tags.push(`<meta name="${key}" content="${value}">`);
108
+ }
109
+ }
110
+ return tags.join('\n');
111
+ }
112
+ // Função para ofuscar dados (não é criptografia, apenas ofuscação)
113
+ function obfuscateData(data) {
114
+ // 1. Serializa para JSON minificado
13
115
  const jsonStr = JSON.stringify(data);
116
+ // 2. Converte para base64
14
117
  const base64 = Buffer.from(jsonStr).toString('base64');
15
- return `hweb_${base64}_config`;
118
+ // 3. Adiciona um hash fake no início para parecer um token
119
+ const hash = Buffer.from(Date.now().toString()).toString('base64').substring(0, 8);
120
+ return `${hash}.${base64}`;
16
121
  }
17
- function createDecodeScript() {
18
- return `
19
-
20
- window.__HWEB_DECODE__ = function(encoded) { const base64 = encoded.replace('hweb_', '').replace('_config', ''); const jsonStr = atob(base64); return JSON.parse(jsonStr); };
21
- `;
122
+ // Função para criar script ofuscado
123
+ function createInitialDataScript(data) {
124
+ const obfuscated = obfuscateData(data);
125
+ // Usa um atributo data-* ao invés de JSON visível
126
+ return `<script id="__hight_data__" type="text/plain" data-h="${obfuscated}"></script>`;
22
127
  }
23
128
  async function render({ req, route, params, allRoutes }) {
24
129
  const { generateMetadata } = route;
@@ -43,22 +148,36 @@ async function render({ req, route, params, allRoutes }) {
43
148
  initialComponentPath: route.componentPath,
44
149
  initialParams: params,
45
150
  };
46
- // Codifica os dados para disfarçar
47
- const encodedData = encodeInitialData(initialData);
151
+ // Cria script JSON limpo
152
+ const initialDataScript = createInitialDataScript(initialData);
48
153
  // Script de hot reload apenas em desenvolvimento
49
154
  const hotReloadScript = !isProduction && hotReloadManager
50
155
  ? hotReloadManager.getClientScript()
51
156
  : '';
52
- const favicon = metadata.favicon ? `<link rel="icon" href="${metadata.favicon}">` : '';
157
+ // Gera todas as meta tags
158
+ const metaTags = generateMetaTags(metadata);
53
159
  // Determina quais arquivos JavaScript carregar
54
160
  const jsFiles = getJavaScriptFiles(req);
161
+ const htmlLang = metadata.language || 'pt-BR';
55
162
  // HTML base sem SSR - apenas o container e scripts para client-side rendering
56
- return `<!DOCTYPE html><html lang="pt-BR"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>${metadata.title || 'App hweb'}</title>${metadata.description ? `<meta name="description" content="${metadata.description}">` : ''}${favicon}</head><body><div id="root"></div><script>${createDecodeScript()}window.__HWEB_INITIAL_DATA__ = window.__HWEB_DECODE__('${encodedData}');</script>${jsFiles}${hotReloadScript}</body></html>`;
163
+ return `<!DOCTYPE html>
164
+ <html lang="${htmlLang}">
165
+ <head>
166
+ ${metaTags}
167
+ <title>${metadata.title || 'App hweb'}</title>
168
+ </head>
169
+ <body>
170
+ <div id="root"></div>
171
+ ${initialDataScript}
172
+ ${jsFiles}
173
+ ${hotReloadScript}
174
+ </body>
175
+ </html>`;
57
176
  }
58
177
  // Função para determinar quais arquivos JavaScript carregar
59
178
  function getJavaScriptFiles(req) {
60
179
  const projectDir = process.cwd();
61
- const distDir = path_1.default.join(projectDir, 'hweb-dist');
180
+ const distDir = path_1.default.join(projectDir, '.hight');
62
181
  try {
63
182
  // Verifica se existe um manifesto de chunks (gerado pelo ESBuild com splitting)
64
183
  const manifestPath = path_1.default.join(distDir, 'manifest.json');
@@ -67,7 +186,7 @@ function getJavaScriptFiles(req) {
67
186
  const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
68
187
  const scripts = Object.values(manifest)
69
188
  .filter((file) => file.endsWith('.js'))
70
- .map((file) => `<script src="/hweb-dist/${file}"></script>`)
189
+ .map((file) => `<script src="/_hight/${file}"></script>`)
71
190
  .join('');
72
191
  return scripts;
73
192
  }
@@ -91,17 +210,17 @@ function getJavaScriptFiles(req) {
91
210
  if (jsFiles.length >= 1) {
92
211
  // Modo chunks sem manifesto
93
212
  return jsFiles
94
- .map(file => `<script src="/hweb-dist/${file}"></script>`)
213
+ .map(file => `<script src="/_hight/${file}"></script>`)
95
214
  .join('');
96
215
  }
97
216
  else {
98
217
  // Modo tradicional - único arquivo
99
- return '<script src="/hweb-dist/main.js"></script>';
218
+ return '<script src="/_hight/main.js"></script>';
100
219
  }
101
220
  }
102
221
  }
103
222
  catch (error) {
104
223
  // Fallback para o modo tradicional
105
- return '<script src="/hweb-dist/main.js"></script>';
224
+ return '<script src="/_hight/main.js"></script>';
106
225
  }
107
226
  }