@zhin.js/console 1.0.47 → 1.0.49

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/lib/index.js CHANGED
@@ -2,14 +2,42 @@ import { usePlugin } from '@zhin.js/core';
2
2
  import mime from 'mime';
3
3
  import * as fs from 'fs';
4
4
  import fs__default from 'fs';
5
- import * as path3 from 'path';
6
- import path3__default from 'path';
5
+ import * as path from 'path';
6
+ import path__default from 'path';
7
7
  import WebSocket from 'ws';
8
8
  import { transform } from 'esbuild';
9
9
 
10
10
  // src/index.ts
11
11
  var { root, logger } = usePlugin();
12
12
  var ENV_WHITELIST = [".env", ".env.development", ".env.production"];
13
+ var FILE_MANAGER_ALLOWED = [
14
+ "src",
15
+ "plugins",
16
+ "client",
17
+ "package.json",
18
+ "tsconfig.json",
19
+ "zhin.config.yml",
20
+ ".env",
21
+ ".env.development",
22
+ ".env.production",
23
+ "README.md"
24
+ ];
25
+ var FILE_MANAGER_BLOCKED = /* @__PURE__ */ new Set([
26
+ "node_modules",
27
+ ".git",
28
+ ".env.local",
29
+ "data",
30
+ "lib",
31
+ "dist",
32
+ "coverage"
33
+ ]);
34
+ function isPathAllowed(relativePath) {
35
+ if (relativePath.includes("..") || path__default.isAbsolute(relativePath)) return false;
36
+ const normalized = relativePath.replace(/\\/g, "/").replace(/^\.\//, "");
37
+ const firstSegment = normalized.split("/")[0];
38
+ if (FILE_MANAGER_BLOCKED.has(firstSegment)) return false;
39
+ return FILE_MANAGER_ALLOWED.some((p) => normalized === p || normalized.startsWith(p + "/"));
40
+ }
13
41
  function resolveConfigKey(pluginName) {
14
42
  const schemaService = root.inject("schema");
15
43
  return schemaService?.resolveConfigKey(pluginName) ?? pluginName;
@@ -24,7 +52,7 @@ function getPluginKeys() {
24
52
  return Array.from(keys);
25
53
  }
26
54
  function getConfigFilePath() {
27
- return path3__default.resolve(process.cwd(), "zhin.config.yml");
55
+ return path__default.resolve(process.cwd(), "zhin.config.yml");
28
56
  }
29
57
  function setupWebSocket(webServer) {
30
58
  webServer.ws.on("connection", (ws) => {
@@ -201,7 +229,7 @@ async function handleWebSocketMessage(ws, message, webServer) {
201
229
  const cwd = process.cwd();
202
230
  const files = ENV_WHITELIST.map((name) => ({
203
231
  name,
204
- exists: fs__default.existsSync(path3__default.resolve(cwd, name))
232
+ exists: fs__default.existsSync(path__default.resolve(cwd, name))
205
233
  }));
206
234
  ws.send(JSON.stringify({ requestId, data: { files } }));
207
235
  } catch (error) {
@@ -215,7 +243,7 @@ async function handleWebSocketMessage(ws, message, webServer) {
215
243
  ws.send(JSON.stringify({ requestId, error: `Invalid env file: ${filename}` }));
216
244
  break;
217
245
  }
218
- const envPath = path3__default.resolve(process.cwd(), filename);
246
+ const envPath = path__default.resolve(process.cwd(), filename);
219
247
  const content = fs__default.existsSync(envPath) ? fs__default.readFileSync(envPath, "utf-8") : "";
220
248
  ws.send(JSON.stringify({ requestId, data: { content } }));
221
249
  } catch (error) {
@@ -233,17 +261,420 @@ async function handleWebSocketMessage(ws, message, webServer) {
233
261
  ws.send(JSON.stringify({ requestId, error: "content field is required" }));
234
262
  break;
235
263
  }
236
- const envPath = path3__default.resolve(process.cwd(), filename);
264
+ const envPath = path__default.resolve(process.cwd(), filename);
237
265
  fs__default.writeFileSync(envPath, content, "utf-8");
238
266
  ws.send(JSON.stringify({ requestId, data: { success: true, message: "\u73AF\u5883\u53D8\u91CF\u5DF2\u4FDD\u5B58\uFF0C\u9700\u91CD\u542F\u751F\u6548" } }));
239
267
  } catch (error) {
240
268
  ws.send(JSON.stringify({ requestId, error: `Failed to save env file: ${error.message}` }));
241
269
  }
242
270
  break;
271
+ // ================================================================
272
+ // 文件管理
273
+ // ================================================================
274
+ case "files:tree":
275
+ try {
276
+ const cwd = process.cwd();
277
+ const tree = buildFileTree(cwd, "", FILE_MANAGER_ALLOWED);
278
+ ws.send(JSON.stringify({ requestId, data: { tree } }));
279
+ } catch (error) {
280
+ ws.send(JSON.stringify({ requestId, error: `Failed to build file tree: ${error.message}` }));
281
+ }
282
+ break;
283
+ case "files:read":
284
+ try {
285
+ const { filePath: fp } = message;
286
+ if (!fp || !isPathAllowed(fp)) {
287
+ ws.send(JSON.stringify({ requestId, error: `Access denied: ${fp}` }));
288
+ break;
289
+ }
290
+ const absPath = path__default.resolve(process.cwd(), fp);
291
+ if (!fs__default.existsSync(absPath)) {
292
+ ws.send(JSON.stringify({ requestId, error: `File not found: ${fp}` }));
293
+ break;
294
+ }
295
+ const stat = fs__default.statSync(absPath);
296
+ if (!stat.isFile()) {
297
+ ws.send(JSON.stringify({ requestId, error: `Not a file: ${fp}` }));
298
+ break;
299
+ }
300
+ if (stat.size > 1024 * 1024) {
301
+ ws.send(JSON.stringify({ requestId, error: `File too large: ${(stat.size / 1024).toFixed(0)}KB (max 1MB)` }));
302
+ break;
303
+ }
304
+ const fileContent = fs__default.readFileSync(absPath, "utf-8");
305
+ ws.send(JSON.stringify({ requestId, data: { content: fileContent, size: stat.size } }));
306
+ } catch (error) {
307
+ ws.send(JSON.stringify({ requestId, error: `Failed to read file: ${error.message}` }));
308
+ }
309
+ break;
310
+ case "files:save":
311
+ try {
312
+ const { filePath: fp, content: fileContent } = message;
313
+ if (!fp || !isPathAllowed(fp)) {
314
+ ws.send(JSON.stringify({ requestId, error: `Access denied: ${fp}` }));
315
+ break;
316
+ }
317
+ if (typeof fileContent !== "string") {
318
+ ws.send(JSON.stringify({ requestId, error: "content field is required" }));
319
+ break;
320
+ }
321
+ const absPath = path__default.resolve(process.cwd(), fp);
322
+ const dir = path__default.dirname(absPath);
323
+ if (!fs__default.existsSync(dir)) {
324
+ fs__default.mkdirSync(dir, { recursive: true });
325
+ }
326
+ fs__default.writeFileSync(absPath, fileContent, "utf-8");
327
+ ws.send(JSON.stringify({ requestId, data: { success: true, message: `\u6587\u4EF6\u5DF2\u4FDD\u5B58: ${fp}` } }));
328
+ } catch (error) {
329
+ ws.send(JSON.stringify({ requestId, error: `Failed to save file: ${error.message}` }));
330
+ }
331
+ break;
332
+ // ================================================================
333
+ // 数据库管理
334
+ // ================================================================
335
+ case "db:info":
336
+ try {
337
+ const dbInfo = getDatabaseInfo();
338
+ ws.send(JSON.stringify({ requestId, data: dbInfo }));
339
+ } catch (error) {
340
+ ws.send(JSON.stringify({ requestId, error: `Failed to get db info: ${error.message}` }));
341
+ }
342
+ break;
343
+ case "db:tables":
344
+ try {
345
+ const tables = getDatabaseTables();
346
+ ws.send(JSON.stringify({ requestId, data: { tables } }));
347
+ } catch (error) {
348
+ ws.send(JSON.stringify({ requestId, error: `Failed to list tables: ${error.message}` }));
349
+ }
350
+ break;
351
+ case "db:select":
352
+ try {
353
+ const { table, page = 1, pageSize = 50, where } = message;
354
+ if (!table) {
355
+ ws.send(JSON.stringify({ requestId, error: "table is required" }));
356
+ break;
357
+ }
358
+ const selectResult = await dbSelect(table, page, pageSize, where);
359
+ ws.send(JSON.stringify({ requestId, data: selectResult }));
360
+ } catch (error) {
361
+ ws.send(JSON.stringify({ requestId, error: `Failed to select: ${error.message}` }));
362
+ }
363
+ break;
364
+ case "db:insert":
365
+ try {
366
+ const { table, row } = message;
367
+ if (!table || !row) {
368
+ ws.send(JSON.stringify({ requestId, error: "table and row are required" }));
369
+ break;
370
+ }
371
+ await dbInsert(table, row);
372
+ ws.send(JSON.stringify({ requestId, data: { success: true } }));
373
+ } catch (error) {
374
+ ws.send(JSON.stringify({ requestId, error: `Failed to insert: ${error.message}` }));
375
+ }
376
+ break;
377
+ case "db:update":
378
+ try {
379
+ const { table, row, where: updateWhere } = message;
380
+ if (!table || !row || !updateWhere) {
381
+ ws.send(JSON.stringify({ requestId, error: "table, row, and where are required" }));
382
+ break;
383
+ }
384
+ const affected = await dbUpdate(table, row, updateWhere);
385
+ ws.send(JSON.stringify({ requestId, data: { success: true, affected } }));
386
+ } catch (error) {
387
+ ws.send(JSON.stringify({ requestId, error: `Failed to update: ${error.message}` }));
388
+ }
389
+ break;
390
+ case "db:delete":
391
+ try {
392
+ const { table, where: deleteWhere } = message;
393
+ if (!table || !deleteWhere) {
394
+ ws.send(JSON.stringify({ requestId, error: "table and where are required" }));
395
+ break;
396
+ }
397
+ const deleted = await dbDelete(table, deleteWhere);
398
+ ws.send(JSON.stringify({ requestId, data: { success: true, deleted } }));
399
+ } catch (error) {
400
+ ws.send(JSON.stringify({ requestId, error: `Failed to delete: ${error.message}` }));
401
+ }
402
+ break;
403
+ case "db:drop-table":
404
+ try {
405
+ const { table: dropTableName } = message;
406
+ if (!dropTableName) {
407
+ ws.send(JSON.stringify({ requestId, error: "table is required" }));
408
+ break;
409
+ }
410
+ await dbDropTable(dropTableName);
411
+ ws.send(JSON.stringify({ requestId, data: { success: true } }));
412
+ } catch (error) {
413
+ ws.send(JSON.stringify({ requestId, error: `Failed to drop table: ${error.message}` }));
414
+ }
415
+ break;
416
+ // KV 专用操作
417
+ case "db:kv:get":
418
+ try {
419
+ const { table, key } = message;
420
+ if (!table || !key) {
421
+ ws.send(JSON.stringify({ requestId, error: "table and key are required" }));
422
+ break;
423
+ }
424
+ const kvValue = await kvGet(table, key);
425
+ ws.send(JSON.stringify({ requestId, data: { key, value: kvValue } }));
426
+ } catch (error) {
427
+ ws.send(JSON.stringify({ requestId, error: `Failed to get kv: ${error.message}` }));
428
+ }
429
+ break;
430
+ case "db:kv:set":
431
+ try {
432
+ const { table, key, value, ttl } = message;
433
+ if (!table || !key) {
434
+ ws.send(JSON.stringify({ requestId, error: "table and key are required" }));
435
+ break;
436
+ }
437
+ await kvSet(table, key, value, ttl);
438
+ ws.send(JSON.stringify({ requestId, data: { success: true } }));
439
+ } catch (error) {
440
+ ws.send(JSON.stringify({ requestId, error: `Failed to set kv: ${error.message}` }));
441
+ }
442
+ break;
443
+ case "db:kv:delete":
444
+ try {
445
+ const { table, key } = message;
446
+ if (!table || !key) {
447
+ ws.send(JSON.stringify({ requestId, error: "table and key are required" }));
448
+ break;
449
+ }
450
+ await kvDelete(table, key);
451
+ ws.send(JSON.stringify({ requestId, data: { success: true } }));
452
+ } catch (error) {
453
+ ws.send(JSON.stringify({ requestId, error: `Failed to delete kv: ${error.message}` }));
454
+ }
455
+ break;
456
+ case "db:kv:entries":
457
+ try {
458
+ const { table } = message;
459
+ if (!table) {
460
+ ws.send(JSON.stringify({ requestId, error: "table is required" }));
461
+ break;
462
+ }
463
+ const kvEntries = await kvGetEntries(table);
464
+ ws.send(JSON.stringify({ requestId, data: { entries: kvEntries } }));
465
+ } catch (error) {
466
+ ws.send(JSON.stringify({ requestId, error: `Failed to get entries: ${error.message}` }));
467
+ }
468
+ break;
243
469
  default:
244
470
  ws.send(JSON.stringify({ requestId, error: `Unknown message type: ${type}` }));
245
471
  }
246
472
  }
473
+ function getDb() {
474
+ return root.inject("database");
475
+ }
476
+ function getDbType() {
477
+ const dbFeature = getDb();
478
+ const dialectName = dbFeature.db.dialect.name;
479
+ if (["mongodb"].includes(dialectName)) return "document";
480
+ if (["redis"].includes(dialectName)) return "keyvalue";
481
+ return "related";
482
+ }
483
+ function getDatabaseInfo() {
484
+ const dbFeature = getDb();
485
+ const db = dbFeature.db;
486
+ return {
487
+ dialect: db.dialectName,
488
+ type: getDbType(),
489
+ tables: Array.from(db.models.keys())
490
+ };
491
+ }
492
+ function getDatabaseTables() {
493
+ const dbFeature = getDb();
494
+ const db = dbFeature.db;
495
+ getDbType();
496
+ const tables = [];
497
+ for (const [name] of db.models) {
498
+ const def = db.definitions.get(name);
499
+ tables.push({ name, columns: def ? Object.fromEntries(Object.entries(def).map(([col, colDef]) => [col, colDef])) : void 0 });
500
+ }
501
+ return tables;
502
+ }
503
+ async function dbSelect(table, page, pageSize, where) {
504
+ const dbFeature = getDb();
505
+ const db = dbFeature.db;
506
+ const dbType = getDbType();
507
+ const model = db.models.get(table);
508
+ if (!model) throw new Error(`Table '${table}' not found`);
509
+ if (dbType === "keyvalue") {
510
+ const kvModel = model;
511
+ const allEntries = await kvModel.entries();
512
+ const total2 = allEntries.length;
513
+ const start = (page - 1) * pageSize;
514
+ const rows2 = allEntries.slice(start, start + pageSize).map(([k, v]) => ({ key: k, value: v }));
515
+ return { rows: rows2, total: total2, page, pageSize };
516
+ }
517
+ let selection = model.select();
518
+ if (where && Object.keys(where).length > 0) {
519
+ selection = selection.where(where);
520
+ }
521
+ let total;
522
+ try {
523
+ const countResult = await db.aggregate(table).count("*", "total").where(where || {});
524
+ total = countResult?.[0]?.total ?? 0;
525
+ } catch {
526
+ const all = await model.select();
527
+ total = all.length;
528
+ }
529
+ const offset = (page - 1) * pageSize;
530
+ let query = model.select();
531
+ if (where && Object.keys(where).length > 0) {
532
+ query = query.where(where);
533
+ }
534
+ const rows = await query.limit(pageSize).offset(offset);
535
+ return { rows, total, page, pageSize };
536
+ }
537
+ async function dbInsert(table, row) {
538
+ const dbFeature = getDb();
539
+ const db = dbFeature.db;
540
+ const dbType = getDbType();
541
+ const model = db.models.get(table);
542
+ if (!model) throw new Error(`Table '${table}' not found`);
543
+ if (dbType === "keyvalue") {
544
+ const kvModel = model;
545
+ if (!row.key) throw new Error("key is required for KV insert");
546
+ await kvModel.set(row.key, row.value);
547
+ return;
548
+ }
549
+ if (dbType === "document") {
550
+ await model.create(row);
551
+ return;
552
+ }
553
+ await model.insert(row);
554
+ }
555
+ async function dbUpdate(table, row, where) {
556
+ const dbFeature = getDb();
557
+ const db = dbFeature.db;
558
+ const dbType = getDbType();
559
+ const model = db.models.get(table);
560
+ if (!model) throw new Error(`Table '${table}' not found`);
561
+ if (dbType === "keyvalue") {
562
+ const kvModel = model;
563
+ if (!where.key) throw new Error("key is required for KV update");
564
+ await kvModel.set(where.key, row.value);
565
+ return 1;
566
+ }
567
+ if (dbType === "document") {
568
+ if (where._id) {
569
+ return await model.updateById(where._id, row);
570
+ }
571
+ }
572
+ return await model.update(row).where(where);
573
+ }
574
+ async function dbDelete(table, where) {
575
+ const dbFeature = getDb();
576
+ const db = dbFeature.db;
577
+ const dbType = getDbType();
578
+ const model = db.models.get(table);
579
+ if (!model) throw new Error(`Table '${table}' not found`);
580
+ if (dbType === "keyvalue") {
581
+ const kvModel = model;
582
+ if (!where.key) throw new Error("key is required for KV delete");
583
+ await kvModel.deleteByKey(where.key);
584
+ return 1;
585
+ }
586
+ if (dbType === "document") {
587
+ if (where._id) {
588
+ return await model.deleteById(where._id);
589
+ }
590
+ }
591
+ return await model.delete(where);
592
+ }
593
+ async function dbDropTable(table) {
594
+ const dbFeature = getDb();
595
+ const db = dbFeature.db;
596
+ const model = db.models.get(table);
597
+ if (!model) throw new Error(`Table '${table}' not found`);
598
+ const sql = db.dialect.formatDropTable(table, true);
599
+ await db.query(sql);
600
+ db.models.delete(table);
601
+ db.definitions.delete(table);
602
+ }
603
+ async function kvGet(table, key) {
604
+ const dbFeature = getDb();
605
+ const model = dbFeature.db.models.get(table);
606
+ if (!model) throw new Error(`Bucket '${table}' not found`);
607
+ return await model.get(key);
608
+ }
609
+ async function kvSet(table, key, value, ttl) {
610
+ const dbFeature = getDb();
611
+ const model = dbFeature.db.models.get(table);
612
+ if (!model) throw new Error(`Bucket '${table}' not found`);
613
+ await model.set(key, value, ttl);
614
+ }
615
+ async function kvDelete(table, key) {
616
+ const dbFeature = getDb();
617
+ const model = dbFeature.db.models.get(table);
618
+ if (!model) throw new Error(`Bucket '${table}' not found`);
619
+ await model.deleteByKey(key);
620
+ }
621
+ async function kvGetEntries(table) {
622
+ const dbFeature = getDb();
623
+ const model = dbFeature.db.models.get(table);
624
+ if (!model) throw new Error(`Bucket '${table}' not found`);
625
+ const entries = await model.entries();
626
+ return entries.map(([k, v]) => ({ key: k, value: v }));
627
+ }
628
+ function buildFileTree(cwd, relativePath, allowed) {
629
+ const tree = [];
630
+ path__default.resolve(cwd, relativePath);
631
+ for (const entry of allowed) {
632
+ const entryRelative = entry;
633
+ if (entryRelative.includes("/")) continue;
634
+ const absPath = path__default.resolve(cwd, entry);
635
+ if (!fs__default.existsSync(absPath)) continue;
636
+ const stat = fs__default.statSync(absPath);
637
+ if (stat.isDirectory()) {
638
+ tree.push({
639
+ name: entryRelative,
640
+ path: entry,
641
+ type: "directory",
642
+ children: buildDirectoryTree(cwd, entry, 3)
643
+ });
644
+ } else if (stat.isFile()) {
645
+ tree.push({ name: entryRelative, path: entry, type: "file" });
646
+ }
647
+ }
648
+ return tree.sort((a, b) => {
649
+ if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
650
+ return a.name.localeCompare(b.name);
651
+ });
652
+ }
653
+ function buildDirectoryTree(cwd, relativePath, maxDepth) {
654
+ if (maxDepth <= 0) return [];
655
+ const absDir = path__default.resolve(cwd, relativePath);
656
+ if (!fs__default.existsSync(absDir) || !fs__default.statSync(absDir).isDirectory()) return [];
657
+ const entries = fs__default.readdirSync(absDir, { withFileTypes: true });
658
+ const result = [];
659
+ for (const entry of entries) {
660
+ if (FILE_MANAGER_BLOCKED.has(entry.name) || entry.name.startsWith(".")) continue;
661
+ const childRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
662
+ if (entry.isDirectory()) {
663
+ result.push({
664
+ name: entry.name,
665
+ path: childRelative,
666
+ type: "directory",
667
+ children: buildDirectoryTree(cwd, childRelative, maxDepth - 1)
668
+ });
669
+ } else if (entry.isFile()) {
670
+ result.push({ name: entry.name, path: childRelative, type: "file" });
671
+ }
672
+ }
673
+ return result.sort((a, b) => {
674
+ if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
675
+ return a.name.localeCompare(b.name);
676
+ });
677
+ }
247
678
  function findPluginByConfigKey(rootPlugin, configKey) {
248
679
  for (const child of rootPlugin.children) {
249
680
  if (child.name === configKey || child.name.endsWith(`-${configKey}`) || child.name.includes(configKey)) {
@@ -268,7 +699,7 @@ var cache = /* @__PURE__ */ new Map();
268
699
  var TRANSFORMABLE_EXTS = [".ts", ".tsx", ".jsx"];
269
700
  var RESOLVE_EXTS = [".tsx", ".ts", ".jsx", ".js"];
270
701
  function isTransformable(filePath) {
271
- const ext = path3.extname(filePath).toLowerCase();
702
+ const ext = path.extname(filePath).toLowerCase();
272
703
  return TRANSFORMABLE_EXTS.includes(ext);
273
704
  }
274
705
  var IMPORT_RE = /(?:import|export)\s+.*?\s+from\s+['"]([^'"]+)['"]|import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
@@ -277,14 +708,14 @@ function isRelative(specifier) {
277
708
  return specifier.startsWith("./") || specifier.startsWith("../");
278
709
  }
279
710
  function hasExtension(specifier) {
280
- const base = path3.basename(specifier);
711
+ const base = path.basename(specifier);
281
712
  return base.includes(".") && !base.startsWith(".");
282
713
  }
283
714
  function resolveRelativeImport(specifier, fromFile) {
284
715
  if (!isRelative(specifier)) return specifier;
285
716
  if (hasExtension(specifier)) return specifier;
286
- const dir = path3.dirname(fromFile);
287
- const target = path3.resolve(dir, specifier);
717
+ const dir = path.dirname(fromFile);
718
+ const target = path.resolve(dir, specifier);
288
719
  for (const ext of RESOLVE_EXTS) {
289
720
  if (fs.existsSync(target + ext)) {
290
721
  return specifier + ext;
@@ -292,7 +723,7 @@ function resolveRelativeImport(specifier, fromFile) {
292
723
  }
293
724
  if (fs.existsSync(target) && fs.statSync(target).isDirectory()) {
294
725
  for (const ext of RESOLVE_EXTS) {
295
- if (fs.existsSync(path3.join(target, `index${ext}`))) {
726
+ if (fs.existsSync(path.join(target, `index${ext}`))) {
296
727
  return specifier + `/index${ext}`;
297
728
  }
298
729
  }
@@ -318,7 +749,7 @@ async function transformFile(filePath) {
318
749
  return cached.code;
319
750
  }
320
751
  const source = fs.readFileSync(filePath, "utf-8");
321
- const ext = path3.extname(filePath).toLowerCase();
752
+ const ext = path.extname(filePath).toLowerCase();
322
753
  const loader = ext === ".tsx" ? "tsx" : ext === ".ts" ? "ts" : ext === ".jsx" ? "jsx" : "js";
323
754
  const result = await transform(source, {
324
755
  loader,
@@ -356,10 +787,10 @@ if (enabled) {
356
787
  const genToken = () => Math.random().toString(36).slice(2, 8);
357
788
  const watchedDirs = /* @__PURE__ */ new Set();
358
789
  const watchers = [];
359
- path3.join(import.meta.dirname, "../client");
360
- const distDir = path3.join(import.meta.dirname, "../dist");
790
+ path.join(import.meta.dirname, "../client");
791
+ const distDir = path.join(import.meta.dirname, "../dist");
361
792
  const resolveFile = (name) => {
362
- const distPath = path3.resolve(distDir, name);
793
+ const distPath = path.resolve(distDir, name);
363
794
  if (fs.existsSync(distPath)) return distPath;
364
795
  return null;
365
796
  };
@@ -368,8 +799,8 @@ if (enabled) {
368
799
  addEntry(entry) {
369
800
  const hash = Date.now().toString(16) + Math.random().toString(16).slice(2, 8);
370
801
  const entryFile = typeof entry === "string" ? entry : entry.production;
371
- const dir = path3.dirname(entryFile);
372
- const filename = path3.basename(entryFile);
802
+ const dir = path.dirname(entryFile);
803
+ const filename = path.basename(entryFile);
373
804
  let token;
374
805
  for (const [t, d] of entryBases) {
375
806
  if (d === dir) {
@@ -433,7 +864,7 @@ if (enabled) {
433
864
  return;
434
865
  }
435
866
  }
436
- ctx.type = path3.extname(filename);
867
+ ctx.type = path.extname(filename);
437
868
  ctx.type = mime.getType(filename) || ctx.type;
438
869
  return ctx.body = fs.createReadStream(filename);
439
870
  };
@@ -451,8 +882,8 @@ if (enabled) {
451
882
  ctx.status = 404;
452
883
  return;
453
884
  }
454
- const fullPath = path3.resolve(baseDir, relPath);
455
- const safePfx = baseDir.endsWith(path3.sep) ? baseDir : baseDir + path3.sep;
885
+ const fullPath = path.resolve(baseDir, relPath);
886
+ const safePfx = baseDir.endsWith(path.sep) ? baseDir : baseDir + path.sep;
456
887
  if (!fullPath.startsWith(safePfx) && fullPath !== baseDir) {
457
888
  ctx.status = 403;
458
889
  return;