rerender-lens 0.4.0 → 0.5.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 +78 -0
- package/README.md +192 -362
- package/dist/{budget-COBu7jBU.d.cts → budget-BnJlYwrV.d.ts} +20 -10
- package/dist/{budget-LkNjGtRc.d.ts → budget-CRswn-nC.d.cts} +20 -10
- package/dist/cli.cjs +248 -31
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +248 -31
- package/dist/cli.js.map +1 -1
- package/dist/{devtools-CZebzpF6.d.ts → devtools-BYWat7nQ.d.ts} +7 -1
- package/dist/{devtools-BkCct3cJ.d.cts → devtools-DJi_6AfJ.d.cts} +7 -1
- package/dist/index.cjs +439 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +131 -8
- package/dist/index.d.ts +131 -8
- package/dist/index.js +424 -42
- package/dist/index.js.map +1 -1
- package/dist/jest-setup.cjs +1673 -0
- package/dist/jest-setup.cjs.map +1 -0
- package/dist/jest-setup.d.cts +8 -0
- package/dist/jest-setup.d.ts +8 -0
- package/dist/jest-setup.js +1671 -0
- package/dist/jest-setup.js.map +1 -0
- package/dist/jest.cjs +1760 -0
- package/dist/jest.cjs.map +1 -0
- package/dist/jest.d.cts +23 -0
- package/dist/jest.d.ts +23 -0
- package/dist/jest.js +1751 -0
- package/dist/jest.js.map +1 -0
- package/dist/{notifiers-BjjGSHpp.d.ts → notifiers-DwKlvv4H.d.cts} +8 -4
- package/dist/{notifiers-BGQtWKfX.d.cts → notifiers-FNzKHs0a.d.ts} +8 -4
- package/dist/playwright.cjs +230 -28
- package/dist/playwright.cjs.map +1 -1
- package/dist/playwright.d.cts +4 -4
- package/dist/playwright.d.ts +4 -4
- package/dist/playwright.js +230 -28
- package/dist/playwright.js.map +1 -1
- package/dist/relay.cjs +10 -2
- package/dist/relay.cjs.map +1 -1
- package/dist/relay.js +10 -2
- package/dist/relay.js.map +1 -1
- package/dist/rerender-lens.iife.js +356 -54
- package/dist/runner-report-B8Sc3FZO.d.cts +46 -0
- package/dist/runner-report-CW8X5RwK.d.ts +46 -0
- package/dist/setup.cjs +112 -27
- package/dist/setup.cjs.map +1 -1
- package/dist/setup.js +112 -27
- package/dist/setup.js.map +1 -1
- package/dist/{types-BzUEVkxJ.d.cts → types-DW5-N2XH.d.cts} +55 -2
- package/dist/{types-BzUEVkxJ.d.ts → types-DW5-N2XH.d.ts} +55 -2
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vitest-setup.cjs +337 -41
- 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 +337 -41
- package/dist/vitest-setup.js.map +1 -1
- package/dist/vitest.cjs +400 -77
- package/dist/vitest.cjs.map +1 -1
- package/dist/vitest.d.cts +21 -39
- package/dist/vitest.d.ts +21 -39
- package/dist/vitest.js +401 -78
- package/dist/vitest.js.map +1 -1
- package/package.json +40 -4
- package/panel/panel.css +1 -0
- package/panel/panel.js +499 -309
package/dist/relay.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/tsup/assets/cjs_shims.js","../src/relay.ts"],"names":["dirname","fileURLToPath","join","existsSync","createServer","readFileSync"],"mappings":"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","file":"relay.cjs","sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\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 // Tell panels an app went away so they show \"disconnected\" instead of waiting.\n if (role === apps) {\n send(panels, { __rerenderLens: true, version: 2, type: 'relay', payload: { apps: apps.size } });\n req.on('close', () => send(panels, { __rerenderLens: true, version: 2, type: 'relay', payload: { apps: apps.size } }));\n }\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":["../node_modules/tsup/assets/cjs_shims.js","../src/relay.ts"],"names":["dirname","fileURLToPath","join","existsSync","createServer","readFileSync"],"mappings":"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","file":"relay.cjs","sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\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"]}
|
package/dist/relay.js
CHANGED
|
@@ -91,12 +91,20 @@ function createRelayServer(options = {}) {
|
|
|
91
91
|
clearInterval(ping);
|
|
92
92
|
role.delete(res);
|
|
93
93
|
});
|
|
94
|
+
const count = () => ({ __rerenderLens: true, version: 2, type: "relay", payload: { apps: apps.size } });
|
|
94
95
|
if (role === apps) {
|
|
95
|
-
send(panels,
|
|
96
|
-
req.on("close", () => send(panels,
|
|
96
|
+
send(panels, count());
|
|
97
|
+
req.on("close", () => send(panels, count()));
|
|
98
|
+
} else {
|
|
99
|
+
send(/* @__PURE__ */ new Set([res]), count());
|
|
97
100
|
}
|
|
98
101
|
return;
|
|
99
102
|
}
|
|
103
|
+
if (u.pathname === "/favicon.ico") {
|
|
104
|
+
res.statusCode = 204;
|
|
105
|
+
res.end();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
100
108
|
if (u.pathname === "/message" && req.method === "POST") {
|
|
101
109
|
try {
|
|
102
110
|
const parsed = JSON.parse(await readBody(req) || "null");
|
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 // Tell panels an app went away so they show \"disconnected\" instead of waiting.\n if (role === apps) {\n send(panels, { __rerenderLens: true, version: 2, type: 'relay', payload: { apps: apps.size } });\n req.on('close', () => send(panels, { __rerenderLens: true, version: 2, type: 'relay', payload: { apps: apps.size } }));\n }\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\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"]}
|