@bananacool467/authtics-host 0.1.5 → 0.1.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/cli.js CHANGED
@@ -45,14 +45,6 @@ const MIME_TYPES = {
45
45
  '.txt': 'text/plain',
46
46
  '.pdf': 'application/pdf',
47
47
  };
48
- function augmentRes(res) {
49
- const r = res;
50
- r.html = (html) => { res.setHeader("Content-Type", "text/html"); res.end(html); };
51
- r.json = (data) => { res.setHeader("Content-Type", "application/json"); res.end(JSON.stringify(data)); };
52
- r.text = (text) => { res.setHeader("Content-Type", "text/plain"); res.end(text); };
53
- r.status = (code) => { res.statusCode = code; return r; };
54
- return r;
55
- }
56
48
  const getCpu = () => {
57
49
  return new Promise((resolve) => {
58
50
  const start = process.cpuUsage();
@@ -97,29 +89,14 @@ export default class App {
97
89
  server;
98
90
  constructor() {
99
91
  this.server = start();
100
- this.get('/failed-to-handle', async (req, res) => {
101
- if (!usersPaused) {
102
- res.writeHead(302, {
103
- 'Location': '/'
104
- });
105
- res.end();
106
- return;
107
- }
108
- ;
109
- res.writeHead(200, { "Content-Type": "application/json" });
110
- res.end(JSON.stringify({
111
- message: "unhandled request"
112
- }));
113
- });
114
92
  this.post('/__authtics_host_apis__/set-users-paused', async (req, res) => {
115
- const reqBody = (await getJsonBody(req));
116
93
  let datMatched = false;
117
- if (config_.dat && config_.dat == reqBody.dat)
94
+ if (config_.dat && config_.dat == req.cookies.dat)
118
95
  datMatched = true;
119
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
96
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
120
97
  datMatched = true;
121
98
  if (datMatched) {
122
- usersPaused = reqBody.paused;
99
+ usersPaused = req.body.paused;
123
100
  res.writeHead(200, { "Content-Type": "application/json" });
124
101
  res.end(JSON.stringify({
125
102
  message: "ok"
@@ -127,27 +104,27 @@ export default class App {
127
104
  }
128
105
  });
129
106
  this.post('/__authtics_host_apis__/is-users-paused', async (req, res) => {
130
- const reqBody = (await getJsonBody(req));
131
107
  let datMatched = false;
132
- if (config_.dat && config_.dat == reqBody.dat)
108
+ if (config_.dat && config_.dat == req.cookies.dat)
133
109
  datMatched = true;
134
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
110
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
135
111
  datMatched = true;
136
112
  res.writeHead(200, { "Content-Type": "application/json" });
137
- res.end(JSON.stringify({
138
- paused: (datMatched ? false : usersPaused),
139
- realInfo: usersPaused
140
- }));
113
+ if (datMatched) {
114
+ res.end(JSON.stringify({
115
+ paused: (datMatched ? false : usersPaused),
116
+ realInfo: usersPaused
117
+ }));
118
+ }
141
119
  });
142
120
  this.post('/__authtics_host_apis__/get-dat-restriction-missing', async (req, res) => {
143
- const reqBody = (await getJsonBody(req));
144
121
  let datMatched = false;
145
122
  let datRestrictedEnv = false;
146
- if (config_.dat && config_.dat == reqBody.dat)
123
+ if (config_.dat && config_.dat == req.cookies.dat)
147
124
  datMatched = true;
148
125
  if (config_.dat == undefined)
149
126
  datMatched = true;
150
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
127
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
151
128
  datMatched = true;
152
129
  if (datMatched) {
153
130
  if (config_.dat !== undefined)
@@ -159,13 +136,12 @@ export default class App {
159
136
  }
160
137
  });
161
138
  this.post('/__authtics_host_apis__/get-dat-matching', async (req, res) => {
162
- const reqBody = (await getJsonBody(req));
163
139
  let datMatched = false;
164
- if (config_.dat && config_.dat == reqBody.dat)
140
+ if (config_.dat && config_.dat == req.cookies.dat)
165
141
  datMatched = true;
166
142
  if (config_.dat == undefined)
167
143
  datMatched = true;
168
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
144
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
169
145
  datMatched = true;
170
146
  res.writeHead(200, { "Content-Type": "application/json" });
171
147
  res.end(JSON.stringify({
@@ -173,11 +149,10 @@ export default class App {
173
149
  }));
174
150
  });
175
151
  this.post('/__authtics_host_apis__/get-cpu_memory', async (req, res) => {
176
- const reqBody = (await getJsonBody(req));
177
152
  let datMatched = false;
178
- if (config_.dat && config_.dat == reqBody.dat)
153
+ if (config_.dat && config_.dat == req.cookies.dat)
179
154
  datMatched = true;
180
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
155
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
181
156
  datMatched = true;
182
157
  if (datMatched) {
183
158
  const { heapUsed, heapTotal, rss } = process.memoryUsage();
@@ -190,11 +165,10 @@ export default class App {
190
165
  }
191
166
  });
192
167
  this.post('/__authtics_host_apis__/get-user-settings', async (req, res) => {
193
- const reqBody = (await getJsonBody(req));
194
168
  let datMatched = false;
195
- if (config_.dat && config_.dat == reqBody.dat)
169
+ if (config_.dat && config_.dat == req.cookies.dat)
196
170
  datMatched = true;
197
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
171
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
198
172
  datMatched = true;
199
173
  if (datMatched) {
200
174
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -204,11 +178,10 @@ export default class App {
204
178
  }
205
179
  });
206
180
  this.post("/__authtics_host_apis__/get-server-info", async (req, res) => {
207
- const reqBody = (await getJsonBody(req));
208
181
  let datMatched = false;
209
- if (config_.dat && config_.dat == reqBody.dat)
182
+ if (config_.dat && config_.dat == req.cookies.dat)
210
183
  datMatched = true;
211
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
184
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
212
185
  datMatched = true;
213
186
  if (datMatched) {
214
187
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -218,11 +191,10 @@ export default class App {
218
191
  }
219
192
  });
220
193
  this.post("/__authtics_host_apis__/restart", async (req, res) => {
221
- const reqBody = (await getJsonBody(req));
222
194
  let datMatched = false;
223
- if (config_.dat && config_.dat == reqBody.dat)
195
+ if (config_.dat && config_.dat == req.cookies.dat)
224
196
  datMatched = true;
225
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
197
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
226
198
  datMatched = true;
227
199
  if (datMatched) {
228
200
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -237,11 +209,10 @@ export default class App {
237
209
  }
238
210
  });
239
211
  this.post("/__authtics_host_apis__/shutdown", async (req, res) => {
240
- const reqBody = (await getJsonBody(req));
241
212
  let datMatched = false;
242
- if (config_.dat && config_.dat == reqBody.dat)
213
+ if (config_.dat && config_.dat == req.cookies.dat)
243
214
  datMatched = true;
244
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
215
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
245
216
  datMatched = true;
246
217
  if (datMatched) {
247
218
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -252,11 +223,10 @@ export default class App {
252
223
  }
253
224
  });
254
225
  this.post("/__authtics_host_apis__/get-is-ssr", async (req, res) => {
255
- const reqBody = (await getJsonBody(req));
256
226
  let datMatched = false;
257
- if (config_.dat && config_.dat == reqBody.dat)
227
+ if (config_.dat && config_.dat == req.cookies.dat)
258
228
  datMatched = true;
259
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
229
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
260
230
  datMatched = true;
261
231
  if (datMatched) {
262
232
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -266,11 +236,10 @@ export default class App {
266
236
  }
267
237
  });
268
238
  this.post("/__authtics_host_apis__/get-compiler", async (req, res) => {
269
- const reqBody = (await getJsonBody(req));
270
239
  let datMatched = false;
271
- if (config_.dat && config_.dat == reqBody.dat)
240
+ if (config_.dat && config_.dat == req.cookies.dat)
272
241
  datMatched = true;
273
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
242
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
274
243
  datMatched = true;
275
244
  if (datMatched) {
276
245
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -280,11 +249,10 @@ export default class App {
280
249
  }
281
250
  });
282
251
  this.post("/__authtics_host_apis__/get-host-ver", async (req, res) => {
283
- const reqBody = (await getJsonBody(req));
284
252
  let datMatched = false;
285
- if (config_.dat && config_.dat == reqBody.dat)
253
+ if (config_.dat && config_.dat == req.cookies.dat)
286
254
  datMatched = true;
287
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
255
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
288
256
  datMatched = true;
289
257
  if (datMatched) {
290
258
  const packageJsonPath = path.join(__dirname, '../package.json');
@@ -299,14 +267,13 @@ export default class App {
299
267
  }
300
268
  });
301
269
  this.post("/__authtics_host_apis__/get-file-by-pathname", async (req, res) => {
302
- const reqBody = (await getJsonBody(req));
303
270
  let datMatched = false;
304
- if (config_.dat && config_.dat == reqBody.dat)
271
+ if (config_.dat && config_.dat == req.cookies.dat)
305
272
  datMatched = true;
306
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
273
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
307
274
  datMatched = true;
308
275
  if (datMatched) {
309
- const pathname = reqBody.pathname;
276
+ const pathname = req.body.pathname;
310
277
  const pagesDir = config_.autoPage === true ? path.join(process.cwd(), config_.autoPageDir || "") : undefined;
311
278
  const safePath = path.normalize(pathname).replace(/^(\.\.[\/\\])+/, '');
312
279
  let filePath = pagesDir ? path.join(pagesDir, (safePath !== "/" ? safePath : "index") + ".tsx") : undefined;
@@ -337,11 +304,10 @@ export default class App {
337
304
  }
338
305
  });
339
306
  this.post("/__authtics_host_apis__/ping", async (req, res) => {
340
- const reqBody = (await getJsonBody(req));
341
307
  let datMatched = false;
342
- if (config_.dat && config_.dat == reqBody.dat)
308
+ if (config_.dat && config_.dat == req.cookies.dat)
343
309
  datMatched = true;
344
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
310
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
345
311
  datMatched = true;
346
312
  if (datMatched) {
347
313
  res.setHeader("Content-Type", "application/json");
@@ -349,11 +315,10 @@ export default class App {
349
315
  }
350
316
  });
351
317
  this.post('/__authtics_host_apis__/get-connection', async (req, res) => {
352
- const reqBody = (await getJsonBody(req));
353
318
  let datMatched = false;
354
- if (config_.dat && config_.dat == reqBody.dat)
319
+ if (config_.dat && config_.dat == req.cookies.dat)
355
320
  datMatched = true;
356
- if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(reqBody.dat))
321
+ if (config_.dat && Array.isArray(config_.dat) && config_.dat.includes(req.cookies.dat))
357
322
  datMatched = true;
358
323
  if (datMatched) {
359
324
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -378,6 +343,10 @@ export default class App {
378
343
  delete(routePath, handler) {
379
344
  routes.set(`DELETE:${routePath}`, handler);
380
345
  }
346
+ remove(method, routePath) {
347
+ if (routes.has(`${method}:${routePath}`))
348
+ routes.delete(`${method}:${routePath}`);
349
+ }
381
350
  }
382
351
  async function start() {
383
352
  let config = {};
@@ -397,26 +366,247 @@ async function start() {
397
366
  const publicDir = config.autoFile === true ? path.join(process.cwd(), config.autoFileDir || "") : undefined;
398
367
  const apiDir = pagesDir ? path.join(pagesDir, "api") : undefined;
399
368
  const server = createServer(async (req, res) => {
400
- const actuallyShowPanel = showPanel;
401
- const r = augmentRes(res);
402
369
  const { url = "/", method } = req;
370
+ const actuallyShowPanel = showPanel;
371
+ req.ip = (req.headers["x-real-ip"] ||
372
+ req.headers["x-forwarded-for"]?.split(",")[0].trim() ||
373
+ req.socket.remoteAddress ||
374
+ undefined);
375
+ req.ipType = req.ip?.includes(":") ? 6 : req.ip?.includes(".") ? 4 : 0;
376
+ req.ua = req.headers["user-agent"] || undefined;
377
+ let ua = req.headers["user-agent"] || "";
378
+ let browserType = "Unknown";
379
+ let browserVersion = "Unknown";
380
+ if (ua.includes("Chrome") && !ua.includes("Edg")) {
381
+ browserType = "Chrome";
382
+ browserVersion = ua.match(/Chrome\/([\d.]+)/)?.[1] || "Unknown";
383
+ }
384
+ else if (ua.includes("Firefox")) {
385
+ browserType = "Firefox";
386
+ browserVersion = ua.match(/Firefox\/([\d.]+)/)?.[1] || "Unknown";
387
+ }
388
+ else if (ua.includes("Safari") && !ua.includes("Chrome")) {
389
+ browserType = "Safari";
390
+ browserVersion = ua.match(/Version\/([\d.]+)/)?.[1] || "Unknown";
391
+ }
392
+ else if (ua.includes("Edg")) {
393
+ browserType = "Edge";
394
+ browserVersion = ua.match(/Edg\/([\d.]+)/)?.[1] || "Unknown";
395
+ }
396
+ let osType = "Unknown";
397
+ let osVersion = "Unknown";
398
+ if (ua.includes("Windows NT")) {
399
+ osType = "Windows";
400
+ osVersion = ua.match(/Windows NT ([\d.]+)/)?.[1] || "Unknown";
401
+ }
402
+ else if (ua.includes("Mac OS X")) {
403
+ osType = "macOS";
404
+ osVersion = ua.match(/Mac OS X ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "Unknown";
405
+ }
406
+ else if (ua.includes("Android")) {
407
+ osType = "Android";
408
+ osVersion = ua.match(/Android ([\d.]+)/)?.[1] || "Unknown";
409
+ }
410
+ else if (ua.includes("iPhone") || ua.includes("iPad")) {
411
+ osType = "iOS";
412
+ osVersion = ua.match(/OS ([\d_]+)/)?.[1]?.replace(/_/g, ".") || "Unknown";
413
+ }
414
+ else if (ua.includes("Linux")) {
415
+ osType = "Linux";
416
+ }
417
+ req.os = {
418
+ type: osType,
419
+ version: osVersion
420
+ };
421
+ req.browser = {
422
+ type: browserType,
423
+ version: browserVersion
424
+ };
425
+ req.sentTime = Date.now();
426
+ req.body = {};
427
+ try {
428
+ req.body = await getJsonBody(req);
429
+ }
430
+ catch (e) {
431
+ req.body = {};
432
+ }
433
+ req.cookies = {};
434
+ const raw = req.headers.cookie;
435
+ if (raw) {
436
+ raw.split(";").forEach(pair => {
437
+ const [key, val] = pair.trim().split("=");
438
+ req.cookies[key] = val;
439
+ });
440
+ }
441
+ req.dat = req.cookies.dat || undefined;
442
+ req.bodySize = JSON.stringify(req.body).length;
443
+ req.bodyType = req.headers['content-type'] || 'text/plain';
444
+ res.redirect = (url) => {
445
+ res.writeHead(302, {
446
+ 'Location': url
447
+ });
448
+ res.end();
449
+ };
450
+ res.html = (content) => {
451
+ res.setHeader("Content-Type", "text/html");
452
+ res.end(content);
453
+ };
454
+ res.json = (content) => {
455
+ res.setHeader("Content-Type", "application/json");
456
+ res.end(JSON.stringify(content));
457
+ };
458
+ res.text = (content) => {
459
+ res.setHeader("Content-Type", "text/plain");
460
+ res.end(content);
461
+ };
462
+ res.file = (path_) => {
463
+ const path__ = path.join(process.cwd(), path_);
464
+ if (fs.existsSync(path__)) {
465
+ const ext = path.extname(path__);
466
+ const mime = MIME_TYPES[ext] ?? 'application/octet-stream';
467
+ res.setHeader("Content-Type", mime);
468
+ res.end(fs.readFileSync(path__));
469
+ }
470
+ };
471
+ res.status = (code) => {
472
+ res.statusCode = code;
473
+ return res;
474
+ };
475
+ res.reload = function () {
476
+ res.writeHead(302, { Location: req.url + '/' });
477
+ res.end();
478
+ };
479
+ res.setCookie = function (name, value) {
480
+ res.setHeader("Set-Cookie", `${name}=${value}; Path=/`);
481
+ };
482
+ res.rmvCookie = function (name) {
483
+ res.setHeader("Set-Cookie", `${name}=; Path=/; Max-Age=0`);
484
+ };
403
485
  let pathname = url.split("?")[0].split("#")[0];
486
+ const safePath = path.normalize(pathname).replace(/^(\.\.[\/\\])+/, '');
487
+ pathname = safePath;
404
488
  if (pathname !== "/" && pathname.endsWith("/"))
405
489
  pathname = pathname.slice(0, -1);
406
- if (!pathname.includes('/__authtics_host_apis__/')) {
490
+ if (!pathname.includes('/__authtics') && !pathname.includes('/hmr')) {
407
491
  totalRequests++;
408
492
  }
409
493
  const routeKey = `${method}:${pathname}`;
410
494
  if (routes.has(routeKey)) {
495
+ if (Array.isArray(config_.dat) && !config_.dat.includes(req.cookies.dat) && usersPaused && !routeKey.endsWith('.js')) {
496
+ if (autoPaging) {
497
+ const pausedTsxFile = pagesDir ? path.join(pagesDir, "_paused.tsx") : undefined;
498
+ if (fs.existsSync(pausedTsxFile || "")) {
499
+ try {
500
+ let html = await renderPage(pausedTsxFile || "", url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
501
+ routes.set(`GET:${p}`, (req, res) => {
502
+ res.setHeader("Content-Type", "application/javascript");
503
+ res.end(f);
504
+ });
505
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
506
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
507
+ res.setHeader("Content-Type", "text/html");
508
+ return res.end(html);
509
+ }
510
+ catch (e) {
511
+ console.error("[authtics] renderPage error:", e.message);
512
+ res.writeHead(500);
513
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
514
+ }
515
+ }
516
+ }
517
+ if (config.hasPausedRoute) {
518
+ if (!autoPaging) {
519
+ const appTsxPath = routes.get("APP_TSX");
520
+ const appPath = path.join(process.cwd(), appTsxPath);
521
+ if (fs.existsSync(appPath)) {
522
+ try {
523
+ let html = await renderPage(appPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
524
+ routes.set(`GET:${p}`, (req, res) => {
525
+ res.setHeader("Content-Type", "application/javascript");
526
+ res.end(f);
527
+ });
528
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
529
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
530
+ res.setHeader("Content-Type", "text/html");
531
+ return res.end(html);
532
+ }
533
+ catch (e) {
534
+ console.error("[authtics] renderPage error:", e.message);
535
+ res.writeHead(500);
536
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
537
+ }
538
+ }
539
+ }
540
+ }
541
+ res.writeHead(200, {
542
+ "Content-Type": "application/json"
543
+ });
544
+ return res.end(JSON.stringify({
545
+ message: "unhandled request"
546
+ }));
547
+ }
548
+ if (config_.dat !== req.cookies.dat && usersPaused && !routeKey.endsWith('.js')) {
549
+ if (autoPaging) {
550
+ const pausedTsxFile = pagesDir ? path.join(pagesDir, "_paused.tsx") : undefined;
551
+ if (fs.existsSync(pausedTsxFile || "")) {
552
+ try {
553
+ let html = await renderPage(pausedTsxFile || "", url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
554
+ routes.set(`GET:${p}`, (req, res) => {
555
+ res.setHeader("Content-Type", "application/javascript");
556
+ res.end(f);
557
+ });
558
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
559
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
560
+ res.setHeader("Content-Type", "text/html");
561
+ return res.end(html);
562
+ }
563
+ catch (e) {
564
+ console.error("[authtics] renderPage error:", e.message);
565
+ res.writeHead(500);
566
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
567
+ }
568
+ }
569
+ }
570
+ if (config.hasPausedRoute) {
571
+ if (!autoPaging) {
572
+ const appTsxPath = routes.get("APP_TSX");
573
+ const appPath = path.join(process.cwd(), appTsxPath);
574
+ if (fs.existsSync(appPath)) {
575
+ try {
576
+ let html = await renderPage(appPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
577
+ routes.set(`GET:${p}`, (req, res) => {
578
+ res.setHeader("Content-Type", "application/javascript");
579
+ res.end(f);
580
+ });
581
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
582
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
583
+ res.setHeader("Content-Type", "text/html");
584
+ return res.end(html);
585
+ }
586
+ catch (e) {
587
+ console.error("[authtics] renderPage error:", e.message);
588
+ res.writeHead(500);
589
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
590
+ }
591
+ }
592
+ }
593
+ }
594
+ res.writeHead(200, {
595
+ "Content-Type": "application/json"
596
+ });
597
+ return res.end(JSON.stringify({
598
+ message: "unhandled request"
599
+ }));
600
+ }
411
601
  const handler = routes.get(routeKey);
412
602
  if (typeof handler === 'string') {
413
603
  return;
414
604
  }
415
605
  else if (typeof handler === 'function') {
416
- return handler(req, r);
606
+ return handler(req, res);
417
607
  }
418
608
  }
419
- if (pathname === '/__authtics_hmr__') {
609
+ if (pathname === '/hmr') {
420
610
  res.writeHead(200, {
421
611
  'Content-Type': 'text/event-stream',
422
612
  'Cache-Control': 'no-cache',
@@ -429,6 +619,112 @@ async function start() {
429
619
  req.on('close', () => { hmrClients.delete(res); users--; });
430
620
  return;
431
621
  }
622
+ if (Array.isArray(config_.dat) && !config_.dat.includes(req.cookies.dat) && usersPaused) {
623
+ if (autoPaging) {
624
+ const pausedTsxFile = pagesDir ? path.join(pagesDir, "_paused.tsx") : undefined;
625
+ if (fs.existsSync(pausedTsxFile || "")) {
626
+ try {
627
+ let html = await renderPage(pausedTsxFile || "", url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
628
+ routes.set(`GET:${p}`, (req, res) => {
629
+ res.setHeader("Content-Type", "application/javascript");
630
+ res.end(f);
631
+ });
632
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
633
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
634
+ res.setHeader("Content-Type", "text/html");
635
+ return res.end(html);
636
+ }
637
+ catch (e) {
638
+ console.error("[authtics] renderPage error:", e.message);
639
+ res.writeHead(500);
640
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
641
+ }
642
+ }
643
+ }
644
+ if (config.hasPausedRoute) {
645
+ if (!autoPaging) {
646
+ const appTsxPath = routes.get("APP_TSX");
647
+ const appPath = path.join(process.cwd(), appTsxPath);
648
+ if (fs.existsSync(appPath)) {
649
+ try {
650
+ let html = await renderPage(appPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
651
+ routes.set(`GET:${p}`, (req, res) => {
652
+ res.setHeader("Content-Type", "application/javascript");
653
+ res.end(f);
654
+ });
655
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
656
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
657
+ res.setHeader("Content-Type", "text/html");
658
+ return res.end(html);
659
+ }
660
+ catch (e) {
661
+ console.error("[authtics] renderPage error:", e.message);
662
+ res.writeHead(500);
663
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
664
+ }
665
+ }
666
+ }
667
+ }
668
+ res.writeHead(200, {
669
+ "Content-Type": "application/json"
670
+ });
671
+ return res.end(JSON.stringify({
672
+ message: "unhandled request"
673
+ }));
674
+ }
675
+ if (config.dat !== req.cookies.dat && usersPaused) {
676
+ if (autoPaging) {
677
+ const pausedTsxFile = pagesDir ? path.join(pagesDir, "_paused.tsx") : undefined;
678
+ if (fs.existsSync(pausedTsxFile || "")) {
679
+ try {
680
+ let html = await renderPage(pausedTsxFile || "", url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
681
+ routes.set(`GET:${p}`, (req, res) => {
682
+ res.setHeader("Content-Type", "application/javascript");
683
+ res.end(f);
684
+ });
685
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
686
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
687
+ res.setHeader("Content-Type", "text/html");
688
+ return res.end(html);
689
+ }
690
+ catch (e) {
691
+ console.error("[authtics] renderPage error:", e.message);
692
+ res.writeHead(500);
693
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
694
+ }
695
+ }
696
+ }
697
+ if (config.hasPausedRoute) {
698
+ if (!autoPaging) {
699
+ const appTsxPath = routes.get("APP_TSX");
700
+ const appPath = path.join(process.cwd(), appTsxPath);
701
+ if (fs.existsSync(appPath)) {
702
+ try {
703
+ let html = await renderPage(appPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
704
+ routes.set(`GET:${p}`, (req, res) => {
705
+ res.setHeader("Content-Type", "application/javascript");
706
+ res.end(f);
707
+ });
708
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
709
+ html = html.replace("<script>", "<script>\nwindow.__paused__ = true;");
710
+ res.setHeader("Content-Type", "text/html");
711
+ return res.end(html);
712
+ }
713
+ catch (e) {
714
+ console.error("[authtics] renderPage error:", e.message);
715
+ res.writeHead(500);
716
+ return res.end(`<html><body><pre>500 | Render error:\n${e.message}</pre></body></html>`);
717
+ }
718
+ }
719
+ }
720
+ }
721
+ res.writeHead(200, {
722
+ "Content-Type": "application/json"
723
+ });
724
+ return res.end(JSON.stringify({
725
+ message: "unhandled request"
726
+ }));
727
+ }
432
728
  if (publicDir && fs.existsSync(publicDir)) {
433
729
  const staticPath = path.join(publicDir, pathname);
434
730
  const safePath = path.resolve(staticPath);
@@ -443,7 +739,7 @@ async function start() {
443
739
  const apiFile = path.join(pagesDir, `${pathname}.ts`);
444
740
  const apiFileTsx = path.join(pagesDir, `${pathname}.tsx`);
445
741
  const resolvedApi = fs.existsSync(apiFile) ? apiFile : fs.existsSync(apiFileTsx) ? apiFileTsx : null;
446
- if (resolvedApi) {
742
+ if (resolvedApi && fs.existsSync(resolvedApi)) {
447
743
  try {
448
744
  const apiModule = await jiti.import(resolvedApi, { default: true });
449
745
  const handler = apiModule.default ?? apiModule.handler ?? null;
@@ -451,7 +747,7 @@ async function start() {
451
747
  res.writeHead(500);
452
748
  return res.end(`[authtics] API route ${pathname} must export a default function`);
453
749
  }
454
- return handler(req, r);
750
+ return handler(req, res);
455
751
  }
456
752
  catch (e) {
457
753
  console.error(`[authtics] API route error (${pathname}):`, e.message);
@@ -462,7 +758,12 @@ async function start() {
462
758
  const notFoundPath = path.join(__dirname, '404.js');
463
759
  if (fs.existsSync(notFoundPath)) {
464
760
  try {
465
- let html = await renderPage(notFoundPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""));
761
+ let html = await renderPage(notFoundPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
762
+ routes.set(`GET:${p}`, (req, res) => {
763
+ res.setHeader("Content-Type", "application/javascript");
764
+ res.end(f);
765
+ });
766
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
466
767
  res.setHeader("Content-Type", "text/html");
467
768
  res.writeHead(404);
468
769
  html = html.replace("<script>", "<script>\nwindow.__status_code__ = 404;");
@@ -483,7 +784,12 @@ async function start() {
483
784
  const htmlPath = pagesDir ? path.join(pagesDir, `${urlPath}.html`) : undefined;
484
785
  if (tsxPath && fs.existsSync(tsxPath)) {
485
786
  try {
486
- const html = await renderPage(tsxPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""));
787
+ const html = await renderPage(tsxPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
788
+ routes.set(`GET:${p}`, (req, res) => {
789
+ res.setHeader("Content-Type", "application/javascript");
790
+ res.end(f);
791
+ });
792
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
487
793
  res.setHeader("Content-Type", "text/html");
488
794
  return res.end(html);
489
795
  }
@@ -502,7 +808,12 @@ async function start() {
502
808
  const appPath = path.join(process.cwd(), appTsxPath);
503
809
  if (fs.existsSync(appPath)) {
504
810
  try {
505
- const html = await renderPage(appPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""));
811
+ const html = await renderPage(appPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
812
+ routes.set(`GET:${p}`, (req, res) => {
813
+ res.setHeader("Content-Type", "application/javascript");
814
+ res.end(f);
815
+ });
816
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
506
817
  res.setHeader("Content-Type", "text/html");
507
818
  return res.end(html);
508
819
  }
@@ -516,7 +827,12 @@ async function start() {
516
827
  const notFoundPath = path.join(__dirname, '404.js');
517
828
  if (fs.existsSync(notFoundPath)) {
518
829
  try {
519
- let html = await renderPage(notFoundPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""));
830
+ let html = await renderPage(notFoundPath, url, actuallyShowPanel, compiler, hotReload, autoPaging, config.autoPageDir, (routes.get("APP_TSX") || ""), (f, p) => {
831
+ routes.set(`GET:${p}`, (req, res) => {
832
+ res.setHeader("Content-Type", "application/javascript");
833
+ res.end(f);
834
+ });
835
+ }, (p) => { routes.delete(`GET:${p}`); }, req.cookies.dat, config_.dat);
520
836
  res.setHeader("Content-Type", "text/html");
521
837
  res.writeHead(404);
522
838
  html = html.replace("<script>", "<script>\nwindow.__status_code__ = 404;");
@@ -538,7 +854,7 @@ async function start() {
538
854
  }, 1000);
539
855
  });
540
856
  if (config.hotReload === true) {
541
- const watchDirs = [pagesDir];
857
+ const watchDirs = [pagesDir || path.join(routes.get("APP_TSX"), "../")];
542
858
  const devPanelDir = path.join(__dirname, 'devPanel.js');
543
859
  const _404Dir = path.join(__dirname, '404.js');
544
860
  if (fs.existsSync(devPanelDir))