@teamvelix/velix 5.0.9 → 5.1.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.
@@ -1,5 +1,5 @@
1
1
  import { getRegisteredIslands, generateAdvancedHydrationScript } from './chunk-OIZNYND3.js';
2
- import { logger_default, buildRouteTree, matchRoute } from './chunk-SPIGTNT7.js';
2
+ import { logger_default, buildRouteTree, matchRoute, VERSION } from './chunk-4FVTRM76.js';
3
3
  import { loadConfig, resolvePaths } from './chunk-F24Q2MX3.js';
4
4
  import http from 'http';
5
5
  import fs4 from 'fs';
@@ -306,7 +306,6 @@ function definePlugin(definition) {
306
306
  function detectTailwindCli() {
307
307
  const v4 = spawnSync("npx", ["@tailwindcss/cli", "--help"], {
308
308
  stdio: "pipe",
309
- shell: process.platform === "win32",
310
309
  timeout: 15e3
311
310
  });
312
311
  if (v4.status === 0) return "@tailwindcss/cli";
@@ -340,8 +339,7 @@ function tailwindPlugin(options = {}) {
340
339
  if (options.minify !== false) args.push("--minify");
341
340
  spawnSync("npx", args, {
342
341
  stdio: "inherit",
343
- cwd: process.cwd(),
344
- shell: process.platform === "win32"
342
+ cwd: process.cwd()
345
343
  });
346
344
  logger_default.success("Tailwind CSS built successfully");
347
345
  } catch (err) {
@@ -363,8 +361,7 @@ function tailwindPlugin(options = {}) {
363
361
  const cli2 = getCli();
364
362
  const buildResult = spawnSync("npx", [cli2, "-i", input, "-o", output], {
365
363
  cwd: process.cwd(),
366
- stdio: "pipe",
367
- shell: process.platform === "win32"
364
+ stdio: "pipe"
368
365
  });
369
366
  if (buildResult.error) {
370
367
  logger_default.error("Tailwind CSS not installed. Run: npm install -D tailwindcss @tailwindcss/postcss");
@@ -384,8 +381,7 @@ function tailwindPlugin(options = {}) {
384
381
  const cli = getCli();
385
382
  const watcher = spawn("npx", [cli, "-i", input, "-o", output, "--watch"], {
386
383
  stdio: "pipe",
387
- cwd: process.cwd(),
388
- shell: process.platform === "win32"
384
+ cwd: process.cwd()
389
385
  });
390
386
  watcher.stdout.on("data", (data) => {
391
387
  const msg = data.toString().trim();
@@ -968,163 +964,332 @@ function bindArgs(action, ...boundArgs) {
968
964
  }
969
965
 
970
966
  // server/devtools.ts
971
- function generateDevToolsHtml(isDev) {
967
+ var ICON_ROUTE = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>`;
968
+ var ICON_PERF = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`;
969
+ var ICON_INFO = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>`;
970
+ var ICON_FILE = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>`;
971
+ var ICON_GEAR = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14M4.93 4.93a10 10 0 0 0 0 14.14"/></svg>`;
972
+ var ICON_MON = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>`;
973
+ var ICON_TS = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 7 4 4 20 4 20 7"/><line x1="9" y1="20" x2="15" y2="20"/><line x1="12" y1="4" x2="12" y2="20"/></svg>`;
974
+ var ICON_CLOCK = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`;
975
+ var ICON_TRI = `<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2L2 19h20L12 2z"/></svg>`;
976
+ var ICON_TERM = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>`;
977
+ function generateDevToolsHtml(isDev, ctx = {}) {
972
978
  if (!isDev) return "";
973
- return `<style>
974
- @keyframes velix-pulse {
975
- 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(34, 211, 238, 0.7); }
976
- 70% { transform: scale(1.05); box-shadow: 0 0 0 10px rgba(34, 211, 238, 0); }
977
- 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(34, 211, 238, 0); }
978
- }
979
+ const version = ctx.version ?? "5.1.0";
980
+ const port = ctx.port ?? 3e3;
981
+ const host = ctx.host ?? "localhost";
982
+ const nodeVersion = ctx.nodeVersion ?? process.version.replace("v", "");
983
+ return `
984
+ <style>
985
+ /* \u2500\u2500 Velix DevTools v5.1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
986
+ #__vdt-btn{position:fixed;bottom:16px;left:16px;z-index:9999;width:40px;height:40px;border-radius:50%;background:#111827;border:2px solid #22D3EE;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.5);transition:transform .2s,box-shadow .2s;outline:none;}
987
+ #__vdt-btn:hover{transform:scale(1.08);box-shadow:0 6px 20px rgba(34,211,238,.25);}
988
+ #__vdt-dot{position:absolute;top:-3px;right:-3px;width:11px;height:11px;border-radius:50%;background:#22D3EE;border:2px solid #111827;transition:background .3s;}
989
+ #__vdt{display:none;position:fixed;bottom:68px;left:16px;width:340px;background:#111827;color:#f3f4f6;border-radius:14px;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:13px;box-shadow:0 24px 60px rgba(0,0,0,.6);z-index:10000;border:1px solid #1f2937;overflow:hidden;}
990
+ /* header */
991
+ .__vdt-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #1f2937;}
992
+ .__vdt-brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:14px;color:#f9fafb;}
993
+ .__vdt-badge{font-size:11px;font-weight:600;background:#1f2937;color:#9ca3af;border-radius:5px;padding:2px 7px;letter-spacing:.3px;}
994
+ .__vdt-close{background:none;border:none;color:#6b7280;cursor:pointer;font-size:20px;line-height:1;padding:0;transition:color .15s;}
995
+ .__vdt-close:hover{color:#f9fafb;}
996
+ /* tabs */
997
+ .__vdt-tabs{display:flex;border-bottom:1px solid #1f2937;}
998
+ .__vdt-tab{flex:1;padding:10px 0;background:none;border:none;color:#6b7280;font-size:12px;font-weight:500;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px;border-bottom:2px solid transparent;transition:color .15s,border-color .15s;font-family:inherit;letter-spacing:.1px;}
999
+ .__vdt-tab:hover{color:#d1d5db;}
1000
+ .__vdt-tab.active{color:#10b981;border-bottom-color:#10b981;}
1001
+ /* body */
1002
+ .__vdt-body{padding:14px 16px;min-height:200px;}
1003
+ .__vdt-section{margin-bottom:14px;}
1004
+ .__vdt-label{font-size:11px;color:#6b7280;text-transform:uppercase;letter-spacing:.6px;margin-bottom:8px;}
1005
+ .__vdt-box{background:#1f2937;border-radius:8px;padding:10px 13px;font-size:13px;color:#e5e7eb;font-family:ui-monospace,'Cascadia Code','Fira Code',monospace;border:1px solid #374151;}
1006
+ .__vdt-row{display:flex;align-items:center;justify-content:space-between;padding:9px 13px;background:#1f2937;border-radius:8px;margin-bottom:6px;border:1px solid #374151;}
1007
+ .__vdt-row-left{display:flex;align-items:center;gap:8px;color:#d1d5db;}
1008
+ .__vdt-row-right{font-family:ui-monospace,'Cascadia Code',monospace;color:#10b981;font-size:12px;font-weight:500;}
1009
+ .__vdt-pill{font-size:10px;font-weight:600;padding:2px 7px;border-radius:4px;letter-spacing:.2px;}
1010
+ .__vdt-pill-green{background:#052e16;color:#4ade80;border:1px solid #166534;}
1011
+ .__vdt-pill-blue{background:#0c1a3a;color:#60a5fa;border:1px solid #1e3a8a;}
1012
+ .__vdt-render{display:flex;align-items:center;gap:6px;padding:8px 13px;background:#1f2937;border-radius:8px;border:1px solid #374151;color:#9ca3af;font-size:12px;}
1013
+ .__vdt-render svg{color:#6b7280;}
1014
+ /* vitals */
1015
+ .__vdt-vital{display:flex;align-items:center;justify-content:space-between;padding:9px 13px;background:#1f2937;border-radius:8px;margin-bottom:6px;border:1px solid #374151;}
1016
+ .__vdt-vital-left{display:flex;align-items:center;gap:8px;}
1017
+ .__vdt-dot-good{width:8px;height:8px;border-radius:50%;background:#10b981;flex-shrink:0;}
1018
+ .__vdt-dot-warn{width:8px;height:8px;border-radius:50%;background:#f59e0b;flex-shrink:0;}
1019
+ .__vdt-dot-bad{width:8px;height:8px;border-radius:50%;background:#ef4444;flex-shrink:0;}
1020
+ .__vdt-vital-name{color:#d1d5db;font-weight:500;}
1021
+ .__vdt-vital-val{font-family:ui-monospace,'Cascadia Code',monospace;color:#10b981;font-size:12px;font-weight:600;}
1022
+ .__vdt-build{display:flex;align-items:center;justify-content:space-between;padding:9px 13px;color:#9ca3af;font-size:12px;border-top:1px solid #374151;margin-top:8px;padding-top:12px;}
1023
+ /* info rows */
1024
+ .__vdt-info-row{display:flex;align-items:center;justify-content:space-between;padding:9px 13px;background:#1f2937;border-radius:8px;margin-bottom:6px;border:1px solid #374151;}
1025
+ .__vdt-info-left{display:flex;align-items:center;gap:8px;color:#d1d5db;}
1026
+ .__vdt-info-val{font-family:ui-monospace,'Cascadia Code',monospace;color:#9ca3af;font-size:12px;}
1027
+ .__vdt-dev-badge{display:flex;align-items:center;gap:8px;padding:10px 13px;background:#052e16;border:1px solid #166534;border-radius:8px;color:#4ade80;font-size:12px;font-weight:500;margin-top:10px;}
1028
+ /* footer */
1029
+ .__vdt-footer{padding:10px 16px;border-top:1px solid #1f2937;display:flex;align-items:center;justify-content:space-between;}
1030
+ .__vdt-host{color:#6b7280;font-size:11px;font-family:ui-monospace,'Cascadia Code',monospace;}
1031
+ .__vdt-conn{display:flex;align-items:center;gap:5px;font-size:11px;color:#10b981;}
1032
+ .__vdt-conn-dot{width:6px;height:6px;border-radius:50%;background:#10b981;}
979
1033
 
980
- @keyframes velix-spin {
981
- from { transform: rotate(0deg); }
982
- to { transform: rotate(360deg); }
983
- }
1034
+ /* \u2500\u2500 Widget state colors \u2500\u2500 */
1035
+ .vdt-idle{border-color:#22D3EE !important;}
1036
+ .vdt-compiling{border-color:#4ade80 !important;}
1037
+ .vdt-rendering{border-color:#fb923c !important;}
1038
+ .vdt-navigating{border-color:#60a5fa !important;}
1039
+ .vdt-error{border-color:#f87171 !important;}
1040
+ #__vdt-dot.idle{background:#22D3EE;}
1041
+ #__vdt-dot.compiling{background:#4ade80;}
1042
+ #__vdt-dot.rendering{background:#fb923c;}
1043
+ #__vdt-dot.navigating{background:#60a5fa;}
1044
+ #__vdt-dot.error{background:#f87171;}
1045
+ @keyframes __vdt-pulse{0%,100%{opacity:1;}50%{opacity:.4;}}
1046
+ .vdt-compiling #__vdt-dot,.vdt-rendering #__vdt-dot,.vdt-navigating #__vdt-dot{animation:__vdt-pulse .9s ease-in-out infinite;}
1047
+ </style>
984
1048
 
985
- .velix-idle { background: #0f172a !important; border: 2px solid #22D3EE !important; }
986
- .velix-rendering { background: #ea580c !important; border: 2px solid #fb923c !important; animation: velix-pulse 1.5s infinite !important; }
987
- .velix-compiling { background: #16a34a !important; border: 2px solid #4ade80 !important; animation: velix-spin 2s linear infinite !important; }
988
- .velix-navigating { background: #2563eb !important; border: 2px solid #60a5fa !important; animation: velix-pulse 1s infinite !important; }
989
- .velix-error { background: #dc2626 !important; border: 2px solid #f87171 !important; animation: velix-pulse 0.8s infinite !important; }
1049
+ <!-- \u2500\u2500 Floating button \u2500\u2500 -->
1050
+ <button id="__vdt-btn" class="vdt-idle" onclick="__vdtOpen()" title="Velix DevTools (${version})">
1051
+ ${ICON_TRI}
1052
+ <div id="__vdt-dot" class="idle"></div>
1053
+ </button>
990
1054
 
991
- .velix-status-badge {
992
- position: absolute;
993
- top: -4px;
994
- right: -4px;
995
- width: 12px;
996
- height: 12px;
997
- border-radius: 50%;
998
- border: 2px solid #0f172a;
999
- }
1055
+ <!-- \u2500\u2500 Panel \u2500\u2500 -->
1056
+ <div id="__vdt">
1057
+ <!-- Header -->
1058
+ <div class="__vdt-header">
1059
+ <div class="__vdt-brand">
1060
+ ${ICON_TRI}
1061
+ Velix
1062
+ <span class="__vdt-badge">${version}</span>
1063
+ </div>
1064
+ <button class="__vdt-close" onclick="__vdtClose()" title="Close">&times;</button>
1065
+ </div>
1000
1066
 
1001
- .velix-status-idle { background: #22D3EE; }
1002
- .velix-status-rendering { background: #fb923c; }
1003
- .velix-status-compiling { background: #4ade80; }
1004
- .velix-status-navigating { background: #60a5fa; }
1005
- .velix-status-error { background: #f87171; }
1006
- </style>
1067
+ <!-- Tabs -->
1068
+ <div class="__vdt-tabs">
1069
+ <button class="__vdt-tab active" id="__vtab-btn-route" onclick="__vdtTab('route')">${ICON_ROUTE} Route</button>
1070
+ <button class="__vdt-tab" id="__vtab-btn-perf" onclick="__vdtTab('perf')">${ICON_PERF} Performance</button>
1071
+ <button class="__vdt-tab" id="__vtab-btn-info" onclick="__vdtTab('info')">${ICON_INFO} Info</button>
1072
+ </div>
1073
+
1074
+ <!-- Tab: Route -->
1075
+ <div class="__vdt-body" id="__vtab-route">
1076
+ <div class="__vdt-section">
1077
+ <div class="__vdt-label">Current Route</div>
1078
+ <div class="__vdt-box" id="__vdt-route-path">/</div>
1079
+ </div>
1080
+ <div class="__vdt-section">
1081
+ <div class="__vdt-label">Route Segments</div>
1082
+ <div class="__vdt-row">
1083
+ <div class="__vdt-row-left">${ICON_FILE} <span>app</span></div>
1084
+ <span class="__vdt-pill __vdt-pill-blue">layout</span>
1085
+ </div>
1086
+ <div class="__vdt-row" id="__vdt-page-row">
1087
+ <div class="__vdt-row-left">${ICON_FILE} <span id="__vdt-page-name">page.tsx</span></div>
1088
+ <span class="__vdt-pill __vdt-pill-green">page</span>
1089
+ </div>
1090
+ </div>
1091
+ <div class="__vdt-render" id="__vdt-rendering">
1092
+ ${ICON_TERM} Rendering: <strong id="__vdt-render-type" style="color:#d1d5db;margin-left:4px;">SSR</strong>
1093
+ </div>
1094
+ </div>
1095
+
1096
+ <!-- Tab: Performance -->
1097
+ <div class="__vdt-body" id="__vtab-perf" style="display:none;">
1098
+ <div class="__vdt-section">
1099
+ <div class="__vdt-label">Vitals</div>
1100
+ <div class="__vdt-vital">
1101
+ <div class="__vdt-vital-left"><div class="__vdt-dot-good"></div><span class="__vdt-vital-name">FCP</span></div>
1102
+ <span class="__vdt-vital-val" id="__vdt-fcp">\u2014</span>
1103
+ </div>
1104
+ <div class="__vdt-vital">
1105
+ <div class="__vdt-vital-left"><div class="__vdt-dot-good"></div><span class="__vdt-vital-name">LCP</span></div>
1106
+ <span class="__vdt-vital-val" id="__vdt-lcp">\u2014</span>
1107
+ </div>
1108
+ <div class="__vdt-vital">
1109
+ <div class="__vdt-vital-left"><div class="__vdt-dot-good"></div><span class="__vdt-vital-name">CLS</span></div>
1110
+ <span class="__vdt-vital-val" id="__vdt-cls">\u2014</span>
1111
+ </div>
1112
+ <div class="__vdt-vital">
1113
+ <div class="__vdt-vital-left"><div class="__vdt-dot-good"></div><span class="__vdt-vital-name">TTFB</span></div>
1114
+ <span class="__vdt-vital-val" id="__vdt-ttfb">\u2014</span>
1115
+ </div>
1116
+ </div>
1117
+ <div class="__vdt-build">
1118
+ <div style="display:flex;align-items:center;gap:6px;">${ICON_CLOCK} Build time:</div>
1119
+ <span id="__vdt-build-time" style="color:#d1d5db;font-family:ui-monospace,monospace;font-size:12px;">\u2014</span>
1120
+ </div>
1121
+ </div>
1122
+
1123
+ <!-- Tab: Info -->
1124
+ <div class="__vdt-body" id="__vtab-info" style="display:none;">
1125
+ <div class="__vdt-info-row">
1126
+ <div class="__vdt-info-left">${ICON_TRI} <span>Velix</span></div>
1127
+ <span class="__vdt-info-val">${version}</span>
1128
+ </div>
1129
+ <div class="__vdt-info-row">
1130
+ <div class="__vdt-info-left">${ICON_GEAR} <span>React</span></div>
1131
+ <span class="__vdt-info-val" id="__vdt-react-ver">\u2014</span>
1132
+ </div>
1133
+ <div class="__vdt-info-row">
1134
+ <div class="__vdt-info-left">${ICON_MON} <span>Node.js</span></div>
1135
+ <span class="__vdt-info-val">${nodeVersion}</span>
1136
+ </div>
1137
+ <div class="__vdt-info-row">
1138
+ <div class="__vdt-info-left">${ICON_TS} <span>TypeScript</span></div>
1139
+ <span class="__vdt-info-val" id="__vdt-ts-ver">\u2014</span>
1140
+ </div>
1141
+ <div class="__vdt-dev-badge">
1142
+ ${ICON_TERM} Development mode active
1143
+ </div>
1144
+ </div>
1145
+
1146
+ <!-- Footer -->
1147
+ <div class="__vdt-footer">
1148
+ <span class="__vdt-host">${host}:${port}</span>
1149
+ <div class="__vdt-conn">
1150
+ <div class="__vdt-conn-dot" id="__vdt-conn-dot"></div>
1151
+ <span id="__vdt-conn-text">connected</span>
1152
+ </div>
1153
+ </div>
1154
+ </div>
1007
1155
 
1008
1156
  <script>
1009
- // DevTools State Management
1010
- window.__VELIX_DEV_TOOLS__ = {
1011
- status: 'idle',
1012
- setStatus: function(newStatus) {
1013
- this.status = newStatus;
1014
- const widget = document.getElementById('__velix-dev-tools');
1015
- const badge = document.getElementById('__velix-status-badge');
1016
- const statusText = document.getElementById('__velix-status-text');
1017
-
1018
- if (widget) {
1019
- widget.className = 'velix-' + newStatus;
1020
- }
1021
-
1022
- if (badge) {
1023
- badge.className = 'velix-status-badge velix-status-' + newStatus;
1024
- }
1025
-
1026
- if (statusText) {
1027
- const statusLabels = {
1028
- idle: 'Ready',
1029
- rendering: 'Rendering',
1030
- compiling: 'Compiling',
1031
- navigating: 'Navigating',
1032
- error: 'Error'
1033
- };
1034
- statusText.textContent = statusLabels[newStatus] || 'Unknown';
1035
- statusText.style.color = {
1036
- idle: '#22D3EE',
1037
- rendering: '#fb923c',
1038
- compiling: '#4ade80',
1039
- navigating: '#60a5fa',
1040
- error: '#f87171'
1041
- }[newStatus] || '#94a3b8';
1042
- }
1043
- }
1157
+ (function(){
1158
+ /* \u2500\u2500 Tab switching \u2500\u2500 */
1159
+ window.__vdtTab = function(name){
1160
+ ['route','perf','info'].forEach(function(t){
1161
+ var body = document.getElementById('__vtab-' + t);
1162
+ var btn = document.getElementById('__vtab-btn-' + t);
1163
+ if(!body || !btn) return;
1164
+ var active = t === name;
1165
+ body.style.display = active ? '' : 'none';
1166
+ btn.classList.toggle('active', active);
1167
+ });
1044
1168
  };
1045
1169
 
1046
- // HMR Connection
1047
- const es = new EventSource('/__velix/hmr');
1048
- es.onmessage = (e) => {
1049
- const data = e.data;
1050
-
1051
- if (data === 'reload') {
1052
- window.__VELIX_DEV_TOOLS__.setStatus('idle');
1053
- setTimeout(() => location.reload(), 100);
1054
- }
1055
-
1056
- if (data === 'building') {
1057
- window.__VELIX_DEV_TOOLS__.setStatus('compiling');
1170
+ window.__vdtOpen = function(){ document.getElementById('__vdt').style.display = ''; };
1171
+ window.__vdtClose = function(){ document.getElementById('__vdt').style.display = 'none'; };
1172
+
1173
+ /* \u2500\u2500 Route info \u2500\u2500 */
1174
+ function updateRoute(){
1175
+ var p = window.location.pathname;
1176
+ var el = document.getElementById('__vdt-route-path');
1177
+ if(el) el.textContent = p;
1178
+ var seg = p.split('/').filter(Boolean);
1179
+ var pageName = seg.length ? seg[seg.length-1] + '.tsx' : 'page.tsx';
1180
+ var pn = document.getElementById('__vdt-page-name');
1181
+ if(pn) pn.textContent = pageName;
1182
+ /* Detect rendering mode from meta generator or search param */
1183
+ var rt = document.getElementById('__vdt-render-type');
1184
+ if(rt){
1185
+ var sp = new URLSearchParams(window.location.search);
1186
+ rt.textContent = sp.get('_render') || (document.querySelector('meta[name="generator"]') ? 'SSR' : 'Static');
1058
1187
  }
1059
-
1060
- if (data === 'built') {
1061
- window.__VELIX_DEV_TOOLS__.setStatus('idle');
1188
+ }
1189
+ updateRoute();
1190
+ window.addEventListener('popstate', updateRoute);
1191
+
1192
+ /* \u2500\u2500 Web Vitals \u2500\u2500 */
1193
+ function fmtMs(v){ return v < 1000 ? Math.round(v) + 'ms' : (v/1000).toFixed(2) + 's'; }
1194
+ function setVital(id, v, threshGood, threshOk){
1195
+ var el = document.getElementById(id);
1196
+ if(!el) return;
1197
+ el.textContent = typeof v === 'number' ? (id === '__vdt-cls' ? v.toFixed(3) : fmtMs(v)) : v;
1198
+ var dot = el.closest('.__vdt-vital')?.querySelector('[class^="__vdt-dot"]');
1199
+ if(dot && typeof v === 'number'){
1200
+ dot.className = v <= threshGood ? '__vdt-dot-good' : v <= threshOk ? '__vdt-dot-warn' : '__vdt-dot-bad';
1062
1201
  }
1063
-
1064
- if (data.startsWith('rendering:')) {
1065
- window.__VELIX_DEV_TOOLS__.setStatus('rendering');
1066
- setTimeout(() => window.__VELIX_DEV_TOOLS__.setStatus('idle'), 1000);
1202
+ if(el && typeof v === 'number'){
1203
+ el.style.color = v <= threshGood ? '#10b981' : v <= threshOk ? '#f59e0b' : '#ef4444';
1067
1204
  }
1068
-
1069
- if (data.startsWith('error:')) {
1070
- window.__VELIX_DEV_TOOLS__.setStatus('error');
1205
+ }
1206
+
1207
+ try {
1208
+ /* FCP */
1209
+ new PerformanceObserver(function(l){
1210
+ var e = l.getEntries()[0]; if(e) setVital('__vdt-fcp', e.startTime, 1800, 3000);
1211
+ }).observe({ type:'paint', buffered:true });
1212
+
1213
+ /* LCP */
1214
+ new PerformanceObserver(function(l){
1215
+ var entries = l.getEntries();
1216
+ var e = entries[entries.length-1]; if(e) setVital('__vdt-lcp', e.startTime, 2500, 4000);
1217
+ }).observe({ type:'largest-contentful-paint', buffered:true });
1218
+
1219
+ /* CLS */
1220
+ var _cls = 0;
1221
+ new PerformanceObserver(function(l){
1222
+ l.getEntries().forEach(function(e){ if(!e.hadRecentInput) _cls += e.value; });
1223
+ setVital('__vdt-cls', _cls, 0.1, 0.25);
1224
+ }).observe({ type:'layout-shift', buffered:true });
1225
+
1226
+ /* TTFB */
1227
+ new PerformanceObserver(function(l){
1228
+ var e = l.getEntries()[0]; if(e) setVital('__vdt-ttfb', e.responseStart - e.requestStart, 800, 1800);
1229
+ }).observe({ type:'navigation', buffered:true });
1230
+ } catch(e){}
1231
+
1232
+ /* Build time from server-injected global */
1233
+ var bt = window.__VELIX_BUILD_TIME__;
1234
+ var btel = document.getElementById('__vdt-build-time');
1235
+ if(btel) btel.textContent = bt ? bt + 'ms' : '\u2014';
1236
+
1237
+ /* React version from window.React */
1238
+ var rv = document.getElementById('__vdt-react-ver');
1239
+ if(rv && window.React) rv.textContent = window.React.version;
1240
+
1241
+ /* TypeScript version (injected by server if available) */
1242
+ var tsv = document.getElementById('__vdt-ts-ver');
1243
+ if(tsv) tsv.textContent = window.__VELIX_TS_VERSION__ || '\u2014';
1244
+
1245
+ /* \u2500\u2500 HMR + Status \u2500\u2500 */
1246
+ var btn = document.getElementById('__vdt-btn');
1247
+ var dot = document.getElementById('__vdt-dot');
1248
+ var connDot = document.getElementById('__vdt-conn-dot');
1249
+ var connText = document.getElementById('__vdt-conn-text');
1250
+
1251
+ function setStatus(s){
1252
+ if(btn){ btn.className = 'vdt-' + s; }
1253
+ if(dot){ dot.className = s; }
1254
+ }
1255
+
1256
+ function setConn(ok){
1257
+ if(connDot) connDot.style.background = ok ? '#10b981' : '#ef4444';
1258
+ if(connText) connText.textContent = ok ? 'connected' : 'disconnected';
1259
+ if(connText) connText.style.color = ok ? '#10b981' : '#ef4444';
1260
+ }
1261
+
1262
+ var es = new EventSource('/__velix/hmr');
1263
+
1264
+ es.onopen = function(){ setConn(true); };
1265
+
1266
+ es.onmessage = function(e){
1267
+ var data = e.data;
1268
+ if(data === 'reload'){
1269
+ setStatus('navigating');
1270
+ setTimeout(function(){ location.reload(); }, 120);
1271
+ } else if(data === 'building'){
1272
+ setStatus('compiling');
1273
+ } else if(data === 'built'){
1274
+ setStatus('idle');
1275
+ } else if(data.startsWith('rendering:')){
1276
+ setStatus('rendering');
1277
+ setTimeout(function(){ setStatus('idle'); }, 900);
1278
+ } else if(data.startsWith('error:')){
1279
+ setStatus('error');
1071
1280
  }
1072
1281
  };
1073
1282
 
1074
- es.onerror = () => {
1075
- // EventSource auto-reconnects \u2014 only show error if connection is fully closed
1076
- if (es.readyState === 2) {
1077
- window.__VELIX_DEV_TOOLS__.setStatus('error');
1283
+ es.onerror = function(){
1284
+ if(es.readyState === 2){
1285
+ setStatus('error');
1286
+ setConn(false);
1078
1287
  }
1079
1288
  };
1080
- </script>
1081
-
1082
- <div id="__velix-dev-tools" class="velix-idle" style="position:fixed;bottom:16px;left:16px;z-index:9999;border-radius:50%;padding:4px;box-shadow:0 4px 12px rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;width:40px;height:40px;cursor:pointer;transition:all 0.3s ease;" onmouseover="this.style.transform='scale(1.1)'" onmouseout="this.style.transform='scale(1)'" onclick="document.getElementById('__velix-dev-panel').style.display='block'" title="Velix DevTools">
1083
- <img src="/__velix/logo.webp" alt="Velix DevTools" style="width:22px;height:22px;" />
1084
- <div id="__velix-status-badge" class="velix-status-badge velix-status-idle"></div>
1085
- </div>
1086
1289
 
1087
- <div id="__velix-dev-panel" style="display:none;position:fixed;bottom:70px;left:16px;width:320px;background:#0f172a;color:white;border-radius:16px;padding:20px;font-family:ui-sans-serif,system-ui,-apple-system,sans-serif;box-shadow:0 20px 50px rgba(0,0,0,0.4);z-index:10000;border:1px solid #1e293b;">
1088
- <div style="display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #334155;padding-bottom:16px;margin-bottom:16px;">
1089
- <h3 style="margin:0;font-size:16px;font-weight:700;display:flex;align-items:center;gap:10px;">
1090
- <img src="/__velix/logo.webp" style="width:18px;height:18px;" />
1091
- Velix DevTools
1092
- </h3>
1093
- <button onclick="document.getElementById('__velix-dev-panel').style.display='none'" style="background:transparent;border:none;color:#94a3b8;cursor:pointer;font-size:22px;line-height:1;padding:0;margin:0;transition:color 0.2s;" onmouseover="this.style.color='white'" onmouseout="this.style.color='#94a3b8'">&times;</button>
1094
- </div>
1095
-
1096
- <div style="margin-bottom:16px;padding:12px;background:#1e293b;border-radius:8px;border:1px solid #334155;">
1097
- <div style="font-size:12px;color:#94a3b8;margin-bottom:4px;text-transform:uppercase;letter-spacing:0.5px;">Status</div>
1098
- <div id="__velix-status-text" style="font-size:16px;font-weight:600;color:#22D3EE;">Ready</div>
1099
- </div>
1100
-
1101
- <div style="font-size:13px;color:#cbd5e1;line-height:2;">
1102
- <div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid #1e293b;">
1103
- <span style="color:#94a3b8;">Framework</span>
1104
- <strong style="color:white;font-weight:600;">v5.0.4</strong>
1105
- </div>
1106
- <div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid #1e293b;">
1107
- <span style="color:#94a3b8;">Environment</span>
1108
- <strong style="color:#10b981;font-weight:600;">Development</strong>
1109
- </div>
1110
- <div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid #1e293b;">
1111
- <span style="color:#94a3b8;">Router</span>
1112
- <strong style="color:white;font-weight:600;">App Directory</strong>
1113
- </div>
1114
- <div style="display:flex;justify-content:space-between;padding:8px 0;">
1115
- <span style="color:#94a3b8;">Rendering</span>
1116
- <strong style="color:#60a5fa;font-weight:600;">Streaming SSR</strong>
1117
- </div>
1118
- </div>
1119
-
1120
- <div style="margin-top:16px;padding-top:16px;border-top:1px solid #334155;">
1121
- <div style="font-size:11px;color:#64748b;text-align:center;">
1122
- <span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:#22D3EE;margin-right:4px;"></span> Idle
1123
- <span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:#fb923c;margin:0 4px 0 12px;"></span> Rendering
1124
- <span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:#4ade80;margin:0 4px 0 12px;"></span> Compiling
1125
- </div>
1126
- </div>
1127
- </div>`;
1290
+ setStatus('idle');
1291
+ })();
1292
+ </script>`;
1128
1293
  }
1129
1294
 
1130
1295
  // server/error-pages.ts
@@ -1581,7 +1746,7 @@ function generate500Page(options) {
1581
1746
  <div class="footer">
1582
1747
  <div class="brand">
1583
1748
  <img src="/__velix/logo.webp" alt="Velix" onerror="this.style.display='none'"/>
1584
- <span>Velix v5.0.9</span>
1749
+ <span>Velix v${VERSION}</span>
1585
1750
  </div>
1586
1751
  <div class="footer-links">
1587
1752
  <a href="/">Home</a>
@@ -1942,12 +2107,17 @@ async function handlePageRoute(route, routes, req, res, url, config, isDev, proj
1942
2107
  const baseUrl = config.app.url || `http://${config.server.host}:${config.server.port}`;
1943
2108
  const metaTags = generateMetadataTags({
1944
2109
  ...metadata,
1945
- generator: `Velix v5.0.9`,
2110
+ generator: `Velix v${VERSION}`,
1946
2111
  viewport: metadata.viewport || "width=device-width, initial-scale=1"
1947
2112
  }, baseUrl);
1948
2113
  const islands = getRegisteredIslands();
1949
2114
  const hydrationScript = generateAdvancedHydrationScript(islands);
1950
- const devToolsHtml = generateDevToolsHtml(isDev);
2115
+ const devToolsHtml = generateDevToolsHtml(isDev, {
2116
+ version: VERSION,
2117
+ port: config.server.port,
2118
+ host: config.server.host,
2119
+ nodeVersion: process.version.replace("v", "")
2120
+ });
1951
2121
  const headInjections = `
1952
2122
  <meta charset="utf-8">
1953
2123
  ${metaTags}
@@ -2147,5 +2317,5 @@ function parseRequestBody(req) {
2147
2317
  var server_default = { createServer, tailwindPlugin };
2148
2318
 
2149
2319
  export { NotFoundError, PluginHooks, PluginManager, RedirectError, bindArgs, callServerAction, composeMiddleware, cookies, createServer, definePlugin, deserializeArgs, executeAction, formAction, generateJsonLd, generateMetadataTags, generateRobotsTxt, generateSitemap, getAction, getMethod, getPathname, headers, html, isMethod, json, jsonLd, loadMiddleware, loadPlugins, mergeMetadata, middlewares, notFound, parseFormData, parseJson, parseSearchParams, pluginManager, redirect, registerAction, runMiddleware, serverAction, server_default, tailwindPlugin, text, useActionContext, useVelixAction };
2150
- //# sourceMappingURL=chunk-XZYJGF3O.js.map
2151
- //# sourceMappingURL=chunk-XZYJGF3O.js.map
2320
+ //# sourceMappingURL=chunk-QOGL32T2.js.map
2321
+ //# sourceMappingURL=chunk-QOGL32T2.js.map