@fairfox/polly 0.71.0 → 0.72.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.
@@ -178,14 +178,18 @@ var signalingApp = new Elysia2().use(signalingServer({ path: "/polly/signaling"
178
178
  console.log(`[browser-runner] signaling server on ws://127.0.0.1:${signalingPort}/polly/signaling`);
179
179
  var browser = await puppeteer.launch({
180
180
  headless,
181
- args: ["--no-sandbox", "--disable-setuid-sandbox"]
181
+ args: ["--no-sandbox", "--disable-setuid-sandbox"],
182
+ protocolTimeout: 30000
182
183
  });
183
184
  var totalPassed = 0;
184
185
  var totalFailed = 0;
185
- for (const testFile of testFiles) {
186
- const shortName = testFile.replace(`${testDir}/`, "");
187
- console.log(`
188
- [browser-runner] running ${shortName}`);
186
+ function isProtocolError(err) {
187
+ return err instanceof Error && err.name === "ProtocolError";
188
+ }
189
+ function errMessage(err) {
190
+ return err instanceof Error ? err.message : String(err);
191
+ }
192
+ async function runFile(testFile) {
189
193
  const buildResult = await Bun.build({
190
194
  entrypoints: [testFile],
191
195
  target: "browser",
@@ -202,14 +206,12 @@ for (const testFile of testFiles) {
202
206
  for (const log of buildResult.logs) {
203
207
  console.log(` ${log}`);
204
208
  }
205
- totalFailed += 1;
206
- continue;
209
+ return { passed: 0, failed: 1 };
207
210
  }
208
211
  const jsText = await buildResult.outputs[0]?.text();
209
212
  if (!jsText) {
210
213
  console.log(" ❌ build produced no output");
211
- totalFailed += 1;
212
- continue;
214
+ return { passed: 0, failed: 1 };
213
215
  }
214
216
  const html = `<!DOCTYPE html>
215
217
  <html><head><meta charset="utf-8"></head>
@@ -222,46 +224,75 @@ for (const testFile of testFiles) {
222
224
  return new Response(html, { headers: { "Content-Type": "text/html" } });
223
225
  }
224
226
  });
225
- const page = await browser.newPage();
226
- page.on("console", (msg) => {
227
- const text = msg.text();
228
- if (text.includes("[test]")) {
229
- console.log(` ${text}`);
227
+ let page;
228
+ try {
229
+ page = await browser.newPage();
230
+ page.on("console", (msg) => {
231
+ const text = msg.text();
232
+ if (text.includes("[test]")) {
233
+ console.log(` ${text}`);
234
+ }
235
+ });
236
+ page.on("pageerror", (err) => {
237
+ console.log(` ❌ page error: ${errMessage(err)}`);
238
+ });
239
+ await page.goto(`http://127.0.0.1:${server.port}/`, { waitUntil: "domcontentloaded" });
240
+ const timeout = 15000;
241
+ const deadline = Date.now() + timeout;
242
+ let finished = false;
243
+ while (Date.now() < deadline) {
244
+ finished = await page.evaluate(() => window["__done"] === true);
245
+ if (finished)
246
+ break;
247
+ await new Promise((r) => setTimeout(r, 100));
248
+ }
249
+ if (!finished) {
250
+ console.log(` ❌ timed out after ${timeout}ms`);
251
+ return { passed: 0, failed: 1 };
252
+ }
253
+ const results = await page.evaluate(() => window["__testResults"]);
254
+ let passed = 0;
255
+ let failed = 0;
256
+ for (const r of results ?? []) {
257
+ if (r.passed) {
258
+ console.log(` ✅ ${r.name}`);
259
+ passed += 1;
260
+ } else {
261
+ console.log(` ❌ ${r.name}: ${r.error}`);
262
+ failed += 1;
263
+ }
264
+ }
265
+ return { passed, failed };
266
+ } finally {
267
+ if (page) {
268
+ await page.close().catch(() => {});
230
269
  }
231
- });
232
- page.on("pageerror", (err) => {
233
- const msg = err instanceof Error ? err.message : String(err);
234
- console.log(` ❌ page error: ${msg}`);
235
- });
236
- await page.goto(`http://127.0.0.1:${server.port}/`, { waitUntil: "domcontentloaded" });
237
- const timeout = 15000;
238
- const deadline = Date.now() + timeout;
239
- let finished = false;
240
- while (Date.now() < deadline) {
241
- finished = await page.evaluate(() => window["__done"] === true);
242
- if (finished)
243
- break;
244
- await new Promise((r) => setTimeout(r, 100));
245
- }
246
- if (!finished) {
247
- console.log(` ❌ timed out after ${timeout}ms`);
248
- totalFailed += 1;
249
- await page.close();
250
270
  server.stop();
251
- continue;
252
271
  }
253
- const results = await page.evaluate(() => window["__testResults"]);
254
- for (const r of results ?? []) {
255
- if (r.passed) {
256
- console.log(` ✅ ${r.name}`);
257
- totalPassed += 1;
272
+ }
273
+ for (const testFile of testFiles) {
274
+ const shortName = testFile.replace(`${testDir}/`, "");
275
+ console.log(`
276
+ [browser-runner] running ${shortName}`);
277
+ let result;
278
+ try {
279
+ result = await runFile(testFile);
280
+ } catch (err) {
281
+ if (isProtocolError(err)) {
282
+ console.log(` ⚠️ protocol error (${errMessage(err)}) — retrying once on a fresh page`);
283
+ try {
284
+ result = await runFile(testFile);
285
+ } catch (retryErr) {
286
+ console.log(` ❌ retry failed: ${errMessage(retryErr)}`);
287
+ result = { passed: 0, failed: 1 };
288
+ }
258
289
  } else {
259
- console.log(` ❌ ${r.name}: ${r.error}`);
260
- totalFailed += 1;
290
+ console.log(` ❌ ${errMessage(err)}`);
291
+ result = { passed: 0, failed: 1 };
261
292
  }
262
293
  }
263
- await page.close();
264
- server.stop();
294
+ totalPassed += result.passed;
295
+ totalFailed += result.failed;
265
296
  }
266
297
  await browser.close();
267
298
  signalingApp.server?.stop?.(true);
@@ -269,4 +300,4 @@ console.log(`
269
300
  [browser-runner] ${totalPassed} passed, ${totalFailed} failed`);
270
301
  process.exit(totalFailed > 0 ? 1 : 0);
271
302
 
272
- //# debugId=C5D6EF174C50CA8A64756E2164756E21
303
+ //# debugId=995635FD6B287CDC64756E2164756E21
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../tools/test/src/browser/run.ts", "../src/elysia/signaling-server-plugin.ts"],
4
4
  "sourcesContent": [
5
- "#!/usr/bin/env bun\n\n/**\n * Browser test runner for Polly applications.\n *\n * Finds all *.browser.ts files in a given directory, bundles each with\n * Bun.build for the browser target (with an internal Automerge WASM fix),\n * serves the bundle on an ephemeral port, opens a Puppeteer page, and\n * polls window.__done for results. Prints pass/fail per test and exits\n * non-zero if any test failed.\n *\n * A signalling server for WebRTC tests starts automatically on a random\n * port. The URL is injected into the bundle via process.env.SIGNALING_URL.\n *\n * Usage (from project root):\n *\n * bun tools/test/src/browser/run.ts [testDir] [filter]\n *\n * Examples:\n *\n * bun tools/test/src/browser/run.ts tests/browser\n * bun tools/test/src/browser/run.ts tests/browser mesh-webrtc\n * HEADLESS=false bun tools/test/src/browser/run.ts tests/browser\n *\n * When invoked without a testDir, defaults to tests/browser relative to cwd.\n */\n\nimport { resolve } from \"node:path\";\nimport { type BunPlugin, Glob } from \"bun\";\nimport { Elysia } from \"elysia\";\nimport puppeteer from \"puppeteer\";\nimport { signalingServer } from \"../../../../src/elysia/signaling-server-plugin\";\n\n// Automerge WASM fix\n// Bun.build's target: \"browser\" picks Automerge's fullfat_bundler.js which\n// does a static .wasm import that Bun can't wire up. Redirect to the\n// base64 variant which embeds the WASM as a string and self-initialises.\n\nconst automergeBase64Path = resolve(\n process.cwd(),\n \"node_modules/@automerge/automerge/dist/mjs/entrypoints/fullfat_base64.js\"\n);\n\nconst automergeBase64Plugin: BunPlugin = {\n name: \"automerge-base64\",\n setup(build) {\n build.onResolve({ filter: /^@automerge\\/automerge(\\/slim)?$/ }, () => {\n return { path: automergeBase64Path };\n });\n },\n};\n\n// Argument parsing\n\nconst testDir = resolve(process.cwd(), process.argv[2] ?? \"tests/browser\");\nconst filter = process.argv[3] ?? \"\";\nconst headless = process.env[\"HEADLESS\"] !== \"false\";\n\nconst glob = new Glob(\"**/*.browser.{ts,tsx}\");\nconst testFiles: string[] = [];\nfor await (const file of glob.scan({ cwd: testDir, absolute: true })) {\n if (file.includes(\"harness\")) continue;\n if (filter && !file.includes(filter)) continue;\n testFiles.push(file);\n}\n\nif (testFiles.length === 0) {\n console.log(`[browser-runner] no test files found${filter ? ` matching \"${filter}\"` : \"\"}`);\n process.exit(0);\n}\n\nconsole.log(`[browser-runner] found ${testFiles.length} test file(s)`);\n\n// Start server-side infrastructure\n\nconst signalingPort = 39000 + Math.floor(Math.random() * 1000);\nconst signalingApp = new Elysia()\n .use(signalingServer({ path: \"/polly/signaling\" }))\n .listen(signalingPort);\nconsole.log(`[browser-runner] signaling server on ws://127.0.0.1:${signalingPort}/polly/signaling`);\n\n// Launch browser\n\nconst browser = await puppeteer.launch({\n headless,\n args: [\"--no-sandbox\", \"--disable-setuid-sandbox\"],\n});\n\nlet totalPassed = 0;\nlet totalFailed = 0;\n\nfor (const testFile of testFiles) {\n const shortName = testFile.replace(`${testDir}/`, \"\");\n console.log(`\\n[browser-runner] running ${shortName}`);\n\n const buildResult = await Bun.build({\n entrypoints: [testFile],\n target: \"browser\",\n format: \"esm\",\n minify: false,\n sourcemap: \"inline\",\n plugins: [automergeBase64Plugin],\n define: {\n \"process.env.SIGNALING_URL\": JSON.stringify(\n `ws://127.0.0.1:${signalingPort}/polly/signaling`\n ),\n },\n });\n\n if (!buildResult.success) {\n console.log(\" ❌ build failed:\");\n for (const log of buildResult.logs) {\n console.log(` ${log}`);\n }\n totalFailed += 1;\n continue;\n }\n\n const jsText = await buildResult.outputs[0]?.text();\n if (!jsText) {\n console.log(\" ❌ build produced no output\");\n totalFailed += 1;\n continue;\n }\n\n const html = `<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"></head>\n<body>\n<script type=\"module\">${jsText}</script>\n</body></html>`;\n\n const server = Bun.serve({\n port: 0,\n fetch() {\n return new Response(html, { headers: { \"Content-Type\": \"text/html\" } });\n },\n });\n\n const page = await browser.newPage();\n page.on(\"console\", (msg) => {\n const text = msg.text();\n if (text.includes(\"[test]\")) {\n console.log(` ${text}`);\n }\n });\n page.on(\"pageerror\", (err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n console.log(` ❌ page error: ${msg}`);\n });\n\n await page.goto(`http://127.0.0.1:${server.port}/`, { waitUntil: \"domcontentloaded\" });\n\n const timeout = 15_000;\n const deadline = Date.now() + timeout;\n let finished = false;\n while (Date.now() < deadline) {\n finished = await page.evaluate(\n () => (window as unknown as Record<string, unknown>)[\"__done\"] === true\n );\n if (finished) break;\n await new Promise((r) => setTimeout(r, 100));\n }\n\n if (!finished) {\n console.log(` ❌ timed out after ${timeout}ms`);\n totalFailed += 1;\n await page.close();\n server.stop();\n continue;\n }\n\n const results = await page.evaluate(\n () =>\n (window as unknown as Record<string, unknown>)[\"__testResults\"] as unknown as Array<{\n name: string;\n passed: boolean;\n error?: string;\n }>\n );\n\n for (const r of results ?? []) {\n if (r.passed) {\n console.log(` ✅ ${r.name}`);\n totalPassed += 1;\n } else {\n console.log(` ❌ ${r.name}: ${r.error}`);\n totalFailed += 1;\n }\n }\n\n await page.close();\n server.stop();\n}\n\nawait browser.close();\n(signalingApp as unknown as { server?: { stop?: (f?: boolean) => void } }).server?.stop?.(true);\n\nconsole.log(`\\n[browser-runner] ${totalPassed} passed, ${totalFailed} failed`);\nprocess.exit(totalFailed > 0 ? 1 : 0);\n",
5
+ "#!/usr/bin/env bun\n\n/**\n * Browser test runner for Polly applications.\n *\n * Finds all *.browser.ts files in a given directory, bundles each with\n * Bun.build for the browser target (with an internal Automerge WASM fix),\n * serves the bundle on an ephemeral port, opens a Puppeteer page, and\n * polls window.__done for results. Prints pass/fail per test and exits\n * non-zero if any test failed.\n *\n * A signalling server for WebRTC tests starts automatically on a random\n * port. The URL is injected into the bundle via process.env.SIGNALING_URL.\n *\n * Usage (from project root):\n *\n * bun tools/test/src/browser/run.ts [testDir] [filter]\n *\n * Examples:\n *\n * bun tools/test/src/browser/run.ts tests/browser\n * bun tools/test/src/browser/run.ts tests/browser mesh-webrtc\n * HEADLESS=false bun tools/test/src/browser/run.ts tests/browser\n *\n * When invoked without a testDir, defaults to tests/browser relative to cwd.\n */\n\nimport { resolve } from \"node:path\";\nimport { type BunPlugin, Glob } from \"bun\";\nimport { Elysia } from \"elysia\";\nimport puppeteer, { type Page } from \"puppeteer\";\nimport { signalingServer } from \"../../../../src/elysia/signaling-server-plugin\";\n\n// Automerge WASM fix\n// Bun.build's target: \"browser\" picks Automerge's fullfat_bundler.js which\n// does a static .wasm import that Bun can't wire up. Redirect to the\n// base64 variant which embeds the WASM as a string and self-initialises.\n\nconst automergeBase64Path = resolve(\n process.cwd(),\n \"node_modules/@automerge/automerge/dist/mjs/entrypoints/fullfat_base64.js\"\n);\n\nconst automergeBase64Plugin: BunPlugin = {\n name: \"automerge-base64\",\n setup(build) {\n build.onResolve({ filter: /^@automerge\\/automerge(\\/slim)?$/ }, () => {\n return { path: automergeBase64Path };\n });\n },\n};\n\n// Argument parsing\n\nconst testDir = resolve(process.cwd(), process.argv[2] ?? \"tests/browser\");\nconst filter = process.argv[3] ?? \"\";\nconst headless = process.env[\"HEADLESS\"] !== \"false\";\n\nconst glob = new Glob(\"**/*.browser.{ts,tsx}\");\nconst testFiles: string[] = [];\nfor await (const file of glob.scan({ cwd: testDir, absolute: true })) {\n if (file.includes(\"harness\")) continue;\n if (filter && !file.includes(filter)) continue;\n testFiles.push(file);\n}\n\nif (testFiles.length === 0) {\n console.log(`[browser-runner] no test files found${filter ? ` matching \"${filter}\"` : \"\"}`);\n process.exit(0);\n}\n\nconsole.log(`[browser-runner] found ${testFiles.length} test file(s)`);\n\n// Start server-side infrastructure\n\nconst signalingPort = 39000 + Math.floor(Math.random() * 1000);\nconst signalingApp = new Elysia()\n .use(signalingServer({ path: \"/polly/signaling\" }))\n .listen(signalingPort);\nconsole.log(`[browser-runner] signaling server on ws://127.0.0.1:${signalingPort}/polly/signaling`);\n\n// Launch browser\n//\n// protocolTimeout caps how long any single CDP call (e.g. page.evaluate)\n// waits before throwing. Puppeteer's default is 180s, so a stalled\n// renderer hangs the runner for three minutes. 30s fails fast while\n// still tolerating a slow-but-healthy initial sync.\n\nconst browser = await puppeteer.launch({\n headless,\n args: [\"--no-sandbox\", \"--disable-setuid-sandbox\"],\n protocolTimeout: 30_000,\n});\n\nlet totalPassed = 0;\nlet totalFailed = 0;\n\n/** A transient CDP timeout (renderer stall) retryable, unlike a red test. */\nfunction isProtocolError(err: unknown): boolean {\n return err instanceof Error && err.name === \"ProtocolError\";\n}\n\nfunction errMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Build, serve, and run one test file on a fresh page. Returns its\n * pass/fail tally. Build failures and test timeouts are reported here\n * (not thrown). A thrown error (e.g. a ProtocolError from a stalled\n * renderer) propagates to the caller so it can retry the file; the\n * page and server are always cleaned up first.\n */\nasync function runFile(testFile: string): Promise<{ passed: number; failed: number }> {\n const buildResult = await Bun.build({\n entrypoints: [testFile],\n target: \"browser\",\n format: \"esm\",\n minify: false,\n sourcemap: \"inline\",\n plugins: [automergeBase64Plugin],\n define: {\n \"process.env.SIGNALING_URL\": JSON.stringify(\n `ws://127.0.0.1:${signalingPort}/polly/signaling`\n ),\n },\n });\n\n if (!buildResult.success) {\n console.log(\" ❌ build failed:\");\n for (const log of buildResult.logs) {\n console.log(` ${log}`);\n }\n return { passed: 0, failed: 1 };\n }\n\n const jsText = await buildResult.outputs[0]?.text();\n if (!jsText) {\n console.log(\" ❌ build produced no output\");\n return { passed: 0, failed: 1 };\n }\n\n const html = `<!DOCTYPE html>\n<html><head><meta charset=\"utf-8\"></head>\n<body>\n<script type=\"module\">${jsText}</script>\n</body></html>`;\n\n const server = Bun.serve({\n port: 0,\n fetch() {\n return new Response(html, { headers: { \"Content-Type\": \"text/html\" } });\n },\n });\n\n let page: Page | undefined;\n try {\n page = await browser.newPage();\n page.on(\"console\", (msg) => {\n const text = msg.text();\n if (text.includes(\"[test]\")) {\n console.log(` ${text}`);\n }\n });\n page.on(\"pageerror\", (err: unknown) => {\n console.log(` ❌ page error: ${errMessage(err)}`);\n });\n\n await page.goto(`http://127.0.0.1:${server.port}/`, { waitUntil: \"domcontentloaded\" });\n\n const timeout = 15_000;\n const deadline = Date.now() + timeout;\n let finished = false;\n while (Date.now() < deadline) {\n finished = await page.evaluate(\n () => (window as unknown as Record<string, unknown>)[\"__done\"] === true\n );\n if (finished) break;\n await new Promise((r) => setTimeout(r, 100));\n }\n\n if (!finished) {\n console.log(` ❌ timed out after ${timeout}ms`);\n return { passed: 0, failed: 1 };\n }\n\n const results = await page.evaluate(\n () =>\n (window as unknown as Record<string, unknown>)[\"__testResults\"] as unknown as Array<{\n name: string;\n passed: boolean;\n error?: string;\n }>\n );\n\n let passed = 0;\n let failed = 0;\n for (const r of results ?? []) {\n if (r.passed) {\n console.log(` ✅ ${r.name}`);\n passed += 1;\n } else {\n console.log(` ❌ ${r.name}: ${r.error}`);\n failed += 1;\n }\n }\n return { passed, failed };\n } finally {\n // Always run, even on the error path. close() can itself throw a\n // ProtocolError under a stall — swallow it so cleanup completes.\n if (page) {\n await page.close().catch(() => {\n // ignore — page may already be gone after a stall\n });\n }\n server.stop();\n }\n}\n\nfor (const testFile of testFiles) {\n const shortName = testFile.replace(`${testDir}/`, \"\");\n console.log(`\\n[browser-runner] running ${shortName}`);\n\n let result: { passed: number; failed: number };\n try {\n result = await runFile(testFile);\n } catch (err) {\n if (isProtocolError(err)) {\n console.log(` ⚠️ protocol error (${errMessage(err)}) — retrying once on a fresh page`);\n try {\n result = await runFile(testFile);\n } catch (retryErr) {\n console.log(` ❌ retry failed: ${errMessage(retryErr)}`);\n result = { passed: 0, failed: 1 };\n }\n } else {\n // A non-protocol error: record the file as failed and keep going,\n // never abort the whole suite.\n console.log(` ❌ ${errMessage(err)}`);\n result = { passed: 0, failed: 1 };\n }\n }\n\n totalPassed += result.passed;\n totalFailed += result.failed;\n}\n\nawait browser.close();\n(signalingApp as unknown as { server?: { stop?: (f?: boolean) => void } }).server?.stop?.(true);\n\nconsole.log(`\\n[browser-runner] ${totalPassed} passed, ${totalFailed} failed`);\nprocess.exit(totalFailed > 0 ? 1 : 0);\n",
6
6
  "// @ts-nocheck - Optional peer dependencies (elysia, @elysiajs/eden)\n/**\n * signalingServer — Phase 2 Elysia plugin that exposes a stateless\n * WebSocket route for SDP/ICE relay between $meshState peers.\n *\n * The mesh transport is a star-of-data-channels: peers establish direct\n * WebRTC connections to each other and exchange document operations\n * peer-to-peer once those channels are open. WebRTC connection setup\n * needs an out-of-band channel for SDP offer/answer and ICE candidate\n * exchange, and that channel is what this plugin provides. The plugin\n * does not own any document state, does not hold any encryption keys,\n * and never inspects the contents of the messages it relays. It is a\n * pure pub-sub by peer id.\n *\n * Once two peers have completed the SDP exchange and opened a direct\n * data channel, the signalling server is no longer on the critical\n * path — the peers talk directly. The signalling server's role is\n * therefore intermittent: peers connect to it only during the brief\n * windows when they are establishing or re-establishing connections.\n *\n * Wire protocol:\n *\n * Client → server (join):\n * { type: \"join\", peerId: \"peer-alice\" }\n *\n * Client → server (signal to another peer):\n * { type: \"signal\", peerId: \"peer-alice\", targetPeerId: \"peer-bob\",\n * payload: { ... } }\n *\n * Server → client (delivered signal):\n * { type: \"signal\", peerId: \"peer-alice\", targetPeerId: \"peer-bob\",\n * payload: { ... } }\n *\n * Server → client (notification of unknown target):\n * { type: \"error\", reason: \"unknown-target\", targetPeerId: \"...\" }\n *\n * The `payload` is opaque to the signalling server — typically it\n * carries an SDP offer, SDP answer, or ICE candidate. Applications can\n * also use the relay for any other peer-to-peer message that needs an\n * intermediary, such as the initial handshake of a pairing flow.\n *\n * @example\n * ```ts\n * import { Elysia } from \"elysia\";\n * import { signalingServer } from \"@fairfox/polly/elysia\";\n *\n * const app = new Elysia()\n * .use(signalingServer({ path: \"/polly/signaling\" }))\n * .listen(8080);\n * ```\n */\n\nimport { Elysia } from \"elysia\";\n\n/** A signalling message. The `type` discriminates between client-to-server\n * requests (join, signal), the error envelope, and the server-to-client\n * discovery frames (peers-present, peer-joined, peer-left) that let\n * peers learn about each other without polling. */\nexport type SignalingMessage =\n | {\n type: \"join\";\n /** The peer registering itself with the signalling server. */\n peerId: string;\n }\n | {\n type: \"signal\";\n /** The peer sending the signal. */\n peerId: string;\n /** The peer the signal is being relayed to. */\n targetPeerId: string;\n /** Opaque payload, typically SDP or ICE. */\n payload: unknown;\n }\n | {\n type: \"error\";\n reason: \"unknown-target\" | \"not-joined\" | \"malformed\";\n targetPeerId?: string;\n }\n | {\n /** Sent to a newcomer immediately after it joins, listing every\n * peer that was already joined at that moment. Empty for a lone\n * newcomer. */\n type: \"peers-present\";\n peerIds: string[];\n }\n | {\n /** Broadcast to every incumbent when a new peer joins. */\n type: \"peer-joined\";\n peerId: string;\n }\n | {\n /** Broadcast to every remaining incumbent when a joined peer\n * closes its socket. Never emitted for a connection that never\n * sent a join frame. */\n type: \"peer-left\";\n peerId: string;\n };\n\n/** A frame whose `type` is outside the built-in signalling vocabulary.\n * Consumers who pass an {@link SignalingServerOptions.onCustomFrame}\n * handler receive these on the server side; everything else — including\n * routing them to a specific peer, storing a session, or rejecting the\n * frame — is the consumer's call. Polly does not touch the body. */\nexport interface CustomSignalingFrame {\n type: string;\n [key: string]: unknown;\n}\n\n/** Minimal surface the custom-frame handler receives in place of the\n * Elysia-specific `ws` object so the plugin stays portable. Exposes the\n * `data` bag (used to stash the authenticated peerId under the existing\n * join handshake) and a `send` method. */\nexport interface CustomFrameSocket {\n data: Record<string, unknown>;\n send: (msg: unknown) => void;\n}\n\nexport interface SignalingServerOptions {\n /** WebSocket route path. Defaults to \"/polly/signaling\". */\n path?: string;\n /** Optional hook for frames whose `type` is outside the built-in\n * vocabulary. The plugin invokes it in place of returning a\n * `malformed` error, so consumers can layer their own application\n * protocol (pairing return tokens, presence pings, etc.) on the\n * existing socket. The `peerId` argument is the sender's\n * authenticated peer id from their prior `join` frame, or\n * `undefined` if they haven't joined yet. */\n onCustomFrame?: (\n socket: CustomFrameSocket,\n frame: CustomSignalingFrame,\n peerId: string | undefined\n ) => void;\n}\n\n/**\n * Construct the signalling-server Elysia plugin. The plugin keeps a\n * per-instance map of peer id → WebSocket connection so that incoming\n * \"signal\" messages can be routed to the right target socket. The map\n * is local to the plugin instance, not shared across processes; for\n * multi-instance deployments behind a load balancer, applications need\n * sticky connection routing or a shared backplane (Redis pub-sub or\n * similar). That is a follow-up.\n */\nexport function signalingServer(options: SignalingServerOptions = {}) {\n const path = options.path ?? \"/polly/signaling\";\n const onCustomFrame = options.onCustomFrame;\n // Per-peer-id map of joined sockets. The inverse mapping is stored\n // directly on ws.data (a mutable property bag that Elysia preserves\n // across message callbacks for a given connection); the webrtc-p2p-chat\n // example in examples/ confirms this pattern is stable under Bun.\n const peerSockets = new Map<string, { send: (msg: unknown) => void }>();\n\n // Intentionally unnamed — Elysia deduplicates plugins by name, and each\n // signalingServer() call needs its own closure-captured peer map.\n const parseMessage = (raw: unknown): SignalingMessage | undefined => {\n try {\n return typeof raw === \"string\" ? JSON.parse(raw) : (raw as unknown as SignalingMessage);\n } catch {\n return undefined;\n }\n };\n\n const handleJoin = (ws: unknown, peerId: string): void => {\n const newcomer = ws as unknown as { send: (m: unknown) => void };\n // Collect the peers that were already joined so we can (a) tell the\n // newcomer who is present and (b) tell each of them about the\n // newcomer. A rejoin with the same peerId replaces the prior entry\n // but is otherwise treated as a fresh arrival.\n const incumbents: Array<{ peerId: string; socket: { send: (m: unknown) => void } }> = [];\n for (const [existingPeerId, existingSocket] of peerSockets) {\n if (existingPeerId === peerId) continue;\n incumbents.push({ peerId: existingPeerId, socket: existingSocket });\n }\n peerSockets.set(peerId, newcomer);\n const wsWithData = ws as unknown as { data: Record<string, unknown> };\n wsWithData.data.peerId = peerId;\n\n newcomer.send({\n type: \"peers-present\",\n peerIds: incumbents.map((i) => i.peerId),\n } as unknown as SignalingMessage);\n\n for (const incumbent of incumbents) {\n try {\n incumbent.socket.send({ type: \"peer-joined\", peerId } as unknown as SignalingMessage);\n } catch {\n // If a send fails we leave the stale socket to its own close\n // handler to evict. Dropping here would open a window where\n // the next signal to this peer still thinks it's alive.\n }\n }\n };\n\n const sendUnknownTarget = (ws: unknown, targetPeerId: string): void => {\n (ws as unknown as { send: (m: unknown) => void }).send({\n type: \"error\",\n reason: \"unknown-target\",\n targetPeerId,\n } as unknown as SignalingMessage);\n };\n\n /** Look up a target socket and confirm it is still open. */\n const findOpenTarget = (targetPeerId: string): { send: (msg: unknown) => void } | undefined => {\n const target = peerSockets.get(targetPeerId);\n if (!target) return undefined;\n const readyState = (target as unknown as { readyState?: number }).readyState;\n const OPEN = 1;\n if (readyState !== undefined && readyState !== OPEN) {\n peerSockets.delete(targetPeerId);\n return undefined;\n }\n return target;\n };\n\n const handleSignal = (ws: unknown, msg: Extract<SignalingMessage, { type: \"signal\" }>): void => {\n const wsWithData = ws as unknown as {\n data: Record<string, unknown>;\n send: (m: unknown) => void;\n };\n const senderId = wsWithData.data.peerId as unknown as string | undefined;\n if (!senderId) {\n wsWithData.send({ type: \"error\", reason: \"not-joined\" } as unknown as SignalingMessage);\n return;\n }\n const target = findOpenTarget(msg.targetPeerId);\n if (!target) {\n sendUnknownTarget(ws, msg.targetPeerId);\n return;\n }\n const relayed: SignalingMessage = {\n type: \"signal\",\n peerId: senderId,\n targetPeerId: msg.targetPeerId,\n payload: msg.payload,\n };\n try {\n target.send(relayed);\n } catch {\n peerSockets.delete(msg.targetPeerId);\n sendUnknownTarget(ws, msg.targetPeerId);\n }\n };\n\n return new Elysia().ws(path, {\n message(ws, raw) {\n const msg = parseMessage(raw);\n if (!msg) {\n ws.send({ type: \"error\", reason: \"malformed\" } as unknown as SignalingMessage);\n return;\n }\n if (msg.type === \"join\") {\n handleJoin(ws, msg.peerId);\n return;\n }\n if (msg.type === \"signal\") {\n handleSignal(ws, msg);\n return;\n }\n // Unknown types route to the consumer's custom-frame hook when\n // one is configured. Without a hook they still fall through to\n // the `malformed` error — same behaviour as before this branch\n // existed.\n if (onCustomFrame !== undefined) {\n const wsWithData = ws as unknown as CustomFrameSocket;\n const senderId = wsWithData.data[\"peerId\"];\n const peerId = typeof senderId === \"string\" ? senderId : undefined;\n onCustomFrame(wsWithData, msg as unknown as CustomSignalingFrame, peerId);\n return;\n }\n ws.send({ type: \"error\", reason: \"malformed\" } as unknown as SignalingMessage);\n },\n\n close(ws) {\n const peerId = (ws.data as unknown as Record<string, unknown>).peerId as unknown as\n | string\n | undefined;\n if (!peerId) {\n // Connection that never sent a join — nothing to broadcast and\n // nothing to evict. A bystander coming and going leaves no trace.\n return;\n }\n // Only evict if the map still points at *this* socket. A stale\n // close after the same peerId rejoined on a new socket should not\n // take the fresh entry with it. The comparison uses the `data` bag\n // Elysia attaches to each connection because it is preserved across\n // message and close callbacks, unlike the `ws` wrapper object which\n // Elysia may or may not reuse.\n const mapped = peerSockets.get(peerId);\n const wsData = (ws as unknown as { data: Record<string, unknown> }).data;\n const mappedData = (mapped as unknown as { data?: Record<string, unknown> } | undefined)\n ?.data;\n if (mapped === undefined || mappedData !== wsData) {\n return;\n }\n peerSockets.delete(peerId);\n for (const [_incumbentId, incumbentSocket] of peerSockets) {\n try {\n incumbentSocket.send({ type: \"peer-left\", peerId } as unknown as SignalingMessage);\n } catch {\n // Incumbent socket is gone; its own close handler will tidy.\n }\n }\n },\n });\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "C5D6EF174C50CA8A64756E2164756E21",
8
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AA2BA;AACA;AACA,mBAAS;AACT;;;ACsBA;AA2FO,SAAS,eAAe,CAAC,UAAkC,CAAC,GAAG;AAAA,EACpE,MAAM,OAAO,QAAQ,QAAQ;AAAA,EAC7B,MAAM,gBAAgB,QAAQ;AAAA,EAK9B,MAAM,cAAc,IAAI;AAAA,EAIxB,MAAM,eAAe,CAAC,QAA+C;AAAA,IACnE,IAAI;AAAA,MACF,OAAO,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,IAAK;AAAA,MACpD,MAAM;AAAA,MACN;AAAA;AAAA;AAAA,EAIJ,MAAM,aAAa,CAAC,IAAa,WAAyB;AAAA,IACxD,MAAM,WAAW;AAAA,IAKjB,MAAM,aAAgF,CAAC;AAAA,IACvF,YAAY,gBAAgB,mBAAmB,aAAa;AAAA,MAC1D,IAAI,mBAAmB;AAAA,QAAQ;AAAA,MAC/B,WAAW,KAAK,EAAE,QAAQ,gBAAgB,QAAQ,eAAe,CAAC;AAAA,IACpE;AAAA,IACA,YAAY,IAAI,QAAQ,QAAQ;AAAA,IAChC,MAAM,aAAa;AAAA,IACnB,WAAW,KAAK,SAAS;AAAA,IAEzB,SAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,SAAS,WAAW,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,IACzC,CAAgC;AAAA,IAEhC,WAAW,aAAa,YAAY;AAAA,MAClC,IAAI;AAAA,QACF,UAAU,OAAO,KAAK,EAAE,MAAM,eAAe,OAAO,CAAgC;AAAA,QACpF,MAAM;AAAA,IAKV;AAAA;AAAA,EAGF,MAAM,oBAAoB,CAAC,IAAa,iBAA+B;AAAA,IACpE,GAAiD,KAAK;AAAA,MACrD,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,IACF,CAAgC;AAAA;AAAA,EAIlC,MAAM,iBAAiB,CAAC,iBAAuE;AAAA,IAC7F,MAAM,SAAS,YAAY,IAAI,YAAY;AAAA,IAC3C,IAAI,CAAC;AAAA,MAAQ;AAAA,IACb,MAAM,aAAc,OAA8C;AAAA,IAClE,MAAM,OAAO;AAAA,IACb,IAAI,eAAe,aAAa,eAAe,MAAM;AAAA,MACnD,YAAY,OAAO,YAAY;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAGT,MAAM,eAAe,CAAC,IAAa,QAA6D;AAAA,IAC9F,MAAM,aAAa;AAAA,IAInB,MAAM,WAAW,WAAW,KAAK;AAAA,IACjC,IAAI,CAAC,UAAU;AAAA,MACb,WAAW,KAAK,EAAE,MAAM,SAAS,QAAQ,aAAa,CAAgC;AAAA,MACtF;AAAA,IACF;AAAA,IACA,MAAM,SAAS,eAAe,IAAI,YAAY;AAAA,IAC9C,IAAI,CAAC,QAAQ;AAAA,MACX,kBAAkB,IAAI,IAAI,YAAY;AAAA,MACtC;AAAA,IACF;AAAA,IACA,MAAM,UAA4B;AAAA,MAChC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,cAAc,IAAI;AAAA,MAClB,SAAS,IAAI;AAAA,IACf;AAAA,IACA,IAAI;AAAA,MACF,OAAO,KAAK,OAAO;AAAA,MACnB,MAAM;AAAA,MACN,YAAY,OAAO,IAAI,YAAY;AAAA,MACnC,kBAAkB,IAAI,IAAI,YAAY;AAAA;AAAA;AAAA,EAI1C,OAAO,IAAI,OAAO,EAAE,GAAG,MAAM;AAAA,IAC3B,OAAO,CAAC,IAAI,KAAK;AAAA,MACf,MAAM,MAAM,aAAa,GAAG;AAAA,MAC5B,IAAI,CAAC,KAAK;AAAA,QACR,GAAG,KAAK,EAAE,MAAM,SAAS,QAAQ,YAAY,CAAgC;AAAA,QAC7E;AAAA,MACF;AAAA,MACA,IAAI,IAAI,SAAS,QAAQ;AAAA,QACvB,WAAW,IAAI,IAAI,MAAM;AAAA,QACzB;AAAA,MACF;AAAA,MACA,IAAI,IAAI,SAAS,UAAU;AAAA,QACzB,aAAa,IAAI,GAAG;AAAA,QACpB;AAAA,MACF;AAAA,MAKA,IAAI,kBAAkB,WAAW;AAAA,QAC/B,MAAM,aAAa;AAAA,QACnB,MAAM,WAAW,WAAW,KAAK;AAAA,QACjC,MAAM,SAAS,OAAO,aAAa,WAAW,WAAW;AAAA,QACzD,cAAc,YAAY,KAAwC,MAAM;AAAA,QACxE;AAAA,MACF;AAAA,MACA,GAAG,KAAK,EAAE,MAAM,SAAS,QAAQ,YAAY,CAAgC;AAAA;AAAA,IAG/E,KAAK,CAAC,IAAI;AAAA,MACR,MAAM,SAAU,GAAG,KAA4C;AAAA,MAG/D,IAAI,CAAC,QAAQ;AAAA,QAGX;AAAA,MACF;AAAA,MAOA,MAAM,SAAS,YAAY,IAAI,MAAM;AAAA,MACrC,MAAM,SAAU,GAAoD;AAAA,MACpE,MAAM,aAAc,QAChB;AAAA,MACJ,IAAI,WAAW,aAAa,eAAe,QAAQ;AAAA,QACjD;AAAA,MACF;AAAA,MACA,YAAY,OAAO,MAAM;AAAA,MACzB,YAAY,cAAc,oBAAoB,aAAa;AAAA,QACzD,IAAI;AAAA,UACF,gBAAgB,KAAK,EAAE,MAAM,aAAa,OAAO,CAAgC;AAAA,UACjF,MAAM;AAAA,MAGV;AAAA;AAAA,EAEJ,CAAC;AAAA;;;ADzQH,IAAM,sBAAsB,QAC1B,QAAQ,IAAI,GACZ,0EACF;AAEA,IAAM,wBAAmC;AAAA,EACvC,MAAM;AAAA,EACN,KAAK,CAAC,OAAO;AAAA,IACX,MAAM,UAAU,EAAE,QAAQ,mCAAmC,GAAG,MAAM;AAAA,MACpE,OAAO,EAAE,MAAM,oBAAoB;AAAA,KACpC;AAAA;AAEL;AAIA,IAAM,UAAU,QAAQ,QAAQ,IAAI,GAAG,QAAQ,KAAK,MAAM,eAAe;AACzE,IAAM,SAAS,QAAQ,KAAK,MAAM;AAClC,IAAM,WAAW,QAAQ,IAAI,gBAAgB;AAE7C,IAAM,OAAO,IAAI,KAAK,uBAAuB;AAC7C,IAAM,YAAsB,CAAC;AAC7B,iBAAiB,QAAQ,KAAK,KAAK,EAAE,KAAK,SAAS,UAAU,KAAK,CAAC,GAAG;AAAA,EACpE,IAAI,KAAK,SAAS,SAAS;AAAA,IAAG;AAAA,EAC9B,IAAI,UAAU,CAAC,KAAK,SAAS,MAAM;AAAA,IAAG;AAAA,EACtC,UAAU,KAAK,IAAI;AACrB;AAEA,IAAI,UAAU,WAAW,GAAG;AAAA,EAC1B,QAAQ,IAAI,uCAAuC,SAAS,cAAc,YAAY,IAAI;AAAA,EAC1F,QAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,IAAI,0BAA0B,UAAU,qBAAqB;AAIrE,IAAM,gBAAgB,QAAQ,KAAK,MAAM,KAAK,OAAO,IAAI,IAAI;AAC7D,IAAM,eAAe,IAAI,QAAO,EAC7B,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC,CAAC,EACjD,OAAO,aAAa;AACvB,QAAQ,IAAI,uDAAuD,+BAA+B;AASlG,IAAM,UAAU,MAAM,UAAU,OAAO;AAAA,EACrC;AAAA,EACA,MAAM,CAAC,gBAAgB,0BAA0B;AAAA,EACjD,iBAAiB;AACnB,CAAC;AAED,IAAI,cAAc;AAClB,IAAI,cAAc;AAGlB,SAAS,eAAe,CAAC,KAAuB;AAAA,EAC9C,OAAO,eAAe,SAAS,IAAI,SAAS;AAAA;AAG9C,SAAS,UAAU,CAAC,KAAsB;AAAA,EACxC,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA;AAUxD,eAAe,OAAO,CAAC,UAA+D;AAAA,EACpF,MAAM,cAAc,MAAM,IAAI,MAAM;AAAA,IAClC,aAAa,CAAC,QAAQ;AAAA,IACtB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,SAAS,CAAC,qBAAqB;AAAA,IAC/B,QAAQ;AAAA,MACN,6BAA6B,KAAK,UAChC,kBAAkB,+BACpB;AAAA,IACF;AAAA,EACF,CAAC;AAAA,EAED,IAAI,CAAC,YAAY,SAAS;AAAA,IACxB,QAAQ,IAAI,mBAAkB;AAAA,IAC9B,WAAW,OAAO,YAAY,MAAM;AAAA,MAClC,QAAQ,IAAI,QAAQ,KAAK;AAAA,IAC3B;AAAA,IACA,OAAO,EAAE,QAAQ,GAAG,QAAQ,EAAE;AAAA,EAChC;AAAA,EAEA,MAAM,SAAS,MAAM,YAAY,QAAQ,IAAI,KAAK;AAAA,EAClD,IAAI,CAAC,QAAQ;AAAA,IACX,QAAQ,IAAI,8BAA6B;AAAA,IACzC,OAAO,EAAE,QAAQ,GAAG,QAAQ,EAAE;AAAA,EAChC;AAAA,EAEA,MAAM,OAAO;AAAA;AAAA;AAAA,wBAGS;AAAA;AAAA,EAGtB,MAAM,SAAS,IAAI,MAAM;AAAA,IACvB,MAAM;AAAA,IACN,KAAK,GAAG;AAAA,MACN,OAAO,IAAI,SAAS,MAAM,EAAE,SAAS,EAAE,gBAAgB,YAAY,EAAE,CAAC;AAAA;AAAA,EAE1E,CAAC;AAAA,EAED,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,OAAO,MAAM,QAAQ,QAAQ;AAAA,IAC7B,KAAK,GAAG,WAAW,CAAC,QAAQ;AAAA,MAC1B,MAAM,OAAO,IAAI,KAAK;AAAA,MACtB,IAAI,KAAK,SAAS,QAAQ,GAAG;AAAA,QAC3B,QAAQ,IAAI,KAAK,MAAM;AAAA,MACzB;AAAA,KACD;AAAA,IACD,KAAK,GAAG,aAAa,CAAC,QAAiB;AAAA,MACrC,QAAQ,IAAI,mBAAkB,WAAW,GAAG,GAAG;AAAA,KAChD;AAAA,IAED,MAAM,KAAK,KAAK,oBAAoB,OAAO,SAAS,EAAE,WAAW,mBAAmB,CAAC;AAAA,IAErF,MAAM,UAAU;AAAA,IAChB,MAAM,WAAW,KAAK,IAAI,IAAI;AAAA,IAC9B,IAAI,WAAW;AAAA,IACf,OAAO,KAAK,IAAI,IAAI,UAAU;AAAA,MAC5B,WAAW,MAAM,KAAK,SACpB,MAAO,OAA8C,cAAc,IACrE;AAAA,MACA,IAAI;AAAA,QAAU;AAAA,MACd,MAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAAA,IAC7C;AAAA,IAEA,IAAI,CAAC,UAAU;AAAA,MACb,QAAQ,IAAI,uBAAsB,WAAW;AAAA,MAC7C,OAAO,EAAE,QAAQ,GAAG,QAAQ,EAAE;AAAA,IAChC;AAAA,IAEA,MAAM,UAAU,MAAM,KAAK,SACzB,MACG,OAA8C,gBAKnD;AAAA,IAEA,IAAI,SAAS;AAAA,IACb,IAAI,SAAS;AAAA,IACb,WAAW,KAAK,WAAW,CAAC,GAAG;AAAA,MAC7B,IAAI,EAAE,QAAQ;AAAA,QACZ,QAAQ,IAAI,OAAM,EAAE,MAAM;AAAA,QAC1B,UAAU;AAAA,MACZ,EAAO;AAAA,QACL,QAAQ,IAAI,OAAM,EAAE,SAAS,EAAE,OAAO;AAAA,QACtC,UAAU;AAAA;AAAA,IAEd;AAAA,IACA,OAAO,EAAE,QAAQ,OAAO;AAAA,YACxB;AAAA,IAGA,IAAI,MAAM;AAAA,MACR,MAAM,KAAK,MAAM,EAAE,MAAM,MAAM,EAE9B;AAAA,IACH;AAAA,IACA,OAAO,KAAK;AAAA;AAAA;AAIhB,WAAW,YAAY,WAAW;AAAA,EAChC,MAAM,YAAY,SAAS,QAAQ,GAAG,YAAY,EAAE;AAAA,EACpD,QAAQ,IAAI;AAAA,2BAA8B,WAAW;AAAA,EAErD,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,SAAS,MAAM,QAAQ,QAAQ;AAAA,IAC/B,OAAO,KAAK;AAAA,IACZ,IAAI,gBAAgB,GAAG,GAAG;AAAA,MACxB,QAAQ,IAAI,yBAAwB,WAAW,GAAG,oCAAoC;AAAA,MACtF,IAAI;AAAA,QACF,SAAS,MAAM,QAAQ,QAAQ;AAAA,QAC/B,OAAO,UAAU;AAAA,QACjB,QAAQ,IAAI,qBAAoB,WAAW,QAAQ,GAAG;AAAA,QACtD,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAAE;AAAA;AAAA,IAEpC,EAAO;AAAA,MAGL,QAAQ,IAAI,OAAM,WAAW,GAAG,GAAG;AAAA,MACnC,SAAS,EAAE,QAAQ,GAAG,QAAQ,EAAE;AAAA;AAAA;AAAA,EAIpC,eAAe,OAAO;AAAA,EACtB,eAAe,OAAO;AACxB;AAEA,MAAM,QAAQ,MAAM;AACnB,aAA0E,QAAQ,OAAO,IAAI;AAE9F,QAAQ,IAAI;AAAA,mBAAsB,uBAAuB,oBAAoB;AAC7E,QAAQ,KAAK,cAAc,IAAI,IAAI,CAAC;",
9
+ "debugId": "995635FD6B287CDC64756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -11487,7 +11487,7 @@ var init_zlib = __esm(() => {
11487
11487
  export_default = import_browserify_zlib.default;
11488
11488
  });
11489
11489
 
11490
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/chunkstream.js
11490
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/chunkstream.js
11491
11491
  var require_chunkstream = __commonJS((exports, module) => {
11492
11492
  var util = (init_util(), __toCommonJS(exports_util));
11493
11493
  var Stream = require_stream();
@@ -11619,7 +11619,7 @@ var require_chunkstream = __commonJS((exports, module) => {
11619
11619
  };
11620
11620
  });
11621
11621
 
11622
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/interlace.js
11622
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/interlace.js
11623
11623
  var require_interlace = __commonJS((exports) => {
11624
11624
  var imagePasses = [
11625
11625
  {
@@ -11692,7 +11692,7 @@ var require_interlace = __commonJS((exports) => {
11692
11692
  };
11693
11693
  });
11694
11694
 
11695
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/paeth-predictor.js
11695
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/paeth-predictor.js
11696
11696
  var require_paeth_predictor = __commonJS((exports, module) => {
11697
11697
  module.exports = function paethPredictor(left, above, upLeft) {
11698
11698
  let paeth = left + above - upLeft;
@@ -11709,7 +11709,7 @@ var require_paeth_predictor = __commonJS((exports, module) => {
11709
11709
  };
11710
11710
  });
11711
11711
 
11712
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-parse.js
11712
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-parse.js
11713
11713
  var require_filter_parse = __commonJS((exports, module) => {
11714
11714
  var interlaceUtils = require_interlace();
11715
11715
  var paethPredictor = require_paeth_predictor();
@@ -11844,7 +11844,7 @@ var require_filter_parse = __commonJS((exports, module) => {
11844
11844
  };
11845
11845
  });
11846
11846
 
11847
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-parse-async.js
11847
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-parse-async.js
11848
11848
  var require_filter_parse_async = __commonJS((exports, module) => {
11849
11849
  var util = (init_util(), __toCommonJS(exports_util));
11850
11850
  var ChunkStream = require_chunkstream();
@@ -11867,7 +11867,7 @@ var require_filter_parse_async = __commonJS((exports, module) => {
11867
11867
  util.inherits(FilterAsync, ChunkStream);
11868
11868
  });
11869
11869
 
11870
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/constants.js
11870
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/constants.js
11871
11871
  var require_constants2 = __commonJS((exports, module) => {
11872
11872
  module.exports = {
11873
11873
  PNG_SIGNATURE: [137, 80, 78, 71, 13, 10, 26, 10],
@@ -11894,7 +11894,7 @@ var require_constants2 = __commonJS((exports, module) => {
11894
11894
  };
11895
11895
  });
11896
11896
 
11897
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/crc.js
11897
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/crc.js
11898
11898
  var require_crc = __commonJS((exports, module) => {
11899
11899
  var crcTable = [];
11900
11900
  (function() {
@@ -11931,7 +11931,7 @@ var require_crc = __commonJS((exports, module) => {
11931
11931
  };
11932
11932
  });
11933
11933
 
11934
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/parser.js
11934
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/parser.js
11935
11935
  var require_parser = __commonJS((exports, module) => {
11936
11936
  var constants2 = require_constants2();
11937
11937
  var CrcCalculator = require_crc();
@@ -12148,7 +12148,7 @@ var require_parser = __commonJS((exports, module) => {
12148
12148
  };
12149
12149
  });
12150
12150
 
12151
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/bitmapper.js
12151
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/bitmapper.js
12152
12152
  var require_bitmapper = __commonJS((exports) => {
12153
12153
  var interlaceUtils = require_interlace();
12154
12154
  var pixelBppMapper = [
@@ -12359,7 +12359,7 @@ var require_bitmapper = __commonJS((exports) => {
12359
12359
  };
12360
12360
  });
12361
12361
 
12362
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/format-normaliser.js
12362
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/format-normaliser.js
12363
12363
  var require_format_normaliser = __commonJS((exports, module) => {
12364
12364
  function dePalette(indata, outdata, width, height, palette) {
12365
12365
  let pxPos = 0;
@@ -12435,7 +12435,7 @@ var require_format_normaliser = __commonJS((exports, module) => {
12435
12435
  };
12436
12436
  });
12437
12437
 
12438
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/parser-async.js
12438
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/parser-async.js
12439
12439
  var require_parser_async = __commonJS((exports, module) => {
12440
12440
  var util = (init_util(), __toCommonJS(exports_util));
12441
12441
  var zlib = (init_zlib(), __toCommonJS(exports_zlib));
@@ -12557,7 +12557,7 @@ var require_parser_async = __commonJS((exports, module) => {
12557
12557
  };
12558
12558
  });
12559
12559
 
12560
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/bitpacker.js
12560
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/bitpacker.js
12561
12561
  var require_bitpacker = __commonJS((exports, module) => {
12562
12562
  var constants2 = require_constants2();
12563
12563
  module.exports = function(dataIn, width, height, options) {
@@ -12686,7 +12686,7 @@ var require_bitpacker = __commonJS((exports, module) => {
12686
12686
  };
12687
12687
  });
12688
12688
 
12689
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-pack.js
12689
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-pack.js
12690
12690
  var require_filter_pack = __commonJS((exports, module) => {
12691
12691
  var paethPredictor = require_paeth_predictor();
12692
12692
  function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
@@ -12825,7 +12825,7 @@ var require_filter_pack = __commonJS((exports, module) => {
12825
12825
  };
12826
12826
  });
12827
12827
 
12828
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/packer.js
12828
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/packer.js
12829
12829
  var require_packer = __commonJS((exports, module) => {
12830
12830
  var constants2 = require_constants2();
12831
12831
  var CrcStream = require_crc();
@@ -12913,7 +12913,7 @@ var require_packer = __commonJS((exports, module) => {
12913
12913
  };
12914
12914
  });
12915
12915
 
12916
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/packer-async.js
12916
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/packer-async.js
12917
12917
  var require_packer_async = __commonJS((exports, module) => {
12918
12918
  var util = (init_util(), __toCommonJS(exports_util));
12919
12919
  var Stream = require_stream();
@@ -12946,7 +12946,7 @@ var require_packer_async = __commonJS((exports, module) => {
12946
12946
  };
12947
12947
  });
12948
12948
 
12949
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/sync-inflate.js
12949
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/sync-inflate.js
12950
12950
  var require_sync_inflate = __commonJS((exports, module) => {
12951
12951
  var assert2 = (init_assert(), __toCommonJS(exports_assert)).ok;
12952
12952
  var zlib = (init_zlib(), __toCommonJS(exports_zlib));
@@ -13065,7 +13065,7 @@ var require_sync_inflate = __commonJS((exports, module) => {
13065
13065
  exports.inflateSync = inflateSync;
13066
13066
  });
13067
13067
 
13068
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/sync-reader.js
13068
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/sync-reader.js
13069
13069
  var require_sync_reader = __commonJS((exports, module) => {
13070
13070
  var SyncReader = module.exports = function(buffer) {
13071
13071
  this._buffer = buffer;
@@ -13099,7 +13099,7 @@ var require_sync_reader = __commonJS((exports, module) => {
13099
13099
  };
13100
13100
  });
13101
13101
 
13102
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-parse-sync.js
13102
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/filter-parse-sync.js
13103
13103
  var require_filter_parse_sync = __commonJS((exports) => {
13104
13104
  var SyncReader = require_sync_reader();
13105
13105
  var Filter = require_filter_parse();
@@ -13119,7 +13119,7 @@ var require_filter_parse_sync = __commonJS((exports) => {
13119
13119
  };
13120
13120
  });
13121
13121
 
13122
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/parser-sync.js
13122
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/parser-sync.js
13123
13123
  var require_parser_sync = __commonJS((exports, module) => {
13124
13124
  var hasSyncZlib = true;
13125
13125
  var zlib = (init_zlib(), __toCommonJS(exports_zlib));
@@ -13205,7 +13205,7 @@ var require_parser_sync = __commonJS((exports, module) => {
13205
13205
  };
13206
13206
  });
13207
13207
 
13208
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/packer-sync.js
13208
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/packer-sync.js
13209
13209
  var require_packer_sync = __commonJS((exports, module) => {
13210
13210
  var hasSyncZlib = true;
13211
13211
  var zlib = (init_zlib(), __toCommonJS(exports_zlib));
@@ -13238,7 +13238,7 @@ var require_packer_sync = __commonJS((exports, module) => {
13238
13238
  };
13239
13239
  });
13240
13240
 
13241
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/png-sync.js
13241
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/png-sync.js
13242
13242
  var require_png_sync = __commonJS((exports) => {
13243
13243
  var parse = require_parser_sync();
13244
13244
  var pack = require_packer_sync();
@@ -13250,7 +13250,7 @@ var require_png_sync = __commonJS((exports) => {
13250
13250
  };
13251
13251
  });
13252
13252
 
13253
- // ../../node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/png.js
13253
+ // node_modules/.bun/pngjs@7.0.0/node_modules/pngjs/lib/png.js
13254
13254
  var require_png = __commonJS((exports) => {
13255
13255
  var util = (init_util(), __toCommonJS(exports_util));
13256
13256
  var Stream = require_stream();
@@ -13377,7 +13377,7 @@ var require_png = __commonJS((exports) => {
13377
13377
  // tools/test/src/visual/compare.ts
13378
13378
  var {readFileSync, writeFileSync} = (() => ({}));
13379
13379
 
13380
- // ../../node_modules/.bun/pixelmatch@7.2.0/node_modules/pixelmatch/index.js
13380
+ // node_modules/.bun/pixelmatch@7.2.0/node_modules/pixelmatch/index.js
13381
13381
  function pixelmatch(img1, img2, output, width, height, options = {}) {
13382
13382
  const {
13383
13383
  threshold = 0.1,
@@ -14017,4 +14017,4 @@ export {
14017
14017
  assertSafeUpdateMode
14018
14018
  };
14019
14019
 
14020
- //# debugId=CD6C9BD84374D6F964756E2164756E21
14020
+ //# debugId=51DC7226BD2C4BE464756E2164756E21