versacompiler 2.0.8 → 2.2.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 (41) hide show
  1. package/README.md +1 -1
  2. package/dist/compiler/compile.js +2520 -26
  3. package/dist/compiler/error-reporter.js +467 -38
  4. package/dist/compiler/linter.js +72 -1
  5. package/dist/compiler/minify.js +272 -1
  6. package/dist/compiler/minifyTemplate.js +230 -0
  7. package/dist/compiler/module-resolution-optimizer.js +844 -1
  8. package/dist/compiler/parser.js +336 -1
  9. package/dist/compiler/performance-monitor.js +204 -56
  10. package/dist/compiler/tailwindcss.js +39 -1
  11. package/dist/compiler/transform-optimizer.js +392 -1
  12. package/dist/compiler/transformTStoJS.js +16 -1
  13. package/dist/compiler/transforms.js +554 -1
  14. package/dist/compiler/typescript-compiler.js +172 -2
  15. package/dist/compiler/typescript-error-parser.js +281 -10
  16. package/dist/compiler/typescript-manager.js +304 -2
  17. package/dist/compiler/typescript-sync-validator.js +295 -31
  18. package/dist/compiler/typescript-worker-pool.js +936 -1
  19. package/dist/compiler/typescript-worker-thread.cjs +466 -41
  20. package/dist/compiler/typescript-worker.js +339 -1
  21. package/dist/compiler/vuejs.js +396 -37
  22. package/dist/hrm/VueHRM.js +359 -1
  23. package/dist/hrm/errorScreen.js +83 -1
  24. package/dist/hrm/getInstanciaVue.js +313 -1
  25. package/dist/hrm/initHRM.js +586 -1
  26. package/dist/main.js +353 -7
  27. package/dist/servicios/browserSync.js +587 -5
  28. package/dist/servicios/file-watcher.js +425 -4
  29. package/dist/servicios/logger.js +63 -3
  30. package/dist/servicios/readConfig.js +399 -105
  31. package/dist/utils/excluded-modules.js +37 -1
  32. package/dist/utils/module-resolver.js +466 -1
  33. package/dist/utils/promptUser.js +48 -2
  34. package/dist/utils/proxyValidator.js +68 -1
  35. package/dist/utils/resolve-bin.js +58 -1
  36. package/dist/utils/utils.js +21 -1
  37. package/dist/utils/vue-types-setup.js +435 -241
  38. package/dist/wrappers/eslint-node.js +147 -1
  39. package/dist/wrappers/oxlint-node.js +122 -1
  40. package/dist/wrappers/tailwind-node.js +94 -1
  41. package/package.json +39 -42
@@ -1,7 +1,589 @@
1
- import{createHash as e}from"node:crypto";import{promises as t}from"node:fs";import n from"node:path";import r,{env as i}from"node:process";import a from"browser-sync";import o from"get-port";import{promptUser as s}from"../utils/promptUser.js";import{getProxyInfo as c,validateProxyAvailability as l}from"../utils/proxyValidator.js";import{logger as u}from"./logger.js";class d{static instance;cache=new Map;MAX_CACHE_SIZE=200;MAX_CACHE_MEMORY=50*1024*1024;CACHE_TTL=900*1e3;currentMemoryUsage=0;cacheHits=0;cacheMisses=0;totalRequests=0;static getInstance(){return d.instance||=new d,d.instance}generateETag(t,n){let r=e(`md5`).update(`${t}:${n.mtime.getTime()}:${n.size}`).digest(`hex`);return`"${r}"`}getContentType(e){let t=n.extname(e).toLowerCase(),r={".js":`application/javascript`,".mjs":`application/javascript`,".ts":`application/javascript`,".css":`text/css`,".html":`text/html`,".json":`application/json`,".png":`image/png`,".jpg":`image/jpeg`,".jpeg":`image/jpeg`,".gif":`image/gif`,".svg":`image/svg+xml`,".ico":`image/x-icon`,".webp":`image/webp`,".avif":`image/avif`,".woff":`font/woff`,".woff2":`font/woff2`,".ttf":`font/ttf`,".eot":`application/vnd.ms-fontobject`,".map":`application/json`,".xml":`application/xml`,".txt":`text/plain`,".pdf":`application/pdf`,".zip":`application/zip`,".mp4":`video/mp4`,".mp3":`audio/mpeg`,".wav":`audio/wav`,".ogg":`audio/ogg`};return r[t]||`application/octet-stream`}shouldCache(e){let t=n.extname(e).toLowerCase(),r=[`.js`,`.mjs`,`.css`,`.json`,`.png`,`.jpg`,`.jpeg`,`.gif`,`.svg`,`.ico`,`.webp`,`.avif`,`.woff`,`.woff2`,`.ttf`,`.eot`,`.map`];return r.includes(t)}async getOrReadFile(e){this.totalRequests++;try{let n=await t.stat(e),r=n.mtime.getTime(),i=this.generateETag(e,n);if(!this.shouldCache(e)){let n=await t.readFile(e,`utf-8`);return{content:n,contentType:this.getContentType(e),etag:i,cached:!1}}let a=this.cache.get(e);if(a&&a.lastModified===r)return this.cacheHits++,{content:a.content,contentType:a.contentType,etag:a.etag,cached:!0};this.cacheMisses++;let o=this.isBinaryFile(e),s=await t.readFile(e,o?void 0:`utf-8`),c=this.getContentType(e);return this.addToCache(e,{content:s,contentType:c,lastModified:r,etag:i,size:n.size}),{content:s,contentType:c,etag:i,cached:!1}}catch{return null}}isBinaryFile(e){let t=n.extname(e).toLowerCase(),r=[`.png`,`.jpg`,`.jpeg`,`.gif`,`.ico`,`.webp`,`.avif`,`.woff`,`.woff2`,`.ttf`,`.eot`,`.pdf`,`.zip`,`.mp4`,`.mp3`,`.wav`,`.ogg`];return r.includes(t)}addToCache(e,t){try{this.evictIfNeeded(t.size);let n={content:t.content,contentType:t.contentType,lastModified:t.lastModified,etag:t.etag,size:t.size};this.cache.set(e,n),this.currentMemoryUsage+=t.size}catch(e){console.warn(`[BrowserSyncFileCache] Error cacheando archivo:`,e)}}evictIfNeeded(e){for(;this.cache.size>=this.MAX_CACHE_SIZE;)this.evictOldest();for(;this.currentMemoryUsage+e>this.MAX_CACHE_MEMORY&&this.cache.size>0;)this.evictOldest()}evictOldest(){let e=``,t=1/0;for(let[n,r]of this.cache)r.lastModified<t&&(t=r.lastModified,e=n);if(e){let t=this.cache.get(e);t&&(this.currentMemoryUsage-=t.size,this.cache.delete(e))}}invalidateFile(e){let t=this.cache.get(e);t&&(this.currentMemoryUsage-=t.size,this.cache.delete(e))}getStats(){let e=this.totalRequests>0?Math.round(this.cacheHits/this.totalRequests*100):0;return{cacheHits:this.cacheHits,cacheMisses:this.cacheMisses,hitRate:e,totalRequests:this.totalRequests,cacheSize:this.cache.size,maxCacheSize:this.MAX_CACHE_SIZE,memoryUsage:this.currentMemoryUsage,maxMemoryUsage:this.MAX_CACHE_MEMORY}}clear(){this.cache.clear(),this.currentMemoryUsage=0,this.cacheHits=0,this.cacheMisses=0,this.totalRequests=0}}const f=d.getInstance(),p=async()=>{let{default:e}=await import(`chalk`);return e};export async function browserSyncServer(){try{let e=null,t=i.AssetsOmit===`true`,d={server:`./`};if(i.proxyUrl){u.info(`🔍 Validando disponibilidad del servidor proxy: ${i.proxyUrl}`);let e=await l(i.proxyUrl,5e3);if(e)u.info(`✅ Servidor proxy disponible`);else{let e=c(i.proxyUrl);u.warn(`⚠️ El servidor proxy no está disponible:`),u.warn(` Host: ${e.host}`),u.warn(` Puerto: ${e.port}`),u.warn(` Protocolo: ${e.protocol}`);let t=await s(`
2
- ¿Desea continuar de todos modos? El modo proxy podría no funcionar correctamente. (s/n): `,3e4);t.toLowerCase().trim()!==`s`&&t.toLowerCase().trim()!==`si`&&(u.info(`🛑 Operación cancelada por el usuario.`),r.exit(0)),u.warn(`⚠️ Continuando con el servidor proxy no disponible...`)}d={proxy:i.proxyUrl}}let m=n.join(i.PATH_PROY||r.cwd(),`hrm`),h=r.cwd(),g=n.relative(h,m);e=a.create();let _=await o({port:3e3}),v=await o({port:4e3});return e.init({...d,files:[`${i.PATH_DIST}/**/*.css`],injectChanges:!0,open:!1,port:_,ui:{port:v},socket:{path:`/browser-sync/socket.io`},snippetOptions:{rule:{match:/<\/body>/i,fn:(e,t)=>`
3
- ${e}${t}
1
+ import { createHash } from 'node:crypto';
2
+ import { promises as fs } from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import * as process from 'node:process';
5
+ const { env } = process;
6
+ import * as browserSync from 'browser-sync';
7
+
8
+ import getPort from 'get-port';
9
+ import { promptUser } from '../utils/promptUser.js';
10
+ import { getProxyInfo, validateProxyAvailability, } from '../utils/proxyValidator.js';
11
+ import { logger } from './logger.js';
12
+ class BrowserSyncFileCache {
13
+ static instance;
14
+ cache = new Map();
15
+ MAX_CACHE_SIZE = 200; // Máximo archivos en cache
16
+ MAX_CACHE_MEMORY = 50 * 1024 * 1024; // 50MB límite
17
+ CACHE_TTL = 15 * 60 * 1000; // 15 minutos para archivos estáticos
18
+ currentMemoryUsage = 0;
19
+ // ✨ FIX #8: Intervalo de limpieza automática
20
+ cleanupInterval = null;
21
+ // Métricas
22
+ cacheHits = 0;
23
+ cacheMisses = 0;
24
+ totalRequests = 0;
25
+ constructor() {
26
+ // ✨ FIX #8: Iniciar limpieza automática cada 5 minutos
27
+ this.startAutoCleanup();
28
+ }
29
+ static getInstance() {
30
+ if (!BrowserSyncFileCache.instance) {
31
+ BrowserSyncFileCache.instance = new BrowserSyncFileCache();
32
+ }
33
+ return BrowserSyncFileCache.instance;
34
+ }
35
+ /**
36
+ * ✨ FIX #8: Inicia la limpieza automática de entradas expiradas
37
+ */
38
+ startAutoCleanup() {
39
+ this.cleanupInterval = setInterval(() => {
40
+ this.cleanupExpiredEntries();
41
+ }, 5 * 60 * 1000); // Cada 5 minutos
42
+ }
43
+ /**
44
+ * ✨ FIX #8: Limpia entradas de cache expiradas
45
+ */
46
+ cleanupExpiredEntries() {
47
+ const now = Date.now();
48
+ let cleaned = 0;
49
+ for (const [filePath, entry] of this.cache.entries()) {
50
+ if (now - entry.lastModified > this.CACHE_TTL) {
51
+ this.currentMemoryUsage -= entry.size;
52
+ this.cache.delete(filePath);
53
+ cleaned++;
54
+ }
55
+ }
56
+ if (cleaned > 0) {
57
+ console.log(`[BrowserSync] Limpiadas ${cleaned} entradas expiradas del cache`);
58
+ }
59
+ }
60
+ /**
61
+ * Genera ETag para el archivo basado en contenido y timestamp
62
+ */
63
+ generateETag(filePath, stats) {
64
+ const hash = createHash('md5')
65
+ .update(`${filePath}:${stats.mtime.getTime()}:${stats.size}`)
66
+ .digest('hex');
67
+ return `"${hash}"`;
68
+ }
69
+ /**
70
+ * Determina el Content-Type basado en la extensión del archivo
71
+ */
72
+ getContentType(filePath) {
73
+ const ext = path.extname(filePath).toLowerCase();
74
+ const mimeTypes = {
75
+ '.js': 'application/javascript',
76
+ '.mjs': 'application/javascript',
77
+ '.ts': 'application/javascript', // Se transpila a JS
78
+ '.css': 'text/css',
79
+ '.html': 'text/html',
80
+ '.json': 'application/json',
81
+ '.png': 'image/png',
82
+ '.jpg': 'image/jpeg',
83
+ '.jpeg': 'image/jpeg',
84
+ '.gif': 'image/gif',
85
+ '.svg': 'image/svg+xml',
86
+ '.ico': 'image/x-icon',
87
+ '.webp': 'image/webp',
88
+ '.avif': 'image/avif',
89
+ '.woff': 'font/woff',
90
+ '.woff2': 'font/woff2',
91
+ '.ttf': 'font/ttf',
92
+ '.eot': 'application/vnd.ms-fontobject',
93
+ '.map': 'application/json',
94
+ '.xml': 'application/xml',
95
+ '.txt': 'text/plain',
96
+ '.pdf': 'application/pdf',
97
+ '.zip': 'application/zip',
98
+ '.mp4': 'video/mp4',
99
+ '.mp3': 'audio/mpeg',
100
+ '.wav': 'audio/wav',
101
+ '.ogg': 'audio/ogg',
102
+ };
103
+ return mimeTypes[ext] || 'application/octet-stream';
104
+ }
105
+ /**
106
+ * Verifica si el archivo debe ser cacheado
107
+ */
108
+ shouldCache(filePath) {
109
+ const ext = path.extname(filePath).toLowerCase();
110
+ const cacheableExtensions = [
111
+ '.js',
112
+ '.mjs',
113
+ '.css',
114
+ '.json',
115
+ '.png',
116
+ '.jpg',
117
+ '.jpeg',
118
+ '.gif',
119
+ '.svg',
120
+ '.ico',
121
+ '.webp',
122
+ '.avif',
123
+ '.woff',
124
+ '.woff2',
125
+ '.ttf',
126
+ '.eot',
127
+ '.map',
128
+ ];
129
+ return cacheableExtensions.includes(ext);
130
+ }
131
+ /**
132
+ * Obtiene archivo desde cache o lo lee del disco
133
+ */
134
+ async getOrReadFile(filePath) {
135
+ this.totalRequests++;
136
+ try {
137
+ // Verificar si el archivo existe y obtener stats
138
+ const stats = await fs.stat(filePath);
139
+ const lastModified = stats.mtime.getTime();
140
+ const etag = this.generateETag(filePath, stats);
141
+ // Si no debe ser cacheado, leer directamente
142
+ if (!this.shouldCache(filePath)) {
143
+ const content = await fs.readFile(filePath, 'utf-8');
144
+ return {
145
+ content,
146
+ contentType: this.getContentType(filePath),
147
+ etag,
148
+ cached: false,
149
+ };
150
+ }
151
+ // Verificar cache
152
+ const cached = this.cache.get(filePath);
153
+ if (cached && cached.lastModified === lastModified) {
154
+ this.cacheHits++;
155
+ return {
156
+ content: cached.content,
157
+ contentType: cached.contentType,
158
+ etag: cached.etag,
159
+ cached: true,
160
+ };
161
+ }
162
+ // Cache miss - leer archivo
163
+ this.cacheMisses++;
164
+ const isBinary = this.isBinaryFile(filePath);
165
+ const content = await fs.readFile(filePath, isBinary ? undefined : 'utf-8');
166
+ const contentType = this.getContentType(filePath);
167
+ // Cachear resultado
168
+ this.addToCache(filePath, {
169
+ content,
170
+ contentType,
171
+ lastModified,
172
+ etag,
173
+ size: stats.size,
174
+ });
175
+ return {
176
+ content,
177
+ contentType,
178
+ etag,
179
+ cached: false,
180
+ };
181
+ }
182
+ catch {
183
+ return null;
184
+ }
185
+ }
186
+ /**
187
+ * Determina si un archivo es binario
188
+ */
189
+ isBinaryFile(filePath) {
190
+ const ext = path.extname(filePath).toLowerCase();
191
+ const binaryExtensions = [
192
+ '.png',
193
+ '.jpg',
194
+ '.jpeg',
195
+ '.gif',
196
+ '.ico',
197
+ '.webp',
198
+ '.avif',
199
+ '.woff',
200
+ '.woff2',
201
+ '.ttf',
202
+ '.eot',
203
+ '.pdf',
204
+ '.zip',
205
+ '.mp4',
206
+ '.mp3',
207
+ '.wav',
208
+ '.ogg',
209
+ ];
210
+ return binaryExtensions.includes(ext);
211
+ }
212
+ /**
213
+ * Añade archivo al cache con gestión de memoria
214
+ */
215
+ addToCache(filePath, fileData) {
216
+ try {
217
+ // Aplicar políticas de eviction si es necesario
218
+ this.evictIfNeeded(fileData.size);
219
+ const cacheEntry = {
220
+ content: fileData.content,
221
+ contentType: fileData.contentType,
222
+ lastModified: fileData.lastModified,
223
+ etag: fileData.etag,
224
+ size: fileData.size,
225
+ };
226
+ this.cache.set(filePath, cacheEntry);
227
+ this.currentMemoryUsage += fileData.size;
228
+ }
229
+ catch (error) {
230
+ console.warn('[BrowserSyncFileCache] Error cacheando archivo:', error);
231
+ }
232
+ }
233
+ /**
234
+ * Aplica políticas de eviction LRU si es necesario
235
+ */
236
+ evictIfNeeded(newFileSize) {
237
+ // Verificar límite de archivos
238
+ while (this.cache.size >= this.MAX_CACHE_SIZE) {
239
+ this.evictOldest();
240
+ }
241
+ // Verificar límite de memoria
242
+ while (this.currentMemoryUsage + newFileSize > this.MAX_CACHE_MEMORY &&
243
+ this.cache.size > 0) {
244
+ this.evictOldest();
245
+ }
246
+ }
247
+ /**
248
+ * Elimina el archivo más antiguo del cache
249
+ */
250
+ evictOldest() {
251
+ let oldestPath = '';
252
+ let oldestTime = Infinity;
253
+ for (const [filePath, entry] of this.cache) {
254
+ if (entry.lastModified < oldestTime) {
255
+ oldestTime = entry.lastModified;
256
+ oldestPath = filePath;
257
+ }
258
+ }
259
+ if (oldestPath) {
260
+ const entry = this.cache.get(oldestPath);
261
+ if (entry) {
262
+ this.currentMemoryUsage -= entry.size;
263
+ this.cache.delete(oldestPath);
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * Invalidar cache para un archivo específico
269
+ */
270
+ invalidateFile(filePath) {
271
+ const entry = this.cache.get(filePath);
272
+ if (entry) {
273
+ this.currentMemoryUsage -= entry.size;
274
+ this.cache.delete(filePath);
275
+ }
276
+ }
277
+ /**
278
+ * Obtiene estadísticas del cache
279
+ */
280
+ getStats() {
281
+ const hitRate = this.totalRequests > 0
282
+ ? Math.round((this.cacheHits / this.totalRequests) * 100)
283
+ : 0;
284
+ return {
285
+ cacheHits: this.cacheHits,
286
+ cacheMisses: this.cacheMisses,
287
+ hitRate,
288
+ totalRequests: this.totalRequests,
289
+ cacheSize: this.cache.size,
290
+ maxCacheSize: this.MAX_CACHE_SIZE,
291
+ memoryUsage: this.currentMemoryUsage,
292
+ maxMemoryUsage: this.MAX_CACHE_MEMORY,
293
+ };
294
+ }
295
+ /**
296
+ * Limpia todo el cache
297
+ */
298
+ clear() {
299
+ this.cache.clear();
300
+ this.currentMemoryUsage = 0;
301
+ this.cacheHits = 0;
302
+ this.cacheMisses = 0;
303
+ this.totalRequests = 0;
304
+ }
305
+ /**
306
+ * ✨ FIX #8: Destruye la instancia y limpia recursos
307
+ */
308
+ terminate() {
309
+ if (this.cleanupInterval) {
310
+ clearInterval(this.cleanupInterval);
311
+ this.cleanupInterval = null;
312
+ }
313
+ this.clear();
314
+ }
315
+ }
316
+ // Instancia global del cache de archivos
317
+ const fileCache = BrowserSyncFileCache.getInstance();
318
+ // Lazy loading para chalk - pre-cargado para mejor rendimiento
319
+ let chalk;
320
+ let chalkPromise = null;
321
+ async function loadChalk() {
322
+ if (!chalk) {
323
+ if (!chalkPromise) {
324
+ chalkPromise = import('chalk').then(m => {
325
+ chalk = m.default;
326
+ return chalk;
327
+ });
328
+ }
329
+ await chalkPromise;
330
+ }
331
+ return chalk;
332
+ }
333
+ // Pre-cargar chalk al cargar el módulo para hot reload más rápido
334
+ loadChalk().catch(() => { });
335
+ export async function browserSyncServer() {
336
+ try {
337
+ let bs = null;
338
+ const AssetsOmit = env.AssetsOmit === 'true';
339
+ let proxy = {
340
+ server: './',
341
+ };
342
+ // ✨ VALIDACIÓN DE PROXY: Verificar disponibilidad antes de inicializar BrowserSync
343
+ if (env.proxyUrl) {
344
+ logger.info(`🔍 Validando disponibilidad del servidor proxy: ${env.proxyUrl}`);
345
+ const isProxyAvailable = await validateProxyAvailability(env.proxyUrl, 5000);
346
+ if (!isProxyAvailable) {
347
+ const proxyInfo = getProxyInfo(env.proxyUrl);
348
+ logger.warn(`⚠️ El servidor proxy no está disponible:`);
349
+ logger.warn(` Host: ${proxyInfo.host}`);
350
+ logger.warn(` Puerto: ${proxyInfo.port}`);
351
+ logger.warn(` Protocolo: ${proxyInfo.protocol}`);
352
+ const response = await promptUser('\n¿Desea continuar de todos modos? El modo proxy podría no funcionar correctamente. (s/n): ', 30000);
353
+ if (response.toLowerCase().trim() !== 's' &&
354
+ response.toLowerCase().trim() !== 'si') {
355
+ logger.info('🛑 Operación cancelada por el usuario.');
356
+ process.exit(0);
357
+ }
358
+ logger.warn('⚠️ Continuando con el servidor proxy no disponible...');
359
+ }
360
+ else {
361
+ logger.info('✅ Servidor proxy disponible');
362
+ }
363
+ proxy = {
364
+ proxy: env.proxyUrl,
365
+ };
366
+ }
367
+ const hrmDir = path.join(env.PATH_PROY || process.cwd(), 'hrm');
368
+ const projectRoot = process.cwd();
369
+ const relativeHrmPath = path.relative(projectRoot, hrmDir);
370
+ bs = browserSync.create();
371
+ const port = await getPort({ port: 3000 });
372
+ const uiPort = await getPort({ port: 4000 });
373
+ bs.init({
374
+ ...proxy,
375
+ files: [`${env.PATH_DIST}/**/*.css`], // Observa cambios en archivos CSS
376
+ injectChanges: true, // Inyecta CSS sin recargar la página
377
+ open: false, // No abre automáticamente el navegador
378
+ port, // Puerto aleatorio para BrowserSync
379
+ ui: {
380
+ port: uiPort, // Puerto aleatorio para la interfaz de usuario
381
+ },
382
+ socket: {
383
+ path: '/browser-sync/socket.io', // Ruta correcta para socket.io
384
+ },
385
+ snippetOptions: {
386
+ rule: {
387
+ match: /<\/body>/i,
388
+ fn: (snippet, match) => {
389
+ return `
390
+ ${snippet}${match}
4
391
  <script
5
392
  type="module"
6
- src="/__versa/initHRM.js"><\/script>
7
- `}},logLevel:`info`,logPrefix:`BS`,logConnections:!0,logFileChanges:!0,watchEvents:[`change`,`add`,`unlink`,`addDir`,`unlinkDir`],reloadDelay:500,reloadDebounce:500,reloadOnRestart:!0,notify:!0,watchOptions:{ignoreInitial:!0,ignored:[`node_modules`,`.git`]},middleware:[async function(e,i,a){if(i.setHeader(`Access-Control-Allow-Origin`,`*`),i.setHeader(`Access-Control-Allow-Methods`,`*`),i.setHeader(`Access-Control-Allow-Headers`,`*`),i.setHeader(`Access-Control-Allow-Credentials`,`true`),i.setHeader(`Access-Control-Max-Age`,`3600`),i.setHeader(`Cache-Control`,`no-cache, no-store, must-revalidate`),i.setHeader(`Pragma`,`no-cache`),i.setHeader(`Expires`,`0`),e.url===`/__versa/initHRM.js`){let e=n.join(g,`/initHRM.js`),t=await f.getOrReadFile(e);if(t)i.setHeader(`Content-Type`,t.contentType),i.setHeader(`ETag`,t.etag),i.end(t.content);else{let t=await p();u.error(t.red(`🚩 :Error al leer el archivo ${e}`)),i.statusCode=404,i.end(`// vueLoader.js not found`)}return}if(e.url.startsWith(`/__versa/`)){let t=n.join(g,e.url.replace(`/__versa/`,``)),r=await f.getOrReadFile(t);if(r)i.setHeader(`Content-Type`,r.contentType),i.setHeader(`ETag`,r.etag),i.end(r.content);else{let e=await p();u.error(e.red(`🚩 :Error al leer el archivo ${t}`)),i.statusCode=404,i.end(`// Not found`)}return}if(e.url.startsWith(`/node_modules/`)){let t=n.join(r.cwd(),e.url),a=await f.getOrReadFile(t);if(a)i.setHeader(`Content-Type`,a.contentType),i.setHeader(`ETag`,a.etag),i.end(a.content);else{let e=await p();u.error(e.red(`🚩 Error al leer el módulo ${t}`)),i.statusCode=404,i.end(`// Module not found`)}return}let o=e.url.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|webp|avif|json|html|xml|txt|pdf|zip|mp4|mp3|wav|ogg)(\?.*)?$/i);if(e.method===`GET`){let n=await p();o&&!t?u.info(n.white(`GET: ${e.url}`)):o||u.info(n.cyan(`GET: ${e.url}`))}else if(e.method===`POST`){let t=await p();u.info(t.blue(`POST: ${e.url}`))}else if(e.method===`PUT`){let t=await p();u.info(t.yellow(`PUT: ${e.url}`))}else if(e.method===`DELETE`){let t=await p();u.info(t.red(`DELETE: ${e.url}`))}else{let t=await p();u.info(t.gray(`${e.method}: ${e.url}`))}a()}]}),e}catch(e){u.error(`🚩 :Error al iniciar BrowserSync: ${e instanceof Error?e.message:String(e)}`),r.exit(1)}}export async function emitirCambios(e,t,r){let i=await p();u.info(i.green(`[HMR] Emitiendo cambios: ${t} ${r}\n`));let a=n.normalize(r).replace(/\\/g,`/`),o=n.basename(a,n.extname(a));e.sockets.emit(t,{action:t,filePath:r,normalizedPath:a,nameFile:o})}export const getBrowserSyncCacheStats=()=>f.getStats();export const clearBrowserSyncCache=()=>{f.clear()};export const invalidateBrowserSyncFile=e=>{f.invalidateFile(e)};
393
+ src="/__versa/initHRM.js"></script>
394
+ `;
395
+ },
396
+ },
397
+ },
398
+ logLevel: 'info',
399
+ logPrefix: 'BS',
400
+ logConnections: true,
401
+ logFileChanges: true,
402
+ watchEvents: ['change', 'add', 'unlink', 'addDir', 'unlinkDir'],
403
+ reloadDelay: 500,
404
+ reloadDebounce: 500,
405
+ reloadOnRestart: true,
406
+ notify: true,
407
+ watchOptions: {
408
+ ignoreInitial: true,
409
+ ignored: ['node_modules', '.git'],
410
+ },
411
+ middleware: [
412
+ async function (req, res, next) {
413
+ //para evitar el error de CORS
414
+ res.setHeader('Access-Control-Allow-Origin', '*');
415
+ res.setHeader('Access-Control-Allow-Methods', '*');
416
+ res.setHeader('Access-Control-Allow-Headers', '*');
417
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
418
+ res.setHeader('Access-Control-Max-Age', '3600');
419
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
420
+ res.setHeader('Pragma', 'no-cache');
421
+ res.setHeader('Expires', '0');
422
+ //para redigir a la ubicación correcta
423
+ if (req.url === '/__versa/initHRM.js') {
424
+ // ✨ OPTIMIZADO: Usar cache para archivos HRM
425
+ const vueLoaderPath = path.join(relativeHrmPath, '/initHRM.js');
426
+ const cachedFile = await fileCache.getOrReadFile(vueLoaderPath);
427
+ if (cachedFile) {
428
+ res.setHeader('Content-Type', cachedFile.contentType);
429
+ res.setHeader('ETag', cachedFile.etag);
430
+ // if (
431
+ // process.env.VERBOSE === 'true' &&
432
+ // cachedFile.cached
433
+ // ) {
434
+ // logger.info(
435
+ // `🚀 File cache hit para ${vueLoaderPath}`,
436
+ // );
437
+ // }
438
+ res.end(cachedFile.content);
439
+ }
440
+ else {
441
+ const chalkInstance = await loadChalk();
442
+ logger.error(chalkInstance.red(`🚩 :Error al leer el archivo ${vueLoaderPath}`));
443
+ res.statusCode = 404;
444
+ res.end('// vueLoader.js not found');
445
+ }
446
+ return;
447
+ }
448
+ // Si la URL comienza con /__versa/hrm/, sirve los archivos de dist/hrm
449
+ if (req.url.startsWith('/__versa/')) {
450
+ // ✨ OPTIMIZADO: Usar cache para archivos Versa
451
+ const filePath = path.join(relativeHrmPath, req.url.replace('/__versa/', ''));
452
+ const cachedFile = await fileCache.getOrReadFile(filePath);
453
+ if (cachedFile) {
454
+ res.setHeader('Content-Type', cachedFile.contentType);
455
+ res.setHeader('ETag', cachedFile.etag);
456
+ // if (
457
+ // process.env.VERBOSE === 'true' &&
458
+ // cachedFile.cached
459
+ // ) {
460
+ // logger.info(
461
+ // `🚀 File cache hit para ${filePath}`,
462
+ // );
463
+ // }
464
+ res.end(cachedFile.content);
465
+ }
466
+ else {
467
+ const chalkInstance = await loadChalk();
468
+ logger.error(chalkInstance.red(`🚩 :Error al leer el archivo ${filePath}`));
469
+ res.statusCode = 404;
470
+ res.end('// Not found');
471
+ }
472
+ return;
473
+ }
474
+ // Si la URL comienza con /node_modules/, sirve los archivos de node_modules
475
+ if (req.url.startsWith('/node_modules/')) {
476
+ // ✨ OPTIMIZADO: Usar cache para módulos de node_modules
477
+ const modulePath = path.join(process.cwd(), req.url);
478
+ const cachedFile = await fileCache.getOrReadFile(modulePath);
479
+ if (cachedFile) {
480
+ res.setHeader('Content-Type', cachedFile.contentType);
481
+ res.setHeader('ETag', cachedFile.etag);
482
+ // if (
483
+ // process.env.VERBOSE === 'true' &&
484
+ // cachedFile.cached
485
+ // ) {
486
+ // logger.info(
487
+ // `🚀 Module cache hit para ${modulePath}`,
488
+ // );
489
+ // }
490
+ res.end(cachedFile.content);
491
+ }
492
+ else {
493
+ const chalkInstance = await loadChalk();
494
+ logger.error(chalkInstance.red(`🚩 Error al leer el módulo ${modulePath}`));
495
+ res.statusCode = 404;
496
+ res.end('// Module not found');
497
+ }
498
+ return;
499
+ }
500
+ // detectar si es un archivo estático, puede que contenga un . y alguna extensión o dashUsers.js?v=1746559083866
501
+ const isAssets = req.url.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|webp|avif|json|html|xml|txt|pdf|zip|mp4|mp3|wav|ogg)(\?.*)?$/i);
502
+ if (req.method === 'GET') {
503
+ const chalkInstance = await loadChalk();
504
+ // omitir archivos estáticos sólo si AssetsOmit es true
505
+ if (isAssets && !AssetsOmit) {
506
+ logger.info(chalkInstance.white(`GET: ${req.url}`));
507
+ }
508
+ else if (!isAssets) {
509
+ logger.info(chalkInstance.cyan(`GET: ${req.url}`));
510
+ }
511
+ }
512
+ else if (req.method === 'POST') {
513
+ const chalkInstance = await loadChalk();
514
+ logger.info(chalkInstance.blue(`POST: ${req.url}`));
515
+ }
516
+ else if (req.method === 'PUT') {
517
+ const chalkInstance = await loadChalk();
518
+ logger.info(chalkInstance.yellow(`PUT: ${req.url}`));
519
+ }
520
+ else if (req.method === 'DELETE') {
521
+ const chalkInstance = await loadChalk();
522
+ logger.info(chalkInstance.red(`DELETE: ${req.url}`));
523
+ }
524
+ else {
525
+ const chalkInstance = await loadChalk();
526
+ logger.info(chalkInstance.gray(`${req.method}: ${req.url}`));
527
+ }
528
+ // Aquí podrías, por ejemplo, escribir estos logs en un archivo o base de datos
529
+ next();
530
+ },
531
+ ],
532
+ });
533
+ // 🔍 Listener para errores del cliente
534
+ bs.sockets.on('connection', (socket) => {
535
+ socket.on('client:error', async (errorData) => {
536
+ const chalkInstance = await loadChalk();
537
+ logger.error(chalkInstance.red('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
538
+ logger.error(chalkInstance.red.bold('🔥 ERROR DEL CLIENTE (NAVEGADOR)'));
539
+ logger.error(chalkInstance.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
540
+ logger.error(chalkInstance.yellow(`📍 Tipo: ${errorData.type}`));
541
+ logger.error(chalkInstance.yellow(`⏰ Timestamp: ${errorData.timestamp}`));
542
+ logger.error(chalkInstance.yellow(`🌐 URL: ${errorData.url}`));
543
+ logger.error(chalkInstance.yellow(`🖥️ User Agent: ${errorData.userAgent}`));
544
+ if (errorData.context &&
545
+ Object.keys(errorData.context).length > 0) {
546
+ logger.error(chalkInstance.cyan('\n📋 Contexto:'));
547
+ logger.error(chalkInstance.cyan(JSON.stringify(errorData.context, null, 2)));
548
+ }
549
+ if (errorData.error) {
550
+ logger.error(chalkInstance.red('\n💥 Error:'));
551
+ logger.error(chalkInstance.red(` Nombre: ${errorData.error.name}`));
552
+ logger.error(chalkInstance.red(` Mensaje: ${errorData.error.message}`));
553
+ if (errorData.error.stack) {
554
+ logger.error(chalkInstance.gray('\n📚 Stack Trace:'));
555
+ logger.error(chalkInstance.gray(errorData.error.stack));
556
+ }
557
+ }
558
+ logger.error(chalkInstance.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
559
+ });
560
+ });
561
+ return bs;
562
+ }
563
+ catch (error) {
564
+ logger.error(`🚩 :Error al iniciar BrowserSync: ${error instanceof Error ? error.message : String(error)}`);
565
+ process.exit(1);
566
+ }
567
+ }
568
+ export async function emitirCambios(bs, action, filePath) {
569
+ // ✨ OPTIMIZACIÓN: Emitir PRIMERO (crítico), logging DESPUÉS (no crítico)
570
+ const normalizedPath = path.normalize(filePath).replace(/\\/g, '/');
571
+ const nameFile = path.basename(normalizedPath, path.extname(normalizedPath));
572
+ bs.sockets.emit(action, { action, filePath, normalizedPath, nameFile });
573
+ // Logging asíncrono para no bloquear la emisión
574
+ setImmediate(async () => {
575
+ const chalkInstance = await loadChalk();
576
+ logger.info(chalkInstance.green(`[HMR] Emitiendo cambios: ${action} ${filePath}\n`));
577
+ });
578
+ }
579
+ // ✨ NUEVAS FUNCIONES: Exportar funcionalidades del cache de archivos para uso externo
580
+ export const getBrowserSyncCacheStats = () => {
581
+ return fileCache.getStats();
582
+ };
583
+ export const clearBrowserSyncCache = () => {
584
+ fileCache.clear();
585
+ };
586
+ export const invalidateBrowserSyncFile = (filePath) => {
587
+ fileCache.invalidateFile(filePath);
588
+ };
589
+ //# sourceMappingURL=browserSync.js.map