vatts 1.2.0-alpha.1 → 1.2.0-alpha.2

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 (46) hide show
  1. package/dist/adapters/express.js +5 -1
  2. package/dist/adapters/factory.js +58 -21
  3. package/dist/adapters/fastify.js +5 -1
  4. package/dist/adapters/native.js +5 -1
  5. package/dist/api/console.js +25 -17
  6. package/dist/api/framework.js +22 -15
  7. package/dist/api/http.js +7 -2
  8. package/dist/builder.js +19 -10
  9. package/dist/client/clientRouter.js +6 -2
  10. package/dist/client/rpc.js +7 -4
  11. package/dist/env/env.js +18 -11
  12. package/dist/global/global.d.ts +177 -122
  13. package/dist/helpers.js +108 -67
  14. package/dist/hotReload.d.ts +6 -0
  15. package/dist/hotReload.js +179 -31
  16. package/dist/index.js +159 -115
  17. package/dist/react/BuildingPage.d.ts +2 -1
  18. package/dist/react/BuildingPage.js +47 -4
  19. package/dist/react/DefaultNotFound.d.ts +2 -1
  20. package/dist/react/DefaultNotFound.js +92 -17
  21. package/dist/react/DevIndicator.js +66 -23
  22. package/dist/react/ErrorModal.js +91 -40
  23. package/dist/react/Link.d.ts +2 -2
  24. package/dist/react/Link.js +27 -5
  25. package/dist/react/client.js +16 -5
  26. package/dist/react/entry.client.js +70 -30
  27. package/dist/react/image/Image.js +8 -3
  28. package/dist/react/renderer-react.js +53 -25
  29. package/dist/renderer.d.ts +4 -0
  30. package/dist/renderer.js +13 -5
  31. package/dist/router.js +82 -63
  32. package/dist/rpc/annotations.js +7 -3
  33. package/dist/rpc/server.js +21 -15
  34. package/dist/rpc/types.js +4 -1
  35. package/dist/types/framework.js +2 -1
  36. package/dist/types.js +2 -1
  37. package/dist/vue/App.vue +34 -37
  38. package/dist/vue/BuildingPage.vue +118 -102
  39. package/dist/vue/ErrorModal.vue +19 -37
  40. package/dist/vue/Link.vue +8 -7
  41. package/dist/vue/client.js +16 -6
  42. package/dist/vue/entry.client.js +8 -3
  43. package/dist/vue/image/Image.vue +25 -19
  44. package/dist/vue/renderer.vue.js +80 -26
  45. package/package.json +25 -12
  46. package/dist/global/global.js +0 -17
package/dist/hotReload.js CHANGED
@@ -1,3 +1,42 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.HotReloadManager = void 0;
1
40
  /*
2
41
  * This file is part of the Vatts.js Project.
3
42
  * Copyright (c) 2026 itsmuzin
@@ -14,16 +53,17 @@
14
53
  * See the License for the specific language governing permissions and
15
54
  * limitations under the License.
16
55
  */
17
- import { WebSocket, WebSocketServer } from 'ws';
18
- import * as chokidar from 'chokidar';
19
- import * as path from 'path';
20
- import ts from 'typescript';
21
- import { clearFileCache } from './router';
22
- import Console, { Colors, Levels } from "./api/console";
56
+ const ws_1 = require("ws");
57
+ const chokidar = __importStar(require("chokidar"));
58
+ const path = __importStar(require("path"));
59
+ const fs = __importStar(require("fs"));
60
+ const typescript_1 = __importDefault(require("typescript"));
61
+ const router_1 = require("./router");
62
+ const console_1 = __importStar(require("./api/console"));
23
63
  // Chaves para persistência global para sobreviver a reloads do backend
24
64
  const GLOBAL_ERROR_KEY = '__VATTS_LAST_BUILD_ERROR__';
25
65
  const GLOBAL_ACTIVE_MANAGER_KEY = '__VATTS_ACTIVE_HOT_RELOAD_MANAGER__';
26
- export class HotReloadManager {
66
+ class HotReloadManager {
27
67
  wss = null;
28
68
  watchers = [];
29
69
  projectDir;
@@ -67,7 +107,7 @@ export class HotReloadManager {
67
107
  return;
68
108
  }
69
109
  if (!this.wss) {
70
- this.wss = new WebSocketServer({
110
+ this.wss = new ws_1.WebSocketServer({
71
111
  noServer: true,
72
112
  perMessageDeflate: false,
73
113
  maxPayload: 1024 * 1024
@@ -88,7 +128,7 @@ export class HotReloadManager {
88
128
  }
89
129
  const pingTimer = setInterval(() => {
90
130
  const client = this.clients.get(ws);
91
- if (client && ws.readyState === WebSocket.OPEN) {
131
+ if (client && ws.readyState === ws_1.WebSocket.OPEN) {
92
132
  if (Date.now() - client.lastPong > 60000) {
93
133
  ws.terminate();
94
134
  return;
@@ -104,7 +144,7 @@ export class HotReloadManager {
104
144
  this.clients.set(ws, clientConnection);
105
145
  // Ao conectar, envia o status atual combinado
106
146
  setTimeout(() => {
107
- if (ws.readyState !== WebSocket.OPEN)
147
+ if (ws.readyState !== ws_1.WebSocket.OPEN)
108
148
  return;
109
149
  this.broadcastCurrentState(ws);
110
150
  }, 0);
@@ -129,7 +169,7 @@ export class HotReloadManager {
129
169
  this.cleanupClient(ws);
130
170
  });
131
171
  ws.on('error', (error) => {
132
- Console.logWithout(Levels.ERROR, Colors.BgRed, `WebSocket error: ${error.message}`);
172
+ console_1.default.logWithout(console_1.Levels.ERROR, console_1.Colors.BgRed, `WebSocket error: ${error.message}`);
133
173
  this.cleanupClient(ws);
134
174
  });
135
175
  });
@@ -182,8 +222,8 @@ export class HotReloadManager {
182
222
  watcher.on('change', debouncedChange);
183
223
  watcher.on('add', debouncedChange);
184
224
  watcher.on('unlink', (filePath) => {
185
- Console.info(`File removed: ${path.basename(filePath)}`);
186
- clearFileCache(filePath);
225
+ console_1.default.info(`File removed: ${path.basename(filePath)}`);
226
+ (0, router_1.clearFileCache)(filePath);
187
227
  this.clearBackendCache(filePath);
188
228
  // Unlink também precisa de try-catch se for chamar callbacks
189
229
  try {
@@ -233,7 +273,7 @@ export class HotReloadManager {
233
273
  errorData.message.includes('TS2304') ||
234
274
  errorData.message.includes('TS1005') ||
235
275
  errorData.message.includes('TS17002'));
236
- Console.error("Captured Backend Error:", errorData.message);
276
+ console_1.default.error("Captured Backend Error:", errorData.message);
237
277
  this.buildState = {
238
278
  ...currentState,
239
279
  backend: errorData,
@@ -243,20 +283,22 @@ export class HotReloadManager {
243
283
  this.notifyStatusChange();
244
284
  }
245
285
  async handleAnySrcChange(filePath) {
246
- const dm = Console.dynamicLine(`File change detected ${path.basename(filePath)}, processing...`);
286
+ const dm = console_1.default.dynamicLine(`File change detected ${path.basename(filePath)}, processing...`);
247
287
  let hasBackendError = false;
248
288
  const isFrontendFile = filePath.includes(path.join('src', 'web', 'routes')) ||
249
289
  filePath.includes(path.join('src', 'web', 'components')) ||
250
290
  filePath.includes('layout.tsx') ||
251
291
  filePath.includes('not-found.tsx') ||
252
- filePath.endsWith('.tsx');
292
+ filePath.endsWith('.tsx') ||
293
+ filePath.endsWith(".ts") ||
294
+ filePath.endsWith(".vue");
253
295
  const isBackendFile = filePath.includes(path.join('src', 'backend')) && !isFrontendFile;
254
- clearFileCache(filePath);
296
+ (0, router_1.clearFileCache)(filePath);
255
297
  this.clearBackendCache(filePath);
256
298
  // Tenta executar os callbacks e captura erros do Backend (Router/SSR)
257
299
  try {
258
300
  if (isFrontendFile) {
259
- Console.logWithout(Levels.INFO, undefined, `Frontend change detected: ${path.basename(filePath)}`);
301
+ console_1.default.logWithout(console_1.Levels.INFO, undefined, `Frontend change detected: ${path.basename(filePath)}`);
260
302
  // CRÍTICO: Executa e captura erro
261
303
  try {
262
304
  this.frontendChangeCallback?.();
@@ -275,7 +317,7 @@ export class HotReloadManager {
275
317
  this.notifyClients('frontend-reload', { file: filePath, event: 'change' });
276
318
  }
277
319
  else if (isBackendFile) {
278
- Console.logWithout(Levels.INFO, undefined, `Backend change detected: ${path.basename(filePath)}. Reloading backend...`);
320
+ console_1.default.logWithout(console_1.Levels.INFO, undefined, `Backend change detected: ${path.basename(filePath)}. Reloading backend...`);
279
321
  try {
280
322
  this.backendApiChangeCallback?.();
281
323
  // Se passou aqui, limpa erro de backend anterior
@@ -323,7 +365,7 @@ export class HotReloadManager {
323
365
  }
324
366
  catch (error) {
325
367
  // @ts-ignore
326
- Console.logWithout(Levels.ERROR, `Error in custom listener: ${error.message}`);
368
+ console_1.default.logWithout(console_1.Levels.ERROR, `Error in custom listener: ${error.message}`);
327
369
  }
328
370
  }
329
371
  }
@@ -351,7 +393,7 @@ export class HotReloadManager {
351
393
  const message = JSON.stringify({ type, data, timestamp: Date.now() });
352
394
  const deadClients = [];
353
395
  this.clients.forEach((client, ws) => {
354
- if (ws.readyState === WebSocket.OPEN) {
396
+ if (ws.readyState === ws_1.WebSocket.OPEN) {
355
397
  try {
356
398
  ws.send(message);
357
399
  }
@@ -589,7 +631,7 @@ export class HotReloadManager {
589
631
  onFrontendChange(callback) { this.frontendChangeCallback = callback; }
590
632
  setHotReloadListener(listener) {
591
633
  this.customHotReloadListener = listener;
592
- Console.info('Hot reload custom listener registered');
634
+ console_1.default.info('Hot reload custom listener registered');
593
635
  }
594
636
  removeHotReloadListener() { this.customHotReloadListener = null; }
595
637
  // DEBUG: stack traces (rate-limited) para descobrir quem dispara onBuildComplete
@@ -622,7 +664,7 @@ export class HotReloadManager {
622
664
  const currentState = this.buildState;
623
665
  const buildId = typeof error?.buildId === 'number' ? error.buildId : undefined;
624
666
  if (success) {
625
- // Não confia no bundler. Antes de ficar "verde", roda typecheck real.
667
+ // Não confia no bundler. Antes de ficar "verde", roda typecheck real (React + Vue).
626
668
  const tc = this.typecheckFrontend();
627
669
  if (!tc.ok) {
628
670
  // Se já existe um erro de bundler (esbuild/rollup) mais específico, preserva ele.
@@ -664,7 +706,7 @@ export class HotReloadManager {
664
706
  this.watchers = [];
665
707
  this.clients.forEach((client, ws) => {
666
708
  clearInterval(client.pingTimer);
667
- if (ws.readyState === WebSocket.OPEN)
709
+ if (ws.readyState === ws_1.WebSocket.OPEN)
668
710
  ws.close();
669
711
  });
670
712
  this.clients.clear();
@@ -675,40 +717,145 @@ export class HotReloadManager {
675
717
  }
676
718
  lastTypecheckAt = 0;
677
719
  lastTypecheckResult = null;
720
+ /**
721
+ * Verifica erros específicos de arquivos Vue usando @vue/compiler-sfc.
722
+ * Isso permite capturar erros de sintaxe (como falta de ponto e vírgula, tags mal fechadas)
723
+ * que o compilador padrão pode emitir mas que precisam ser formatados para o cliente.
724
+ */
725
+ checkVueFiles() {
726
+ try {
727
+ // 1. Tenta carregar o compilador do Vue dinamicamente
728
+ let compiler;
729
+ try {
730
+ compiler = require('vue/compiler-sfc');
731
+ }
732
+ catch {
733
+ try {
734
+ compiler = require('@vue/compiler-sfc');
735
+ }
736
+ catch {
737
+ // Não é um projeto Vue ou dependência faltando, apenas ignora
738
+ return null;
739
+ }
740
+ }
741
+ // 2. Scan síncrono para encontrar arquivos .vue em src/web
742
+ // Em projetos gigantes isso deve ser otimizado, mas para dev server é ok.
743
+ const findVueFiles = (dir) => {
744
+ let results = [];
745
+ if (!fs.existsSync(dir))
746
+ return results;
747
+ const list = fs.readdirSync(dir);
748
+ list.forEach(file => {
749
+ const filePath = path.join(dir, file);
750
+ const stat = fs.statSync(filePath);
751
+ if (stat && stat.isDirectory()) {
752
+ if (file !== 'node_modules' && file !== '.git' && file !== 'dist') {
753
+ results = results.concat(findVueFiles(filePath));
754
+ }
755
+ }
756
+ else if (file.endsWith('.vue')) {
757
+ results.push(filePath);
758
+ }
759
+ });
760
+ return results;
761
+ };
762
+ const webSrc = path.join(this.projectDir, 'src');
763
+ const vueFiles = findVueFiles(webSrc);
764
+ if (vueFiles.length === 0)
765
+ return { ok: true };
766
+ // 3. Analisa cada arquivo Vue
767
+ for (const file of vueFiles) {
768
+ try {
769
+ const content = fs.readFileSync(file, 'utf-8');
770
+ const parsed = compiler.parse(content, {
771
+ filename: file,
772
+ sourceMap: false
773
+ });
774
+ // Verifica erros de compilação do template/script
775
+ if (parsed.errors && parsed.errors.length > 0) {
776
+ const firstError = parsed.errors[0];
777
+ const loc = firstError.loc ? {
778
+ file: file,
779
+ line: firstError.loc.start.line,
780
+ column: firstError.loc.start.column
781
+ } : undefined;
782
+ // Stack simulada para o overlay exibir bonito
783
+ const syntheticStack = `SyntaxError: ${firstError.message}\n at ${file}:${loc?.line}:${loc?.column}`;
784
+ return {
785
+ ok: false,
786
+ error: {
787
+ message: `Vue Error: ${firstError.message}`,
788
+ type: 'VueCompilerError',
789
+ loc,
790
+ stack: syntheticStack,
791
+ ts: Date.now()
792
+ }
793
+ };
794
+ }
795
+ }
796
+ catch (readError) {
797
+ // Ignora erro de leitura de arquivo individual
798
+ }
799
+ }
800
+ }
801
+ catch (e) {
802
+ // Ignora falha geral no checker do Vue
803
+ }
804
+ return { ok: true };
805
+ }
678
806
  typecheckFrontend() {
679
807
  try {
680
808
  const now = Date.now();
681
809
  if (this.lastTypecheckResult && now - this.lastTypecheckAt < 750)
682
810
  return this.lastTypecheckResult;
811
+ // --- 1. Vue Check (New) ---
812
+ // Verifica arquivos Vue primeiro, pois o TS compiler padrão pode ignorá-los
813
+ // ou dar erros confusos se não estiver configurado com plugins.
814
+ const vueResult = this.checkVueFiles();
815
+ if (vueResult && !vueResult.ok) {
816
+ this.lastTypecheckAt = now;
817
+ this.lastTypecheckResult = vueResult;
818
+ return vueResult;
819
+ }
820
+ // --- 2. TypeScript Check (Existing) ---
683
821
  const projectDir = this.projectDir;
684
- const configPath = ts.findConfigFile(projectDir, ts.sys.fileExists, 'tsconfig.json');
822
+ const configPath = typescript_1.default.findConfigFile(projectDir, typescript_1.default.sys.fileExists, 'tsconfig.json');
685
823
  if (!configPath) {
686
824
  this.lastTypecheckAt = now;
687
825
  this.lastTypecheckResult = { ok: true };
688
826
  return this.lastTypecheckResult;
689
827
  }
690
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
828
+ const configFile = typescript_1.default.readConfigFile(configPath, typescript_1.default.sys.readFile);
691
829
  if (configFile.error) {
692
- const msg = ts.flattenDiagnosticMessageText(configFile.error.messageText, '\n');
830
+ const msg = typescript_1.default.flattenDiagnosticMessageText(configFile.error.messageText, '\n');
693
831
  const err = { message: `tsconfig read error: ${msg}`, type: 'TypeScriptConfigError', ts: Date.now() };
694
832
  this.lastTypecheckAt = now;
695
833
  this.lastTypecheckResult = { ok: false, error: err };
696
834
  return this.lastTypecheckResult;
697
835
  }
698
- const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath));
836
+ const parsed = typescript_1.default.parseJsonConfigFileContent(configFile.config, typescript_1.default.sys, path.dirname(configPath));
699
837
  const options = { ...parsed.options, noEmit: true };
700
838
  const rootNames = parsed.fileNames;
701
839
  const webRoot = path.resolve(projectDir, 'src', 'web') + path.sep;
840
+ // Filtra apenas arquivos dentro de src/web para não checar backend aqui
702
841
  const filteredRoots = rootNames.filter(f => f.startsWith(webRoot));
703
- const program = ts.createProgram(filteredRoots.length ? filteredRoots : rootNames, options);
704
- const diagnostics = ts.getPreEmitDiagnostics(program);
842
+ // Se for um projeto Vue puro sem .ts/.tsx explícito na config, o createProgram pode ficar vazio,
843
+ // então usamos os rootNames originais se o filtro zerar tudo.
844
+ const filesToCheck = filteredRoots.length ? filteredRoots : rootNames;
845
+ if (filesToCheck.length === 0) {
846
+ this.lastTypecheckAt = now;
847
+ this.lastTypecheckResult = { ok: true };
848
+ return this.lastTypecheckResult;
849
+ }
850
+ const program = typescript_1.default.createProgram(filesToCheck, options);
851
+ const diagnostics = typescript_1.default.getPreEmitDiagnostics(program);
705
852
  if (!diagnostics.length) {
706
853
  this.lastTypecheckAt = now;
707
854
  this.lastTypecheckResult = { ok: true };
708
855
  return this.lastTypecheckResult;
709
856
  }
710
857
  const first = diagnostics[0];
711
- const message = ts.flattenDiagnosticMessageText(first.messageText, '\n');
858
+ const message = typescript_1.default.flattenDiagnosticMessageText(first.messageText, '\n');
712
859
  const code = typeof first.code === 'number' ? `TS${first.code}` : undefined;
713
860
  const loc = first.file && typeof first.start === 'number'
714
861
  ? (() => {
@@ -743,3 +890,4 @@ export class HotReloadManager {
743
890
  }
744
891
  }
745
892
  }
893
+ exports.HotReloadManager = HotReloadManager;