@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.
- package/dist/build/index.js +3 -3
- package/dist/chunk-BQ4HFLRL.js +16 -0
- package/dist/chunk-BQ4HFLRL.js.map +1 -0
- package/dist/{chunk-HGP4TUJS.js → chunk-HMCBOHTD.js} +472 -605
- package/dist/chunk-HMCBOHTD.js.map +1 -0
- package/dist/{chunk-MLLSS7Y5.js → chunk-RU23OKU5.js} +143 -8
- package/dist/chunk-RU23OKU5.js.map +1 -0
- package/dist/{chunk-3LWUS6AC.js → chunk-YZDIHMDS.js} +7 -3
- package/dist/chunk-YZDIHMDS.js.map +1 -0
- package/dist/client/index.js +1 -1
- package/dist/config.js +1 -1
- package/dist/{image-optimizer-KPRXE5VI.js → image-optimizer-QDXS3LHQ.js} +3 -3
- package/dist/{image-optimizer-KPRXE5VI.js.map → image-optimizer-QDXS3LHQ.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/islands/index.js +1 -1
- package/dist/runtime/start-build.js +164 -21
- package/dist/runtime/start-build.js.map +1 -1
- package/dist/runtime/start-dev.js +425 -416
- package/dist/runtime/start-dev.js.map +1 -1
- package/dist/runtime/start-prod.js +425 -416
- package/dist/runtime/start-prod.js.map +1 -1
- package/dist/server/index.js +3 -3
- package/package.json +3 -3
- package/dist/chunk-3LWUS6AC.js.map +0 -1
- package/dist/chunk-4S5YQJHB.js +0 -11
- package/dist/chunk-4S5YQJHB.js.map +0 -1
- package/dist/chunk-HGP4TUJS.js.map +0 -1
- package/dist/chunk-MLLSS7Y5.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { logger_default, buildRouteTree, matchRoute, VERSION } from './chunk-
|
|
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-
|
|
4
|
+
import { __dirname as __dirname$1, __require } from './chunk-BQ4HFLRL.js';
|
|
5
5
|
import http from 'http';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
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 =
|
|
77
|
-
if (!
|
|
76
|
+
const filePath = path3.join(projectRoot, file);
|
|
77
|
+
if (!fs3.existsSync(filePath)) continue;
|
|
78
78
|
try {
|
|
79
|
-
const { pathToFileURL:
|
|
80
|
-
const url =
|
|
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 (!
|
|
231
|
+
if (!fs3.existsSync(input)) {
|
|
366
232
|
logger_default.warn(`Tailwind input file not found: ${input}`);
|
|
367
233
|
return;
|
|
368
234
|
}
|
|
369
|
-
const outputDir =
|
|
370
|
-
if (!
|
|
371
|
-
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
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
|
|
1191
|
+
<title>404 - Page Not Found | Velix v${VERSION}</title>
|
|
1323
1192
|
<link rel="icon" href="/favicon.webp">
|
|
1324
1193
|
<style>
|
|
1325
|
-
|
|
1326
|
-
body {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
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
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
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
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
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
|
-
.
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
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
|
-
.
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
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
|
-
.
|
|
1407
|
-
|
|
1408
|
-
|
|
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
|
-
.
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
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-
|
|
1417
|
-
background:
|
|
1418
|
-
|
|
1249
|
+
.btn-primary {
|
|
1250
|
+
background: #fff;
|
|
1251
|
+
color: #000;
|
|
1419
1252
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
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
|
-
<
|
|
1436
|
-
<
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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 {
|
|
1448
|
-
let
|
|
1449
|
-
let
|
|
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((
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
const
|
|
1456
|
-
if (
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
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
|
-
|
|
1470
|
-
|
|
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
|
|
1364
|
+
<title>Error | Velix v${VERSION}</title>
|
|
1478
1365
|
<link rel="icon" href="/favicon.webp">
|
|
1479
1366
|
<style>
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
background:
|
|
1484
|
-
color: #
|
|
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
|
-
|
|
1374
|
+
display: flex;
|
|
1375
|
+
align-items: center;
|
|
1376
|
+
justify-content: center;
|
|
1377
|
+
padding: 24px;
|
|
1378
|
+
-webkit-font-smoothing: antialiased;
|
|
1488
1379
|
}
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
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
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
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
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
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
|
-
.
|
|
1513
|
-
display:
|
|
1514
|
-
|
|
1515
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
1551
|
-
|
|
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
|
-
.
|
|
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:
|
|
1557
|
-
|
|
1432
|
+
justify-content: center;
|
|
1433
|
+
font-size: 13px;
|
|
1434
|
+
transition: all .15s;
|
|
1558
1435
|
}
|
|
1559
|
-
.
|
|
1560
|
-
|
|
1561
|
-
|
|
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:
|
|
1441
|
+
gap: 6px;
|
|
1442
|
+
font-size: 12px;
|
|
1443
|
+
color: #666;
|
|
1566
1444
|
}
|
|
1567
|
-
.
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
border-radius:
|
|
1572
|
-
|
|
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
|
-
|
|
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-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
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-
|
|
1587
|
-
|
|
1588
|
-
|
|
1488
|
+
.error-location {
|
|
1489
|
+
margin-top: 10px;
|
|
1490
|
+
font-size: 13px;
|
|
1491
|
+
color: #888;
|
|
1589
1492
|
}
|
|
1590
|
-
.error-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
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
|
-
.
|
|
1499
|
+
.source-topbar {
|
|
1596
1500
|
display: flex;
|
|
1597
|
-
justify-content: space-between;
|
|
1598
1501
|
align-items: center;
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
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
|
-
|
|
1507
|
+
color: #666;
|
|
1614
1508
|
}
|
|
1615
|
-
.
|
|
1616
|
-
|
|
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
|
-
|
|
1619
|
-
word-break: break-all;
|
|
1620
|
-
line-height: 1.6;
|
|
1516
|
+
line-height: 1.7;
|
|
1621
1517
|
}
|
|
1622
|
-
.
|
|
1518
|
+
.src-line {
|
|
1623
1519
|
display: flex;
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1520
|
+
align-items: flex-start;
|
|
1521
|
+
padding: 0 20px;
|
|
1522
|
+
white-space: pre;
|
|
1523
|
+
color: #555;
|
|
1628
1524
|
}
|
|
1629
|
-
.
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
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
|
-
.
|
|
1641
|
-
background:
|
|
1642
|
-
color: #
|
|
1643
|
-
|
|
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
|
-
.
|
|
1647
|
-
|
|
1648
|
-
|
|
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
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1547
|
+
|
|
1548
|
+
/* \u2500\u2500 Call Stack \u2500\u2500 */
|
|
1549
|
+
.callstack {
|
|
1550
|
+
padding: 20px 24px;
|
|
1654
1551
|
}
|
|
1655
|
-
.
|
|
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
|
-
|
|
1663
|
-
|
|
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
|
-
.
|
|
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:
|
|
1669
|
-
|
|
1670
|
-
color: #22D3EE;
|
|
1671
|
-
font-size: 15px;
|
|
1573
|
+
gap: 4px;
|
|
1574
|
+
transition: color .15s;
|
|
1672
1575
|
}
|
|
1673
|
-
.
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
.
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
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
|
-
.
|
|
1683
|
-
|
|
1684
|
-
|
|
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
|
-
|
|
1687
|
-
|
|
1591
|
+
color: #e2e8f0;
|
|
1592
|
+
margin-bottom: 3px;
|
|
1688
1593
|
}
|
|
1689
|
-
.
|
|
1690
|
-
|
|
1691
|
-
|
|
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="
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
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
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
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
|
-
${
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
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
|
-
` :
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
<
|
|
1772
|
-
|
|
1773
|
-
<
|
|
1774
|
-
|
|
1775
|
-
|
|
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
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1677
|
+
|
|
1678
|
+
</div><!-- /content -->
|
|
1679
|
+
</div><!-- /overlay -->
|
|
1680
|
+
|
|
1781
1681
|
<script>
|
|
1782
|
-
|
|
1783
|
-
const
|
|
1784
|
-
const
|
|
1785
|
-
|
|
1786
|
-
const
|
|
1787
|
-
|
|
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(
|
|
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 ||
|
|
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-
|
|
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 ||
|
|
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 =
|
|
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 =
|
|
1857
|
+
const ext = path3.extname(filePath);
|
|
1990
1858
|
const tmpPath = filePath.replace(ext, `.__velix_ssr${ext}`);
|
|
1991
|
-
|
|
1859
|
+
fs3.writeFileSync(tmpPath, stripped);
|
|
1992
1860
|
try {
|
|
1993
1861
|
const mod = await import(`${pathToFileURL(tmpPath).href}?t=${Date.now()}`);
|
|
1994
1862
|
try {
|
|
1995
|
-
|
|
1863
|
+
fs3.unlinkSync(tmpPath);
|
|
1996
1864
|
} catch {
|
|
1997
1865
|
}
|
|
1998
1866
|
return mod;
|
|
1999
1867
|
} catch (e2) {
|
|
2000
1868
|
try {
|
|
2001
|
-
|
|
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 =
|
|
2013
|
-
let current =
|
|
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 =
|
|
2017
|
-
if (
|
|
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 (
|
|
2023
|
-
const parent =
|
|
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 =
|
|
1911
|
+
const filePath = path3.join(publicDir, pathname);
|
|
2044
1912
|
if (!filePath.startsWith(publicDir)) return false;
|
|
2045
|
-
if (!
|
|
2046
|
-
const ext =
|
|
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 =
|
|
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 ||
|
|
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 =
|
|
2168
|
+
const __dirname2 = path3.dirname(__filename2);
|
|
2302
2169
|
const candidates = [
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
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) =>
|
|
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(
|
|
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
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
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) =>
|
|
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
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
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 (!
|
|
2363
|
-
const files =
|
|
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 =
|
|
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 {
|
|
2454
|
-
//# sourceMappingURL=chunk-
|
|
2455
|
-
//# sourceMappingURL=chunk-
|
|
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
|