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/relay.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/relay.ts"],"names":[],"mappings":"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","file":"relay.js","sourcesContent":["/**\n * A tiny local relay (`npx rerender-lens panel`): serves the panel and forwards messages between\n * app pages and panel pages over Server-Sent Events + POST, so any app (Next.js, Webpack, a\n * production-like build) gets the panel without the extension and without a same-origin channel.\n *\n * GET / redirect to /panel.html?relay=<this server>\n * GET /panel.(html|js|css) the panel page\n * GET /events?role=app SSE: commands from panels\n * GET /events?role=panel SSE: hello / report / clear from apps, replies to commands\n * POST /message one message or an array; `{ __rerenderLens }` and replies go to\n * panels, `{ __rerenderLensCmd }` goes to apps\n *\n * Dependency-free (node:http). CORS is open: the relay is a local dev tool, bind it to 127.0.0.1.\n */\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport interface RelayOptions {\n port?: number;\n host?: string;\n /** Directory with panel.html/js/css; found automatically in the package. */\n panelDir?: string | null;\n /** Milliseconds between SSE keep-alive comments. Default 15000. */\n keepAliveMs?: number;\n}\n\nexport interface RelayServer {\n server: Server;\n /** `http://127.0.0.1:4141` once listening. */\n url: string;\n port: number;\n close(): Promise<void>;\n /** Connected app and panel streams. */\n counts(): { apps: number; panels: number };\n}\n\nconst MIME: Record<string, string> = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8' };\n\nexport function findPanelDir(): string | null {\n const here = dirname(fileURLToPath(import.meta.url));\n for (const dir of [join(here, '..', 'panel'), join(here, '..', 'extension'), join(here, '..', '..', 'extension')]) {\n if (existsSync(join(dir, 'panel.html')) && existsSync(join(dir, 'panel.js'))) return dir;\n }\n return null;\n}\n\nconst cors = (res: ServerResponse): void => {\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n};\n\nfunction readBody(req: IncomingMessage, limit = 8 * 1024 * 1024): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on('data', (c: Buffer) => {\n size += c.length;\n if (size > limit) {\n reject(new Error('body too large'));\n req.destroy();\n return;\n }\n chunks.push(c);\n });\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));\n req.on('error', reject);\n });\n}\n\nexport function createRelayServer(options: RelayOptions = {}): Promise<RelayServer> {\n const host = options.host ?? '127.0.0.1';\n const panelDir = options.panelDir === undefined ? findPanelDir() : options.panelDir;\n const keepAliveMs = options.keepAliveMs ?? 15_000;\n const apps = new Set<ServerResponse>();\n const panels = new Set<ServerResponse>();\n let url = '';\n\n const send = (targets: Set<ServerResponse>, message: unknown): void => {\n const line = `data: ${JSON.stringify(message)}\\n\\n`;\n for (const res of targets) {\n try {\n res.write(line);\n } catch {\n targets.delete(res);\n }\n }\n };\n\n const route = (message: unknown): void => {\n if (!message || typeof message !== 'object') return;\n const m = message as Record<string, unknown>;\n if (m.__rerenderLensCmd === true) send(apps, m);\n else if (m.__rerenderLens === true || m.__rerenderLensReply === true) send(panels, m);\n };\n\n const server = createServer(async (req, res) => {\n cors(res);\n const u = new URL(req.url || '/', 'http://relay');\n if (req.method === 'OPTIONS') {\n res.statusCode = 204;\n res.end();\n return;\n }\n if (u.pathname === '/' && req.method === 'GET') {\n res.statusCode = 302;\n res.setHeader('Location', `/panel.html?relay=${encodeURIComponent(url)}`);\n res.end();\n return;\n }\n if (u.pathname === '/events' && req.method === 'GET') {\n const role = u.searchParams.get('role') === 'app' ? apps : panels;\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-store');\n res.setHeader('Connection', 'keep-alive');\n res.write(': connected\\n\\n');\n role.add(res);\n const ping = setInterval(() => {\n try {\n res.write(': ping\\n\\n');\n } catch {\n /* closed */\n }\n }, keepAliveMs);\n req.on('close', () => {\n clearInterval(ping);\n role.delete(res);\n });\n // Panels learn the app count as soon as their stream is open (that first message is also how a\n // panel knows it is safe to send commands: replies only reach panels that are already connected),\n // and again whenever an app comes or goes, so they show \"disconnected\" instead of waiting.\n const count = (): unknown => ({ __rerenderLens: true, version: 2, type: 'relay', payload: { apps: apps.size } });\n if (role === apps) {\n send(panels, count());\n req.on('close', () => send(panels, count()));\n } else {\n send(new Set([res]), count());\n }\n return;\n }\n if (u.pathname === '/favicon.ico') {\n res.statusCode = 204;\n res.end();\n return;\n }\n if (u.pathname === '/message' && req.method === 'POST') {\n try {\n const parsed = JSON.parse((await readBody(req)) || 'null') as unknown;\n for (const m of Array.isArray(parsed) ? parsed : [parsed]) route(m);\n res.statusCode = 204;\n res.end();\n } catch (e) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'text/plain');\n res.end(String((e as Error).message || e));\n }\n return;\n }\n if (u.pathname === '/status' && req.method === 'GET') {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, apps: apps.size, panels: panels.size }));\n return;\n }\n const file = u.pathname.replace(/^\\//, '');\n if (/^panel\\.(html|js|css)$/.test(file) && req.method === 'GET') {\n if (!panelDir) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'text/plain');\n res.end('rerender-lens: panel files not found (is the package built?)');\n return;\n }\n res.statusCode = 200;\n res.setHeader('Content-Type', MIME[file.slice(file.lastIndexOf('.'))] || 'application/octet-stream');\n res.setHeader('Cache-Control', 'no-store');\n res.end(readFileSync(join(panelDir, file)));\n return;\n }\n res.statusCode = 404;\n res.setHeader('Content-Type', 'text/plain');\n res.end('not found');\n });\n\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(options.port ?? 4141, host, () => {\n const addr = server.address();\n const port = typeof addr === 'object' && addr ? addr.port : options.port ?? 4141;\n url = `http://${host === '0.0.0.0' || host === '::' ? 'localhost' : host}:${port}`;\n resolve({\n server,\n url,\n port,\n counts: () => ({ apps: apps.size, panels: panels.size }),\n close: () =>\n new Promise<void>((done) => {\n for (const res of [...apps, ...panels]) res.end();\n apps.clear();\n panels.clear();\n server.close(() => done());\n }),\n });\n });\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/relay.ts"],"names":[],"mappings":"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","file":"relay.js","sourcesContent":["/**\n * A tiny local relay (`npx rerender-lens panel`): serves the panel and forwards messages between\n * app pages and panel pages over Server-Sent Events + POST, so any app (Next.js, Webpack, a\n * production-like build) gets the panel without the extension and without a same-origin channel.\n *\n * GET / redirect to /panel.html?relay=<this server>\n * GET /panel.(html|js|css) the panel page\n * GET /events?role=app SSE: commands from panels (first message: this app's id)\n * GET /events?role=panel SSE: hello / report / clear from apps, replies to commands\n * POST /message one message or an array; `{ __rerenderLens }` and replies go to\n * panels, `{ __rerenderLensCmd }` goes to apps\n *\n * Several apps can share one relay. Each app connection gets an id; the relay tells the app its id,\n * stamps `app` on everything that app sends, and sends panels the roster whenever it changes. A\n * command carrying `app` goes to that one app, a command without it goes to all of them, so a panel\n * or a library that knows nothing about ids behaves exactly as before.\n *\n * Dependency-free (node:http). Bound to 127.0.0.1 by default, where CORS is open and no token is\n * needed. On any other host `rerender-lens panel` generates a token: `/events`, `/message` and\n * `/status` then require it (`?token=` or the `x-rerender-lens-token` header) and the URL it prints\n * carries it, because reports contain the app's prop, state and context values.\n */\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport interface RelayOptions {\n port?: number;\n host?: string;\n /** Directory with panel.html/js/css; found automatically in the package. */\n panelDir?: string | null;\n /** Milliseconds between SSE keep-alive comments. Default 15000. */\n keepAliveMs?: number;\n /**\n * Require this token on `/events`, `/message` and `/status`. `rerender-lens panel` generates one\n * whenever it binds to anything but loopback; the URL it prints carries it as `?token=`.\n */\n token?: string;\n}\n\n/** One connected app page. `label` is what the panel's app chooser shows. */\nexport interface RelayApp {\n id: string;\n label: string;\n}\n\nexport interface RelayServer {\n server: Server;\n /** `http://127.0.0.1:4141` once listening. */\n url: string;\n /** The URL to hand to a panel or an app: `url`, plus `?token=` when one is required. */\n connectUrl: string;\n port: number;\n close(): Promise<void>;\n /** Connected app and panel streams. */\n counts(): { apps: number; panels: number };\n /** The connected apps, in connection order. */\n appList(): RelayApp[];\n}\n\n/** Same marker and protocol the library and the panel use (`src/devtools.ts`); kept literal so the relay stays dependency-free. */\nconst MARKER = '__rerenderLens';\nconst PROTOCOL = 2;\n\nconst MIME: Record<string, string> = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8' };\n\nexport function findPanelDir(): string | null {\n const here = dirname(fileURLToPath(import.meta.url));\n for (const dir of [join(here, '..', 'panel'), join(here, '..', 'extension'), join(here, '..', '..', 'extension')]) {\n if (existsSync(join(dir, 'panel.html')) && existsSync(join(dir, 'panel.js'))) return dir;\n }\n return null;\n}\n\nconst cors = (res: ServerResponse): void => {\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n};\n\nfunction readBody(req: IncomingMessage, limit = 8 * 1024 * 1024): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on('data', (c: Buffer) => {\n size += c.length;\n if (size > limit) {\n reject(new Error('body too large'));\n req.destroy();\n return;\n }\n chunks.push(c);\n });\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));\n req.on('error', reject);\n });\n}\n\nexport function createRelayServer(options: RelayOptions = {}): Promise<RelayServer> {\n const host = options.host ?? '127.0.0.1';\n const panelDir = options.panelDir === undefined ? findPanelDir() : options.panelDir;\n const keepAliveMs = options.keepAliveMs ?? 15_000;\n const token = options.token || null;\n const apps = new Map<ServerResponse, RelayApp>();\n const panels = new Set<ServerResponse>();\n let url = '';\n let nextAppId = 1;\n const connectUrl = (): string => (token ? `${url}?token=${encodeURIComponent(token)}` : url);\n\n const line = (message: unknown): string => `data: ${JSON.stringify(message)}\\n\\n`;\n const sendTo = (res: ServerResponse, message: unknown): void => {\n try {\n res.write(line(message));\n } catch {\n apps.delete(res);\n panels.delete(res);\n }\n };\n const send = (targets: Iterable<ServerResponse>, message: unknown): void => {\n const text = line(message);\n for (const res of [...targets]) {\n try {\n res.write(text);\n } catch {\n apps.delete(res);\n panels.delete(res);\n }\n }\n };\n\n const appList = (): RelayApp[] => [...apps.values()];\n const roster = (): unknown => ({ [MARKER]: true, version: PROTOCOL, type: 'relay', payload: { apps: apps.size, list: appList() } });\n const streamOf = (id: string): ServerResponse | null => {\n for (const [res, app] of apps) if (app.id === id) return res;\n return null;\n };\n\n const route = (message: unknown, from?: RelayApp): void => {\n if (!message || typeof message !== 'object') return;\n const m = message as Record<string, unknown>;\n if (m.__rerenderLensCmd === true) {\n // A command names its app when the panel is watching one of several; otherwise every app answers.\n const target = typeof m.app === 'string' ? streamOf(m.app) : null;\n if (target) sendTo(target, m);\n else send(apps.keys(), m);\n } else if (m.__rerenderLens === true || m.__rerenderLensReply === true) {\n send(panels, from ? { ...m, app: from.id } : m);\n }\n };\n\n /** With a token set, everything that carries data needs it; the static panel files do not. */\n const authorized = (req: IncomingMessage, u: URL): boolean => {\n if (!token) return true;\n const given = u.searchParams.get('token') || (typeof req.headers['x-rerender-lens-token'] === 'string' ? req.headers['x-rerender-lens-token'] : '');\n return given === token;\n };\n\n const server = createServer(async (req, res) => {\n cors(res);\n const u = new URL(req.url || '/', 'http://relay');\n if (req.method === 'OPTIONS') {\n res.statusCode = 204;\n res.end();\n return;\n }\n if (u.pathname === '/' && req.method === 'GET') {\n res.statusCode = 302;\n res.setHeader('Location', `/panel.html?relay=${encodeURIComponent(connectUrl())}`);\n res.end();\n return;\n }\n if (/^\\/(events|message|status)$/.test(u.pathname) && !authorized(req, u)) {\n res.statusCode = 401;\n res.setHeader('Content-Type', 'text/plain');\n res.end('rerender-lens relay: this relay needs the token from the URL it printed (?token=...)');\n return;\n }\n if (u.pathname === '/events' && req.method === 'GET') {\n const isApp = u.searchParams.get('role') === 'app';\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-store');\n res.setHeader('Connection', 'keep-alive');\n res.write(': connected\\n\\n');\n const app: RelayApp | null = isApp ? { id: `a${nextAppId++}`, label: (u.searchParams.get('label') || req.headers.origin || '').slice(0, 120) || `app ${nextAppId - 1}` } : null;\n if (app) apps.set(res, app);\n else panels.add(res);\n const ping = setInterval(() => {\n try {\n res.write(': ping\\n\\n');\n } catch {\n /* closed */\n }\n }, keepAliveMs);\n req.on('close', () => {\n clearInterval(ping);\n apps.delete(res);\n panels.delete(res);\n });\n // Panels learn the roster as soon as their stream is open (that first message is also how a\n // panel knows it is safe to send commands: replies only reach panels that are already connected),\n // and again whenever an app comes or goes, so they show \"disconnected\" instead of waiting.\n if (app) {\n sendTo(res, { __rerenderLensRelay: true, version: PROTOCOL, app: app.id }); // the app stamps this on what it sends\n send(panels, roster());\n req.on('close', () => send(panels, roster()));\n } else {\n sendTo(res, roster());\n }\n return;\n }\n if (u.pathname === '/favicon.ico') {\n res.statusCode = 204;\n res.end();\n return;\n }\n if (u.pathname === '/message' && req.method === 'POST') {\n try {\n const parsed = JSON.parse((await readBody(req)) || 'null') as unknown;\n const sender = u.searchParams.get('app');\n const from = sender ? (appList().find((a) => a.id === sender) ?? undefined) : undefined;\n for (const m of Array.isArray(parsed) ? parsed : [parsed]) route(m, from);\n res.statusCode = 204;\n res.end();\n } catch (e) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'text/plain');\n res.end(String((e as Error).message || e));\n }\n return;\n }\n if (u.pathname === '/status' && req.method === 'GET') {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ ok: true, apps: apps.size, panels: panels.size, list: appList() }));\n return;\n }\n const file = u.pathname.replace(/^\\//, '');\n if (/^panel\\.(html|js|css)$/.test(file) && req.method === 'GET') {\n if (!panelDir) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'text/plain');\n res.end('rerender-lens: panel files not found (is the package built?)');\n return;\n }\n res.statusCode = 200;\n res.setHeader('Content-Type', MIME[file.slice(file.lastIndexOf('.'))] || 'application/octet-stream');\n res.setHeader('Cache-Control', 'no-store');\n res.end(readFileSync(join(panelDir, file)));\n return;\n }\n res.statusCode = 404;\n res.setHeader('Content-Type', 'text/plain');\n res.end('not found');\n });\n\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(options.port ?? 4141, host, () => {\n const addr = server.address();\n const port = typeof addr === 'object' && addr ? addr.port : options.port ?? 4141;\n url = `http://${host === '0.0.0.0' || host === '::' ? 'localhost' : host}:${port}`;\n resolve({\n server,\n url,\n connectUrl: connectUrl(),\n port,\n counts: () => ({ apps: apps.size, panels: panels.size }),\n appList,\n close: () =>\n new Promise<void>((done) => {\n for (const res of [...apps.keys(), ...panels]) res.end();\n apps.clear();\n panels.clear();\n server.close(() => done());\n }),\n });\n });\n });\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* rerender-lens 0.
|
|
1
|
+
/* rerender-lens 0.7.0 — rerender-lens.core.js: types, version, diff, report, state, overlay. Built by scripts/build-vendor.mjs; do not edit. */
|
|
2
2
|
(() => {
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __export = (target, all) => {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
__export(version_exports, {
|
|
19
19
|
VERSION: () => VERSION
|
|
20
20
|
});
|
|
21
|
-
var VERSION = true ? "0.
|
|
21
|
+
var VERSION = true ? "0.7.0" : "dev";
|
|
22
22
|
|
|
23
23
|
// src/diff.ts
|
|
24
24
|
var diff_exports = {};
|
|
@@ -443,20 +443,33 @@
|
|
|
443
443
|
// src/state.ts
|
|
444
444
|
var state_exports = {};
|
|
445
445
|
__export(state_exports, {
|
|
446
|
+
MAX_SEEN_COMPONENTS: () => MAX_SEEN_COMPONENTS,
|
|
446
447
|
dispatch: () => dispatch,
|
|
447
448
|
getState: () => getState,
|
|
449
|
+
noteRendered: () => noteRendered,
|
|
448
450
|
warnOnce: () => warnOnce
|
|
449
451
|
});
|
|
452
|
+
var MAX_SEEN_COMPONENTS = 500;
|
|
450
453
|
var KEY = /* @__PURE__ */ Symbol.for("rerender-lens.state");
|
|
451
454
|
function getState() {
|
|
452
455
|
const g = globalThis;
|
|
453
456
|
let s = g[KEY];
|
|
454
457
|
if (!s) {
|
|
455
|
-
s = { options: {}, enabled: false, printed: /* @__PURE__ */ new Map(), detach: null, nextInstanceId: 1, nextCommitId: 1, warnedOnce: /* @__PURE__ */ new Set(), scheduled: 0, commits: 0, overheadMs: 0, maxCommitMs: 0, truncated: 0 };
|
|
458
|
+
s = { options: {}, enabled: false, printed: /* @__PURE__ */ new Map(), detach: null, nextInstanceId: 1, nextCommitId: 1, warnedOnce: /* @__PURE__ */ new Set(), scheduled: 0, commits: 0, overheadMs: 0, maxCommitMs: 0, truncated: 0, seen: /* @__PURE__ */ new Set(), seenTracked: /* @__PURE__ */ new Set(), seenOverflow: false };
|
|
456
459
|
g[KEY] = s;
|
|
457
460
|
}
|
|
458
461
|
return s;
|
|
459
462
|
}
|
|
463
|
+
function noteRendered(s, name, tracked) {
|
|
464
|
+
if (!s.seen.has(name)) {
|
|
465
|
+
if (s.seen.size >= MAX_SEEN_COMPONENTS) {
|
|
466
|
+
s.seenOverflow = true;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
s.seen.add(name);
|
|
470
|
+
}
|
|
471
|
+
if (tracked) s.seenTracked.add(name);
|
|
472
|
+
}
|
|
460
473
|
function warnOnce(key, message) {
|
|
461
474
|
const s = getState();
|
|
462
475
|
if (s.warnedOnce.has(key)) return;
|
|
@@ -612,7 +625,7 @@
|
|
|
612
625
|
})();
|
|
613
626
|
|
|
614
627
|
;
|
|
615
|
-
/* rerender-lens 0.
|
|
628
|
+
/* rerender-lens 0.7.0 — rerender-lens.engine.js: fiber, tracker, hookNames. Built by scripts/build-vendor.mjs; do not edit. */
|
|
616
629
|
(() => {
|
|
617
630
|
var __create = Object.create;
|
|
618
631
|
var __defProp = Object.defineProperty;
|
|
@@ -717,6 +730,7 @@
|
|
|
717
730
|
__export(tracker_exports, {
|
|
718
731
|
configure: () => configure,
|
|
719
732
|
disable: () => disable,
|
|
733
|
+
explainTracking: () => explainTracking,
|
|
720
734
|
getDisplayName: () => getDisplayName,
|
|
721
735
|
init: () => init,
|
|
722
736
|
isEnabled: () => isEnabled,
|
|
@@ -764,10 +778,53 @@
|
|
|
764
778
|
if (o.trackAllMemoized) return isMemo(type) || isPureClass(type);
|
|
765
779
|
return false;
|
|
766
780
|
}
|
|
781
|
+
var ANONYMOUS = "Anonymous";
|
|
782
|
+
function explainTracking(type, o) {
|
|
783
|
+
if (typeof type === "string")
|
|
784
|
+
return { tracked: false, name: type, memoized: false, reason: `<${type}> is a DOM element, not a React component; only components are tracked.` };
|
|
785
|
+
if (!isComponentLike(type))
|
|
786
|
+
return { tracked: false, name: ANONYMOUS, memoized: false, reason: "This is not a React component type, so it is never tracked." };
|
|
787
|
+
const name = getDisplayName(type);
|
|
788
|
+
const memo = isMemo(type);
|
|
789
|
+
const memoized = memo || isPureClass(type);
|
|
790
|
+
if (o.exclude?.some((m) => matches(m, name)))
|
|
791
|
+
return { tracked: false, name, memoized, reason: `<${name}> matches "exclude", which wins over every other rule.`, fix: `Remove "${name}" from the exclude list.` };
|
|
792
|
+
if (hasMarker(type)) return { tracked: true, name, memoized, reason: `<${name}> is marked with track() (the ${import_types.MARKER} static).` };
|
|
793
|
+
if (o.include?.some((m) => matches(m, name))) return { tracked: true, name, memoized, reason: `<${name}> matches "include".` };
|
|
794
|
+
if (o.trackAllComponents) return { tracked: true, name, memoized, reason: '"Track every component" is on, so every component is tracked.' };
|
|
795
|
+
if (o.trackAllMemoized && memoized)
|
|
796
|
+
return { tracked: true, name, memoized, reason: `<${name}> is ${memo ? "a React.memo component" : "a PureComponent"}, and "Track every React.memo and PureComponent" is on.` };
|
|
797
|
+
if (name === ANONYMOUS)
|
|
798
|
+
return {
|
|
799
|
+
tracked: false,
|
|
800
|
+
name,
|
|
801
|
+
memoized,
|
|
802
|
+
reason: 'This component has no display name, so "include" and "exclude" cannot address it.',
|
|
803
|
+
fix: "Give the function a name, set displayName, or mark it with track(fn, 'Name')."
|
|
804
|
+
};
|
|
805
|
+
if (o.trackAllMemoized)
|
|
806
|
+
return {
|
|
807
|
+
tracked: false,
|
|
808
|
+
name,
|
|
809
|
+
memoized,
|
|
810
|
+
reason: `"Track every React.memo and PureComponent" only covers React.memo components and PureComponent classes, and <${name}> is neither.`,
|
|
811
|
+
fix: `Add "${name}" to include, wrap it in React.memo, or turn on "Track every component".`
|
|
812
|
+
};
|
|
813
|
+
return {
|
|
814
|
+
tracked: false,
|
|
815
|
+
name,
|
|
816
|
+
memoized,
|
|
817
|
+
reason: `Nothing selects <${name}>: it is not marked with track(), no "include" pattern matches it, and neither "track every" option is on.`,
|
|
818
|
+
fix: `Add "${name}" to include, or turn on "Track every React.memo and PureComponent" / "Track every component".`
|
|
819
|
+
};
|
|
820
|
+
}
|
|
767
821
|
function init(options = {}) {
|
|
768
822
|
const s = (0, import_state.getState)();
|
|
769
823
|
s.options = { ...options };
|
|
770
824
|
s.printed.clear();
|
|
825
|
+
s.seen.clear();
|
|
826
|
+
s.seenTracked.clear();
|
|
827
|
+
s.seenOverflow = false;
|
|
771
828
|
if (!s.enabled) {
|
|
772
829
|
s.detach = attach();
|
|
773
830
|
s.enabled = true;
|
|
@@ -1502,8 +1559,11 @@
|
|
|
1502
1559
|
const alt = fiber.alternate;
|
|
1503
1560
|
if (alt && isComponentTag(fiber.tag) && didRender(fiber)) {
|
|
1504
1561
|
if (isHotSwapped(fiber, alt)) hot = true;
|
|
1505
|
-
|
|
1506
|
-
|
|
1562
|
+
const name = fiberName(fiber);
|
|
1563
|
+
renderedNames.add(name);
|
|
1564
|
+
const tracked = shouldTrack(fiberType(fiber), o);
|
|
1565
|
+
(0, import_state2.noteRendered)(s, name, tracked);
|
|
1566
|
+
if (tracked) rendered.push(fiber);
|
|
1507
1567
|
}
|
|
1508
1568
|
if (fiber.tag === SuspenseComponent && alt && alt.memoizedState !== null && fiber.memoizedState === null) (resolvedBoundaries ?? (resolvedBoundaries = [])).push(fiber);
|
|
1509
1569
|
if (!alt || fiber.child !== alt.child) {
|
|
@@ -1596,7 +1656,7 @@
|
|
|
1596
1656
|
})();
|
|
1597
1657
|
|
|
1598
1658
|
;
|
|
1599
|
-
/* rerender-lens 0.
|
|
1659
|
+
/* rerender-lens 0.7.0 — rerender-lens.js: devtools bridge + notifiers (window.RerenderLens). Built by scripts/build-vendor.mjs; do not edit. */
|
|
1600
1660
|
"use strict";
|
|
1601
1661
|
var RerenderLens = (() => {
|
|
1602
1662
|
var __create = Object.create;
|
|
@@ -1719,6 +1779,7 @@ var RerenderLens = (() => {
|
|
|
1719
1779
|
diffRecords: () => import_diff4.diffRecords,
|
|
1720
1780
|
disable: () => import_tracker2.disable,
|
|
1721
1781
|
ensureDevtoolsHook: () => import_fiber2.ensureDevtoolsHook,
|
|
1782
|
+
explainTracking: () => import_tracker2.explainTracking,
|
|
1722
1783
|
getDisplayName: () => import_tracker2.getDisplayName,
|
|
1723
1784
|
getRenderers: () => import_fiber2.getRenderers,
|
|
1724
1785
|
init: () => import_tracker2.init,
|
|
@@ -2267,6 +2328,18 @@ ${formatFixes(reports)}`);
|
|
|
2267
2328
|
target.postMessage(msg, "*");
|
|
2268
2329
|
};
|
|
2269
2330
|
const source = options.source ?? "page";
|
|
2331
|
+
const trackingSummary = () => {
|
|
2332
|
+
const s = (0, import_state.getState)();
|
|
2333
|
+
const o = s.options;
|
|
2334
|
+
return {
|
|
2335
|
+
mode: o.trackAllComponents ? "all" : o.trackAllMemoized ? "memoized" : "marked",
|
|
2336
|
+
include: (o.include ?? []).map(matcherToString).filter((x) => x !== null),
|
|
2337
|
+
exclude: (o.exclude ?? []).map(matcherToString).filter((x) => x !== null),
|
|
2338
|
+
renderedCount: s.seen.size,
|
|
2339
|
+
trackedCount: s.seenTracked.size,
|
|
2340
|
+
overflow: s.seenOverflow
|
|
2341
|
+
};
|
|
2342
|
+
};
|
|
2270
2343
|
const info = () => ({
|
|
2271
2344
|
count: buffer.length,
|
|
2272
2345
|
library: import_version.VERSION,
|
|
@@ -2280,7 +2353,8 @@ ${formatFixes(reports)}`);
|
|
|
2280
2353
|
scheduled: (0, import_state.getState)().scheduled,
|
|
2281
2354
|
commits: (0, import_state.getState)().commits,
|
|
2282
2355
|
overhead: { totalMs: (0, import_state.getState)().overheadMs, maxCommitMs: (0, import_state.getState)().maxCommitMs },
|
|
2283
|
-
truncated: (0, import_state.getState)().truncated
|
|
2356
|
+
truncated: (0, import_state.getState)().truncated,
|
|
2357
|
+
tracking: trackingSummary()
|
|
2284
2358
|
});
|
|
2285
2359
|
const bridge = {
|
|
2286
2360
|
replay: () => {
|
|
@@ -2326,6 +2400,10 @@ ${formatFixes(reports)}`);
|
|
|
2326
2400
|
flashAvoidable: (on) => {
|
|
2327
2401
|
flashOn = !!on;
|
|
2328
2402
|
},
|
|
2403
|
+
explain: (target2) => {
|
|
2404
|
+
const comp = typeof target2 === "number" ? (0, import_fiber.fiberById)(target2) : (0, import_fiber.nearestComponent)((0, import_fiber.fiberForNode)(target2));
|
|
2405
|
+
return comp ? (0, import_tracker.explainTracking)((0, import_fiber.fiberType)(comp), (0, import_state.getState)().options) : null;
|
|
2406
|
+
},
|
|
2329
2407
|
inspect: (node) => {
|
|
2330
2408
|
const comp = (0, import_fiber.nearestComponent)((0, import_fiber.fiberForNode)(node));
|
|
2331
2409
|
if (!comp) return null;
|
|
@@ -2340,6 +2418,7 @@ ${formatFixes(reports)}`);
|
|
|
2340
2418
|
component: (0, import_fiber.fiberName)(comp),
|
|
2341
2419
|
instanceId: id,
|
|
2342
2420
|
tracked: (0, import_tracker.shouldTrack)((0, import_fiber.fiberType)(comp), (0, import_state.getState)().options),
|
|
2421
|
+
tracking: (0, import_tracker.explainTracking)((0, import_fiber.fiberType)(comp), (0, import_state.getState)().options),
|
|
2343
2422
|
path,
|
|
2344
2423
|
reports: id === null ? [] : buffer.filter((e) => e.instanceId === id).slice(-20).map((e) => e.payload)
|
|
2345
2424
|
};
|
|
@@ -2374,6 +2453,9 @@ ${formatFixes(reports)}`);
|
|
|
2374
2453
|
bridge.flashAvoidable(!!data.arg);
|
|
2375
2454
|
reply.result = true;
|
|
2376
2455
|
break;
|
|
2456
|
+
case "explain":
|
|
2457
|
+
reply.result = bridge.explain(data.arg);
|
|
2458
|
+
break;
|
|
2377
2459
|
default:
|
|
2378
2460
|
reply.error = `unknown command ${String(data.cmd)}`;
|
|
2379
2461
|
}
|
|
@@ -2382,6 +2464,7 @@ ${formatFixes(reports)}`);
|
|
|
2382
2464
|
}
|
|
2383
2465
|
return reply;
|
|
2384
2466
|
};
|
|
2467
|
+
const isRelayGreeting = (data) => !!data && typeof data === "object" && data.__rerenderLensRelay === true && typeof data.app === "string";
|
|
2385
2468
|
const isCommand = (data) => !!data && typeof data === "object" && data.__rerenderLensCmd === true && typeof data.id === "string";
|
|
2386
2469
|
const envelope = (type, payload) => ({ [DEVTOOLS_MARKER]: true, version: PROTOCOL_VERSION, type, payload });
|
|
2387
2470
|
const sinks = [];
|
|
@@ -2404,14 +2487,20 @@ ${formatFixes(reports)}`);
|
|
|
2404
2487
|
const relayUrl = options.relay ?? (typeof window !== "undefined" ? window.__RERENDER_LENS_RELAY__ : void 0);
|
|
2405
2488
|
const ES = options.eventSource ?? (typeof EventSource === "function" ? EventSource : null);
|
|
2406
2489
|
if (relayUrl && ES && typeof fetch === "function") {
|
|
2407
|
-
const
|
|
2490
|
+
const [rawBase, relayQuery = ""] = relayUrl.split("?");
|
|
2491
|
+
const base = (rawBase ?? "").replace(/\/$/, "");
|
|
2492
|
+
const relayToken = new URLSearchParams(relayQuery).get("token");
|
|
2493
|
+
const auth = relayToken ? `token=${encodeURIComponent(relayToken)}` : "";
|
|
2408
2494
|
let queue = [];
|
|
2409
2495
|
let scheduled = false;
|
|
2496
|
+
let appId = null;
|
|
2410
2497
|
const flush = () => {
|
|
2411
2498
|
scheduled = false;
|
|
2412
2499
|
const batch = queue;
|
|
2413
2500
|
queue = [];
|
|
2414
|
-
|
|
2501
|
+
const params = [appId ? `app=${encodeURIComponent(appId)}` : "", auth].filter(Boolean).join("&");
|
|
2502
|
+
const to = `${base}/message${params ? `?${params}` : ""}`;
|
|
2503
|
+
fetch(to, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(batch), keepalive: true }).catch(() => {
|
|
2415
2504
|
});
|
|
2416
2505
|
};
|
|
2417
2506
|
const relaySend = (message) => {
|
|
@@ -2422,7 +2511,8 @@ ${formatFixes(reports)}`);
|
|
|
2422
2511
|
}
|
|
2423
2512
|
};
|
|
2424
2513
|
try {
|
|
2425
|
-
const
|
|
2514
|
+
const label = typeof location !== "undefined" ? `${location.host}${location.pathname}`.slice(0, 120) : "";
|
|
2515
|
+
const stream = new ES(`${base}/events?role=app${label ? `&label=${encodeURIComponent(label)}` : ""}${auth ? `&${auth}` : ""}`);
|
|
2426
2516
|
stream.onmessage = (event) => {
|
|
2427
2517
|
let parsed;
|
|
2428
2518
|
try {
|
|
@@ -2430,7 +2520,10 @@ ${formatFixes(reports)}`);
|
|
|
2430
2520
|
} catch {
|
|
2431
2521
|
return;
|
|
2432
2522
|
}
|
|
2433
|
-
for (const m of Array.isArray(parsed) ? parsed : [parsed])
|
|
2523
|
+
for (const m of Array.isArray(parsed) ? parsed : [parsed]) {
|
|
2524
|
+
if (isRelayGreeting(m)) appId = m.app;
|
|
2525
|
+
else if (isCommand(m)) relaySend(runCommand(m));
|
|
2526
|
+
}
|
|
2434
2527
|
};
|
|
2435
2528
|
stream.onerror = () => {
|
|
2436
2529
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RenderReport, O as Options } from './types-
|
|
2
|
-
import { C as Collector } from './notifiers-
|
|
1
|
+
import { R as RenderReport, O as Options } from './types-DwNN5cWe.js';
|
|
2
|
+
import { C as Collector } from './notifiers-CqQW0Eum.js';
|
|
3
3
|
|
|
4
4
|
/** Environment variable carrying the path of the run's JSONL file from the reporter to the workers. */
|
|
5
5
|
declare const OUT_ENV = "RERENDER_LENS_OUT";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RenderReport, O as Options } from './types-
|
|
2
|
-
import { C as Collector } from './notifiers-
|
|
1
|
+
import { R as RenderReport, O as Options } from './types-DwNN5cWe.cjs';
|
|
2
|
+
import { C as Collector } from './notifiers-B5poAEvE.cjs';
|
|
3
3
|
|
|
4
4
|
/** Environment variable carrying the path of the run's JSONL file from the reporter to the workers. */
|
|
5
5
|
declare const OUT_ENV = "RERENDER_LENS_OUT";
|
package/dist/setup.cjs
CHANGED
|
@@ -383,16 +383,27 @@ function printReport(report, options) {
|
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
// src/state.ts
|
|
386
|
+
var MAX_SEEN_COMPONENTS = 500;
|
|
386
387
|
var KEY = /* @__PURE__ */ Symbol.for("rerender-lens.state");
|
|
387
388
|
function getState() {
|
|
388
389
|
const g = globalThis;
|
|
389
390
|
let s = g[KEY];
|
|
390
391
|
if (!s) {
|
|
391
|
-
s = { options: {}, enabled: false, printed: /* @__PURE__ */ new Map(), detach: null, nextInstanceId: 1, nextCommitId: 1, warnedOnce: /* @__PURE__ */ new Set(), scheduled: 0, commits: 0, overheadMs: 0, maxCommitMs: 0, truncated: 0 };
|
|
392
|
+
s = { options: {}, enabled: false, printed: /* @__PURE__ */ new Map(), detach: null, nextInstanceId: 1, nextCommitId: 1, warnedOnce: /* @__PURE__ */ new Set(), scheduled: 0, commits: 0, overheadMs: 0, maxCommitMs: 0, truncated: 0, seen: /* @__PURE__ */ new Set(), seenTracked: /* @__PURE__ */ new Set(), seenOverflow: false };
|
|
392
393
|
g[KEY] = s;
|
|
393
394
|
}
|
|
394
395
|
return s;
|
|
395
396
|
}
|
|
397
|
+
function noteRendered(s, name, tracked) {
|
|
398
|
+
if (!s.seen.has(name)) {
|
|
399
|
+
if (s.seen.size >= MAX_SEEN_COMPONENTS) {
|
|
400
|
+
s.seenOverflow = true;
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
s.seen.add(name);
|
|
404
|
+
}
|
|
405
|
+
if (tracked) s.seenTracked.add(name);
|
|
406
|
+
}
|
|
396
407
|
function warnOnce(key, message) {
|
|
397
408
|
const s = getState();
|
|
398
409
|
if (s.warnedOnce.has(key)) return;
|
|
@@ -1119,8 +1130,11 @@ function onCommit(root, commitPriority) {
|
|
|
1119
1130
|
const alt = fiber.alternate;
|
|
1120
1131
|
if (alt && isComponentTag(fiber.tag) && didRender(fiber)) {
|
|
1121
1132
|
if (isHotSwapped(fiber, alt)) hot = true;
|
|
1122
|
-
|
|
1123
|
-
|
|
1133
|
+
const name = fiberName(fiber);
|
|
1134
|
+
renderedNames.add(name);
|
|
1135
|
+
const tracked = shouldTrack(fiberType(fiber), o);
|
|
1136
|
+
noteRendered(s, name, tracked);
|
|
1137
|
+
if (tracked) rendered.push(fiber);
|
|
1124
1138
|
}
|
|
1125
1139
|
if (fiber.tag === SuspenseComponent && alt && alt.memoizedState !== null && fiber.memoizedState === null) (resolvedBoundaries ?? (resolvedBoundaries = [])).push(fiber);
|
|
1126
1140
|
if (!alt || fiber.child !== alt.child) {
|
|
@@ -1245,10 +1259,53 @@ function shouldTrack(type, o) {
|
|
|
1245
1259
|
if (o.trackAllMemoized) return isMemo(type) || isPureClass(type);
|
|
1246
1260
|
return false;
|
|
1247
1261
|
}
|
|
1262
|
+
var ANONYMOUS = "Anonymous";
|
|
1263
|
+
function explainTracking(type, o) {
|
|
1264
|
+
if (typeof type === "string")
|
|
1265
|
+
return { tracked: false, name: type, memoized: false, reason: `<${type}> is a DOM element, not a React component; only components are tracked.` };
|
|
1266
|
+
if (!isComponentLike(type))
|
|
1267
|
+
return { tracked: false, name: ANONYMOUS, memoized: false, reason: "This is not a React component type, so it is never tracked." };
|
|
1268
|
+
const name = getDisplayName(type);
|
|
1269
|
+
const memo = isMemo(type);
|
|
1270
|
+
const memoized = memo || isPureClass(type);
|
|
1271
|
+
if (o.exclude?.some((m) => matches(m, name)))
|
|
1272
|
+
return { tracked: false, name, memoized, reason: `<${name}> matches "exclude", which wins over every other rule.`, fix: `Remove "${name}" from the exclude list.` };
|
|
1273
|
+
if (hasMarker(type)) return { tracked: true, name, memoized, reason: `<${name}> is marked with track() (the ${MARKER} static).` };
|
|
1274
|
+
if (o.include?.some((m) => matches(m, name))) return { tracked: true, name, memoized, reason: `<${name}> matches "include".` };
|
|
1275
|
+
if (o.trackAllComponents) return { tracked: true, name, memoized, reason: '"Track every component" is on, so every component is tracked.' };
|
|
1276
|
+
if (o.trackAllMemoized && memoized)
|
|
1277
|
+
return { tracked: true, name, memoized, reason: `<${name}> is ${memo ? "a React.memo component" : "a PureComponent"}, and "Track every React.memo and PureComponent" is on.` };
|
|
1278
|
+
if (name === ANONYMOUS)
|
|
1279
|
+
return {
|
|
1280
|
+
tracked: false,
|
|
1281
|
+
name,
|
|
1282
|
+
memoized,
|
|
1283
|
+
reason: 'This component has no display name, so "include" and "exclude" cannot address it.',
|
|
1284
|
+
fix: "Give the function a name, set displayName, or mark it with track(fn, 'Name')."
|
|
1285
|
+
};
|
|
1286
|
+
if (o.trackAllMemoized)
|
|
1287
|
+
return {
|
|
1288
|
+
tracked: false,
|
|
1289
|
+
name,
|
|
1290
|
+
memoized,
|
|
1291
|
+
reason: `"Track every React.memo and PureComponent" only covers React.memo components and PureComponent classes, and <${name}> is neither.`,
|
|
1292
|
+
fix: `Add "${name}" to include, wrap it in React.memo, or turn on "Track every component".`
|
|
1293
|
+
};
|
|
1294
|
+
return {
|
|
1295
|
+
tracked: false,
|
|
1296
|
+
name,
|
|
1297
|
+
memoized,
|
|
1298
|
+
reason: `Nothing selects <${name}>: it is not marked with track(), no "include" pattern matches it, and neither "track every" option is on.`,
|
|
1299
|
+
fix: `Add "${name}" to include, or turn on "Track every React.memo and PureComponent" / "Track every component".`
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1248
1302
|
function init(options = {}) {
|
|
1249
1303
|
const s = getState();
|
|
1250
1304
|
s.options = { ...options };
|
|
1251
1305
|
s.printed.clear();
|
|
1306
|
+
s.seen.clear();
|
|
1307
|
+
s.seenTracked.clear();
|
|
1308
|
+
s.seenOverflow = false;
|
|
1252
1309
|
if (!s.enabled) {
|
|
1253
1310
|
s.detach = attach();
|
|
1254
1311
|
s.enabled = true;
|
|
@@ -1374,7 +1431,7 @@ function flash(target, duration = 500) {
|
|
|
1374
1431
|
}
|
|
1375
1432
|
|
|
1376
1433
|
// src/version.ts
|
|
1377
|
-
var VERSION = "0.
|
|
1434
|
+
var VERSION = "0.7.0" ;
|
|
1378
1435
|
|
|
1379
1436
|
// src/devtools.ts
|
|
1380
1437
|
var DEVTOOLS_MARKER = "__rerenderLens";
|
|
@@ -1500,6 +1557,18 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1500
1557
|
target.postMessage(msg, "*");
|
|
1501
1558
|
};
|
|
1502
1559
|
const source = options.source ?? "page";
|
|
1560
|
+
const trackingSummary = () => {
|
|
1561
|
+
const s = getState();
|
|
1562
|
+
const o = s.options;
|
|
1563
|
+
return {
|
|
1564
|
+
mode: o.trackAllComponents ? "all" : o.trackAllMemoized ? "memoized" : "marked",
|
|
1565
|
+
include: (o.include ?? []).map(matcherToString).filter((x) => x !== null),
|
|
1566
|
+
exclude: (o.exclude ?? []).map(matcherToString).filter((x) => x !== null),
|
|
1567
|
+
renderedCount: s.seen.size,
|
|
1568
|
+
trackedCount: s.seenTracked.size,
|
|
1569
|
+
overflow: s.seenOverflow
|
|
1570
|
+
};
|
|
1571
|
+
};
|
|
1503
1572
|
const info = () => ({
|
|
1504
1573
|
count: buffer.length,
|
|
1505
1574
|
library: VERSION,
|
|
@@ -1513,7 +1582,8 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1513
1582
|
scheduled: getState().scheduled,
|
|
1514
1583
|
commits: getState().commits,
|
|
1515
1584
|
overhead: { totalMs: getState().overheadMs, maxCommitMs: getState().maxCommitMs },
|
|
1516
|
-
truncated: getState().truncated
|
|
1585
|
+
truncated: getState().truncated,
|
|
1586
|
+
tracking: trackingSummary()
|
|
1517
1587
|
});
|
|
1518
1588
|
const bridge = {
|
|
1519
1589
|
replay: () => {
|
|
@@ -1559,6 +1629,10 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1559
1629
|
flashAvoidable: (on) => {
|
|
1560
1630
|
flashOn = !!on;
|
|
1561
1631
|
},
|
|
1632
|
+
explain: (target2) => {
|
|
1633
|
+
const comp = typeof target2 === "number" ? fiberById(target2) : nearestComponent(fiberForNode(target2));
|
|
1634
|
+
return comp ? explainTracking(fiberType(comp), getState().options) : null;
|
|
1635
|
+
},
|
|
1562
1636
|
inspect: (node) => {
|
|
1563
1637
|
const comp = nearestComponent(fiberForNode(node));
|
|
1564
1638
|
if (!comp) return null;
|
|
@@ -1573,6 +1647,7 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1573
1647
|
component: fiberName(comp),
|
|
1574
1648
|
instanceId: id,
|
|
1575
1649
|
tracked: shouldTrack(fiberType(comp), getState().options),
|
|
1650
|
+
tracking: explainTracking(fiberType(comp), getState().options),
|
|
1576
1651
|
path,
|
|
1577
1652
|
reports: id === null ? [] : buffer.filter((e) => e.instanceId === id).slice(-20).map((e) => e.payload)
|
|
1578
1653
|
};
|
|
@@ -1607,6 +1682,9 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1607
1682
|
bridge.flashAvoidable(!!data.arg);
|
|
1608
1683
|
reply.result = true;
|
|
1609
1684
|
break;
|
|
1685
|
+
case "explain":
|
|
1686
|
+
reply.result = bridge.explain(data.arg);
|
|
1687
|
+
break;
|
|
1610
1688
|
default:
|
|
1611
1689
|
reply.error = `unknown command ${String(data.cmd)}`;
|
|
1612
1690
|
}
|
|
@@ -1615,6 +1693,7 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1615
1693
|
}
|
|
1616
1694
|
return reply;
|
|
1617
1695
|
};
|
|
1696
|
+
const isRelayGreeting = (data) => !!data && typeof data === "object" && data.__rerenderLensRelay === true && typeof data.app === "string";
|
|
1618
1697
|
const isCommand = (data) => !!data && typeof data === "object" && data.__rerenderLensCmd === true && typeof data.id === "string";
|
|
1619
1698
|
const envelope = (type, payload) => ({ [DEVTOOLS_MARKER]: true, version: PROTOCOL_VERSION, type, payload });
|
|
1620
1699
|
const sinks = [];
|
|
@@ -1637,14 +1716,20 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1637
1716
|
const relayUrl = options.relay ?? (typeof window !== "undefined" ? window.__RERENDER_LENS_RELAY__ : void 0);
|
|
1638
1717
|
const ES = options.eventSource ?? (typeof EventSource === "function" ? EventSource : null);
|
|
1639
1718
|
if (relayUrl && ES && typeof fetch === "function") {
|
|
1640
|
-
const
|
|
1719
|
+
const [rawBase, relayQuery = ""] = relayUrl.split("?");
|
|
1720
|
+
const base = (rawBase ?? "").replace(/\/$/, "");
|
|
1721
|
+
const relayToken = new URLSearchParams(relayQuery).get("token");
|
|
1722
|
+
const auth = relayToken ? `token=${encodeURIComponent(relayToken)}` : "";
|
|
1641
1723
|
let queue = [];
|
|
1642
1724
|
let scheduled = false;
|
|
1725
|
+
let appId = null;
|
|
1643
1726
|
const flush = () => {
|
|
1644
1727
|
scheduled = false;
|
|
1645
1728
|
const batch = queue;
|
|
1646
1729
|
queue = [];
|
|
1647
|
-
|
|
1730
|
+
const params = [appId ? `app=${encodeURIComponent(appId)}` : "", auth].filter(Boolean).join("&");
|
|
1731
|
+
const to = `${base}/message${params ? `?${params}` : ""}`;
|
|
1732
|
+
fetch(to, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(batch), keepalive: true }).catch(() => {
|
|
1648
1733
|
});
|
|
1649
1734
|
};
|
|
1650
1735
|
const relaySend = (message) => {
|
|
@@ -1655,7 +1740,8 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1655
1740
|
}
|
|
1656
1741
|
};
|
|
1657
1742
|
try {
|
|
1658
|
-
const
|
|
1743
|
+
const label = typeof location !== "undefined" ? `${location.host}${location.pathname}`.slice(0, 120) : "";
|
|
1744
|
+
const stream = new ES(`${base}/events?role=app${label ? `&label=${encodeURIComponent(label)}` : ""}${auth ? `&${auth}` : ""}`);
|
|
1659
1745
|
stream.onmessage = (event) => {
|
|
1660
1746
|
let parsed;
|
|
1661
1747
|
try {
|
|
@@ -1663,7 +1749,10 @@ function createDevtoolsNotifier(options = {}) {
|
|
|
1663
1749
|
} catch {
|
|
1664
1750
|
return;
|
|
1665
1751
|
}
|
|
1666
|
-
for (const m of Array.isArray(parsed) ? parsed : [parsed])
|
|
1752
|
+
for (const m of Array.isArray(parsed) ? parsed : [parsed]) {
|
|
1753
|
+
if (isRelayGreeting(m)) appId = m.app;
|
|
1754
|
+
else if (isCommand(m)) relaySend(runCommand(m));
|
|
1755
|
+
}
|
|
1667
1756
|
};
|
|
1668
1757
|
stream.onerror = () => {
|
|
1669
1758
|
};
|