rerender-lens 0.5.0 → 0.7.0
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/CHANGELOG.md +50 -1
- package/README.md +23 -4
- package/dist/{budget-CRswn-nC.d.cts → budget-CA1MS7lB.d.cts} +1 -1
- package/dist/{budget-BnJlYwrV.d.ts → budget-ok1VDJ4t.d.ts} +1 -1
- package/dist/cli.cjs +78 -26
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +78 -26
- package/dist/cli.js.map +1 -1
- package/dist/{devtools-BYWat7nQ.d.ts → devtools-Cl5n_52v.d.ts} +11 -2
- package/dist/{devtools-DJi_6AfJ.d.cts → devtools-UwQx2VYS.d.cts} +11 -2
- package/dist/index.cjs +99 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +99 -10
- package/dist/index.js.map +1 -1
- package/dist/jest-setup.cjs +20 -3
- package/dist/jest-setup.cjs.map +1 -1
- package/dist/jest-setup.d.cts +4 -4
- package/dist/jest-setup.d.ts +4 -4
- package/dist/jest-setup.js +20 -3
- package/dist/jest-setup.js.map +1 -1
- package/dist/jest.cjs +20 -3
- package/dist/jest.cjs.map +1 -1
- package/dist/jest.d.cts +4 -4
- package/dist/jest.d.ts +4 -4
- package/dist/jest.js +20 -3
- package/dist/jest.js.map +1 -1
- package/dist/{notifiers-DwKlvv4H.d.cts → notifiers-B5poAEvE.d.cts} +2 -2
- package/dist/{notifiers-FNzKHs0a.d.ts → notifiers-CqQW0Eum.d.ts} +2 -2
- package/dist/playwright.d.cts +4 -4
- package/dist/playwright.d.ts +4 -4
- package/dist/relay.cjs +65 -21
- package/dist/relay.cjs.map +1 -1
- package/dist/relay.d.cts +25 -3
- package/dist/relay.d.ts +25 -3
- package/dist/relay.js +65 -21
- package/dist/relay.js.map +1 -1
- package/dist/rerender-lens.iife.js +105 -12
- package/dist/{runner-report-CW8X5RwK.d.ts → runner-report-Bvqoe89M.d.ts} +2 -2
- package/dist/{runner-report-B8Sc3FZO.d.cts → runner-report-CvpDg2zt.d.cts} +2 -2
- package/dist/setup.cjs +98 -9
- package/dist/setup.cjs.map +1 -1
- package/dist/setup.js +98 -9
- package/dist/setup.js.map +1 -1
- package/dist/{types-DW5-N2XH.d.cts → types-DwNN5cWe.d.cts} +28 -1
- package/dist/{types-DW5-N2XH.d.ts → types-DwNN5cWe.d.ts} +28 -1
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vitest-setup.cjs +20 -3
- package/dist/vitest-setup.cjs.map +1 -1
- package/dist/vitest-setup.d.cts +4 -4
- package/dist/vitest-setup.d.ts +4 -4
- package/dist/vitest-setup.js +20 -3
- package/dist/vitest-setup.js.map +1 -1
- package/dist/vitest.cjs +20 -3
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +5 -5
- package/dist/vitest.d.ts +5 -5
- package/dist/vitest.js +20 -3
- package/dist/vitest.js.map +1 -1
- package/package.json +3 -2
- package/panel/panel.css +48 -0
- package/panel/panel.js +348 -20
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { writeFileSync, readFileSync, existsSync } from 'fs';
|
|
|
3
3
|
import { createServer } from 'http';
|
|
4
4
|
import { join, dirname } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { randomBytes } from 'crypto';
|
|
6
7
|
|
|
7
8
|
// src/diff.ts
|
|
8
9
|
var AVOIDABLE_KINDS = /* @__PURE__ */ new Set(["deep-equal", "function", "element"]);
|
|
@@ -402,6 +403,8 @@ function checkBudget(reports, budget) {
|
|
|
402
403
|
function toBudget(reports) {
|
|
403
404
|
return { "*": 0, ...avoidableCounts(reports) };
|
|
404
405
|
}
|
|
406
|
+
var MARKER = "__rerenderLens";
|
|
407
|
+
var PROTOCOL = 2;
|
|
405
408
|
var MIME = { ".html": "text/html; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".css": "text/css; charset=utf-8" };
|
|
406
409
|
function findPanelDir() {
|
|
407
410
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -436,26 +439,55 @@ function createRelayServer(options = {}) {
|
|
|
436
439
|
const host = options.host ?? "127.0.0.1";
|
|
437
440
|
const panelDir = options.panelDir === void 0 ? findPanelDir() : options.panelDir;
|
|
438
441
|
const keepAliveMs = options.keepAliveMs ?? 15e3;
|
|
439
|
-
const
|
|
442
|
+
const token = options.token || null;
|
|
443
|
+
const apps = /* @__PURE__ */ new Map();
|
|
440
444
|
const panels = /* @__PURE__ */ new Set();
|
|
441
445
|
let url = "";
|
|
442
|
-
|
|
443
|
-
|
|
446
|
+
let nextAppId = 1;
|
|
447
|
+
const connectUrl = () => token ? `${url}?token=${encodeURIComponent(token)}` : url;
|
|
448
|
+
const line = (message) => `data: ${JSON.stringify(message)}
|
|
444
449
|
|
|
445
450
|
`;
|
|
446
|
-
|
|
451
|
+
const sendTo = (res, message) => {
|
|
452
|
+
try {
|
|
453
|
+
res.write(line(message));
|
|
454
|
+
} catch {
|
|
455
|
+
apps.delete(res);
|
|
456
|
+
panels.delete(res);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
const send = (targets, message) => {
|
|
460
|
+
const text = line(message);
|
|
461
|
+
for (const res of [...targets]) {
|
|
447
462
|
try {
|
|
448
|
-
res.write(
|
|
463
|
+
res.write(text);
|
|
449
464
|
} catch {
|
|
450
|
-
|
|
465
|
+
apps.delete(res);
|
|
466
|
+
panels.delete(res);
|
|
451
467
|
}
|
|
452
468
|
}
|
|
453
469
|
};
|
|
454
|
-
const
|
|
470
|
+
const appList = () => [...apps.values()];
|
|
471
|
+
const roster = () => ({ [MARKER]: true, version: PROTOCOL, type: "relay", payload: { apps: apps.size, list: appList() } });
|
|
472
|
+
const streamOf = (id) => {
|
|
473
|
+
for (const [res, app] of apps) if (app.id === id) return res;
|
|
474
|
+
return null;
|
|
475
|
+
};
|
|
476
|
+
const route = (message, from) => {
|
|
455
477
|
if (!message || typeof message !== "object") return;
|
|
456
478
|
const m = message;
|
|
457
|
-
if (m.__rerenderLensCmd === true)
|
|
458
|
-
|
|
479
|
+
if (m.__rerenderLensCmd === true) {
|
|
480
|
+
const target = typeof m.app === "string" ? streamOf(m.app) : null;
|
|
481
|
+
if (target) sendTo(target, m);
|
|
482
|
+
else send(apps.keys(), m);
|
|
483
|
+
} else if (m.__rerenderLens === true || m.__rerenderLensReply === true) {
|
|
484
|
+
send(panels, from ? { ...m, app: from.id } : m);
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
const authorized = (req, u) => {
|
|
488
|
+
if (!token) return true;
|
|
489
|
+
const given = u.searchParams.get("token") || (typeof req.headers["x-rerender-lens-token"] === "string" ? req.headers["x-rerender-lens-token"] : "");
|
|
490
|
+
return given === token;
|
|
459
491
|
};
|
|
460
492
|
const server = createServer(async (req, res) => {
|
|
461
493
|
cors(res);
|
|
@@ -467,18 +499,26 @@ function createRelayServer(options = {}) {
|
|
|
467
499
|
}
|
|
468
500
|
if (u.pathname === "/" && req.method === "GET") {
|
|
469
501
|
res.statusCode = 302;
|
|
470
|
-
res.setHeader("Location", `/panel.html?relay=${encodeURIComponent(
|
|
502
|
+
res.setHeader("Location", `/panel.html?relay=${encodeURIComponent(connectUrl())}`);
|
|
471
503
|
res.end();
|
|
472
504
|
return;
|
|
473
505
|
}
|
|
506
|
+
if (/^\/(events|message|status)$/.test(u.pathname) && !authorized(req, u)) {
|
|
507
|
+
res.statusCode = 401;
|
|
508
|
+
res.setHeader("Content-Type", "text/plain");
|
|
509
|
+
res.end("rerender-lens relay: this relay needs the token from the URL it printed (?token=...)");
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
474
512
|
if (u.pathname === "/events" && req.method === "GET") {
|
|
475
|
-
const
|
|
513
|
+
const isApp = u.searchParams.get("role") === "app";
|
|
476
514
|
res.statusCode = 200;
|
|
477
515
|
res.setHeader("Content-Type", "text/event-stream");
|
|
478
516
|
res.setHeader("Cache-Control", "no-store");
|
|
479
517
|
res.setHeader("Connection", "keep-alive");
|
|
480
518
|
res.write(": connected\n\n");
|
|
481
|
-
|
|
519
|
+
const app = isApp ? { id: `a${nextAppId++}`, label: (u.searchParams.get("label") || req.headers.origin || "").slice(0, 120) || `app ${nextAppId - 1}` } : null;
|
|
520
|
+
if (app) apps.set(res, app);
|
|
521
|
+
else panels.add(res);
|
|
482
522
|
const ping = setInterval(() => {
|
|
483
523
|
try {
|
|
484
524
|
res.write(": ping\n\n");
|
|
@@ -487,14 +527,15 @@ function createRelayServer(options = {}) {
|
|
|
487
527
|
}, keepAliveMs);
|
|
488
528
|
req.on("close", () => {
|
|
489
529
|
clearInterval(ping);
|
|
490
|
-
|
|
530
|
+
apps.delete(res);
|
|
531
|
+
panels.delete(res);
|
|
491
532
|
});
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
send(panels,
|
|
495
|
-
req.on("close", () => send(panels,
|
|
533
|
+
if (app) {
|
|
534
|
+
sendTo(res, { __rerenderLensRelay: true, version: PROTOCOL, app: app.id });
|
|
535
|
+
send(panels, roster());
|
|
536
|
+
req.on("close", () => send(panels, roster()));
|
|
496
537
|
} else {
|
|
497
|
-
|
|
538
|
+
sendTo(res, roster());
|
|
498
539
|
}
|
|
499
540
|
return;
|
|
500
541
|
}
|
|
@@ -506,7 +547,9 @@ function createRelayServer(options = {}) {
|
|
|
506
547
|
if (u.pathname === "/message" && req.method === "POST") {
|
|
507
548
|
try {
|
|
508
549
|
const parsed = JSON.parse(await readBody(req) || "null");
|
|
509
|
-
|
|
550
|
+
const sender = u.searchParams.get("app");
|
|
551
|
+
const from = sender ? appList().find((a) => a.id === sender) ?? void 0 : void 0;
|
|
552
|
+
for (const m of Array.isArray(parsed) ? parsed : [parsed]) route(m, from);
|
|
510
553
|
res.statusCode = 204;
|
|
511
554
|
res.end();
|
|
512
555
|
} catch (e) {
|
|
@@ -519,7 +562,7 @@ function createRelayServer(options = {}) {
|
|
|
519
562
|
if (u.pathname === "/status" && req.method === "GET") {
|
|
520
563
|
res.statusCode = 200;
|
|
521
564
|
res.setHeader("Content-Type", "application/json");
|
|
522
|
-
res.end(JSON.stringify({ ok: true, apps: apps.size, panels: panels.size }));
|
|
565
|
+
res.end(JSON.stringify({ ok: true, apps: apps.size, panels: panels.size, list: appList() }));
|
|
523
566
|
return;
|
|
524
567
|
}
|
|
525
568
|
const file = u.pathname.replace(/^\//, "");
|
|
@@ -549,10 +592,12 @@ function createRelayServer(options = {}) {
|
|
|
549
592
|
resolve({
|
|
550
593
|
server,
|
|
551
594
|
url,
|
|
595
|
+
connectUrl: connectUrl(),
|
|
552
596
|
port,
|
|
553
597
|
counts: () => ({ apps: apps.size, panels: panels.size }),
|
|
598
|
+
appList,
|
|
554
599
|
close: () => new Promise((done) => {
|
|
555
|
-
for (const res of [...apps, ...panels]) res.end();
|
|
600
|
+
for (const res of [...apps.keys(), ...panels]) res.end();
|
|
556
601
|
apps.clear();
|
|
557
602
|
panels.clear();
|
|
558
603
|
server.close(() => done());
|
|
@@ -561,8 +606,6 @@ function createRelayServer(options = {}) {
|
|
|
561
606
|
});
|
|
562
607
|
});
|
|
563
608
|
}
|
|
564
|
-
|
|
565
|
-
// src/cli.ts
|
|
566
609
|
var read = (file) => JSON.parse(readFileSync(file, "utf8"));
|
|
567
610
|
function summaryOf(file) {
|
|
568
611
|
const parsed = parseExport(read(file));
|
|
@@ -570,14 +613,20 @@ function summaryOf(file) {
|
|
|
570
613
|
if (parsed.sessions.length && !parsed.reports.length) return parsed.sessions[parsed.sessions.length - 1];
|
|
571
614
|
return summarizeReports(parsed.reports, { name: file.replace(/^.*[\\/]/, "").replace(/\.json$/, "") });
|
|
572
615
|
}
|
|
616
|
+
var isLoopback = (host) => host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
573
617
|
async function panelCommand(args) {
|
|
574
618
|
const flag = (name) => {
|
|
575
619
|
const i = args.indexOf(name);
|
|
576
620
|
return i >= 0 ? args[i + 1] ?? "" : null;
|
|
577
621
|
};
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
622
|
+
const host = flag("--host") || "127.0.0.1";
|
|
623
|
+
const given = flag("--token");
|
|
624
|
+
const token = args.includes("--no-token") ? null : given || (isLoopback(host) ? null : randomToken());
|
|
625
|
+
const relay = await createRelayServer({ port: Number(flag("--port") || 4141), host, token: token ?? void 0 });
|
|
626
|
+
console.log(`rerender-lens panel: ${relay.connectUrl}/`);
|
|
627
|
+
console.log(`in the app: createDevtoolsNotifier({ relay: '${relay.connectUrl}' }) or window.__RERENDER_LENS_RELAY__ = '${relay.connectUrl}'`);
|
|
628
|
+
if (token) console.log("The token in that URL is required: reports carry your app's prop, state and context values.");
|
|
629
|
+
else if (!isLoopback(host)) console.log(`WARNING: ${host} is reachable by other machines and --no-token was given: anyone who can reach this port can read every report.`);
|
|
581
630
|
console.log("Ctrl+C to stop.");
|
|
582
631
|
return new Promise((resolve) => {
|
|
583
632
|
const stop = () => void relay.close().then(() => resolve(0));
|
|
@@ -586,6 +635,9 @@ async function panelCommand(args) {
|
|
|
586
635
|
relay.server.once("close", () => resolve(0));
|
|
587
636
|
});
|
|
588
637
|
}
|
|
638
|
+
function randomToken() {
|
|
639
|
+
return randomBytes(16).toString("base64url");
|
|
640
|
+
}
|
|
589
641
|
function main(argv) {
|
|
590
642
|
const [cmd, ...args] = argv;
|
|
591
643
|
if (cmd === "panel") return panelCommand(args).catch((e) => (console.error(e.message), 1));
|