@bananacool467/authtics-host 0.0.1-beta.9 → 0.0.2-beta.2

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/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # Authtics Host
2
2
 
3
- Version 0.0.1-beta.9
3
+ Version 0.0.2-beta.2
4
4
  License: MIT
5
5
 
6
- **(UPDATE (Security Update): Now versions, 0.0.1-beta.9 and over now requires DAT (Developer Access Token) restriction to access remote controls such as: Restarting and Shutting Down)**
7
-
8
6
  **(NOTE: This version is in BETA, bugs are expected)**
9
7
 
10
8
  Authtics Host is a framework inspired by Next.js. Authtics Host supports SSR (Server-Side Rendering) and uses esbuild.
package/dist/cli.js CHANGED
@@ -5,7 +5,6 @@ import path from "node:path";
5
5
  import fs from "node:fs";
6
6
  import url from "node:url";
7
7
  import { renderPage } from "./renderEngine.js";
8
- import tls from 'tls';
9
8
  let config_ = {};
10
9
  let uptime = 0;
11
10
  let totalRequests = 0;
@@ -14,7 +13,6 @@ const jiti = createJiti(import.meta.url);
14
13
  const routes = new Map();
15
14
  const __filename = url.fileURLToPath(import.meta.url);
16
15
  const __dirname = path.dirname(__filename);
17
- // SSE clients waiting for hot reload signals
18
16
  const hmrClients = new Set();
19
17
  function notifyHmrClients() {
20
18
  for (const client of hmrClients) {
@@ -25,11 +23,7 @@ function notifyHmrClients() {
25
23
  hmrClients.delete(client);
26
24
  }
27
25
  }
28
- //console.log(`[authtics] hot reload triggered (${hmrClients.size} client(s))`);
29
26
  }
30
- // ---------------------------------------------------------------------------
31
- // MIME types for static files in public/
32
- // ---------------------------------------------------------------------------
33
27
  const MIME_TYPES = {
34
28
  '.html': 'text/html',
35
29
  '.css': 'text/css',
@@ -50,9 +44,6 @@ const MIME_TYPES = {
50
44
  '.txt': 'text/plain',
51
45
  '.pdf': 'application/pdf',
52
46
  };
53
- // ---------------------------------------------------------------------------
54
- // Augment ServerResponse with helper methods
55
- // ---------------------------------------------------------------------------
56
47
  function augmentRes(res) {
57
48
  const r = res;
58
49
  r.html = (html) => { res.setHeader("Content-Type", "text/html"); res.end(html); };
@@ -73,13 +64,11 @@ const getCpu = () => {
73
64
  };
74
65
  async function getJsonBody(req) {
75
66
  return new Promise((resolve, reject) => {
76
- // 1. Immediate exit for methods that shouldn't have a body
77
67
  const hasBody = req.headers['content-length'] || req.headers['transfer-encoding'];
78
68
  if (!hasBody && (req.method === 'GET' || req.method === 'DELETE')) {
79
69
  return resolve({});
80
70
  }
81
71
  const chunks = [];
82
- // 2. Safety Timeout: If it takes more than 5s, kill the request
83
72
  const timeout = setTimeout(() => {
84
73
  req.destroy();
85
74
  reject(new Error('Request Timeout: Body took too long to arrive'));
@@ -103,9 +92,6 @@ async function getJsonBody(req) {
103
92
  });
104
93
  });
105
94
  }
106
- // ---------------------------------------------------------------------------
107
- // App class
108
- // ---------------------------------------------------------------------------
109
95
  export default class App {
110
96
  server;
111
97
  constructor() {
@@ -210,9 +196,7 @@ export default class App {
210
196
  stdio: 'inherit'
211
197
  });
212
198
  child.unref();
213
- //this.server.close(() => {
214
199
  process.kill(process.pid, 'SIGTERM');
215
- //})
216
200
  }
217
201
  });
218
202
  this.post("/__authtics_host_apis__/shutdown", async (req, res) => {
@@ -329,22 +313,10 @@ export default class App {
329
313
  if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
330
314
  datMatched = true;
331
315
  if (datMatched) {
332
- if (req.socket instanceof tls.TLSSocket) {
333
- const protocol = req.socket.getProtocol();
334
- const cipher = req.socket.getCipher();
335
- res.writeHead(200, { "Content-Type": "application/json" });
336
- res.end(JSON.stringify({
337
- protocol,
338
- cipher: cipher.name,
339
- httpVersion: req.httpVersion
340
- }));
341
- }
342
- else {
343
- res.writeHead(200, { "Content-Type": "application/json" });
344
- res.end(JSON.stringify({
345
- httpVersion: req.httpVersion
346
- }));
347
- }
316
+ res.writeHead(200, { "Content-Type": "application/json" });
317
+ res.end(JSON.stringify({
318
+ httpVersion: req.httpVersion
319
+ }));
348
320
  }
349
321
  else {
350
322
  const { url = "/", method } = req;
@@ -388,11 +360,7 @@ export default class App {
388
360
  routes.set(`DELETE:${routePath}`, handler);
389
361
  }
390
362
  }
391
- // ---------------------------------------------------------------------------
392
- // Server
393
- // ---------------------------------------------------------------------------
394
363
  async function start() {
395
- //console.log("đŸ› ī¸ Initializing Authtics Host...");
396
364
  let config = {};
397
365
  try {
398
366
  const configPath = path.join(process.cwd(), "authtics_host.config.ts");
@@ -400,7 +368,6 @@ async function start() {
400
368
  config_ = config;
401
369
  }
402
370
  catch {
403
- //console.log("â„šī¸ No config found, using defaults.");
404
371
  }
405
372
  if (config.autoPage == null)
406
373
  config.autoPage = true;
@@ -416,21 +383,15 @@ async function start() {
416
383
  const publicDir = config.autoFile === true ? path.join(process.cwd(), config.autoFileDir || "") : undefined;
417
384
  const apiDir = pagesDir ? path.join(pagesDir, "api") : undefined;
418
385
  const server = createServer(async (req, res) => {
419
- //const body = await getJsonBody(req) as any;
420
- const actuallyShowPanel = showPanel; /* && (config.dat != undefined ? (body.dat == config.dat || (Array.isArray(config.dat) && config.dat.includes(body.dat))) : true)*/
386
+ const actuallyShowPanel = showPanel;
421
387
  const r = augmentRes(res);
422
388
  const { url = "/", method } = req;
423
- // Strip query string, hash, trailing slash
424
389
  let pathname = url.split("?")[0].split("#")[0];
425
390
  if (pathname !== "/" && pathname.endsWith("/"))
426
391
  pathname = pathname.slice(0, -1);
427
- /*if (pathname !== "/__authtics_host_apis__/ping" && pathname !== "/__authtics_host_apis__/get-connection" && pathname !== "/__authtics_hmr__" && pathname !== "/__authtics_host_apis__/get-file-by-pathname" && pathname !== "/__authtics_host_apis__/get-is-ssr" && pathname !== "/__authtics_host_apis__/get-compiler" && pathname !== "/__authtics_host_apis__/restart" && pathname !== "/__authtics_host_apis__/shutdown" && pathname !== "/__authtics_host_apis__/get-server-info" && pathname !== "/__authtics_host_apis__/get-cpu_memory") {
428
- totalRequests++;
429
- }*/
430
392
  if (!pathname.includes('/__authtics_host_apis__/')) {
431
393
  totalRequests++;
432
394
  }
433
- // ── 1. Registered routes (from app.get/post/etc.) ──────────────────────
434
395
  const routeKey = `${method}:${pathname}`;
435
396
  if (routes.has(routeKey)) {
436
397
  const handler = routes.get(routeKey);
@@ -441,8 +402,6 @@ async function start() {
441
402
  return handler(req, r);
442
403
  }
443
404
  }
444
- // ── 2. Hot reload SSE endpoint ─────────────────────────────────────────
445
- // Browser connects here and waits for a 'reload' event
446
405
  if (pathname === '/__authtics_hmr__') {
447
406
  res.writeHead(200, {
448
407
  'Content-Type': 'text/event-stream',
@@ -456,11 +415,8 @@ async function start() {
456
415
  req.on('close', () => { hmrClients.delete(res); users--; });
457
416
  return;
458
417
  }
459
- // ── 3. Public folder — serves files from /public ────────────────────────
460
- // e.g. GET /logo.png → public/logo.png
461
418
  if (publicDir && fs.existsSync(publicDir)) {
462
419
  const staticPath = path.join(publicDir, pathname);
463
- // Make sure the resolved path is still inside publicDir (prevent traversal)
464
420
  const safePath = path.resolve(staticPath);
465
421
  if (safePath.startsWith(path.resolve(publicDir)) && fs.existsSync(safePath) && fs.statSync(safePath).isFile()) {
466
422
  const ext = path.extname(safePath).toLowerCase();
@@ -469,15 +425,12 @@ async function start() {
469
425
  return fs.createReadStream(safePath).pipe(res);
470
426
  }
471
427
  }
472
- // ── 4. API routes — pages/api/*.ts files ────────────────────────────────
473
- // e.g. GET /api/users → pages/api/users.ts
474
428
  if (pathname.startsWith("/api/") && pagesDir != null) {
475
429
  const apiFile = path.join(pagesDir, `${pathname}.ts`);
476
430
  const apiFileTsx = path.join(pagesDir, `${pathname}.tsx`);
477
431
  const resolvedApi = fs.existsSync(apiFile) ? apiFile : fs.existsSync(apiFileTsx) ? apiFileTsx : null;
478
432
  if (resolvedApi) {
479
433
  try {
480
- // Use jiti to import the API route handler on the fly
481
434
  const apiModule = await jiti.import(resolvedApi, { default: true });
482
435
  const handler = apiModule.default ?? apiModule.handler ?? null;
483
436
  if (typeof handler !== 'function') {
@@ -492,11 +445,9 @@ async function start() {
492
445
  return res.end(JSON.stringify({ error: e.message }));
493
446
  }
494
447
  }
495
- // /api/ path but no matching file → 404
496
448
  res.writeHead(404);
497
449
  return res.end(JSON.stringify({ error: `API route not found: ${pathname}` }));
498
450
  }
499
- // ── 5. TSX pages (SSR) ──────────────────────────────────────────────────
500
451
  const urlPath = pathname === "/" ? "/index" : pathname;
501
452
  const tsxPath = pagesDir ? path.join(pagesDir, `${urlPath}.tsx`) : undefined;
502
453
  const htmlPath = pagesDir ? path.join(pagesDir, `${urlPath}.html`) : undefined;
@@ -512,12 +463,10 @@ async function start() {
512
463
  return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
513
464
  }
514
465
  }
515
- // ── 6. Static HTML pages ────────────────────────────────────────────────
516
466
  if (htmlPath && fs.existsSync(htmlPath)) {
517
467
  res.setHeader("Content-Type", "text/html");
518
468
  return res.end(fs.readFileSync(htmlPath, "utf-8"));
519
469
  }
520
- // ── 7. App.tsx file handling ──────────────────────────────────────────────────────────────
521
470
  if (routes.has("APP_TSX")) {
522
471
  const appTsxPath = routes.get("APP_TSX");
523
472
  const appPath = path.join(process.cwd(), appTsxPath);
@@ -534,7 +483,6 @@ async function start() {
534
483
  }
535
484
  }
536
485
  }
537
- // ── 8. 404 ──────────────────────────────────────────────────────────────
538
486
  const notFoundPath = path.join(__dirname, '404.js');
539
487
  if (fs.existsSync(notFoundPath)) {
540
488
  try {
@@ -555,15 +503,12 @@ async function start() {
555
503
  }
556
504
  });
557
505
  server.listen(PORT, () => {
558
- //console.log(`🚀 Authtics Host live at http://localhost:${PORT}`);
559
506
  setInterval(() => {
560
507
  uptime++;
561
508
  }, 1000);
562
509
  });
563
- // ── Hot reload file watcher ─────────────────────────────────────────────
564
510
  if (config.hotReload === true) {
565
511
  const watchDirs = [pagesDir];
566
- // Also watch src/devPanel.tsx if it exists
567
512
  const devPanelDir = path.join(__dirname, 'devPanel.js');
568
513
  const _404Dir = path.join(__dirname, '404.js');
569
514
  if (fs.existsSync(devPanelDir))
@@ -575,8 +520,6 @@ async function start() {
575
520
  fs.watch(dir, { recursive: true }, (eventType, filename) => {
576
521
  if (!filename)
577
522
  return;
578
- //console.log(`[authtics] file changed: ${filename}`);
579
- // Clear the cache for any .tsx/.ts/.html file change
580
523
  notifyHmrClients();
581
524
  });
582
525
  }
@@ -590,13 +533,10 @@ async function start() {
590
533
  fs.watch(dir, { recursive: true }, (eventType, filename) => {
591
534
  if (!filename)
592
535
  return;
593
- //console.log(`[authtics] file changed: ${filename}`);
594
- // Clear the cache for any .tsx/.ts/.html file change
595
536
  notifyHmrClients();
596
537
  });
597
538
  }
598
539
  }
599
- //console.log('đŸ”Ĩ Hot reload enabled — watching for file changes...');
600
540
  }
601
541
  return server;
602
542
  }
package/dist/devPanel.js CHANGED
@@ -1,31 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useState, useEffect, useRef } from 'react';
3
3
  import { ShieldCheck, CircleX, ChevronDown, ChevronUp, Bug, AlertTriangle, Info, ArrowLeft, Wifi, Terminal, Route, Globe, ChevronRight, ChevronLeft, Server } from 'lucide-react';
4
- //import { isMobile } from 'react-device-detect';
5
4
  import Prism from 'prismjs';
6
5
  import 'prismjs/components/prism-javascript';
7
6
  Prism.languages.javascript['builtin'] = /\b(window|document|console|navigator|localStorage|sessionStorage|fetch|Promise|setTimeout|setInterval|clearTimeout|clearInterval|requestAnimationFrame|Math|JSON|Object|Array|String|Number|Boolean|Date|RegExp|Error|Map|Set|Symbol|Proxy|Reflect|performance|history|location|screen|crypto|indexedDB|alert|confirm|prompt)\b/;
8
- //const isMobile = true;
9
7
  function getCallerSource() {
10
8
  try {
11
9
  const stack = new Error().stack ?? '';
12
10
  const lines = stack.split('\n');
13
- // Skip frames: Error, getCallerSource, the patched console[type], and installConsoleInterceptor
14
11
  for (let i = 3; i < lines.length; i++) {
15
12
  const line = lines[i];
16
- // Skip internals and DevPanel's own frames
17
- if (
18
- /*line.includes('installConsoleInterceptor') ||
19
- line.includes('devPanel') ||
20
- line.includes('<anonymous>') ||*/
21
- line.trim() === '')
13
+ if (line.trim() === '')
22
14
  continue;
23
- // Extract filename:line from something like "at foo (http://localhost:5000/pages/index.tsx:42:10)"
24
15
  const match = line.match(/\(?(https?:\/\/[^)]+)\)?$/) ??
25
16
  line.match(/at\s+(https?:\/\/\S+)/);
26
17
  if (match) {
27
18
  const url = match[1];
28
- // Turn full URL into just "filename:line"
29
19
  const parts = url.replace(/\?.*/, '').split('/');
30
20
  const file = parts[parts.length - 1];
31
21
  const colonLine = url.match(/:(\d+):\d+$/);
@@ -33,17 +23,15 @@ function getCallerSource() {
33
23
  }
34
24
  }
35
25
  }
36
- catch { /* ignore */ }
26
+ catch { }
37
27
  return '';
38
28
  }
39
29
  const LOG_TYPES = ['Log', 'Info', 'Warn', 'Error', 'Debug'];
40
- const LOG_TYPE_2 = ['Eval'];
41
30
  let fetchId = 0;
42
31
  const TYPE_STYLE = {
43
32
  Error: { bg: '#fff0f0', color: '#e53e3e', icon: _jsx(CircleX, { size: 11 }) },
44
33
  Warn: { bg: '#fffbea', color: '#d97706', icon: _jsx(AlertTriangle, { size: 11 }) },
45
34
  Log: { bg: '#ffffff', color: '#888', textColor: '#333', icon: null },
46
- Eval: { bg: '#ffffff', color: '#888', textColor: '#333', icon: null },
47
35
  Info: { bg: '#eff6ff', color: '#3b82f6', icon: _jsx(Info, { size: 11 }) },
48
36
  Debug: { bg: '#f0fdf4', color: '#16a34a', icon: _jsx(Bug, { size: 11 }) },
49
37
  };
@@ -51,7 +39,6 @@ const FILTER_COLORS = {
51
39
  Error: '#e53e3e',
52
40
  Warn: '#d97706',
53
41
  Log: '#888',
54
- Eval: '#888',
55
42
  Info: '#3b82f6',
56
43
  Debug: '#16a34a',
57
44
  };
@@ -62,7 +49,6 @@ const TruncatedText = ({ content, id }) => {
62
49
  : content;
63
50
  return _jsx("div", { id: id, children: truncated });
64
51
  };
65
- // ── Sparkline chart (SVG, no dependencies) ──────────────────────────────────
66
52
  function Sparkline({ data, color, label, unit }) {
67
53
  const W = 280, H = 48;
68
54
  const max = Math.max(...data, 1);
@@ -87,14 +73,11 @@ function installNetworkInterceptor(onFetch, setFetch, onBytesClient, onBytesServ
87
73
  const savedFetchId = fetchId;
88
74
  const url = typeof args[0] === 'string' ? args[0] : args[0].url;
89
75
  const method = (args[1]?.method ?? 'GET').toUpperCase();
90
- // Filter out DevPanel's own internal pings so they don't show up in the network tab
91
76
  if (url.startsWith('/__authtics_host_apis__/') || url === "/__authtics_hmr__") {
92
77
  return originalFetch(...args);
93
78
  }
94
- // Estimate bytes sent: body size + rough header/URL overhead
95
79
  const body = args[1]?.body;
96
80
  const bodyBytes = body ? new Blob([body]).size : 0;
97
- // Headers + URL as a rough proxy for request overhead (like Chrome devtools does)
98
81
  const headerStr = JSON.stringify(args[1]?.headers ?? {});
99
82
  const sentBytes = bodyBytes + url.length + headerStr.length;
100
83
  onBytesClient(sentBytes);
@@ -164,7 +147,7 @@ function PanelButton({ onClick, onClick2, children, style, fullWidth, disabled }
164
147
  ...style,
165
148
  }, children: children }));
166
149
  }
167
- const MAX_POINTS = 20; // number of data points shown in charts
150
+ const MAX_POINTS = 20;
168
151
  const generateToken = () => {
169
152
  return crypto.randomUUID().replace(/-/g, '').substring(0, 16);
170
153
  };
@@ -221,7 +204,7 @@ export default function DevPanel() {
221
204
  const [rootEl, setRootEl] = useState(null);
222
205
  const [doc, setDoc] = useState(null);
223
206
  const [filters, setFilters] = useState({
224
- Log: true, Info: true, Warn: true, Error: true, Debug: false, Eval: true
207
+ Log: true, Info: true, Warn: true, Error: true, Debug: false
225
208
  });
226
209
  const errorCount = logs.filter(l => l.type === 'Error').length;
227
210
  const warnCount = logs.filter(l => l.type === 'Warn').length;
@@ -229,7 +212,6 @@ export default function DevPanel() {
229
212
  const handleScroll = () => {
230
213
  if (consoleScrollRef.current) {
231
214
  const { scrollTop, scrollHeight, clientHeight } = consoleScrollRef.current;
232
- // Buffer of 5px to handle zoom or rounding issues
233
215
  const reachedBottom = scrollHeight - scrollTop - clientHeight < 5;
234
216
  setIsAtBottom(reachedBottom);
235
217
  }
@@ -239,230 +221,6 @@ export default function DevPanel() {
239
221
  consoleScrollRef.current.scrollTop = consoleScrollRef.current.scrollHeight;
240
222
  }
241
223
  }, [filteredLogs, isAtBottom]);
242
- /*useEffect(() => {
243
- setRootEl(doc?.documentElement as HTMLElement);
244
- }, []);
245
- const [picking, setPicking] = React.useState(false);*/
246
- /*const onMouseDown = (e: React.MouseEvent) => {
247
- dragging || setDragging(true);
248
- offset.current = { x: e.clientX - pos.x, y: e.clientY - pos.y };
249
- e.preventDefault();
250
- };
251
-
252
- const onTouchStart = (e: React.TouchEvent) => {
253
- const t = e.touches[0];
254
- offset.current = { x: t.clientX - pos.x, y: t.clientY - pos.y };
255
- };
256
-
257
- const [rect, setRect] = React.useState<DOMRect | null>(null);
258
-
259
- const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set());
260
- const [domVersion, setDomVersion] = useState(0);
261
-
262
- const [currentNode, setCurrentNode] = useState<Element>(doc?.documentElement as HTMLElement);
263
- const [history, setHistory] = useState<Element[]>([]);
264
-
265
- const goInto = (el: Element) => {
266
- setHistory(prev => [...prev, currentNode]);
267
- setCurrentNode(el);
268
- };
269
-
270
- const goBack = () => {
271
- setHistory(prev => {
272
- const next = [...prev];
273
- setCurrentNode(next.pop()!);
274
- return next;
275
- });
276
- };
277
-
278
- useEffect(() => {
279
- const observer = new MutationObserver(() => setDomVersion(v => v + 1));
280
- observer.observe(doc?.documentElement as HTMLElement, { childList: true, subtree: true, attributes: true });
281
- return () => observer.disconnect();
282
- }, []);
283
-
284
- const getPath = (el: Element, depth: number) => el.tagName + depth + el.className + el.id;
285
-
286
- const toggle = (path: string) => {
287
- setExpandedPaths(prev => {
288
- const next = new Set(prev);
289
- next.has(path) ? next.delete(path) : next.add(path);
290
- return next;
291
- });
292
- };
293
-
294
- const colorizeJS = (code: string): string => {
295
- const escaped = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
296
- return escaped
297
- .replace(/(\/\/[^\n]*)/g, '<span style="color:#888">$1</span>')
298
- .replace(/(".*?"|'.*?')/g, '<span style="color:#0a0">$1</span>')
299
- .replace(/\b(const|let|var|function|return|if|else|for|while|import|export|default|class|new)\b/g, '<span style="color:#e05">$1</span>')
300
- .replace(/\b(\d+)\b/g, '<span style="color:#f90">$1</span>');
301
- };
302
-
303
- const colorizeCSS = (code: string): string => {
304
- const escaped = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
305
- return escaped
306
- .replace(/([\w-]+)(\s*:)/g, '<span style="color:#f90">$1</span>$2')
307
- .replace(/([.#]?[\w-]+)\s*\{/g, '<span style="color:#e05">$1</span> {');
308
- };
309
-
310
- const colorizeHtml = (code: string): React.ReactElement => {
311
- const tokens: React.ReactElement[] = [];
312
- let rest = code;
313
- let i = 0;
314
-
315
- const tagRegex = /(<\/?)([a-zA-Z][a-zA-Z0-9]*)([^>]*)(>)/g;
316
- let last = 0;
317
- let match;
318
-
319
- while ((match = tagRegex.exec(code)) !== null) {
320
- if (match.index > last)
321
- tokens.push(<span key={i++} style={{ color: '#555' }}>{code.slice(last, match.index)}</span>);
322
- tokens.push(<span key={i++} style={{ color: '#666' }}>{match[1]}</span>);
323
- tokens.push(<span key={i++} style={{ color: '#e05' }}>{match[2]}</span>);
324
- // colorize attributes
325
- const attrStr = match[3];
326
- const attrRegex = /(\s[a-zA-Z-]+)(="([^"]*)")?/g;
327
- let am;
328
- while ((am = attrRegex.exec(attrStr)) !== null) {
329
- tokens.push(<span key={i++} style={{ color: '#f90' }}>{am[1]}</span>);
330
- if (am[2]) {
331
- tokens.push(<span key={i++} style={{ color: '#999' }}>="</span>);
332
- tokens.push(<span key={i++} style={{ color: '#0a0' }}>{am[3]}</span>);
333
- tokens.push(<span key={i++} style={{ color: '#999' }}>"</span>);
334
- }
335
- }
336
- tokens.push(<span key={i++} style={{ color: '#666' }}>{match[4]}</span>);
337
- last = match.index + match[0].length;
338
- }
339
-
340
- if (last < code.length)
341
- tokens.push(<span key={i++} style={{ color: '#555' }}>{code.slice(last)}</span>);
342
-
343
- return <>{tokens}</>;
344
- };
345
-
346
- const renderNode = (el: Element, depth = 0, path = el.tagName): React.ReactElement => {
347
- const isSelected = selected === el;
348
- const tag = el.tagName.toLowerCase();
349
- ;const idAttr = el.id ? el.id : null;
350
- const classAttr = el.className ? String(el.className).slice(0, 15) : null;
351
- const otherAttrs = Array.from(el.attributes)
352
- .filter(a => a.name !== 'id' && a.name !== 'class')
353
- .slice(0, 2);
354
- const text = Array.from(el.childNodes)
355
- .filter(n => n.nodeType === Node.TEXT_NODE)
356
- .map(n => n.textContent?.trim())
357
- .filter(Boolean)
358
- .join(' ');
359
-
360
- const hasChildren = el.children.length > 0;
361
- const hasText = text.length > 0;
362
- const expandable = hasChildren || hasText;
363
- const isExpanded = expandedPaths.has(path);*/
364
- /*return (
365
- <div key={path}>
366
- {*/ /* opening tag */ /*}
367
- <div
368
- onClick={() => { setSelected(el); setRect(el.getBoundingClientRect()); if (expandable) toggle(path); }}
369
- style={{ paddingLeft: depth * 10 + 4, cursor: 'pointer', background: isSelected ? '#e0edff' : 'transparent', borderRadius: 4, fontSize: 11, fontFamily: 'monospace', whiteSpace: 'nowrap' }}
370
- >
371
- <span style={{ color: '#999' }}>{expandable ? (isExpanded ? '▾' : '▸') : '·'} </span>
372
- <span style={{ color: '#666' }}>&lt;</span>
373
- <span style={{ color: '#e05' }}>{tag}</span>
374
- {idAttr && <><span style={{ color: '#f90' }}> id</span><span style={{ color: '#999' }}>="</span><span style={{ color: '#0a0' }}>{idAttr}</span><span style={{ color: '#999' }}>"</span></>}
375
- {classAttr && <><span style={{ color: '#f90' }}> class</span><span style={{ color: '#999' }}>="</span><span style={{ color: '#0a0' }}>{classAttr}</span><span style={{ color: '#999' }}>"</span></>}
376
- {otherAttrs.map(a => (
377
- <span key={a.name}>
378
- <span style={{ color: '#f90' }}> {a.name}</span>
379
- <span style={{ color: '#999' }}>="</span>
380
- <span style={{ color: '#0a0' }}>{a.value.slice(0, 20)}</span>
381
- <span style={{ color: '#999' }}>"</span>
382
- </span>
383
- ))}
384
- <span style={{ color: '#666' }}>&gt;</span>
385
- {!isExpanded && hasText && <span style={{ color: '#333' }}>{text.slice(0, 30)}{text.length > 30 ? '...' : ''}</span>}
386
- {!isExpanded && <span style={{ color: '#e05' }}>&lt;/{tag}&gt;</span>}
387
- </div>
388
-
389
- {/* expanded content */ /*}
390
- {isExpanded && (
391
- <>
392
- {hasText && (
393
- <div
394
- style={{ paddingLeft: (depth + 2) * 10 + 4, fontSize: 11, fontFamily: 'monospace', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
395
- dangerouslySetInnerHTML={{
396
- __html: tag === 'script'
397
- ? colorizeJS(text)
398
- : tag === 'style'
399
- ? colorizeCSS(text)
400
- : `"${text}"`
401
- }}
402
- />
403
- )}
404
- {hasChildren && Array.from(el.children).map((child, i) =>
405
- renderNode(child, depth + 1, path + '>' + child.tagName + i)
406
- )}
407
- {/* closing tag only shows separately when expanded */ /*}
408
- <div style={{ paddingLeft: depth * 10 + 4, fontSize: 11, fontFamily: 'monospace', color: '#e05' }}>
409
- <span style={{ color: '#666' }}>&lt;/</span>
410
- <span style={{ color: '#e05' }}>{tag}</span>
411
- <span style={{ color: '#666' }}>&gt;</span>
412
- </div>
413
- </>
414
- )}
415
- </div>
416
- );
417
- };
418
-
419
- useEffect(() => {
420
- if (!picking) return;
421
- const onOver = (e: MouseEvent) => (e.target as HTMLElement).style.outline = '2px solid #e05';
422
- const onOut = (e: MouseEvent) => (e.target as HTMLElement).style.outline = '';
423
- const onClick = (e: MouseEvent) => {
424
- e.preventDefault();
425
- e.stopPropagation();
426
- const el = e.target as HTMLElement;
427
- el.style.outline = '';
428
- setSelected(el);
429
- setRect(el.getBoundingClientRect());
430
- setPicking(false);
431
- };
432
- document.addEventListener('mouseover', onOver);
433
- document.addEventListener('mouseout', onOut);
434
- document.addEventListener('click', onClick, true);
435
- return () => {
436
- document.removeEventListener('mouseover', onOver);
437
- document.removeEventListener('mouseout', onOut);
438
- document.removeEventListener('click', onClick, true);
439
- };
440
- }, [picking]);
441
-
442
- const styles = selected ? window.getComputedStyle(selected) : null;
443
- const isFlex = styles?.display === 'flex';
444
- const isGrid = styles?.display === 'grid';
445
- const rotation = styles?.transform !== 'none' ? styles?.transform : null;
446
- const styleKeys = ['color','background','fontSize','margin','padding','display','width','height','position','borderRadius'];
447
-
448
- useEffect(() => {
449
- const onMove = (e: MouseEvent | TouchEvent) => {
450
- if (!dragging) return;
451
- const point = 'touches' in e ? e.touches[0] : e;
452
- setPos({ x: point.clientX - offset.current.x, y: point.clientY - offset.current.y });
453
- };
454
- const onUp = () => setDragging(false);
455
- window.addEventListener('mousemove', onMove as any);
456
- window.addEventListener('mouseup', onUp);
457
- window.addEventListener('touchmove', onMove as any);
458
- window.addEventListener('touchend', onUp);
459
- return () => {
460
- window.removeEventListener('mousemove', onMove as any);
461
- window.removeEventListener('mouseup', onUp);
462
- window.removeEventListener('touchmove', onMove as any);
463
- window.removeEventListener('touchend', onUp);
464
- };
465
- }, [dragging]);*/
466
224
  const loop = () => {
467
225
  frameCount.current++;
468
226
  requestAnimationFrame(loop);
@@ -606,18 +364,6 @@ useEffect(() => {
606
364
  update();
607
365
  }, 500);
608
366
  }, 250);
609
- /*setInterval(() => {
610
- //setFps(Math.round(1000 / (performance.now() - (window as any).lastFrameTime)));
611
- const now = performance.now();
612
- const last = (window as any).lastFrameTime;
613
- if (typeof last === 'number') {
614
- const _ = now - last;
615
- if (fpsSpanRef.current) {
616
- fpsSpanRef.current.textContent = _ > 0 ? Math.round(1000 / _).toString() : '0';
617
- }
618
- }
619
- (window as any).lastFrameTime = now;
620
- }, 1000)*/
621
367
  }, []);
622
368
  const restart = async () => {
623
369
  const resp = await fetch('/__authtics_host_apis__/restart', {
@@ -647,7 +393,6 @@ useEffect(() => {
647
393
  clearInterval(intervalId);
648
394
  };
649
395
  }, []);
650
- // Accumulated bytes per 2s tick
651
396
  const pendingSent = useRef(0);
652
397
  const pendingReceived = useRef(0);
653
398
  const [sentHistory, setSentHistory] = useState(Array(MAX_POINTS).fill(0));
@@ -659,7 +404,6 @@ useEffect(() => {
659
404
  : consoleOpen || networkOpen || routeOpen || webpageInfoOpen || clientInfoOpen || aboutHostOpen
660
405
  ? '320px'
661
406
  : '320px';
662
- // Ping every second
663
407
  useEffect(() => {
664
408
  const dat = localStorage.getItem('dat');
665
409
  const interval = setInterval(async () => {
@@ -676,11 +420,10 @@ useEffect(() => {
676
420
  setPing__(Date.now() - timeStart);
677
421
  }
678
422
  }
679
- catch { /* server not reachable */ }
423
+ catch { }
680
424
  }, 1000);
681
425
  return () => clearInterval(interval);
682
426
  }, []);
683
- // Chart tick every 2 seconds — snapshot pending bytes then reset
684
427
  useEffect(() => {
685
428
  const interval = setInterval(() => {
686
429
  const s = pendingSent.current;
@@ -698,7 +441,6 @@ useEffect(() => {
698
441
  }, 1000);
699
442
  return () => clearInterval(interval);
700
443
  }, []);
701
- // Console + network interceptors
702
444
  useEffect(() => {
703
445
  installConsoleInterceptor();
704
446
  installNetworkInterceptor((f) => setNetworkFetches(prev => [...prev.slice(-49), f]), (f) => setNetworkFetches(prev => prev.map(p => p.id === f.id ? f : p)), (sent) => {
@@ -749,13 +491,6 @@ useEffect(() => {
749
491
  setHostName(window.location.hostname);
750
492
  setDoc(document);
751
493
  setProtocol(window.location.protocol.replace(':', '').toUpperCase());
752
- // Test logs
753
- //setTimeout(() => console.error('DevPanel rendered.'), 2000);
754
- //setTimeout(() => console.error('DevPanel rendered. 2'), 2000);
755
- /*setTimeout(() => console.debug('DevPanel rendered.'), 2000);
756
- setTimeout(() => console.info('DevPanel rendered.'), 2000);
757
- setTimeout(() => console.log('DevPanel rendered.'), 2000);
758
- setTimeout(() => console.warn('DevPanel rendered.'), 2000);*/
759
494
  return () => window.removeEventListener('authtics:log', handler);
760
495
  }, []);
761
496
  const getOS = () => {
@@ -941,7 +676,7 @@ useEffect(() => {
941
676
  userSelect: 'none',
942
677
  }, children: [_jsx("input", { type: "checkbox", checked: filters[type], onChange: () => toggleFilter(type), style: { display: 'none' } }), type] }, type))) }), _jsx("div", { style: { overflowY: 'auto', maxHeight: '220px' }, ref: consoleScrollRef, onScroll: handleScroll, children: filteredLogs.length === 0
943
678
  ? _jsx("div", { style: { padding: '16px 12px', color: '#aaa', fontSize: '12px' }, children: "No logs yet." })
944
- : [...filteredLogs] /*.reverse()*/.map(log => {
679
+ : [...filteredLogs].map(log => {
945
680
  const s = TYPE_STYLE[log.type];
946
681
  return (_jsxs("div", { style: {
947
682
  display: 'flex',
@@ -955,12 +690,7 @@ useEffect(() => {
955
690
  fontSize: '11px',
956
691
  fontFamily: 'monospace',
957
692
  wordBreak: 'break-all',
958
- }, children: log.type === "Eval" ? (_jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: '4px', justifyContent: 'center', alignItems: 'center' }, children: ["(You): ", _jsx("div", { style: {
959
- fontFamily: 'monospace',
960
- fontSize: '12px',
961
- whiteSpace: 'pre-wrap',
962
- wordBreak: 'break-all',
963
- }, dangerouslySetInnerHTML: { __html: Prism.highlight(log.message, Prism.languages.javascript, 'javascript') } })] })) : log.message })] }, log.id));
693
+ }, children: log.message })] }, log.id));
964
694
  }) })] })) : networkOpen ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
965
695
  padding: '6px 8px',
966
696
  borderBottom: '1px solid #ddd',
@@ -1,36 +1,20 @@
1
- // src/renderEngine.ts
2
1
  import path from "node:path";
3
2
  import fs from "node:fs";
4
3
  import { fileURLToPath } from "node:url";
5
- import { createRequire } from "node:module";
6
4
  import * as esbuild from "esbuild";
5
+ import * as babel from "@babel/core";
6
+ import * as babelPresetEnv from "@babel/preset-env";
7
7
  import React from "react";
8
8
  import { renderToString } from "react-dom/server";
9
9
  import { tempFileForTsx, writeTempFile, readTempFile, ensureTempDirs, } from "./rendererTempFiles.js";
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
- //const __dirname = fileURLToPath(new URL(".", import.meta.url));
13
- const require = createRequire(import.meta.url);
14
- // ---------------------------------------------------------------------------
15
- // Babel compiler (optional — only used if compilerType: 'babel' in config)
16
- // Lazily required so babel doesn't need to be installed for esbuild users.
17
- // ---------------------------------------------------------------------------
18
12
  async function buildWithBabel(entryPath, virtualContent, platform) {
19
- let babel;
20
- try {
21
- babel = require('@babel/core');
22
- }
23
- catch {
24
- throw new Error('[authtics] compilerType is "babel" but @babel/core is not installed.\n' +
25
- 'Run: npm install --save-dev @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript');
26
- }
27
13
  const presets = [
28
- [require('@babel/preset-env'), {
14
+ [babelPresetEnv, {
29
15
  targets: platform === 'node' ? { node: 'current' } : { browsers: '>0.5%, not dead' },
30
16
  modules: platform === 'node' ? 'commonjs' : false,
31
17
  }],
32
- [require('@babel/preset-react'), { runtime: 'automatic' }],
33
- [require('@babel/preset-typescript'), {}],
34
18
  ];
35
19
  const result = await babel.transformAsync(virtualContent, {
36
20
  filename: entryPath,
@@ -41,9 +25,6 @@ async function buildWithBabel(entryPath, virtualContent, platform) {
41
25
  throw new Error('[authtics] Babel produced no output');
42
26
  return result.code;
43
27
  }
44
- // ---------------------------------------------------------------------------
45
- // esbuild compiler (default)
46
- // ---------------------------------------------------------------------------
47
28
  async function buildWithEsbuild(virtualContent, resolveDir, platform) {
48
29
  const isNode = platform === 'node';
49
30
  const result = await esbuild.build({
@@ -54,8 +35,6 @@ async function buildWithEsbuild(virtualContent, resolveDir, platform) {
54
35
  },
55
36
  bundle: true,
56
37
  write: false,
57
- // Server: CJS so require() works (e.g. lucide-react)
58
- // Client: IIFE so it runs as a plain <script> tag
59
38
  format: isNode ? 'cjs' : 'iife',
60
39
  platform,
61
40
  jsx: 'automatic',
@@ -63,8 +42,6 @@ async function buildWithEsbuild(virtualContent, resolveDir, platform) {
63
42
  target: isNode ? ['node18'] : ['es2020'],
64
43
  minify: false,
65
44
  treeShaking: true,
66
- // Server: externalize React to avoid duplicate instance → "Invalid hook call"
67
- // Client: bundle React in so the browser needs no CDN or importmap
68
45
  external: isNode
69
46
  ? ['react', 'react-dom', 'react-dom/server', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'node:http',
70
47
  'node:path',
@@ -78,9 +55,6 @@ async function buildWithEsbuild(virtualContent, resolveDir, platform) {
78
55
  });
79
56
  return result.outputFiles[0].text;
80
57
  }
81
- // ---------------------------------------------------------------------------
82
- // Resolve devPanel.tsx
83
- // ---------------------------------------------------------------------------
84
58
  export function findFileUpwards(startDir, relativePath) {
85
59
  let dir = path.resolve(startDir);
86
60
  const root = path.parse(dir).root;
@@ -95,19 +69,12 @@ export function findFileUpwards(startDir, relativePath) {
95
69
  return null;
96
70
  }
97
71
  function resolveDevPanelPath() {
98
- /*const fromCwd = findFileUpwards(process.cwd(), path.join("src", "devPanel.tsx"));
99
- if (fromCwd) return fromCwd;
100
- const fromParent = findFileUpwards(path.join(process.cwd(), ".."), path.join("src", "devPanel.tsx"));
101
- if (fromParent) return fromParent;*/
102
72
  const nextToCli = path.join(__dirname, "devPanel.js");
103
73
  if (fs.existsSync(nextToCli))
104
74
  return nextToCli;
105
75
  return null;
106
76
  }
107
77
  const devPanelPath = resolveDevPanelPath();
108
- // ---------------------------------------------------------------------------
109
- // Template resolution
110
- // ---------------------------------------------------------------------------
111
78
  function resolveTemplate(tsxPath) {
112
79
  const pagesDir = path.join(process.cwd(), "pages");
113
80
  let dir = path.dirname(tsxPath);
@@ -144,7 +111,6 @@ function buildHtml(opts) {
144
111
  <head>
145
112
  <meta charset="utf-8" />
146
113
  <meta name="viewport" content="width=device-width, initial-scale=1" />
147
- <title>Authtics</title>
148
114
  </head>
149
115
  <body>
150
116
  <div id="root">${pageHtml}</div>
@@ -154,21 +120,15 @@ function buildHtml(opts) {
154
120
  </body>
155
121
  </html>`;
156
122
  }
157
- // ---------------------------------------------------------------------------
158
- // Cache validity
159
- // ---------------------------------------------------------------------------
160
123
  function isCacheValid(tsxPath, tempPath, serverCjsPath, templatePath, devPanelPath) {
161
124
  if (!fs.existsSync(tempPath) || !fs.existsSync(serverCjsPath))
162
125
  return false;
163
126
  try {
164
127
  const cacheMtime = fs.statSync(tempPath).mtimeMs;
165
- // Page file changed?
166
128
  if (fs.statSync(tsxPath).mtimeMs > cacheMtime)
167
129
  return false;
168
- // Template changed?
169
130
  if (templatePath && fs.existsSync(templatePath) && fs.statSync(templatePath).mtimeMs > cacheMtime)
170
131
  return false;
171
- // DevPanel changed?
172
132
  if (devPanelPath && fs.existsSync(devPanelPath) && fs.statSync(devPanelPath).mtimeMs > cacheMtime)
173
133
  return false;
174
134
  return true;
@@ -177,11 +137,6 @@ function isCacheValid(tsxPath, tempPath, serverCjsPath, templatePath, devPanelPa
177
137
  return false;
178
138
  }
179
139
  }
180
- // ---------------------------------------------------------------------------
181
- // renderPage
182
- // ---------------------------------------------------------------------------
183
- // Small script injected into every page when hotReload is enabled.
184
- // It opens an SSE connection to /__authtics_hmr__ and reloads on signal.
185
140
  const HMR_SCRIPT = `
186
141
  <script>
187
142
  (function() {
@@ -198,10 +153,6 @@ export async function renderPage(tsxPath, reqUrl, showPanel = true, compiler = '
198
153
  }
199
154
  const usesDevPanel = showPanel && devPanelPath !== null;
200
155
  const templatePath = resolveTemplate(tsxPath);
201
- /*console.log(`[authtics] compiler = ${compiler}`);
202
- console.log(`[authtics] devPanelPath = ${devPanelPath ?? "(not found)"}`);
203
- console.log(`[authtics] usesDevPanel = ${usesDevPanel}`);
204
- console.log(`[authtics] template = ${templatePath ?? "(none, using default)"}`);*/
205
156
  const tempPath = tempFileForTsx(tsxPath);
206
157
  const serverCjsPath = tempPath.replace(/\.json$/, ".server.cjs");
207
158
  let clientCode;
@@ -211,14 +162,11 @@ export async function renderPage(tsxPath, reqUrl, showPanel = true, compiler = '
211
162
  const parsed = JSON.parse(readTempFile(tempPath));
212
163
  clientCode = parsed.clientCode;
213
164
  serverCode = fs.readFileSync(serverCjsPath, "utf-8");
214
- //console.log(`[authtics] using cached bundle for ${path.basename(tsxPath)}`);
215
165
  }
216
166
  catch {
217
- // corrupt — rebuild
218
167
  }
219
168
  }
220
169
  if (!clientCode || !serverCode) {
221
- //console.log(`[authtics] building bundle (${compiler}) for ${path.basename(tsxPath)}...`);
222
170
  const virtualServer = `
223
171
  import Page from ${JSON.stringify(tsxPath)};
224
172
  ${usesDevPanel ? `import DevPanel from ${JSON.stringify(devPanelPath)};` : ""}
@@ -248,9 +196,7 @@ export async function renderPage(tsxPath, reqUrl, showPanel = true, compiler = '
248
196
  }
249
197
  fs.writeFileSync(serverCjsPath, serverCode, "utf-8");
250
198
  writeTempFile(tempPath, JSON.stringify({ clientCode }));
251
- //console.log(`[authtics] bundle cached for ${path.basename(tsxPath)}`);
252
199
  }
253
- // SSR
254
200
  const serverModule = await import(`${serverCjsPath}?t=${Date.now()}`);
255
201
  const exports = serverModule.default ?? serverModule;
256
202
  const PageComponent = exports.default ?? exports.Page ?? exports.page ?? null;
@@ -1,19 +1,6 @@
1
1
  export declare function ensureTempDirs(): void;
2
- /**
3
- * Returns the cache file path for a given source .tsx file.
4
- * Uses the basename + a short hash of the full path to avoid collisions
5
- * between files named the same thing in different directories.
6
- *
7
- * Example: /project/pages/about.tsx → .authtics_host/cache/about.tsx_a3f9b2.json
8
- */
9
2
  export declare function tempFileForTsx(tsxPath: string): string;
10
- /**
11
- * Returns true if the cache file exists and is at least as new as the source file.
12
- */
13
3
  export declare function isTempUpToDate(tsxPath: string, tempPath: string): boolean;
14
4
  export declare function writeTempFile(tempPath: string, content: string): void;
15
5
  export declare function readTempFile(tempPath: string): string;
16
- /**
17
- * Wipes the entire cache directory. Useful for a `authtics clean` CLI command.
18
- */
19
6
  export declare function clearCache(): void;
@@ -1,11 +1,5 @@
1
- // src/rendererTempFiles.ts
2
1
  import fs from "node:fs";
3
2
  import path from "node:path";
4
- // ---------------------------------------------------------------------------
5
- // Directory layout:
6
- // <project>/.authtics_host/
7
- // cache/ ← compiled server+client bundles (JSON, keyed by source)
8
- // ---------------------------------------------------------------------------
9
3
  const AUTHTICS_DIR = path.join(process.cwd(), ".authtics_host");
10
4
  const CACHE_DIR = path.join(AUTHTICS_DIR, "cache");
11
5
  export function ensureTempDirs() {
@@ -14,22 +8,12 @@ export function ensureTempDirs() {
14
8
  if (!fs.existsSync(CACHE_DIR))
15
9
  fs.mkdirSync(CACHE_DIR, { recursive: true });
16
10
  }
17
- /**
18
- * Returns the cache file path for a given source .tsx file.
19
- * Uses the basename + a short hash of the full path to avoid collisions
20
- * between files named the same thing in different directories.
21
- *
22
- * Example: /project/pages/about.tsx → .authtics_host/cache/about.tsx_a3f9b2.json
23
- */
24
11
  export function tempFileForTsx(tsxPath) {
25
12
  ensureTempDirs();
26
13
  const base = path.basename(tsxPath);
27
14
  const hash = simpleHash(tsxPath);
28
15
  return path.join(CACHE_DIR, `${base}_${hash}.json`);
29
16
  }
30
- /**
31
- * Returns true if the cache file exists and is at least as new as the source file.
32
- */
33
17
  export function isTempUpToDate(tsxPath, tempPath) {
34
18
  try {
35
19
  const srcMtime = fs.statSync(tsxPath).mtimeMs;
@@ -46,19 +30,12 @@ export function writeTempFile(tempPath, content) {
46
30
  export function readTempFile(tempPath) {
47
31
  return fs.readFileSync(tempPath, "utf-8");
48
32
  }
49
- /**
50
- * Wipes the entire cache directory. Useful for a `authtics clean` CLI command.
51
- */
52
33
  export function clearCache() {
53
34
  if (fs.existsSync(CACHE_DIR)) {
54
35
  fs.rmSync(CACHE_DIR, { recursive: true, force: true });
55
36
  }
56
37
  ensureTempDirs();
57
38
  }
58
- // ---------------------------------------------------------------------------
59
- // Internal helpers
60
- // ---------------------------------------------------------------------------
61
- /** Tiny non-cryptographic hash — good enough to avoid filename collisions. */
62
39
  function simpleHash(str) {
63
40
  let h = 0;
64
41
  for (let i = 0; i < str.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananacool467/authtics-host",
3
- "version": "0.0.1-beta.9",
3
+ "version": "0.0.2-beta.2",
4
4
  "description": "A Next.js-inspired SSR framework for Node.js with TypeScript and JSX support.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -40,25 +40,27 @@
40
40
  "author": "bananacool467",
41
41
  "license": "MIT",
42
42
  "dependencies": {
43
+ "@babel/core": "^7.29.0",
44
+ "@babel/preset-env": "^7.29.0",
45
+ "@babel/preset-react": "^7.28.5",
46
+ "@babel/preset-typescript": "^7.28.5",
47
+ "@types/babel__core": "^7.20.5",
48
+ "@types/babel__preset-env": "^7.10.0",
43
49
  "esbuild": "^0.27.3",
44
50
  "jiti": "^2.6.1",
45
51
  "lucide-react": "^0.577.0",
46
52
  "prismjs": "^1.30.0",
47
- "react-device-detect": "^2.2.3",
48
- "@babel/core": "^7.29.0",
49
- "@babel/preset-env": "^7.29.0",
50
- "@babel/preset-react": "^7.28.5",
51
- "@babel/preset-typescript": "^7.28.5"
53
+ "react-device-detect": "^2.2.3"
52
54
  },
53
55
  "peerDependencies": {
54
56
  "react": "^19.2.4",
55
57
  "react-dom": "^19.2.4"
56
58
  },
57
59
  "devDependencies": {
60
+ "@types/node": "^22.13.11",
61
+ "@types/prismjs": "^1.26.6",
58
62
  "@types/react": "^19.2.14",
59
63
  "@types/react-dom": "^19.2.3",
60
- "@types/react-syntax-highlighter": "^15.5.13",
61
- "@types/node": "^22.13.11",
62
- "@types/prismjs": "^1.26.6"
64
+ "@types/react-syntax-highlighter": "^15.5.13"
63
65
  }
64
66
  }