@bananacool467/authtics-host 0.2.5 → 0.2.7

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/devPanel.js CHANGED
@@ -1,27 +1,119 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useRef } from 'react';
3
- import { ShieldCheck, CircleX, ChevronDown, ChevronUp, Bug, AlertTriangle, Info, ArrowLeft, Wifi, Terminal, Route, Globe, ChevronRight, ChevronLeft, Server, TriangleAlert, Eye, Zap, Power } from 'lucide-react';
4
- function getCallerSource() {
3
+ import { ShieldCheck, Shield, CircleX, ChevronDown, ChevronUp, Bug, AlertTriangle, Info, ArrowLeft, Wifi, Terminal, Route, Globe, ChevronRight, ChevronLeft, Server, Cog, TriangleAlert, Eye, Zap, Power, Check as Tick, CheckCircle2 } from 'lucide-react';
4
+ import { TraceMap, originalPositionFor, sourceContentFor, } from "@jridgewell/trace-mapping";
5
+ export async function mapGeneratedLocation(location) {
5
6
  try {
6
- const stack = new Error().stack ?? '';
7
- const lines = stack.split('\n');
8
- for (let i = 3; i < lines.length; i++) {
9
- const line = lines[i];
10
- if (line.trim() === '')
11
- continue;
12
- const match = line.match(/\(?(https?:\/\/[^)]+)\)?$/) ??
13
- line.match(/at\s+(https?:\/\/\S+)/);
14
- if (match) {
15
- const url = match[1];
16
- const parts = url.replace(/\?.*/, '').split('/');
17
- const file = parts[parts.length - 1];
18
- const colonLine = url.match(/:(\d+):\d+$/);
19
- return colonLine ? `${file.split(':')[0]}:${colonLine[1]}` : file;
7
+ if (!location.file || !location.line || !location.column) {
8
+ return location;
9
+ }
10
+ const response = await fetch(location.file, {
11
+ cache: "no-store",
12
+ });
13
+ if (!response.ok) {
14
+ return location;
15
+ }
16
+ const generatedCode = await response.text();
17
+ const sourceMapReference = generatedCode.match(/\/\/[#@]\s*sourceMappingURL=([^\s]+)/)?.[1];
18
+ if (!sourceMapReference) {
19
+ console.warn("[HostJS] No source map URL found in", location.file);
20
+ return location;
21
+ }
22
+ let sourceMapJson;
23
+ if (sourceMapReference.startsWith("data:")) {
24
+ const commaIndex = sourceMapReference.indexOf(",");
25
+ if (commaIndex === -1)
26
+ return location;
27
+ const metadata = sourceMapReference.slice(0, commaIndex);
28
+ const encodedMap = sourceMapReference.slice(commaIndex + 1);
29
+ if (metadata.includes(";base64")) {
30
+ const binary = atob(encodedMap);
31
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
32
+ sourceMapJson = new TextDecoder().decode(bytes);
33
+ }
34
+ else {
35
+ sourceMapJson = decodeURIComponent(encodedMap);
20
36
  }
21
37
  }
38
+ else {
39
+ const mapUrl = new URL(sourceMapReference, response.url || new URL(location.file, window.location.href).href);
40
+ const mapResponse = await fetch(mapUrl, {
41
+ cache: "no-store",
42
+ credentials: "same-origin",
43
+ });
44
+ if (!mapResponse.ok) {
45
+ console.warn("[HostJS] Could not load source map:", mapUrl.href);
46
+ return location;
47
+ }
48
+ sourceMapJson = await mapResponse.text();
49
+ }
50
+ const sourceMap = JSON.parse(sourceMapJson);
51
+ const traceMap = new TraceMap(sourceMap);
52
+ const original = originalPositionFor(traceMap, {
53
+ line: location.line,
54
+ column: Math.max(0, location.column - 1),
55
+ });
56
+ if (!original.source || !original.line) {
57
+ return location;
58
+ }
59
+ const sourceText = sourceContentFor(traceMap, original.source) ?? "";
60
+ const originalLine = sourceText.split(/\r?\n/)[original.line - 1] ?? "";
61
+ return {
62
+ ...location,
63
+ file: original.source,
64
+ line: original.line,
65
+ column: (original.column ?? 0) + 1,
66
+ sourceText: originalLine,
67
+ mapped: true,
68
+ lines: getApproximateLines(sourceText, original.line),
69
+ };
70
+ }
71
+ catch (error) {
72
+ console.warn("[HostJS] Could not map source location:", error);
73
+ return location;
22
74
  }
23
- catch { }
24
- return '';
75
+ }
76
+ function getCallerSource() {
77
+ const location = parseStackLocation(new Error().stack ?? "");
78
+ if (!location) {
79
+ return "";
80
+ }
81
+ return `${location.file}:${location.line}:${location.column}`;
82
+ }
83
+ function getApproximateLines(source, line) {
84
+ const allLines = source.split(/\r?\n/);
85
+ const start = Math.max(0, line - 2);
86
+ const end = Math.min(allLines.length, line + 1);
87
+ return allLines.slice(start, end).map((text, index) => {
88
+ const lineNumber = start + index + 1;
89
+ return `${lineNumber} | ${text}`;
90
+ });
91
+ }
92
+ function getPreciseMarker(sourceLine, column, length = 1, lineNumber) {
93
+ const safeColumn = Math.min(Math.max(1, column), Math.max(1, sourceLine.length + 1));
94
+ const marker = length > 1
95
+ ? "\u25B2" + "~".repeat(length - 1)
96
+ : "\u25B2";
97
+ return `${String(lineNumber).length ? " ".repeat(String(lineNumber).length) + " " : " "}| ${" ".repeat(safeColumn - 1)}${marker}`;
98
+ }
99
+ function parseStackLocations(stack) {
100
+ const locations = [];
101
+ for (const stackLine of stack.split(/\r?\n/)) {
102
+ const match = stackLine.match(/(?:\(|\s|^)((?:https?:\/\/|file:\/\/|\/|\.\.?\/)[^)\s]+):(\d+):(\d+)\)?$/);
103
+ if (!match)
104
+ continue;
105
+ const [, file, line, column] = match;
106
+ locations.push({
107
+ file: file.replace(/\?.*$/, ""),
108
+ line: Number(line),
109
+ column: Number(column),
110
+ mapped: false,
111
+ });
112
+ }
113
+ return locations;
114
+ }
115
+ function parseStackLocation(stack, skip = 0) {
116
+ return parseStackLocations(stack)[skip];
25
117
  }
26
118
  const LOG_TYPES = ['Log', 'Info', 'Warn', 'Error', 'Debug'];
27
119
  let fetchId = 0;
@@ -278,19 +370,87 @@ function installConsoleInterceptor() {
278
370
  if (window.__authtics_intercepted__)
279
371
  return;
280
372
  window.__authtics_intercepted__ = true;
373
+ window.addEventListener("error", event => {
374
+ const error = event.error;
375
+ const stack = error?.stack ?? "";
376
+ const location = stack
377
+ ? parseStackLocation(stack)
378
+ : event.filename
379
+ ? {
380
+ file: event.filename,
381
+ line: event.lineno || 0,
382
+ column: event.colno || 0,
383
+ mapped: false,
384
+ }
385
+ : undefined;
386
+ window.dispatchEvent(new CustomEvent("authtics:log", {
387
+ detail: {
388
+ type: "Error",
389
+ message: error?.message || event.message,
390
+ source: location?.file || "browser",
391
+ stack,
392
+ location,
393
+ time: Date.now(),
394
+ },
395
+ }));
396
+ });
397
+ window.addEventListener("unhandledrejection", event => {
398
+ const reason = event.reason;
399
+ const error = reason instanceof Error
400
+ ? reason
401
+ : new Error(String(reason));
402
+ const stack = error.stack ?? "";
403
+ window.dispatchEvent(new CustomEvent("authtics:log", {
404
+ detail: {
405
+ type: "Error",
406
+ message: error.message,
407
+ source: "unhandledrejection",
408
+ stack,
409
+ location: parseStackLocation(stack),
410
+ time: Date.now(),
411
+ },
412
+ }));
413
+ });
281
414
  LOG_TYPES.forEach(type => {
282
415
  const t = type.toLowerCase();
283
416
  const original = console[t].bind(console);
284
417
  console[t] = (...args) => {
285
418
  original(...args);
286
- window.dispatchEvent(new CustomEvent('authtics:log', {
287
- detail: {
288
- type,
289
- message: args.map(a => typeof a === 'object' ? JSON.stringify(a, null, 2) : String(a)).join(' '),
290
- time: Date.now(),
291
- source: getCallerSource(),
419
+ const errorArgument = args.find(value => value instanceof Error);
420
+ const stack = errorArgument?.stack || new Error().stack || "";
421
+ const generatedLocation = parseStackLocation(stack, errorArgument ? 0 : 1);
422
+ const message = args
423
+ .map(value => {
424
+ if (value instanceof Error) {
425
+ return value.message;
292
426
  }
293
- }));
427
+ if (typeof value === "object") {
428
+ try {
429
+ return JSON.stringify(value, null, 2);
430
+ }
431
+ catch {
432
+ return String(value);
433
+ }
434
+ }
435
+ return String(value);
436
+ })
437
+ .join(" ");
438
+ void mapGeneratedLocation(generatedLocation ?? {
439
+ file: "",
440
+ line: 0,
441
+ column: 0,
442
+ }).then(location => {
443
+ window.dispatchEvent(new CustomEvent("authtics:log", {
444
+ detail: {
445
+ type,
446
+ message,
447
+ time: Date.now(),
448
+ source: location.file || getCallerSource(),
449
+ stack,
450
+ location: location.file ? location : undefined,
451
+ },
452
+ }));
453
+ });
294
454
  };
295
455
  });
296
456
  }
@@ -340,7 +500,7 @@ export default function DevPanel() {
340
500
  const [logs, setLogs] = useState([]);
341
501
  const [open, setOpen] = useState(false);
342
502
  const [errorBoxOpen, setErrorBoxOpen] = useState(false);
343
- const [errorMsgs, setErrorMsgs] = useState([]);
503
+ const [errors, setErrors] = useState([]);
344
504
  const [selectedError, setSelectedError] = useState(1);
345
505
  const [consoleOpen, setConsoleOpen] = useState(false);
346
506
  const [networkOpen, setNetworkOpen] = useState(false);
@@ -349,8 +509,18 @@ export default function DevPanel() {
349
509
  const [clientInfoOpen, setClientInfoOpen] = useState(false);
350
510
  const [aboutHostOpen, setAboutHostOpen] = useState(false);
351
511
  const [serverInfoOpen, setServerInfoOpen] = useState(false);
512
+ const [panelCustomOpen, setPanelCustomOpen] = useState(false);
513
+ const [settingsOpen, setSettingsOpen] = useState(false);
352
514
  const [shutdown, setShutdown] = useState(false);
353
515
  const [shuttingDown, setShuttingDown] = useState(false);
516
+ const [packageSecurityOpen, setPackageSecurityOpen] = useState(false);
517
+ const [highRiskDeps, setHighRiskDeps] = useState([]);
518
+ const [mediumRiskDeps, setMediumRiskDeps] = useState([]);
519
+ const [lowRiskDeps, setLowRiskDeps] = useState([]);
520
+ const [panelColor, setPanelColor] = useState({
521
+ background: '#111',
522
+ border: '#333'
523
+ });
354
524
  const [hasIssue, setHasIssue] = useState(false);
355
525
  const [ping__, setPing__] = useState(0);
356
526
  const [networkFetches, setNetworkFetches] = useState([]);
@@ -363,7 +533,7 @@ export default function DevPanel() {
363
533
  const [hostName, setHostName] = useState(undefined);
364
534
  const [protocol, setProtocol] = useState(undefined);
365
535
  const [path, setPath] = useState(undefined);
366
- const [isSsr, setIsSsr] = useState(false);
536
+ const [renderType, setRenderType] = useState("???");
367
537
  const datRestrictionMissingRef = useRef(true);
368
538
  const cpuUsage = useRef(0);
369
539
  const heapUsage = useRef(0);
@@ -371,7 +541,7 @@ export default function DevPanel() {
371
541
  const [datMatch, setDatMatch] = useState(false);
372
542
  const [compilerType, setCompilerType] = useState("?");
373
543
  const [httpVersion, setHttpVersion] = useState("v?.?");
374
- const [errorBoxOpenable, setErrorBoxOpenable] = useState(false);
544
+ const [errorBoxOpenable, setErrorBoxOpenable] = useState(true);
375
545
  const [uptime, setUptime] = useState("00:00:00:00");
376
546
  const [requests, setRequests] = useState(0);
377
547
  const [hostVersion, setHostVersion] = useState("Loading...");
@@ -379,6 +549,17 @@ export default function DevPanel() {
379
549
  const [token, setToken] = useState(null);
380
550
  const [tokenLength, setTokenLength] = useState(0);
381
551
  const [tokenHidden, setTokenHidden] = useState(true);
552
+ const [locationMode, setLocationMode] = useState("approximate");
553
+ const NOTIFICATION_SLEEP_MS = 10 * 60 * 1000;
554
+ const notificationSleepingUntilRef = useRef(0);
555
+ const [notificationSleepingUntil, setNotificationSleepingUntil] = useState(0);
556
+ const sleepErrorNotifications = () => {
557
+ const until = Date.now() + NOTIFICATION_SLEEP_MS;
558
+ notificationSleepingUntilRef.current = until;
559
+ setNotificationSleepingUntil(until);
560
+ setErrorBoxOpen(false);
561
+ setHasIssue(false);
562
+ };
382
563
  const fpsSpanRef = useRef(null);
383
564
  const frameCount = useRef(0);
384
565
  const frames = useRef(0);
@@ -387,11 +568,33 @@ export default function DevPanel() {
387
568
  const [datRestrictionMissing, setDatRestrictionMissing] = useState(true);
388
569
  const [heapResult, setHeapResult] = useState("0 Bytes / 0 Bytes");
389
570
  const cookie = {
390
- set: (k, v) => document.cookie = `${k}=${v}; path=/`,
391
- get: (k) => Object.fromEntries(document.cookie.split(";")
392
- .filter(Boolean)
393
- .map(c => c.trim().split("=")))[k],
394
- del: (k) => document.cookie = `${k}=; path=/; max-age=0`
571
+ set: (k, v, sS = "Lax", s = true, mA = null) => {
572
+ const cookieParts = [`${encodeURIComponent(k)}=${encodeURIComponent(v)}`, "path=/"];
573
+ if (mA !== null) {
574
+ cookieParts.push(`max-age=${mA}`);
575
+ const d = new Date();
576
+ d.setTime(d.getTime() + (mA * 1000));
577
+ cookieParts.push(`expires=${d.toUTCString()}`);
578
+ }
579
+ if (s)
580
+ cookieParts.push("secure");
581
+ if (sS)
582
+ cookieParts.push(`samesite=${sS}`);
583
+ document.cookie = cookieParts.join("; ");
584
+ },
585
+ get: (k) => {
586
+ const cookies = document.cookie.split(";").filter(Boolean);
587
+ for (const c of cookies) {
588
+ const [key, ...valParts] = c.trim().split("=");
589
+ if (decodeURIComponent(key) === k) {
590
+ return decodeURIComponent(valParts.join("="));
591
+ }
592
+ }
593
+ return undefined;
594
+ },
595
+ del: (k) => {
596
+ document.cookie = `${encodeURIComponent(k)}=; path=/; max-age=0; samesite=Lax; secure`;
597
+ }
395
598
  };
396
599
  const [doc, setDoc] = useState(null);
397
600
  const [filters, setFilters] = useState({
@@ -465,15 +668,15 @@ export default function DevPanel() {
465
668
  }
466
669
  return "";
467
670
  };
468
- const isSSR = async () => {
469
- const resp = await fetch('/__authtics_host_apis__/get-is-ssr', {
671
+ const getRenderType = async () => {
672
+ const resp = await fetch('/__authtics_host_apis__/get-render-type', {
470
673
  method: 'POST',
471
674
  headers: { 'Content-Type': 'application/json' },
472
675
  body: JSON.stringify({})
473
676
  });
474
677
  if (resp.status === 200) {
475
678
  const data = await resp.json();
476
- setIsSsr(data.isSsr);
679
+ setRenderType(data.renderType);
477
680
  }
478
681
  };
479
682
  const getUsage = async () => {
@@ -561,7 +764,7 @@ export default function DevPanel() {
561
764
  getPath();
562
765
  getCompilerType();
563
766
  getHttpVersion();
564
- isSSR();
767
+ getRenderType();
565
768
  userSettings();
566
769
  getHostVersion();
567
770
  setInterval(() => {
@@ -664,6 +867,16 @@ export default function DevPanel() {
664
867
  }, 1000);
665
868
  return () => clearInterval(interval);
666
869
  }, []);
870
+ useEffect(() => {
871
+ if (!notificationSleepingUntil)
872
+ return;
873
+ const remaining = notificationSleepingUntil - Date.now();
874
+ const timer = window.setTimeout(() => {
875
+ notificationSleepingUntilRef.current = 0;
876
+ setNotificationSleepingUntil(0);
877
+ }, Math.max(remaining, 0));
878
+ return () => window.clearTimeout(timer);
879
+ }, [notificationSleepingUntil]);
667
880
  useEffect(() => {
668
881
  installConsoleInterceptor();
669
882
  installNetworkInterceptor((f) => setNetworkFetches(prev => [...prev.slice(-499), f]), (f) => setNetworkFetches(prev => prev.map(p => p.id === f.id ? f : p)), (f) => setEventSources(prev => [...prev.slice(-499), f]), (f) => setEventSources(prev => prev.map(p => p.id === f.id ? f : p)), (f) => setWebSockets(prev => [...prev.slice(-499), f]), (f) => setWebSockets(prev => prev.map(p => p.id === f.id ? f : p)), (f) => setResourcesFound(prev => [...prev.slice(-499), f]), (f) => setResourcesFound(prev => prev.map(p => p.id === f.id ? f : p)), (f) => setResourcesFound(prev => prev.filter(p => p.id !== f.id)), (sent) => {
@@ -671,18 +884,39 @@ export default function DevPanel() {
671
884
  }, (received) => {
672
885
  pendingReceived.current += received;
673
886
  });
674
- const handler = (e) => {
675
- const detail = e.detail;
676
- setLogs(prev => [...prev.slice(-19999), { ...detail, id: Date.now() + Math.random() }]);
677
- if (detail.type === 'Error') {
678
- setHasIssue(true);
679
- setErrorMsgs(prev => [...prev, detail.message]);
680
- setErrorBoxOpen(true);
887
+ const handler = (event) => {
888
+ const detail = event.detail;
889
+ const entry = {
890
+ ...detail,
891
+ id: Date.now() + Math.random(),
892
+ };
893
+ setLogs(prev => [...prev.slice(-99), entry]);
894
+ const isNotificationSleeping = notificationSleepingUntilRef.current > Date.now();
895
+ if (detail.type === "Error") {
896
+ setErrors(prev => [...prev, entry]);
897
+ if (!isNotificationSleeping) {
898
+ setHasIssue(true);
899
+ setErrorBoxOpen(true);
900
+ }
681
901
  }
682
- ;
683
902
  };
684
903
  try {
685
904
  const existingToken = cookie.get('dat');
905
+ const panelColor = cookie.get('panelColor');
906
+ if (panelColor) {
907
+ setPanelColor({
908
+ background: panelColor.split('|')[0],
909
+ border: panelColor.split('|')[1]
910
+ });
911
+ }
912
+ else {
913
+ const cfg = window.__authtics_config__;
914
+ const serverDevMode = cfg?.devMode !== false;
915
+ const serverDatRestricted = cfg?.datRestricted === true;
916
+ if (serverDevMode && !serverDatRestricted) {
917
+ cookie.set('panelColor', '#111|#333', "Lax", true, 365 * 24 * 60 * 60);
918
+ }
919
+ }
686
920
  if (existingToken) {
687
921
  setToken(existingToken);
688
922
  let length_ = existingToken?.split('');
@@ -696,7 +930,7 @@ export default function DevPanel() {
696
930
  const serverDatRestricted = cfg?.datRestricted === true;
697
931
  if (serverDevMode && !serverDatRestricted) {
698
932
  const newToken = generateToken();
699
- cookie.set('dat', newToken);
933
+ cookie.set('dat', newToken, "Lax", true, 5 * 365 * 24 * 60 * 60);
700
934
  setToken(newToken);
701
935
  let length_ = newToken?.split('');
702
936
  let length;
@@ -815,11 +1049,11 @@ export default function DevPanel() {
815
1049
  left: 0,
816
1050
  width: '100%',
817
1051
  height: '100%',
818
- display: errorBoxOpen && errorBoxOpenable && errorMsgs.length > 0 ? 'flex' : 'none',
1052
+ display: errorBoxOpen && errorBoxOpenable && errors.length > 0 ? 'flex' : 'none',
819
1053
  justifyContent: 'center',
820
1054
  alignItems: 'center',
821
- transition: errorBoxOpen && errorBoxOpenable && errorMsgs.length > 0 ? 'opacity 0.25s ease' : '',
822
- }, ref: errorBoxRef, children: errorBoxOpen && errorBoxOpenable && errorMsgs.length > 0 ? (_jsxs("div", { style: {
1055
+ transition: errorBoxOpen && errorBoxOpenable && errors.length > 0 ? 'opacity 0.25s ease' : '',
1056
+ }, ref: errorBoxRef, children: errorBoxOpen && errorBoxOpenable && errors.length > 0 ? (_jsxs("div", { style: {
823
1057
  background: '#f7f7f7',
824
1058
  border: '1px solid #e6e3e3',
825
1059
  borderRadius: '10px',
@@ -828,7 +1062,9 @@ export default function DevPanel() {
828
1062
  display: 'flex',
829
1063
  flexDirection: 'column',
830
1064
  zIndex: 9999999,
831
- width: '320px'
1065
+ width: '320px',
1066
+ maxHeight: '320px',
1067
+ overflow: 'auto'
832
1068
  }, children: [_jsxs("div", { style: {
833
1069
  padding: '6px 8px',
834
1070
  display: 'flex',
@@ -845,19 +1081,83 @@ export default function DevPanel() {
845
1081
  alignItems: 'center',
846
1082
  whiteSpace: 'nowrap',
847
1083
  gap: '4px'
848
- }, children: [_jsx(ShieldCheck, { size: 16, color: "#f472b6", style: { flexShrink: 0 } }), " Authtics Host"] }), _jsxs("p", { style: { color: 'red', fontSize: '12px' }, children: ["Error found (", selectedError, "/", errorMsgs.length, ")"] }), _jsx(PanelButton, { onClick: () => { setErrorBoxOpen(false); }, style: { marginLeft: 'auto', }, children: "Close" })] }), _jsx("div", { style: {
1084
+ }, children: [_jsx(ShieldCheck, { size: 16, color: "#f472b6", style: { flexShrink: 0 } }), " Authtics Host"] }), _jsxs("p", { style: { color: 'red', fontSize: '12px' }, children: ["Error found (", selectedError, "/", errors.length, ")"] }), _jsx(PanelButton, { onClick: () => { setErrorBoxOpen(false); sleepErrorNotifications(); }, style: { marginLeft: 'auto', }, children: "Close" })] }), _jsxs("div", { style: {
849
1085
  padding: '6px 2px',
850
1086
  display: 'flex',
851
1087
  alignItems: 'center',
852
1088
  gap: '6px',
853
- fontFamily: 'system-ui, sans-serif'
854
- }, children: _jsxs("p", { style: { color: 'red', fontSize: '24px', gap: '6px', display: 'flex', justifyContent: 'center', alignItems: 'center', marginLeft: '10px' }, children: [_jsx(CircleX, { size: 24, color: 'red' }), errorMsgs[selectedError - 1]] }) }), _jsxs("div", { style: {
1089
+ fontFamily: 'system-ui, sans-serif',
1090
+ flexDirection: 'column'
1091
+ }, children: [_jsxs("p", { style: { color: 'red', fontSize: '24px', gap: '6px', display: 'flex', justifyContent: 'left', alignItems: 'left', textAlign: 'left', marginLeft: '10px', whiteSpace: 'normal', wordBreak: 'break-word', width: '100%' }, children: [_jsx(CircleX, { size: 24, color: 'red' }), errors[selectedError - 1]?.message] }), _jsxs("div", { style: {
1092
+ display: "flex",
1093
+ gap: "6px",
1094
+ marginTop: "10px",
1095
+ marginBottom: "6px",
1096
+ flexDirection: 'row'
1097
+ }, children: [_jsx(PanelButton, { onClick: () => setLocationMode("approximate"), style: {
1098
+ background: locationMode === "approximate"
1099
+ ? "#34a8eb"
1100
+ : undefined,
1101
+ }, children: "Approximate" }), _jsx(PanelButton, { onClick: () => setLocationMode("precise"), style: {
1102
+ background: locationMode === "precise"
1103
+ ? "#34a8eb"
1104
+ : undefined,
1105
+ }, children: "Precise" })] }), (() => {
1106
+ const selected = errors[selectedError - 1];
1107
+ const location = selected?.location;
1108
+ if (!location) {
1109
+ return _jsx("p", { style: { textAlign: "left" }, children: "At an unknown location" });
1110
+ }
1111
+ const line = location.line || 0;
1112
+ const column = location.column || 1;
1113
+ return _jsxs("p", { style: { textAlign: "left" }, children: ["At ", location ? `${location.file.replace(window?.location.host, "")}:${line}:${column}` : `an unknown location`] });
1114
+ })(), (() => {
1115
+ const selected = errors[selectedError - 1];
1116
+ const location = selected?.location;
1117
+ if (!location) {
1118
+ return (_jsx("pre", { style: { color: "#777", fontSize: "12px" }, children: "No source location available." }));
1119
+ }
1120
+ const sourceLine = location.sourceText || "";
1121
+ const line = location.line || 0;
1122
+ const column = location.column || 1;
1123
+ const length = location.length || 1;
1124
+ if (locationMode === "precise") {
1125
+ return (_jsxs("pre", { style: {
1126
+ background: "#1e1e1e",
1127
+ color: "#ddd",
1128
+ padding: "8px",
1129
+ overflowX: "auto",
1130
+ fontSize: "12px",
1131
+ width: "310px",
1132
+ maxWidth: "90%",
1133
+ whiteSpace: "pre-wrap",
1134
+ wordBreak: "break-all",
1135
+ overflowWrap: "break-word",
1136
+ borderRadius: "10px"
1137
+ }, children: [line, " | ", sourceLine, "\n", _jsx("div", { style: {
1138
+ color: "#f472b6"
1139
+ }, children: getPreciseMarker(sourceLine, column, length, line) })] }));
1140
+ }
1141
+ return (_jsx("pre", { style: {
1142
+ background: "#1e1e1e",
1143
+ color: "#ddd",
1144
+ padding: "8px",
1145
+ overflowX: "auto",
1146
+ fontSize: "12px",
1147
+ width: "310px",
1148
+ maxWidth: "90%",
1149
+ whiteSpace: "pre-wrap",
1150
+ wordBreak: "break-all",
1151
+ overflowWrap: "break-word",
1152
+ borderRadius: "10px"
1153
+ }, children: location.lines?.join("\n") || `` }));
1154
+ })()] }), _jsxs("div", { style: {
855
1155
  padding: '6px 8px',
856
1156
  display: 'flex',
857
1157
  alignItems: 'center',
858
1158
  gap: '6px',
859
1159
  fontFamily: 'system-ui, sans-serif'
860
- }, children: [_jsxs(PanelButton, { onClick: () => { setSelectedError(selectedError - 1 < 1 ? selectedError : selectedError - 1); }, style: { marginLeft: 'auto', width: '50%', justifyContent: 'space-between', display: 'flex' }, children: ["Previous ", _jsx(ChevronLeft, { size: 12 })] }), _jsxs(PanelButton, { onClick: () => { setSelectedError(selectedError + 1 > errorMsgs.length ? selectedError : selectedError + 1); }, style: { marginLeft: 'auto', width: '50%', justifyContent: 'space-between', display: 'flex', background: '#34a8eb' }, children: ["Next ", _jsx(ChevronRight, { size: 12 })] })] })] })) : (_jsx(_Fragment, {})) }), _jsxs("div", { style: {
1160
+ }, children: [_jsxs(PanelButton, { onClick: () => { setSelectedError(selectedError - 1 < 1 ? selectedError : selectedError - 1); }, style: { marginLeft: 'auto', width: '50%', justifyContent: 'space-between', display: 'flex' }, children: [_jsx(ChevronLeft, { size: 12 }), " Previous"] }), _jsxs(PanelButton, { onClick: () => { setSelectedError(selectedError + 1 > errors.length ? selectedError : selectedError + 1); }, style: { marginLeft: 'auto', width: '50%', justifyContent: 'space-between', display: 'flex', background: '#34a8eb' }, children: ["Next ", _jsx(ChevronRight, { size: 12 })] })] })] })) : (_jsx(_Fragment, {})) }), _jsxs("div", { style: {
861
1161
  position: 'fixed',
862
1162
  bottom: '15px',
863
1163
  right: '15px',
@@ -1056,7 +1356,7 @@ export default function DevPanel() {
1056
1356
  border: '1px solid #eee',
1057
1357
  fontSize: '12px',
1058
1358
  color: '#333',
1059
- }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "Renderer Type" }), _jsx("span", { style: { fontSize: '12px', color: 'blue' }, children: isSsr ? 'SSR (Server-Side Rendering)' : 'CSR (Client-Side Rendering)' })] }), _jsxs("div", { style: {
1359
+ }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "Renderer Type" }), _jsx("span", { style: { fontSize: '12px', color: 'blue' }, children: renderType === "ssr" ? 'SSR (Server-Side Rendering)' : renderType === "csr" ? 'CSR (Client-Side Rendering)' : renderType === "ssg" ? 'SSG (Static Site Generation)' : renderType === "srtws" ? "SRTWS (Site Rendering Through WebSockets)" : '???' })] }), _jsxs("div", { style: {
1060
1360
  display: 'flex',
1061
1361
  justifyContent: 'space-between',
1062
1362
  padding: '6px 10px',
@@ -1099,7 +1399,46 @@ export default function DevPanel() {
1099
1399
  border: '1px solid #eee',
1100
1400
  fontSize: '12px',
1101
1401
  color: '#333',
1102
- }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "OS" }), _jsx("span", { style: { fontSize: '12px', color: 'blue' }, children: getOS() })] }), _jsx(Sparkline, { data: fpsHistory, color: frames.current < 30 ? '#e53e3e' : frames.current < 60 ? '#d97706' : '#16a34a', label: "FPS", unit: " frames" })] })] })) : aboutHostOpen && !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
1402
+ }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "OS" }), _jsx("span", { style: { fontSize: '12px', color: 'blue' }, children: getOS() })] }), _jsx(Sparkline, { data: fpsHistory, color: frames.current < 30 ? '#e53e3e' : frames.current < 60 ? '#d97706' : '#16a34a', label: "FPS", unit: " frames" })] })] })) : panelCustomOpen && !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
1403
+ padding: '6px 8px',
1404
+ borderBottom: '1px solid #ddd',
1405
+ background: '#fff',
1406
+ display: 'flex',
1407
+ alignItems: 'center',
1408
+ gap: '6px',
1409
+ }, children: [_jsxs(PanelButton, { onClick: () => setPanelCustomOpen(false), style: { color: '#555' }, children: [_jsx(ArrowLeft, { size: 12 }), " Back"] }), _jsxs("span", { style: { fontSize: '12px', display: 'flex', alignItems: 'center', gap: '4px', color: '#333' }, children: [_jsx(Cog, { size: 12, color: "#3b82f6" }), " Panel Configuration"] })] }), _jsxs("div", { style: { overflowY: 'auto', maxHeight: '260px', padding: '10px', display: 'flex', flexDirection: 'column', gap: '8px' }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "Colors" }), _jsxs("div", { style: {
1410
+ display: 'flex',
1411
+ justifyContent: 'space-between',
1412
+ padding: '6px 10px',
1413
+ background: '#fff',
1414
+ borderRadius: '10px',
1415
+ border: '1px solid #eee',
1416
+ alignItems: 'center'
1417
+ }, children: [_jsxs("div", { style: { background: '#16a34a', width: '50px', height: '50px', borderRadius: '100px', cursor: 'pointer', alignItems: 'center', textAlign: 'center', justifyContent: 'center', flexDirection: 'column', display: 'flex', border: '1px solid #15803d', gap: '8px' }, onClick: () => {
1418
+ setPanelColor({
1419
+ background: '#16a34a',
1420
+ border: '#15803d'
1421
+ });
1422
+ cookie.set('panelColor', '#16a34a|#15803d', "Lax", true, 365 * 24 * 60 * 60);
1423
+ }, children: [panelColor.background === '#16a34a' ? _jsx(Tick, { color: "white", size: 12 }) : _jsx(_Fragment, {}), " ", _jsx("span", { style: { fontSize: '12px', color: '#fff' }, children: "Green" })] }), _jsxs("div", { style: { background: '#111', width: '50px', height: '50px', borderRadius: '100px', cursor: 'pointer', alignItems: 'center', textAlign: 'center', justifyContent: 'center', flexDirection: 'column', display: 'flex', border: '1px solid #333', gap: '8px' }, onClick: () => {
1424
+ setPanelColor({
1425
+ background: '#111',
1426
+ border: '#333'
1427
+ });
1428
+ cookie.set('panelColor', '#111|#333', "Lax", true, 365 * 24 * 60 * 60);
1429
+ }, children: [panelColor.background === '#111' ? _jsx(Tick, { color: "white", size: 12 }) : _jsx(_Fragment, {}), " ", _jsx("span", { style: { fontSize: '12px', color: '#fff' }, children: "Black" })] }), _jsxs("div", { style: { background: '#f7c623', width: '50px', height: '50px', borderRadius: '100px', cursor: 'pointer', alignItems: 'center', textAlign: 'center', justifyContent: 'center', flexDirection: 'column', display: 'flex', border: '1px solid #d9ad1e', gap: '8px' }, onClick: () => {
1430
+ setPanelColor({
1431
+ background: '#f7c623',
1432
+ border: '#d9ad1e'
1433
+ });
1434
+ cookie.set('panelColor', '#f7c623|#d9ad1e', "Lax", true, 365 * 24 * 60 * 60);
1435
+ }, children: [panelColor.background === '#f7c623' ? _jsx(Tick, { color: "white", size: 12 }) : _jsx(_Fragment, {}), " ", _jsx("span", { style: { fontSize: '12px', color: '#fff' }, children: "Yellow" })] }), _jsxs("div", { style: { background: '#3bb0ff', width: '50px', height: '50px', borderRadius: '100px', cursor: 'pointer', alignItems: 'center', textAlign: 'center', justifyContent: 'center', flexDirection: 'column', display: 'flex', border: '1px solid #3290cf', gap: '8px' }, onClick: () => {
1436
+ setPanelColor({
1437
+ background: '#3bb0ff',
1438
+ border: '#3290cf'
1439
+ });
1440
+ cookie.set('panelColor', '#3bb0ff|#3290cf', "Lax", true, 365 * 24 * 60 * 60);
1441
+ }, children: [panelColor.background === '#3bb0ff' ? _jsx(Tick, { color: "white", size: 12 }) : _jsx(_Fragment, {}), " ", _jsx("span", { style: { fontSize: '12px', color: '#fff' }, children: "Blue" })] })] })] })] })) : aboutHostOpen && !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
1103
1442
  padding: '6px 8px',
1104
1443
  borderBottom: '1px solid #ddd',
1105
1444
  background: '#fff',
@@ -1169,7 +1508,24 @@ export default function DevPanel() {
1169
1508
  border: '1px solid #eee',
1170
1509
  fontSize: '12px',
1171
1510
  color: '#333',
1172
- }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "Total current users" }), _jsx("span", { style: { fontSize: '12px', color: 'blue' }, children: users })] }), _jsx(Sparkline, { data: cpuUsageHistory, color: "#3b82f6", label: "CPU Usage", unit: "" }), _jsx(Sparkline, { data: heapUsageHistory, color: "#3b82f6", label: "Heap Used", unit: heapResult })] })] })) : !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { padding: '8px', gap: '4px', display: 'flex', flexDirection: 'column' }, children: [_jsxs(PanelButton, { onClick: () => setConsoleOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Terminal, { size: 12, color: "#16a34a" }), " Console"] }), logs.length > 0 && (_jsx("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px' }, children: logs.length }))] }), _jsxs(PanelButton, { onClick: () => setRouteOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Route, { size: 12, color: "#3b82f6" }), " Route"] }), _jsxs("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '4px' }, children: [datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" }), pathName] })] }), _jsxs(PanelButton, { onClick: () => setWebpageInfoOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Globe, { size: 12, color: "#3b82f6" }), " Webpage Info"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] }), _jsx(PanelButton, { onClick: () => setNetworkOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: _jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Wifi, { size: 12, color: "#3b82f6" }), " Network"] }) }), _jsxs(PanelButton, { onClick: () => setClientInfoOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Info, { size: 12, color: "#3b82f6" }), " Client Info"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] }), _jsxs(PanelButton, { onClick: () => setAboutHostOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(ShieldCheck, { size: 12, color: "#f472b6" }), " About HostJS"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] }), _jsxs(PanelButton, { onClick: () => setServerInfoOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Server, { size: 12, color: "#f472b6" }), " Server Info"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] })] }), _jsxs("div", { style: {
1511
+ }, children: [_jsx("span", { style: { fontSize: '12px', color: '#333' }, children: "Total current users" }), _jsx("span", { style: { fontSize: '12px', color: 'blue' }, children: users })] }), _jsx(Sparkline, { data: cpuUsageHistory, color: "#3b82f6", label: "CPU Usage", unit: "" }), _jsx(Sparkline, { data: heapUsageHistory, color: "#3b82f6", label: "Heap Used", unit: heapResult })] })] })) : packageSecurityOpen && !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
1512
+ padding: '6px 8px',
1513
+ borderBottom: '1px solid #ddd',
1514
+ background: '#fff',
1515
+ display: 'flex',
1516
+ alignItems: 'center',
1517
+ gap: '6px',
1518
+ }, children: [_jsxs(PanelButton, { onClick: () => setPackageSecurityOpen(false), style: { color: '#555' }, children: [_jsx(ArrowLeft, { size: 12 }), " Back"] }), _jsxs("span", { style: { fontSize: '12px', display: 'flex', alignItems: 'center', gap: '4px', color: '#333' }, children: [_jsx(Shield, { size: 12, color: "#f472b6" }), " Package Security"] })] }), _jsxs("div", { style: { overflowY: 'auto', maxHeight: '260px', padding: '10px', display: 'flex', flexDirection: 'column', gap: '8px' }, children: [_jsx(ShieldCheck, { size: 36, color: "#f472b6", style: { flexShrink: 0, marginTop: '20px' } }), _jsx("span", { style: { display: 'flex', alignItems: 'center', gap: '6px', color: '#333', fontSize: 26, fontWeight: 'bold' }, children: "This feature is currently in BETA." }), _jsx("span", { style: { display: 'flex', alignItems: 'center', gap: '6px', color: '#333', fontSize: 13 }, children: "The newest version of Authtics Host may have this feature completely implemented." })] })] })) : settingsOpen && !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
1519
+ padding: '6px 8px',
1520
+ borderBottom: '1px solid #ddd',
1521
+ background: '#fff',
1522
+ display: 'flex',
1523
+ alignItems: 'center',
1524
+ gap: '6px',
1525
+ }, children: [_jsxs(PanelButton, { onClick: () => setSettingsOpen(false), style: { color: '#555' }, children: [_jsx(ArrowLeft, { size: 12 }), " Back"] }), _jsxs("span", { style: { fontSize: '12px', display: 'flex', alignItems: 'center', gap: '4px', color: '#333' }, children: [_jsx(Cog, { size: 12, color: "#f472b6" }), " Settings"] })] }), _jsx("div", { style: { overflowY: 'auto', maxHeight: '260px', padding: '10px', display: 'flex', flexDirection: 'column', gap: '8px' }, children: _jsxs(PanelButton, { onClick: () => setPanelCustomOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Cog, { size: 12, color: "#3b82f6" }), " Panel Customization"] }), _jsx(ChevronRight, { size: 12 })] }) })] })) : !shutdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { padding: '8px', gap: '4px', display: 'flex', flexDirection: 'column' }, children: [_jsxs(PanelButton, { onClick: () => setConsoleOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Terminal, { size: 12, color: "#16a34a" }), " Console"] }), logs.length > 0 && (_jsx("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px' }, children: logs.length }))] }), _jsxs(PanelButton, { onClick: () => setRouteOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Route, { size: 12, color: "#3b82f6" }), " Route"] }), _jsxs("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '4px' }, children: [datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" }), pathName] })] }), _jsxs(PanelButton, { onClick: () => setWebpageInfoOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Globe, { size: 12, color: "#3b82f6" }), " Webpage Info"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] }), _jsx(PanelButton, { onClick: () => setSettingsOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: _jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Cog, { size: 12, color: "#f472b6" }), " Settings"] }) }), _jsxs(PanelButton, { onClick: () => setPackageSecurityOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Shield, { size: 12, color: "#f472b6" }), " Package Security"] }), highRiskDeps.length > 0 ?
1526
+ (_jsxs("div", { style: { gap: '4px', alignItems: 'center', justifyContent: 'center', display: 'flex' }, children: [_jsx(TriangleAlert, { size: 12, color: "red" }), _jsx("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px' }, children: highRiskDeps.length })] })) : mediumRiskDeps.length > 0 ?
1527
+ (_jsxs("div", { style: { gap: '8px', alignItems: 'center', justifyContent: 'center', display: 'flex' }, children: [_jsx(TriangleAlert, { size: 12, color: "#f7c623" }), _jsx("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px' }, children: mediumRiskDeps.length })] })) : lowRiskDeps.length > 0 ?
1528
+ (_jsxs("div", { style: { gap: '8px', alignItems: 'center', justifyContent: 'center', display: 'flex' }, children: [_jsx(Info, { size: 12, color: "#3bb0ff" }), _jsx("span", { style: { color: '#111', borderRadius: '100px', padding: '1px 6px', fontSize: '10px' }, children: lowRiskDeps.length })] })) : _jsx(CheckCircle2, { size: 12, color: "#16a34a" })] }), _jsx(PanelButton, { onClick: () => setNetworkOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: _jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Wifi, { size: 12, color: "#3b82f6" }), " Network"] }) }), _jsxs(PanelButton, { onClick: () => setClientInfoOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Info, { size: 12, color: "#3b82f6" }), " Client Info"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] }), _jsxs(PanelButton, { onClick: () => setAboutHostOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(ShieldCheck, { size: 12, color: "#f472b6" }), " About HostJS"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] }), _jsxs(PanelButton, { onClick: () => setServerInfoOpen(true), fullWidth: true, style: { color: '#333', justifyContent: 'space-between', height: '32px' }, children: [_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '6px' }, children: [_jsx(Server, { size: 12, color: "#f472b6" }), " Server Info"] }), datRestrictionMissing && _jsx(TriangleAlert, { size: 12, color: "orange" })] })] }), _jsxs("div", { style: {
1173
1529
  padding: '6px 8px',
1174
1530
  borderTop: '1px solid #ddd',
1175
1531
  background: '#fff',
@@ -1229,8 +1585,8 @@ export default function DevPanel() {
1229
1585
  alignItems: 'center',
1230
1586
  padding: '8px 12px',
1231
1587
  borderRadius: hasIssue ? '100px' : '10px',
1232
- background: hasIssue ? '#ba4e4e' : '#111',
1233
- border: hasIssue ? '1px solid #991b1b' : '1px solid #333',
1588
+ background: hasIssue ? '#ba4e4e' : panelColor.background,
1589
+ border: hasIssue ? '1px solid #991b1b' : `1px solid ${panelColor.border ?? '#333'}`,
1234
1590
  boxShadow: hasIssue
1235
1591
  ? '0 4px 20px rgba(220,38,38,0.2)'
1236
1592
  : '0 4px 20px rgba(0,0,0,0.4)',