@teamvelix/velix 5.2.6 → 5.2.8

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,10 +1,10 @@
1
- import { logger_default, buildRouteTree, matchRoute, VERSION } from './chunk-MLLSS7Y5.js';
1
+ import { definePlugin, PluginHooks, logger_default, loadPlugins, pluginManager, buildRouteTree, matchRoute, VERSION } from './chunk-RU23OKU5.js';
2
2
  import { loadConfig, resolvePaths } from './chunk-F24Q2MX3.js';
3
3
  import { getRegisteredIslands, generateAdvancedHydrationScript } from './chunk-JI2HJFUT.js';
4
- import { __dirname as __dirname$1 } from './chunk-4S5YQJHB.js';
4
+ import { __dirname as __dirname$1, __require } from './chunk-BQ4HFLRL.js';
5
5
  import http from 'http';
6
- import fs4 from 'fs';
7
- import path4 from 'path';
6
+ import fs3 from 'fs';
7
+ import path3 from 'path';
8
8
  import { pathToFileURL, fileURLToPath } from 'url';
9
9
  import { createRequire } from 'module';
10
10
  import React, { useActionState } from 'react';
@@ -73,11 +73,11 @@ async function loadMiddleware(projectRoot) {
73
73
  const fns = [];
74
74
  const possibleFiles = ["proxy.ts", "proxy.js"];
75
75
  for (const file of possibleFiles) {
76
- const filePath = path4.join(projectRoot, file);
77
- if (!fs4.existsSync(filePath)) continue;
76
+ const filePath = path3.join(projectRoot, file);
77
+ if (!fs3.existsSync(filePath)) continue;
78
78
  try {
79
- const { pathToFileURL: pathToFileURL3 } = await import('url');
80
- const url = pathToFileURL3(filePath).href;
79
+ const { pathToFileURL: pathToFileURL2 } = await import('url');
80
+ const url = pathToFileURL2(filePath).href;
81
81
  const mod = await import(`${url}?t=${Date.now()}`);
82
82
  const fn = mod.default || mod.proxy || mod.middleware;
83
83
  if (typeof fn === "function") {
@@ -179,140 +179,6 @@ function composeMiddleware(...fns) {
179
179
  await run();
180
180
  };
181
181
  }
182
- var PluginHooks = {
183
- CONFIG: "config",
184
- SERVER_START: "server:start",
185
- REQUEST: "request",
186
- RESPONSE: "response",
187
- ROUTES_LOADED: "routes:loaded",
188
- BEFORE_RENDER: "render:before",
189
- AFTER_RENDER: "render:after",
190
- BUILD_START: "build:start",
191
- BUILD_END: "build:end"
192
- };
193
- var PluginManager = class {
194
- plugins = [];
195
- hooks = /* @__PURE__ */ new Map();
196
- /**
197
- * Register a plugin
198
- */
199
- register(plugin) {
200
- this.plugins.push(plugin);
201
- if (plugin.hooks) {
202
- for (const [hookName, handler] of Object.entries(plugin.hooks)) {
203
- if (handler) {
204
- const existing = this.hooks.get(hookName) || [];
205
- existing.push(handler);
206
- this.hooks.set(hookName, existing);
207
- }
208
- }
209
- }
210
- }
211
- /**
212
- * Run a hook with arguments
213
- */
214
- async runHook(hookName, ...args) {
215
- const handlers = this.hooks.get(hookName) || [];
216
- for (const handler of handlers) {
217
- await handler(...args);
218
- }
219
- }
220
- /**
221
- * Run a waterfall hook — each handler transforms the first argument
222
- */
223
- async runWaterfallHook(hookName, value, ...args) {
224
- const handlers = this.hooks.get(hookName) || [];
225
- let result = value;
226
- for (const handler of handlers) {
227
- const transformed = await handler(result, ...args);
228
- if (transformed !== void 0) result = transformed;
229
- }
230
- return result;
231
- }
232
- /**
233
- * Get all registered plugins
234
- */
235
- getPlugins() {
236
- return [...this.plugins];
237
- }
238
- /**
239
- * Check if a plugin is registered
240
- */
241
- hasPlugin(name) {
242
- return this.plugins.some((p) => p.name === name);
243
- }
244
- };
245
- var pluginManager = new PluginManager();
246
- async function loadPlugins(projectRoot, config) {
247
- const pluginEntries = config.plugins || [];
248
- for (const entry of pluginEntries) {
249
- try {
250
- if (typeof entry === "string") {
251
- const localPath = path4.join(projectRoot, "plugins", entry + ".ts");
252
- const localPathJs = path4.join(projectRoot, "plugins", entry + ".js");
253
- const localPathDir = path4.join(projectRoot, "plugins", entry, "index.ts");
254
- let pluginPath = null;
255
- if (fs4.existsSync(localPath)) pluginPath = localPath;
256
- else if (fs4.existsSync(localPathJs)) pluginPath = localPathJs;
257
- else if (fs4.existsSync(localPathDir)) pluginPath = localPathDir;
258
- if (pluginPath) {
259
- const url = pathToFileURL(pluginPath).href;
260
- const mod = await import(`${url}?t=${Date.now()}`);
261
- const plugin = mod.default || mod;
262
- if (plugin.name) {
263
- pluginManager.register(plugin);
264
- }
265
- } else {
266
- try {
267
- const mod = await import(entry);
268
- const plugin = mod.default || mod;
269
- if (plugin.name) pluginManager.register(plugin);
270
- } catch {
271
- console.warn(`\u26A0 Plugin not found: ${entry}`);
272
- }
273
- }
274
- } else if (typeof entry === "object" && entry !== null && "name" in entry) {
275
- pluginManager.register(entry);
276
- }
277
- } catch (err) {
278
- const error = err;
279
- console.warn(`\u26A0 Failed to load plugin: ${error?.message || String(error)}`);
280
- }
281
- }
282
- }
283
- function definePlugin(definition) {
284
- return definition;
285
- }
286
- ({
287
- /**
288
- * Security headers plugin
289
- */
290
- security: definePlugin({
291
- name: "velix:security",
292
- hooks: {
293
- [PluginHooks.RESPONSE]: (_req, res) => {
294
- const response = res;
295
- if (!response.headersSent) {
296
- response.setHeader("X-Content-Type-Options", "nosniff");
297
- response.setHeader("X-Frame-Options", "DENY");
298
- response.setHeader("X-XSS-Protection", "1; mode=block");
299
- }
300
- }
301
- }
302
- }),
303
- /**
304
- * Request logging plugin
305
- */
306
- logger: definePlugin({
307
- name: "velix:logger",
308
- hooks: {
309
- [PluginHooks.RESPONSE]: (req, _res, duration) => {
310
- const request = req;
311
- console.log(` ${request.method} ${request.url} ${duration}ms`);
312
- }
313
- }
314
- })
315
- });
316
182
  function detectTailwindCli() {
317
183
  const v4 = spawnSync("npx @tailwindcss/cli --help", {
318
184
  stdio: "pipe",
@@ -362,13 +228,13 @@ function tailwindPlugin(options = {}) {
362
228
  [PluginHooks.SERVER_START]: async (server, isDevArg) => {
363
229
  const isDev = isDevArg;
364
230
  if (!isDev) return;
365
- if (!fs4.existsSync(input)) {
231
+ if (!fs3.existsSync(input)) {
366
232
  logger_default.warn(`Tailwind input file not found: ${input}`);
367
233
  return;
368
234
  }
369
- const outputDir = path4.dirname(output);
370
- if (!fs4.existsSync(outputDir)) {
371
- fs4.mkdirSync(outputDir, { recursive: true });
235
+ const outputDir = path3.dirname(output);
236
+ if (!fs3.existsSync(outputDir)) {
237
+ fs3.mkdirSync(outputDir, { recursive: true });
372
238
  }
373
239
  logger_default.info("Building initial Tailwind CSS...");
374
240
  try {
@@ -1313,517 +1179,520 @@ function generateDevToolsHtml(isDev, ctx = {}) {
1313
1179
  }
1314
1180
 
1315
1181
  // server/error-pages.ts
1182
+ function escapeHtml2(str) {
1183
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1184
+ }
1316
1185
  function generate404Page(pathname = "/") {
1317
1186
  return `<!DOCTYPE html>
1318
1187
  <html lang="en">
1319
1188
  <head>
1320
1189
  <meta charset="UTF-8">
1321
1190
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1322
- <title>404 - Page Not Found | Velix v5</title>
1191
+ <title>404 - Page Not Found | Velix v${VERSION}</title>
1323
1192
  <link rel="icon" href="/favicon.webp">
1324
1193
  <style>
1325
- * { margin: 0; padding: 0; box-sizing: border-box; }
1326
- body {
1327
- margin: 0;
1328
- background: linear-gradient(135deg, #0F172A 0%, #1E293B 100%);
1329
- color: white;
1330
- font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
1331
- display: flex;
1332
- align-items: center;
1333
- justify-content: center;
1334
- min-height: 100vh;
1335
- text-align: center;
1336
- overflow: hidden;
1337
- }
1338
- .container {
1339
- max-width: 700px;
1340
- padding: 60px 40px;
1341
- position: relative;
1342
- z-index: 10;
1343
- }
1344
- .bg-pattern {
1345
- position: absolute;
1346
- inset: 0;
1347
- background-image: radial-gradient(circle at 20% 50%, rgba(34, 211, 238, 0.1) 0%, transparent 50%),
1348
- radial-gradient(circle at 80% 80%, rgba(37, 99, 235, 0.1) 0%, transparent 50%);
1349
- z-index: 1;
1350
- }
1351
- h1 {
1352
- font-size: 180px;
1353
- font-weight: 900;
1354
- margin: 0;
1355
- background: linear-gradient(135deg, #22D3EE 0%, #2563EB 100%);
1356
- -webkit-background-clip: text;
1357
- -webkit-text-fill-color: transparent;
1358
- line-height: 1;
1359
- letter-spacing: -0.05em;
1360
- animation: fadeInUp 0.6s ease-out;
1361
- }
1362
- h2 {
1363
- font-size: 36px;
1364
- font-weight: 800;
1365
- margin: 30px 0 15px;
1366
- color: #F8FAFC;
1367
- animation: fadeInUp 0.6s ease-out 0.1s backwards;
1194
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
1195
+ body {
1196
+ background: #0a0a0a;
1197
+ color: #ededed;
1198
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
1199
+ display: flex;
1200
+ align-items: center;
1201
+ justify-content: center;
1202
+ min-height: 100vh;
1203
+ -webkit-font-smoothing: antialiased;
1368
1204
  }
1369
- p {
1370
- color: #94A3B8;
1371
- font-size: 18px;
1372
- line-height: 1.7;
1373
- margin-bottom: 40px;
1374
- animation: fadeInUp 0.6s ease-out 0.2s backwards;
1205
+ .container {
1206
+ display: flex;
1207
+ align-items: center;
1208
+ gap: 32px;
1209
+ padding: 32px;
1375
1210
  }
1376
- code {
1377
- background: rgba(255,255,255,0.1);
1378
- padding: 4px 10px;
1379
- border-radius: 6px;
1380
- font-family: 'Fira Code', 'Courier New', monospace;
1381
- color: #22D3EE;
1382
- font-size: 16px;
1383
- border: 1px solid rgba(34, 211, 238, 0.2);
1211
+ .code {
1212
+ font-size: 48px;
1213
+ font-weight: 700;
1214
+ line-height: 1;
1215
+ color: #fff;
1216
+ border-right: 1px solid rgba(255,255,255,0.15);
1217
+ padding-right: 32px;
1384
1218
  }
1385
- .btn-group {
1386
- display: flex;
1387
- gap: 16px;
1388
- justify-content: center;
1389
- flex-wrap: wrap;
1390
- animation: fadeInUp 0.6s ease-out 0.3s backwards;
1219
+ .body h1 {
1220
+ font-size: 18px;
1221
+ font-weight: 600;
1222
+ color: #ededed;
1223
+ margin-bottom: 8px;
1391
1224
  }
1392
- .btn {
1393
- display: inline-block;
1394
- background: linear-gradient(135deg, #2563EB 0%, #1D4ED8 100%);
1395
- color: white;
1396
- text-decoration: none;
1397
- padding: 14px 36px;
1398
- border-radius: 12px;
1399
- font-weight: 600;
1400
- font-size: 16px;
1401
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1402
- box-shadow: 0 10px 30px rgba(37, 99, 235, 0.3);
1403
- border: none;
1404
- cursor: pointer;
1225
+ .body p {
1226
+ font-size: 14px;
1227
+ color: #888;
1228
+ margin-bottom: 20px;
1405
1229
  }
1406
- .btn:hover {
1407
- transform: translateY(-2px);
1408
- box-shadow: 0 15px 40px rgba(37, 99, 235, 0.4);
1230
+ .body p code {
1231
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1232
+ font-size: 13px;
1233
+ background: rgba(255,255,255,0.07);
1234
+ padding: 2px 6px;
1235
+ border-radius: 4px;
1236
+ color: #ccc;
1409
1237
  }
1410
- .btn-outline {
1411
- background: transparent;
1412
- color: #22D3EE;
1413
- border: 2px solid #22D3EE;
1414
- box-shadow: none;
1238
+ .actions { display: flex; gap: 10px; }
1239
+ .btn {
1240
+ display: inline-block;
1241
+ padding: 8px 18px;
1242
+ border-radius: 8px;
1243
+ font-size: 14px;
1244
+ font-weight: 500;
1245
+ text-decoration: none;
1246
+ transition: all .15s;
1247
+ border: 1px solid transparent;
1415
1248
  }
1416
- .btn-outline:hover {
1417
- background: rgba(34, 211, 238, 0.1);
1418
- box-shadow: 0 10px 30px rgba(34, 211, 238, 0.2);
1249
+ .btn-primary {
1250
+ background: #fff;
1251
+ color: #000;
1419
1252
  }
1420
- @keyframes fadeInUp {
1421
- from {
1422
- opacity: 0;
1423
- transform: translateY(30px);
1424
- }
1425
- to {
1426
- opacity: 1;
1427
- transform: translateY(0);
1428
- }
1253
+ .btn-primary:hover { background: #e5e5e5; }
1254
+ .btn-secondary {
1255
+ background: rgba(255,255,255,0.06);
1256
+ color: #ededed;
1257
+ border-color: rgba(255,255,255,0.1);
1429
1258
  }
1259
+ .btn-secondary:hover { background: rgba(255,255,255,0.1); }
1430
1260
  </style>
1431
1261
  </head>
1432
1262
  <body>
1433
- <div class="bg-pattern"></div>
1434
1263
  <div class="container">
1435
- <h1>404</h1>
1436
- <h2>Page Not Found</h2>
1437
- <p>The page <code>${pathname}</code> could not be found.<br>It may have been moved or deleted.</p>
1438
- <div class="btn-group">
1439
- <a href="/" class="btn">Return Home</a>
1440
- <a href="javascript:history.back()" class="btn btn-outline">Go Back</a>
1264
+ <div class="code">404</div>
1265
+ <div class="body">
1266
+ <h1>This page could not be found</h1>
1267
+ <p>The path <code>${escapeHtml2(pathname)}</code> does not exist.</p>
1268
+ <div class="actions">
1269
+ <a href="/" class="btn btn-primary">Return Home</a>
1270
+ <a href="javascript:history.back()" class="btn btn-secondary">Go Back</a>
1271
+ </div>
1441
1272
  </div>
1442
1273
  </div>
1443
1274
  </body>
1444
1275
  </html>`;
1445
1276
  }
1446
1277
  function generate500Page(options) {
1447
- const { title, message, stack, isDev, pathname } = options;
1448
- let callStackCards = "";
1449
- let frameCount = 0;
1278
+ const { message, stack, isDev, pathname } = options;
1279
+ let frames = [];
1280
+ let sourceSnippet = "";
1281
+ let errorLine = 0;
1282
+ let errorFile = "";
1450
1283
  if (isDev && stack) {
1451
- const stackLines = stack.split("\n").filter((line) => line.trim());
1452
- const frames = stackLines.slice(1).filter((line) => line.includes("at "));
1453
- frameCount = frames.length;
1454
- callStackCards = frames.map((frame, index) => {
1455
- const match = frame.match(/at\s+(.+?)\s+\((.+?)\)/) || frame.match(/at\s+(.+)/);
1456
- if (match) {
1457
- const funcName = match[1] || "anonymous";
1458
- const location = match[2] || match[1];
1459
- return `
1460
- <div class="error-card" data-frame="${index}">
1461
- <div class="card-header">
1462
- <div class="card-title">${funcName.trim()}</div>
1463
- <div class="card-number">${index + 1}</div>
1464
- </div>
1465
- <div class="card-location">${location.trim()}</div>
1466
- </div>
1467
- `;
1284
+ const stackLines = stack.split("\n").filter((l) => l.trim());
1285
+ frames = stackLines.slice(1).filter((line) => line.includes("at ")).map((frame) => {
1286
+ const m1 = frame.match(/at\s+(.+?)\s+\((.+?):(\d+):\d+\)/);
1287
+ if (m1) return { call: m1[1].trim(), file: m1[2], line: parseInt(m1[3], 10) };
1288
+ const m2 = frame.match(/at\s+(.+?):(\d+):\d+/);
1289
+ if (m2) return { call: "(anonymous)", file: m2[1].trim(), line: parseInt(m2[2], 10) };
1290
+ return { call: frame.replace(/^\s*at\s+/, "").trim(), file: "", line: null };
1291
+ });
1292
+ const firstUserFrame = frames.find((f) => f.file && !f.file.includes("node_modules")) || frames[0];
1293
+ if (firstUserFrame) {
1294
+ errorFile = firstUserFrame.file;
1295
+ errorLine = firstUserFrame.line || 0;
1296
+ if (errorFile && errorLine > 0) {
1297
+ try {
1298
+ const fs4 = __require("fs");
1299
+ if (fs4.existsSync(errorFile)) {
1300
+ const src = fs4.readFileSync(errorFile, "utf-8").split("\n");
1301
+ const start = Math.max(0, errorLine - 4);
1302
+ const end = Math.min(src.length, errorLine + 3);
1303
+ sourceSnippet = src.slice(start, end).map((l, i) => {
1304
+ const num = start + i + 1;
1305
+ const isErr = num === errorLine;
1306
+ const numStr = String(num).padStart(3, " ");
1307
+ if (isErr) {
1308
+ return `<div class="src-line src-err"><span class="ln">${numStr}</span>${escapeHtml2(l)}</div>`;
1309
+ }
1310
+ return `<div class="src-line"><span class="ln">${numStr}</span>${escapeHtml2(l)}</div>`;
1311
+ }).join("");
1312
+ }
1313
+ } catch (_) {
1314
+ }
1468
1315
  }
1469
- return "";
1470
- }).join("");
1316
+ }
1317
+ }
1318
+ const userFrames = frames.filter((f) => f.file && !f.file.includes("node_modules"));
1319
+ const ignoredFrames = frames.filter((f) => !f.file || f.file.includes("node_modules"));
1320
+ const shortFile = errorFile.replace(/\\/g, "/").replace(/.*\/(?=app\/|server\/|src\/|pages\/)/, "");
1321
+ if (!isDev) {
1322
+ return `<!DOCTYPE html>
1323
+ <html lang="en">
1324
+ <head>
1325
+ <meta charset="UTF-8">
1326
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1327
+ <title>500 - Internal Server Error | Velix</title>
1328
+ <link rel="icon" href="/favicon.webp">
1329
+ <style>
1330
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
1331
+ body {
1332
+ background: #0a0a0a;
1333
+ color: #ededed;
1334
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
1335
+ display: flex; align-items: center; justify-content: center;
1336
+ min-height: 100vh;
1337
+ -webkit-font-smoothing: antialiased;
1338
+ }
1339
+ .container { display: flex; align-items: center; gap: 32px; padding: 32px; }
1340
+ .code { font-size: 48px; font-weight: 700; color: #fff; border-right: 1px solid rgba(255,255,255,0.15); padding-right: 32px; }
1341
+ .body h1 { font-size: 18px; font-weight: 600; color: #ededed; margin-bottom: 8px; }
1342
+ .body p { font-size: 14px; color: #888; margin-bottom: 20px; }
1343
+ .btn { display: inline-block; padding: 8px 18px; border-radius: 8px; font-size: 14px; font-weight: 500; text-decoration: none; background: #fff; color: #000; transition: all .15s; }
1344
+ .btn:hover { background: #e5e5e5; }
1345
+ </style>
1346
+ </head>
1347
+ <body>
1348
+ <div class="container">
1349
+ <div class="code">500</div>
1350
+ <div class="body">
1351
+ <h1>Internal Server Error</h1>
1352
+ <p>A server-side exception has occurred. Please try again later.</p>
1353
+ <a href="/" class="btn">Return Home</a>
1354
+ </div>
1355
+ </div>
1356
+ </body>
1357
+ </html>`;
1471
1358
  }
1472
1359
  return `<!DOCTYPE html>
1473
1360
  <html lang="en">
1474
1361
  <head>
1475
1362
  <meta charset="UTF-8">
1476
1363
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1477
- <title>Error | Velix v5</title>
1364
+ <title>Error | Velix v${VERSION}</title>
1478
1365
  <link rel="icon" href="/favicon.webp">
1479
1366
  <style>
1480
- * { margin: 0; padding: 0; box-sizing: border-box; }
1481
- body {
1482
- margin: 0;
1483
- background: linear-gradient(135deg, #0F172A 0%, #1E293B 100%);
1484
- color: #F8FAFC;
1485
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1367
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
1368
+
1369
+ body {
1370
+ background: rgba(0, 0, 0, 0.85);
1371
+ color: #ededed;
1372
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
1486
1373
  min-height: 100vh;
1487
- overflow-x: hidden;
1374
+ display: flex;
1375
+ align-items: center;
1376
+ justify-content: center;
1377
+ padding: 24px;
1378
+ -webkit-font-smoothing: antialiased;
1488
1379
  }
1489
- .container {
1490
- max-width: 900px;
1491
- margin: 0 auto;
1492
- padding: 40px 20px;
1380
+
1381
+ /* \u2500\u2500 Overlay Card \u2500\u2500 */
1382
+ .overlay {
1383
+ width: 100%;
1384
+ max-width: 940px;
1385
+ background: #111;
1386
+ border: 1px solid #2a2a2a;
1387
+ border-radius: 12px;
1388
+ box-shadow: 0 24px 64px rgba(0,0,0,0.6);
1389
+ overflow: hidden;
1390
+ display: flex;
1391
+ flex-direction: column;
1392
+ max-height: calc(100vh - 48px);
1493
1393
  }
1494
- .error-header {
1495
- background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%);
1496
- color: white;
1497
- padding: 20px 28px;
1498
- border-radius: 16px;
1394
+
1395
+ /* \u2500\u2500 Header Bar \u2500\u2500 */
1396
+ .header {
1499
1397
  display: flex;
1500
1398
  align-items: center;
1501
- gap: 14px;
1502
- margin-bottom: 28px;
1503
- font-size: 18px;
1504
- font-weight: 700;
1505
- box-shadow: 0 10px 40px rgba(239, 68, 68, 0.3);
1506
- }
1507
- .error-header svg {
1508
- width: 24px;
1509
- height: 24px;
1399
+ justify-content: space-between;
1400
+ padding: 12px 20px;
1401
+ background: #161616;
1402
+ border-bottom: 1px solid #2a2a2a;
1403
+ gap: 12px;
1510
1404
  flex-shrink: 0;
1511
1405
  }
1512
- .error-badge {
1513
- display: inline-block;
1514
- background: linear-gradient(135deg, #1E40AF 0%, #1E3A8A 100%);
1515
- color: #60A5FA;
1516
- padding: 6px 16px;
1517
- border-radius: 8px;
1406
+ .header-left {
1407
+ display: flex;
1408
+ align-items: center;
1409
+ gap: 8px;
1518
1410
  font-size: 13px;
1519
- font-weight: 700;
1520
- margin-bottom: 18px;
1521
- text-transform: uppercase;
1522
- letter-spacing: 0.8px;
1523
- box-shadow: 0 4px 12px rgba(30, 64, 175, 0.3);
1524
- }
1525
- .route-badge {
1526
- background: linear-gradient(135deg, #0C4A6E 0%, #075985 100%);
1527
- color: #22D3EE;
1528
- padding: 10px 18px;
1529
- border-radius: 10px;
1530
- font-size: 14px;
1531
- margin-bottom: 24px;
1532
- font-family: 'Courier New', monospace;
1533
- box-shadow: 0 4px 12px rgba(12, 74, 110, 0.3);
1534
- border: 1px solid rgba(34, 211, 238, 0.2);
1535
- }
1536
- .error-message {
1537
- background: rgba(239, 68, 68, 0.1);
1538
- border-left: 4px solid #EF4444;
1539
- padding: 18px 20px;
1540
- border-radius: 10px;
1541
- margin-bottom: 32px;
1542
- }
1543
- .error-message-text {
1544
- color: #FCA5A5;
1545
- font-size: 16px;
1546
- font-weight: 600;
1547
- line-height: 1.6;
1548
- font-family: 'Courier New', monospace;
1411
+ color: #888;
1549
1412
  }
1550
- .stack-section {
1551
- margin-top: 32px;
1413
+ .counter-badge {
1414
+ background: #1e1e1e;
1415
+ border: 1px solid #333;
1416
+ border-radius: 6px;
1417
+ padding: 2px 8px;
1418
+ font-size: 12px;
1419
+ color: #999;
1420
+ font-variant-numeric: tabular-nums;
1552
1421
  }
1553
- .stack-header {
1422
+ .nav-btn {
1423
+ background: #1e1e1e;
1424
+ border: 1px solid #333;
1425
+ border-radius: 6px;
1426
+ color: #888;
1427
+ cursor: pointer;
1428
+ width: 24px;
1429
+ height: 24px;
1554
1430
  display: flex;
1555
1431
  align-items: center;
1556
- justify-content: space-between;
1557
- margin-bottom: 20px;
1432
+ justify-content: center;
1433
+ font-size: 13px;
1434
+ transition: all .15s;
1558
1435
  }
1559
- .stack-title {
1560
- font-size: 18px;
1561
- font-weight: 700;
1562
- color: #F1F5F9;
1436
+ .nav-btn:hover:not(:disabled) { background: #2a2a2a; color: #fff; }
1437
+ .nav-btn:disabled { opacity: 0.3; cursor: default; }
1438
+ .framework-tag {
1563
1439
  display: flex;
1564
1440
  align-items: center;
1565
- gap: 10px;
1441
+ gap: 6px;
1442
+ font-size: 12px;
1443
+ color: #666;
1566
1444
  }
1567
- .frame-counter {
1568
- background: linear-gradient(135deg, #1F2937 0%, #111827 100%);
1569
- color: #22D3EE;
1570
- padding: 6px 14px;
1571
- border-radius: 8px;
1572
- font-size: 13px;
1445
+ .framework-tag::before {
1446
+ content: '';
1447
+ display: inline-block;
1448
+ width: 6px; height: 6px;
1449
+ border-radius: 50%;
1450
+ background: #3b82f6;
1451
+ }
1452
+
1453
+ /* \u2500\u2500 Scrollable Content \u2500\u2500 */
1454
+ .content {
1455
+ overflow-y: auto;
1456
+ flex: 1;
1457
+ }
1458
+
1459
+ /* \u2500\u2500 Error Summary \u2500\u2500 */
1460
+ .error-summary {
1461
+ padding: 28px 24px 20px;
1462
+ border-bottom: 1px solid #1e1e1e;
1463
+ }
1464
+ .error-label {
1465
+ display: inline-flex;
1466
+ align-items: center;
1467
+ gap: 6px;
1468
+ font-size: 11px;
1573
1469
  font-weight: 700;
1574
- border: 1px solid rgba(34, 211, 238, 0.2);
1470
+ letter-spacing: 0.08em;
1471
+ text-transform: uppercase;
1472
+ color: #f87171;
1473
+ background: rgba(248, 113, 113, 0.1);
1474
+ border: 1px solid rgba(248, 113, 113, 0.25);
1475
+ padding: 3px 8px;
1476
+ border-radius: 4px;
1477
+ margin-bottom: 14px;
1575
1478
  }
1576
- .error-card {
1577
- background: linear-gradient(135deg, #1E293B 0%, #0F172A 100%);
1578
- border: 1px solid rgba(34, 211, 238, 0.2);
1579
- border-radius: 14px;
1580
- padding: 20px;
1581
- margin-bottom: 12px;
1582
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1583
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
1584
- display: none;
1479
+ .error-label svg { width: 10px; height: 10px; fill: currentColor; }
1480
+ .error-message {
1481
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1482
+ font-size: 18px;
1483
+ font-weight: 600;
1484
+ line-height: 1.5;
1485
+ color: #fff;
1486
+ word-break: break-word;
1585
1487
  }
1586
- .error-card.active {
1587
- display: block;
1588
- animation: slideIn 0.3s ease-out;
1488
+ .error-location {
1489
+ margin-top: 10px;
1490
+ font-size: 13px;
1491
+ color: #888;
1589
1492
  }
1590
- .error-card:hover {
1591
- border-color: rgba(34, 211, 238, 0.5);
1592
- box-shadow: 0 8px 24px rgba(34, 211, 238, 0.2);
1593
- transform: translateY(-2px);
1493
+ .error-location strong { color: #ccc; }
1494
+
1495
+ /* \u2500\u2500 Source Block \u2500\u2500 */
1496
+ .source-block {
1497
+ border-bottom: 1px solid #1e1e1e;
1594
1498
  }
1595
- .card-header {
1499
+ .source-topbar {
1596
1500
  display: flex;
1597
- justify-content: space-between;
1598
1501
  align-items: center;
1599
- margin-bottom: 12px;
1600
- }
1601
- .card-title {
1602
- color: #22D3EE;
1603
- font-size: 15px;
1604
- font-weight: 700;
1605
- font-family: 'Courier New', monospace;
1606
- }
1607
- .card-number {
1608
- background: rgba(34, 211, 238, 0.2);
1609
- color: #22D3EE;
1610
- padding: 4px 10px;
1611
- border-radius: 6px;
1502
+ padding: 10px 16px;
1503
+ background: #161616;
1504
+ border-bottom: 1px solid #1e1e1e;
1505
+ gap: 8px;
1612
1506
  font-size: 12px;
1613
- font-weight: 700;
1507
+ color: #666;
1614
1508
  }
1615
- .card-location {
1616
- color: #94A3B8;
1509
+ .source-topbar .filepath { color: #aaa; font-family: ui-monospace, monospace; }
1510
+ .source-code {
1511
+ background: #0d0d0d;
1512
+ overflow-x: auto;
1513
+ padding: 10px 0;
1514
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1617
1515
  font-size: 13px;
1618
- font-family: 'Courier New', monospace;
1619
- word-break: break-all;
1620
- line-height: 1.6;
1516
+ line-height: 1.7;
1621
1517
  }
1622
- .pagination {
1518
+ .src-line {
1623
1519
  display: flex;
1624
- justify-content: center;
1625
- align-items: center;
1626
- gap: 12px;
1627
- margin-top: 24px;
1520
+ align-items: flex-start;
1521
+ padding: 0 20px;
1522
+ white-space: pre;
1523
+ color: #555;
1628
1524
  }
1629
- .pagination-btn {
1630
- background: linear-gradient(135deg, #1E293B 0%, #0F172A 100%);
1631
- border: 1px solid rgba(34, 211, 238, 0.3);
1632
- color: #22D3EE;
1633
- padding: 10px 20px;
1634
- border-radius: 10px;
1635
- font-size: 14px;
1636
- font-weight: 600;
1637
- cursor: pointer;
1638
- transition: all 0.2s;
1525
+ .src-line .ln {
1526
+ color: #3a3a3a;
1527
+ text-align: right;
1528
+ width: 36px;
1529
+ margin-right: 16px;
1530
+ flex-shrink: 0;
1531
+ user-select: none;
1639
1532
  }
1640
- .pagination-btn:hover:not(:disabled) {
1641
- background: linear-gradient(135deg, #22D3EE 0%, #06B6D4 100%);
1642
- color: #0F172A;
1643
- transform: translateY(-2px);
1644
- box-shadow: 0 6px 20px rgba(34, 211, 238, 0.4);
1533
+ .src-err {
1534
+ background: rgba(239, 68, 68, 0.08);
1535
+ color: #fca5a5;
1536
+ position: relative;
1645
1537
  }
1646
- .pagination-btn:disabled {
1647
- opacity: 0.3;
1648
- cursor: not-allowed;
1538
+ .src-err .ln { color: #ef4444; }
1539
+ .src-err::before {
1540
+ content: '';
1541
+ position: absolute;
1542
+ left: 0;
1543
+ top: 0; bottom: 0;
1544
+ width: 3px;
1545
+ background: #ef4444;
1649
1546
  }
1650
- .pagination-info {
1651
- color: #94A3B8;
1652
- font-size: 14px;
1653
- font-weight: 600;
1547
+
1548
+ /* \u2500\u2500 Call Stack \u2500\u2500 */
1549
+ .callstack {
1550
+ padding: 20px 24px;
1654
1551
  }
1655
- .footer {
1656
- margin-top: 48px;
1657
- padding-top: 28px;
1658
- border-top: 1px solid rgba(34, 211, 238, 0.2);
1552
+ .callstack-header {
1659
1553
  display: flex;
1660
- justify-content: space-between;
1661
1554
  align-items: center;
1662
- flex-wrap: wrap;
1663
- gap: 20px;
1555
+ justify-content: space-between;
1556
+ margin-bottom: 14px;
1557
+ }
1558
+ .callstack-title {
1559
+ font-size: 13px;
1560
+ font-weight: 600;
1561
+ color: #aaa;
1562
+ text-transform: uppercase;
1563
+ letter-spacing: 0.06em;
1664
1564
  }
1665
- .brand {
1565
+ .ignore-btn {
1566
+ font-size: 12px;
1567
+ color: #555;
1568
+ background: none;
1569
+ border: none;
1570
+ cursor: pointer;
1666
1571
  display: flex;
1667
1572
  align-items: center;
1668
- gap: 10px;
1669
- font-weight: 700;
1670
- color: #22D3EE;
1671
- font-size: 15px;
1573
+ gap: 4px;
1574
+ transition: color .15s;
1672
1575
  }
1673
- .brand img {
1674
- width: 20px;
1675
- height: 20px;
1676
- }
1677
- .footer-links {
1678
- display: flex;
1679
- gap: 24px;
1680
- flex-wrap: wrap;
1576
+ .ignore-btn:hover { color: #aaa; }
1577
+ .ignore-caret { transition: transform .2s; }
1578
+ .ignore-btn.open .ignore-caret { transform: rotate(90deg); }
1579
+
1580
+ .frame {
1581
+ padding: 10px 12px;
1582
+ border-radius: 6px;
1583
+ margin-bottom: 4px;
1584
+ font-size: 13px;
1585
+ cursor: default;
1681
1586
  }
1682
- .footer-links a {
1683
- color: #60A5FA;
1684
- text-decoration: none;
1587
+ .frame:hover { background: rgba(255,255,255,0.03); }
1588
+ .frame-call {
1589
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1685
1590
  font-weight: 600;
1686
- transition: all 0.2s;
1687
- font-size: 14px;
1591
+ color: #e2e8f0;
1592
+ margin-bottom: 3px;
1688
1593
  }
1689
- .footer-links a:hover {
1690
- color: #22D3EE;
1691
- transform: translateY(-1px);
1692
- }
1693
- .no-stack {
1694
- background: rgba(239, 68, 68, 0.1);
1695
- border: 1px solid rgba(239, 68, 68, 0.3);
1696
- border-radius: 12px;
1697
- padding: 32px;
1698
- color: #FCA5A5;
1699
- text-align: center;
1700
- font-size: 15px;
1701
- }
1702
- @keyframes slideIn {
1703
- from {
1704
- opacity: 0;
1705
- transform: translateY(10px);
1706
- }
1707
- to {
1708
- opacity: 1;
1709
- transform: translateY(0);
1710
- }
1594
+ .frame-loc {
1595
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1596
+ font-size: 12px;
1597
+ color: #555;
1711
1598
  }
1599
+ .frame.ignored .frame-call { color: #444; }
1600
+
1601
+ .ignored-section { margin-top: 8px; display: none; }
1602
+ .ignored-section.open { display: block; }
1712
1603
  </style>
1713
1604
  </head>
1714
1605
  <body>
1715
- <div class="container">
1716
- <div class="error-header">
1717
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
1718
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
1719
- </svg>
1720
- <span>Unhandled Runtime Error</span>
1606
+ <div class="overlay">
1607
+
1608
+ <!-- Header bar -->
1609
+ <div class="header">
1610
+ <div class="header-left">
1611
+ <button class="nav-btn" disabled>\u2039</button>
1612
+ <span class="counter-badge">1 / 1</span>
1613
+ <button class="nav-btn" disabled>\u203A</button>
1614
+ <span style="margin-left: 4px;">Unhandled Runtime Error</span>
1721
1615
  </div>
1722
-
1723
- <div class="error-badge">SERVER ERROR 500</div>
1724
- ${pathname ? `<div class="route-badge">Route: ${pathname}</div>` : ""}
1725
-
1726
- <div class="error-message">
1727
- <div class="error-message-text">${message}</div>
1616
+ <div class="framework-tag">Velix v${VERSION} \xB7 esbuild</div>
1617
+ </div>
1618
+
1619
+ <!-- Scrollable content -->
1620
+ <div class="content">
1621
+
1622
+ <!-- Error summary -->
1623
+ <div class="error-summary">
1624
+ <div class="error-label">
1625
+ <svg viewBox="0 0 16 16"><path d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zm-.75 3.5a.75.75 0 0 1 1.5 0v4a.75.75 0 0 1-1.5 0v-4zm.75 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5z"/></svg>
1626
+ Runtime Error
1627
+ </div>
1628
+ <div class="error-message">${escapeHtml2(message)}</div>
1629
+ ${pathname ? `<div class="error-location">in <strong>${escapeHtml2(pathname)}</strong></div>` : ""}
1728
1630
  </div>
1729
-
1730
- ${isDev && callStackCards ? `
1731
- <div class="stack-section">
1732
- <div class="stack-header">
1733
- <div class="stack-title">
1734
- <svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1735
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
1736
- </svg>
1737
- Call Stack
1738
- </div>
1739
- <div class="frame-counter">${frameCount}</div>
1740
- </div>
1741
- <div id="error-cards">
1742
- ${callStackCards}
1743
- </div>
1744
- ${frameCount > 1 ? `
1745
- <div class="pagination">
1746
- <button class="pagination-btn" id="prev-btn" onclick="changePage(-1)">
1747
- <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="display:inline;vertical-align:middle;margin-right:4px;">
1748
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
1749
- </svg>
1750
- Previous
1751
- </button>
1752
- <div class="pagination-info">
1753
- <span id="current-page">1</span> / <span id="total-pages">${frameCount}</span>
1754
- </div>
1755
- <button class="pagination-btn" id="next-btn" onclick="changePage(1)">
1756
- Next
1757
- <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="display:inline;vertical-align:middle;margin-left:4px;">
1758
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
1759
- </svg>
1760
- </button>
1761
- </div>
1762
- ` : ""}
1631
+
1632
+ ${sourceSnippet ? `
1633
+ <!-- Source code snippet -->
1634
+ <div class="source-block">
1635
+ <div class="source-topbar">
1636
+ <svg width="12" height="12" fill="none" viewBox="0 0 24 24"><path stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/><polyline stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" points="14 2 14 8 20 8"/></svg>
1637
+ <span class="filepath">${escapeHtml2(shortFile)}${errorLine ? `:${errorLine}` : ""}</span>
1638
+ </div>
1639
+ <div class="source-code">${sourceSnippet}</div>
1763
1640
  </div>
1764
- ` : '<div class="no-stack">An error occurred while processing your request. Please check the server logs for more details.</div>'}
1765
-
1766
- <div class="footer">
1767
- <div class="brand">
1768
- <img src="/__velix/logo.webp" alt="Velix" onerror="this.style.display='none'"/>
1769
- <span>Velix v${VERSION}</span>
1770
- </div>
1771
- <div class="footer-links">
1772
- <a href="/">Home</a>
1773
- <a href="javascript:location.reload()">Reload</a>
1774
- <a href="https://github.com/velix/velix/tree/main/docs" target="_blank">Documentation</a>
1775
- ${isDev ? '<span style="color:#94A3B8;">Development Mode</span>' : ""}
1641
+ ` : ""}
1642
+
1643
+ <!-- Call stack -->
1644
+ <div class="callstack">
1645
+ <div class="callstack-header">
1646
+ <div class="callstack-title">Call Stack</div>
1647
+ ${ignoredFrames.length > 0 ? `
1648
+ <button class="ignore-btn" id="ignoreBtn" onclick="toggleIgnored()">
1649
+ <svg class="ignore-caret" width="12" height="12" viewBox="0 0 12 12" fill="none">
1650
+ <path d="M4.5 3L7.5 6L4.5 9" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
1651
+ </svg>
1652
+ ${ignoredFrames.length} ignored frames
1653
+ </button>
1654
+ ` : ""}
1655
+ </div>
1656
+
1657
+ <!-- User frames -->
1658
+ ${userFrames.map((f) => `
1659
+ <div class="frame">
1660
+ <div class="frame-call">${escapeHtml2(f.call)}</div>
1661
+ <div class="frame-loc">${escapeHtml2(f.file.replace(/\\/g, "/").replace(/.*\/(?=app\/|server\/|src\/|pages\/)/, ""))}${f.line ? `:${f.line}` : ""}</div>
1662
+ </div>
1663
+ `).join("")}
1664
+
1665
+ <!-- Ignored frames -->
1666
+ ${ignoredFrames.length > 0 ? `
1667
+ <div class="ignored-section" id="ignoredSection">
1668
+ ${ignoredFrames.map((f) => `
1669
+ <div class="frame ignored">
1670
+ <div class="frame-call">${escapeHtml2(f.call)}</div>
1671
+ <div class="frame-loc">${escapeHtml2(f.file)}${f.line ? `:${f.line}` : ""}</div>
1776
1672
  </div>
1673
+ `).join("")}
1674
+ </div>
1675
+ ` : ""}
1777
1676
  </div>
1778
- </div>
1779
-
1780
- ${isDev && frameCount > 0 ? `
1677
+
1678
+ </div><!-- /content -->
1679
+ </div><!-- /overlay -->
1680
+
1781
1681
  <script>
1782
- let currentPage = 1;
1783
- const totalPages = ${frameCount};
1784
- const cards = document.querySelectorAll('.error-card');
1785
- const prevBtn = document.getElementById('prev-btn');
1786
- const nextBtn = document.getElementById('next-btn');
1787
- const currentPageSpan = document.getElementById('current-page');
1788
-
1789
- function showPage(page) {
1790
- cards.forEach((card, index) => {
1791
- card.classList.remove('active');
1792
- if (index === page - 1) {
1793
- card.classList.add('active');
1794
- }
1795
- });
1796
-
1797
- currentPage = page;
1798
- currentPageSpan.textContent = page;
1799
-
1800
- if (prevBtn) prevBtn.disabled = page === 1;
1801
- if (nextBtn) nextBtn.disabled = page === totalPages;
1802
- }
1803
-
1804
- function changePage(direction) {
1805
- const newPage = currentPage + direction;
1806
- if (newPage >= 1 && newPage <= totalPages) {
1807
- showPage(newPage);
1808
- }
1809
- }
1810
-
1811
- // Show first page on load
1812
- showPage(1);
1813
-
1814
- // Keyboard navigation
1815
- document.addEventListener('keydown', (e) => {
1816
- if (e.key === 'ArrowLeft') changePage(-1);
1817
- if (e.key === 'ArrowRight') changePage(1);
1818
- });
1682
+ function toggleIgnored() {
1683
+ const btn = document.getElementById('ignoreBtn');
1684
+ const sec = document.getElementById('ignoredSection');
1685
+ if (!btn || !sec) return;
1686
+ const open = sec.classList.toggle('open');
1687
+ btn.classList.toggle('open', open);
1688
+ }
1819
1689
  </script>
1820
- ` : ""}
1821
1690
  </body>
1822
1691
  </html>`;
1823
1692
  }
1824
1693
  function getProjectVersion(dep, projectRoot) {
1825
1694
  try {
1826
- const projectRequire = createRequire(pathToFileURL(path4.join(projectRoot, "package.json")).href);
1695
+ const projectRequire = createRequire(pathToFileURL(path3.join(projectRoot, "package.json")).href);
1827
1696
  return projectRequire(`${dep}/package.json`).version;
1828
1697
  } catch (e) {
1829
1698
  try {
@@ -1868,7 +1737,7 @@ async function createServer(options = {}) {
1868
1737
  await loadPlugins(projectRoot, config);
1869
1738
  await pluginManager.runHook(PluginHooks.CONFIG, config);
1870
1739
  const middlewareFns = await loadMiddleware(projectRoot);
1871
- const appDir = config.resolvedAppDir || path4.join(projectRoot, "app");
1740
+ const appDir = config.resolvedAppDir || path3.join(projectRoot, "app");
1872
1741
  const routes = buildRouteTree(appDir);
1873
1742
  await pluginManager.runHook(PluginHooks.ROUTES_LOADED, routes);
1874
1743
  const startTime = Date.now();
@@ -1902,7 +1771,7 @@ async function createServer(options = {}) {
1902
1771
  return;
1903
1772
  }
1904
1773
  if (pathname === "/__velix/image") {
1905
- const { handleImageOptimization } = await import('./image-optimizer-KPRXE5VI.js');
1774
+ const { handleImageOptimization } = await import('./image-optimizer-QDXS3LHQ.js');
1906
1775
  await handleImageOptimization(req, res, projectRoot);
1907
1776
  return;
1908
1777
  }
@@ -1910,7 +1779,7 @@ async function createServer(options = {}) {
1910
1779
  await serveVelixInternal(pathname, req, res, projectRoot);
1911
1780
  return;
1912
1781
  }
1913
- const publicDir = config.resolvedPublicDir || path4.join(projectRoot, "public");
1782
+ const publicDir = config.resolvedPublicDir || path3.join(projectRoot, "public");
1914
1783
  if (await serveStaticFile(pathname, publicDir, res, isDev)) {
1915
1784
  if (isDev) logger_default.request(req.method || "GET", pathname, 200, Date.now() - requestStart, { type: "static" });
1916
1785
  return;
@@ -1936,7 +1805,6 @@ async function createServer(options = {}) {
1936
1805
  if (!res.headersSent) {
1937
1806
  res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
1938
1807
  res.end(generate500Page({
1939
- title: "Server Error",
1940
1808
  message: err.message || "An unexpected error occurred",
1941
1809
  stack: isDev ? err.stack : void 0,
1942
1810
  isDev,
@@ -1983,22 +1851,22 @@ async function importModuleSSR(filePath) {
1983
1851
  try {
1984
1852
  return await import(`${fileUrl}?t=${Date.now()}`);
1985
1853
  } catch (err) {
1986
- const source = fs4.readFileSync(filePath, "utf-8");
1854
+ const source = fs3.readFileSync(filePath, "utf-8");
1987
1855
  if (source.match(/^import\s+['"][^'"]+\.(css|scss|less|sass)['"];?\s*$/m)) {
1988
1856
  const stripped = source.replace(/^import\s+['"][^'"]+\.(css|scss|less|sass)['"];?\s*$/gm, "// [velix:ssr] css import stripped");
1989
- const ext = path4.extname(filePath);
1857
+ const ext = path3.extname(filePath);
1990
1858
  const tmpPath = filePath.replace(ext, `.__velix_ssr${ext}`);
1991
- fs4.writeFileSync(tmpPath, stripped);
1859
+ fs3.writeFileSync(tmpPath, stripped);
1992
1860
  try {
1993
1861
  const mod = await import(`${pathToFileURL(tmpPath).href}?t=${Date.now()}`);
1994
1862
  try {
1995
- fs4.unlinkSync(tmpPath);
1863
+ fs3.unlinkSync(tmpPath);
1996
1864
  } catch {
1997
1865
  }
1998
1866
  return mod;
1999
1867
  } catch (e2) {
2000
1868
  try {
2001
- fs4.unlinkSync(tmpPath);
1869
+ fs3.unlinkSync(tmpPath);
2002
1870
  } catch {
2003
1871
  }
2004
1872
  throw e2;
@@ -2009,18 +1877,18 @@ async function importModuleSSR(filePath) {
2009
1877
  }
2010
1878
  function collectLayouts(pageFilePath, appDir) {
2011
1879
  const layouts = [];
2012
- const normalizedAppDir = path4.resolve(appDir);
2013
- let current = path4.dirname(path4.resolve(pageFilePath));
1880
+ const normalizedAppDir = path3.resolve(appDir);
1881
+ let current = path3.dirname(path3.resolve(pageFilePath));
2014
1882
  while (true) {
2015
1883
  for (const ext of [".tsx", ".jsx", ".ts", ".js"]) {
2016
- const layoutPath = path4.join(current, `layout${ext}`);
2017
- if (fs4.existsSync(layoutPath)) {
1884
+ const layoutPath = path3.join(current, `layout${ext}`);
1885
+ if (fs3.existsSync(layoutPath)) {
2018
1886
  layouts.unshift(layoutPath);
2019
1887
  break;
2020
1888
  }
2021
1889
  }
2022
- if (path4.resolve(current) === normalizedAppDir) break;
2023
- const parent = path4.dirname(current);
1890
+ if (path3.resolve(current) === normalizedAppDir) break;
1891
+ const parent = path3.dirname(current);
2024
1892
  if (parent === current) break;
2025
1893
  current = parent;
2026
1894
  }
@@ -2040,12 +1908,12 @@ async function renderComponentAsync(Component, props) {
2040
1908
  return element;
2041
1909
  }
2042
1910
  async function serveStaticFile(pathname, publicDir, res, isDev = false) {
2043
- const filePath = path4.join(publicDir, pathname);
1911
+ const filePath = path3.join(publicDir, pathname);
2044
1912
  if (!filePath.startsWith(publicDir)) return false;
2045
- if (!fs4.existsSync(filePath) || fs4.statSync(filePath).isDirectory()) return false;
2046
- const ext = path4.extname(filePath);
1913
+ if (!fs3.existsSync(filePath) || fs3.statSync(filePath).isDirectory()) return false;
1914
+ const ext = path3.extname(filePath);
2047
1915
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
2048
- const content = fs4.readFileSync(filePath);
1916
+ const content = fs3.readFileSync(filePath);
2049
1917
  res.writeHead(200, {
2050
1918
  "Content-Type": contentType,
2051
1919
  "Content-Length": content.length,
@@ -2124,7 +1992,7 @@ async function handlePageRoute(route, routes, req, res, url, config, isDev, proj
2124
1992
  const mod = await import(`${fileUrl}?t=${Date.now()}`);
2125
1993
  const PageComponent = mod.default;
2126
1994
  let metadata = mod.metadata || mod.generateMetadata?.(route.params) || {};
2127
- const appDir = config.resolvedAppDir || path4.join(projectRoot, "app");
1995
+ const appDir = config.resolvedAppDir || path3.join(projectRoot, "app");
2128
1996
  const layoutPaths = collectLayouts(route.filePath, appDir);
2129
1997
  const layoutModules = [];
2130
1998
  for (const lp of layoutPaths) {
@@ -2272,7 +2140,6 @@ async function handlePageRoute(route, routes, req, res, url, config, isDev, proj
2272
2140
  logger_default.error(`Render error: ${route.path}`, error);
2273
2141
  res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
2274
2142
  res.end(generate500Page({
2275
- title: "Render Error",
2276
2143
  message: error.message || "Failed to render page",
2277
2144
  stack: isDev ? error.stack : void 0,
2278
2145
  isDev,
@@ -2298,19 +2165,19 @@ async function serveVelixInternal(pathname, req, res, projectRoot) {
2298
2165
  }
2299
2166
  if (pathname === "/__velix/logo.webp") {
2300
2167
  const __filename2 = fileURLToPath(import.meta.url);
2301
- const __dirname2 = path4.dirname(__filename2);
2168
+ const __dirname2 = path3.dirname(__filename2);
2302
2169
  const candidates = [
2303
- path4.join(__dirname2, "..", "assets", "logo.webp"),
2304
- path4.join(__dirname2, "..", "..", "assets", "logo.webp"),
2305
- path4.join(process.cwd(), "node_modules", "@teamvelix", "velix", "assets", "logo.webp"),
2306
- path4.join(process.cwd(), "packages", "velix", "assets", "logo.webp"),
2307
- path4.join(process.cwd(), "node_modules", "velix", "assets", "logo.webp"),
2308
- path4.join(process.cwd(), "public", "favicon.webp")
2170
+ path3.join(__dirname2, "..", "assets", "logo.webp"),
2171
+ path3.join(__dirname2, "..", "..", "assets", "logo.webp"),
2172
+ path3.join(process.cwd(), "node_modules", "@teamvelix", "velix", "assets", "logo.webp"),
2173
+ path3.join(process.cwd(), "packages", "velix", "assets", "logo.webp"),
2174
+ path3.join(process.cwd(), "node_modules", "velix", "assets", "logo.webp"),
2175
+ path3.join(process.cwd(), "public", "favicon.webp")
2309
2176
  ];
2310
- const logoPath = candidates.find((p) => fs4.existsSync(p));
2177
+ const logoPath = candidates.find((p) => fs3.existsSync(p));
2311
2178
  if (logoPath) {
2312
2179
  res.writeHead(200, { "Content-Type": "image/webp", "Cache-Control": "public, max-age=31536000, immutable" });
2313
- res.end(fs4.readFileSync(logoPath));
2180
+ res.end(fs3.readFileSync(logoPath));
2314
2181
  } else {
2315
2182
  res.writeHead(404);
2316
2183
  res.end();
@@ -2320,11 +2187,11 @@ async function serveVelixInternal(pathname, req, res, projectRoot) {
2320
2187
  if (pathname === "/__velix/hmr-client.js") {
2321
2188
  try {
2322
2189
  const candidates = [
2323
- path4.join(process.cwd(), "packages", "velix-react", "src", "hmr", "hmr-client.ts"),
2324
- path4.join(process.cwd(), "node_modules", "@teamvelix", "velix-react", "src", "hmr", "hmr-client.ts"),
2325
- path4.join(__dirname$1, "..", "..", "velix-react", "src", "hmr", "hmr-client.ts")
2190
+ path3.join(process.cwd(), "packages", "velix-react", "src", "hmr", "hmr-client.ts"),
2191
+ path3.join(process.cwd(), "node_modules", "@teamvelix", "velix-react", "src", "hmr", "hmr-client.ts"),
2192
+ path3.join(__dirname$1, "..", "..", "velix-react", "src", "hmr", "hmr-client.ts")
2326
2193
  ];
2327
- const hmrClientSrc = candidates.find((p) => fs4.existsSync(p));
2194
+ const hmrClientSrc = candidates.find((p) => fs3.existsSync(p));
2328
2195
  if (!hmrClientSrc) {
2329
2196
  res.writeHead(404);
2330
2197
  res.end();
@@ -2353,17 +2220,17 @@ async function serveVelixInternal(pathname, req, res, projectRoot) {
2353
2220
  const componentName = pathname.replace("/__velix/islands/", "").replace(".js", "");
2354
2221
  try {
2355
2222
  const searchDirs = [
2356
- path4.join(projectRoot, "components"),
2357
- path4.join(projectRoot, "app"),
2358
- path4.join(projectRoot, "islands")
2223
+ path3.join(projectRoot, "components"),
2224
+ path3.join(projectRoot, "app"),
2225
+ path3.join(projectRoot, "islands")
2359
2226
  ];
2360
2227
  let componentPath = "";
2361
2228
  for (const dir of searchDirs) {
2362
- if (!fs4.existsSync(dir)) continue;
2363
- const files = fs4.readdirSync(dir, { recursive: true });
2229
+ if (!fs3.existsSync(dir)) continue;
2230
+ const files = fs3.readdirSync(dir, { recursive: true });
2364
2231
  const found = files.find((f) => f.replace(/\\/g, "/").endsWith(`${componentName}.tsx`) || f.replace(/\\/g, "/").endsWith(`${componentName}.jsx`));
2365
2232
  if (found) {
2366
- componentPath = path4.join(dir, found);
2233
+ componentPath = path3.join(dir, found);
2367
2234
  break;
2368
2235
  }
2369
2236
  }
@@ -2450,6 +2317,6 @@ function parseRawBody(req) {
2450
2317
  }
2451
2318
  var server_default = { createServer, tailwindPlugin };
2452
2319
 
2453
- export { 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 };
2454
- //# sourceMappingURL=chunk-HGP4TUJS.js.map
2455
- //# sourceMappingURL=chunk-HGP4TUJS.js.map
2320
+ export { RedirectError, bindArgs, callServerAction, composeMiddleware, cookies, createServer, deserializeArgs, executeAction, formAction, generateJsonLd, generateMetadataTags, generateRobotsTxt, generateSitemap, getAction, getMethod, getPathname, headers, html, isMethod, json, jsonLd, loadMiddleware, mergeMetadata, middlewares, notFound, parseFormData, parseJson, parseSearchParams, redirect, registerAction, runMiddleware, serverAction, server_default, tailwindPlugin, text, useActionContext, useVelixAction };
2321
+ //# sourceMappingURL=chunk-HMCBOHTD.js.map
2322
+ //# sourceMappingURL=chunk-HMCBOHTD.js.map