From 044c3048f6cb549d4c6b583a7afddd367c3dbb5a Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 11:52:25 -0400 Subject: [PATCH 01/18] chore: add LICENSE file Signed-off-by: Xe Iaso --- LICENSE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1381b98 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2021 Pau Marfany +Copyright (c) 2026 Xe Iaso + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From b9ced836ba01fe4921ef1bdfb7ecd984d6125a28 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:08:23 -0400 Subject: [PATCH 02/18] build: modernize toolchain and move to TecharoHQ org Upgrade the build toolchain to current versions: ts-loader in place of awesome-typescript-loader, TypeScript 6, webpack 5, webpack-cli 7, and rimraf 6. Update tsconfig with rootDir and ignoreDeprecations. Rename the package to @techaro/worker-polyfill and point the repo/issue/homepage URLs at the TecharoHQ GitHub organization. Signed-off-by: Xe Iaso --- package.json | 18 +++++++++--------- tsconfig.json | 2 ++ webpack.config.js | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 67e844d..cec803b 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "worker-polyfill", + "name": "@techaro/worker-polyfill", "version": "1.0.0", "description": "Polyfill for the Web Worker API that works in Internet Explorer and other old browsers that don't support this API", "main": "lib/worker-polyfill.js", @@ -9,7 +9,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/pmarfany/worker-polyfill.git" + "url": "git+https://github.com/TecharoHQ/worker-polyfill.git" }, "keywords": [ "worker", @@ -19,14 +19,14 @@ "author": "Pau Marfany", "license": "MIT", "bugs": { - "url": "https://github.com/pmarfany/worker-polyfill/issues" + "url": "https://github.com/TecharoHQ/worker-polyfill/issues" }, - "homepage": "https://github.com/pmarfany/worker-polyfill#readme", + "homepage": "https://github.com/TecharoHQ/worker-polyfill#readme", "devDependencies": { - "awesome-typescript-loader": "^5.2.1", - "rimraf": "^2.6.3", - "typescript": "^3.4.1", - "webpack": "^4.29.6", - "webpack-cli": "^3.3.0" + "rimraf": "^6.0.1", + "ts-loader": "^9.5.4", + "typescript": "^6.0.3", + "webpack": "^5.108.1", + "webpack-cli": "^7.1.0" } } diff --git a/tsconfig.json b/tsconfig.json index 6e88eb3..33c42a1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,10 @@ { "compilerOptions": { "target": "es5", + "ignoreDeprecations": "6.0", "module": "commonjs", "lib": ["es2015", "dom", "scripthost"], + "rootDir": "src", "outDir": "lib", "strict": false, "declaration": false, diff --git a/webpack.config.js b/webpack.config.js index d0cb07f..76d4686 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -38,7 +38,7 @@ const config = { { test: /\.ts?$/, exclude: /node_modules/, - use: 'awesome-typescript-loader', + use: 'ts-loader', }, ] }, From 1e8579833ba8976ade5ded06f290d9055b31dac5 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:08:34 -0400 Subject: [PATCH 03/18] docs: add spec-conformance implementation plan Plan for bringing the Worker polyfill up to the WHATWG/MDN Dedicated Worker spec: structured-clone messages, real message/error events, multi-listener EventTarget, isolated worker scope (self), synchronous importScripts, FIFO message ordering, terminate/close, and a Vitest + jsdom conformance suite. Signed-off-by: Xe Iaso --- ...-06-28-worker-polyfill-spec-conformance.md | 1354 +++++++++++++++++ 1 file changed, 1354 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-28-worker-polyfill-spec-conformance.md diff --git a/docs/superpowers/plans/2026-06-28-worker-polyfill-spec-conformance.md b/docs/superpowers/plans/2026-06-28-worker-polyfill-spec-conformance.md new file mode 100644 index 0000000..40e8d4c --- /dev/null +++ b/docs/superpowers/plans/2026-06-28-worker-polyfill-spec-conformance.md @@ -0,0 +1,1354 @@ +# Worker Polyfill Spec-Conformance Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Fix the wiring bugs in the Worker polyfill and bring its core surface up to the WHATWG/MDN Dedicated Worker spec (real EventTarget semantics, real message/error events, structured-clone messages, ordered delivery, a proper worker-side `self`/`close`/`name`, and synchronous `importScripts`), backed by a Vitest + jsdom conformance suite. + +**Architecture:** The polyfill keeps its core approach — fetch the worker script with synchronous `XHR` and `eval` it in-process (single-threaded fake worker). We split responsibilities into small modules: a deep-clone shim, event-object factories, a reusable `EventTarget` mixin used by *both* the `Worker` object and the worker scope, and a dedicated worker-scope builder. The worker script is evaluated inside its **own** scope object (so `self`, `postMessage`, `onmessage`, etc. resolve to the worker globals, not the `Worker` instance) via a sloppy-mode `Function`-constructor evaluator that uses `with`. Messages flow through FIFO queues drained on `setTimeout`, so ordering and async semantics match the spec. + +**Tech Stack:** TypeScript (target ES5), webpack 5 (UMD bundle), Vitest + jsdom for tests. Zero runtime dependencies. + +## Global Constraints + +- **No runtime dependencies.** The shipped bundle must stay dependency-free (testing deps are `devDependencies` only). +- **IE / old-browser safe at runtime.** Source may use modern TS syntax (compiled to ES5), but must not call runtime APIs missing in IE11: no `Promise`, `Map`/`WeakMap`, `Array.from`, `structuredClone`, `MessageEvent`/`ErrorEvent` constructors, `Object.assign`, or arrow-function-only features at runtime. Use `for` loops, `indexOf`, `splice`, array-based bookkeeping. +- **TypeScript:** `typescript@^6` (matches `package.json`). `tsconfig.json` stays `target: es5`, `module: commonjs`, `lib: ["es2015","dom","scripthost"]`, `strict: false`. +- **Scope:** Dedicated Workers only. Out of scope: module workers (`type:"module"`), transferables, `blob:`/`data:` URLs, `credentials`. These must be accepted-but-ignored without throwing where the constructor signature allows them. +- **The script evaluator must not assume strict mode is off in the surrounding module.** Use `new Function(...)` (sloppy-mode body) for any `with`-based evaluation. +- **Author/license unchanged.** MIT, existing author field preserved. + +--- + +## File Structure + +| File | Responsibility | Action | +|---|---|---| +| `src/utils.ts` | `isFunction`, `getHTTPObject`, `getGlobal`, `fetchScriptSync` | Modify | +| `src/clone.ts` | `structuredCloneShim` — deep copy with cycle support | Create | +| `src/events.ts` | `createMessageEvent`, `createErrorEvent`, `createMessageErrorEvent` + `PolyfillEvent` type | Create | +| `src/event-target.ts` | `installEventTarget` mixin (multi-listener add/remove/dispatch + `on*` handlers) | Create | +| `src/worker-scope.ts` | `createWorkerScope` — the DedicatedWorkerGlobalScope-like object + sloppy-mode evaluator | Create | +| `src/worker-polyfill.ts` | `WorkerPolyfill` constructor (queues, terminate, error dispatch) + guarded global install | Rewrite | +| `test/helpers/mockXHR.ts` | Fake synchronous `XMLHttpRequest` serving canned scripts | Create | +| `test/*.test.ts` | Unit + integration conformance tests | Create | +| `vitest.config.ts` | Vitest config (jsdom env) | Create | +| `tsconfig.json` | Ensure `test/**` excluded from build | Modify | +| `webpack.config.js` | Rename UMD global to `WorkerPolyfill` so it doesn't clobber the side-effect install | Modify | +| `package.json` | Add `test`/`test:run` scripts + dev deps | Modify | +| `README.md` | Document new behaviour | Modify | + +--- + +## Task 1: Test harness (Vitest + jsdom + mock XHR) + +**Files:** +- Create: `vitest.config.ts` +- Create: `test/helpers/mockXHR.ts` +- Create: `test/harness.test.ts` +- Modify: `package.json` +- Modify: `tsconfig.json:13` (exclude `test`) + +**Interfaces:** +- Produces: + - `installMockXHR(): void` — replaces `globalThis.XMLHttpRequest` with the mock. + - `setScript(url: string, code: string): void` — register a script body for a URL. + - `failScript(url: string): void` — make a URL return HTTP 404. + - `resetScripts(): void` — clear registry. + +- [ ] **Step 1: Add dev dependencies** + +Run: +```bash +npm install --save-dev vitest@^3 jsdom@^25 +``` +Expected: `vitest` and `jsdom` appear under `devDependencies` in `package.json`. + +- [ ] **Step 2: Add test scripts to `package.json`** + +In `package.json`, add to the `"scripts"` object (keep existing `prebuild`/`build`): +```json +"test": "vitest", +"test:run": "vitest run" +``` + +- [ ] **Step 3: Create `vitest.config.ts`** + +```ts +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "jsdom", + include: ["test/**/*.test.ts"], + }, +}); +``` + +- [ ] **Step 4: Exclude `test` from the TS build** + +In `tsconfig.json`, change the `exclude` array (line 14) to: +```json +"exclude": ["node_modules", "lib", "test"] +``` + +- [ ] **Step 5: Create the mock XHR helper `test/helpers/mockXHR.ts`** + +```ts +// A minimal synchronous XMLHttpRequest stand-in. The polyfill fetches +// worker scripts with sync XHR; jsdom can't fetch arbitrary URLs, so tests +// register script bodies here and the mock serves them. +type ScriptMap = { [url: string]: string }; + +let scripts: ScriptMap = {}; +let failUrls: string[] = []; + +class MockXHR { + status = 0; + readyState = 0; + responseText = ""; + private url = ""; + + open(_method: string, url: string, _async?: boolean) { + this.url = url; + } + + send(_body?: any) { + this.readyState = 4; + if (failUrls.indexOf(this.url) !== -1) { + this.status = 404; + this.responseText = ""; + return; + } + if (Object.prototype.hasOwnProperty.call(scripts, this.url)) { + this.status = 200; + this.responseText = scripts[this.url]; + } else { + this.status = 404; + this.responseText = ""; + } + } +} + +export function setScript(url: string, code: string): void { + scripts[url] = code; +} + +export function failScript(url: string): void { + failUrls.push(url); +} + +export function resetScripts(): void { + scripts = {}; + failUrls = []; +} + +export function installMockXHR(): void { + (globalThis as any).XMLHttpRequest = MockXHR as any; +} +``` + +- [ ] **Step 6: Write a harness smoke test `test/harness.test.ts`** + +```ts +import { describe, it, expect, beforeEach } from "vitest"; +import { installMockXHR, setScript, resetScripts } from "./helpers/mockXHR"; + +describe("test harness", () => { + beforeEach(() => { + resetScripts(); + installMockXHR(); + }); + + it("serves a registered script over sync XHR", () => { + setScript("hello.js", "var x = 1;"); + const xhr: any = new (globalThis as any).XMLHttpRequest(); + xhr.open("GET", "hello.js", false); + xhr.send(null); + expect(xhr.readyState).toBe(4); + expect(xhr.status).toBe(200); + expect(xhr.responseText).toBe("var x = 1;"); + }); +}); +``` + +- [ ] **Step 7: Run the harness test** + +Run: `npx vitest run test/harness.test.ts` +Expected: PASS (1 test). + +- [ ] **Step 8: Commit** + +```bash +git add package.json package-lock.json vitest.config.ts tsconfig.json test/helpers/mockXHR.ts test/harness.test.ts +git commit -m "test: add vitest + jsdom harness with mock XHR" +``` + +--- + +## Task 2: `structuredCloneShim` (deep clone) + +**Files:** +- Create: `src/clone.ts` +- Create: `test/clone.test.ts` + +**Interfaces:** +- Produces: `structuredCloneShim(value: any): any` — returns a deep copy of plain data (primitives, arrays, plain objects, `Date`, `RegExp`), preserving internal cyclic references. Functions/DOM nodes are copied by reference inside the object graph (best-effort; the polyfill's contract is plain data). + +- [ ] **Step 1: Write the failing test `test/clone.test.ts`** + +```ts +import { describe, it, expect } from "vitest"; +import { structuredCloneShim } from "../src/clone"; + +describe("structuredCloneShim", () => { + it("returns primitives unchanged", () => { + expect(structuredCloneShim(5)).toBe(5); + expect(structuredCloneShim("a")).toBe("a"); + expect(structuredCloneShim(null)).toBe(null); + }); + + it("deep-copies objects so mutations do not leak", () => { + const src = { a: 1, nested: { b: 2 } }; + const copy = structuredCloneShim(src); + copy.nested.b = 99; + expect(src.nested.b).toBe(2); + expect(copy.nested.b).toBe(99); + }); + + it("deep-copies arrays", () => { + const src = [1, [2, 3]]; + const copy = structuredCloneShim(src); + copy[1][0] = 9; + expect(src[1][0]).toBe(2); + }); + + it("preserves cyclic references", () => { + const src: any = { name: "x" }; + src.me = src; + const copy = structuredCloneShim(src); + expect(copy.me).toBe(copy); + expect(copy).not.toBe(src); + }); + + it("clones Date and RegExp", () => { + const d = structuredCloneShim(new Date(1000)); + expect(d instanceof Date).toBe(true); + expect(d.getTime()).toBe(1000); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `npx vitest run test/clone.test.ts` +Expected: FAIL — cannot resolve `../src/clone`. + +- [ ] **Step 3: Implement `src/clone.ts`** + +```ts +// Minimal structured-clone approximation for the Worker polyfill. +// Handles primitives, arrays, plain objects, Date, RegExp, and cyclic +// references using paired arrays (no Map/WeakMap, for IE compatibility). +// Non-cloneable values (functions, DOM nodes) are kept by reference. +const structuredCloneShim = (value: any, seen?: any[], copies?: any[]): any => { + if (value === null || typeof value !== "object") { + return value; + } + + seen = seen || []; + copies = copies || []; + + for (let i = 0; i < seen.length; i++) { + if (seen[i] === value) { + return copies[i]; + } + } + + if (value instanceof Date) { + return new Date(value.getTime()); + } + if (value instanceof RegExp) { + return new RegExp(value.source, value.flags); + } + + const out: any = Array.isArray(value) ? [] : {}; + seen.push(value); + copies.push(out); + + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + out[key] = structuredCloneShim(value[key], seen, copies); + } + } + + return out; +}; + +export { structuredCloneShim }; +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx vitest run test/clone.test.ts` +Expected: PASS (5 tests). + +- [ ] **Step 5: Commit** + +```bash +git add src/clone.ts test/clone.test.ts +git commit -m "feat: add structured-clone shim for postMessage" +``` + +--- + +## Task 3: Event factories + +**Files:** +- Create: `src/events.ts` +- Create: `test/events.test.ts` + +**Interfaces:** +- Produces: + - `PolyfillEvent` — interface: `{ type: string; target: any; currentTarget: any; [k: string]: any }`. + - `createMessageEvent(data: any, target: any): PolyfillEvent` — `type:"message"`, `.data`, `.origin:""`, `.lastEventId:""`, `.source:null`, `.ports:[]`. + - `createErrorEvent(error: any, target: any): PolyfillEvent` — `type:"error"`, `.message`, `.filename:""`, `.lineno:0`, `.colno:0`, `.error`. + - `createMessageErrorEvent(target: any): PolyfillEvent` — `type:"messageerror"`, `.data:null`. + +- [ ] **Step 1: Write the failing test `test/events.test.ts`** + +```ts +import { describe, it, expect } from "vitest"; +import { + createMessageEvent, + createErrorEvent, + createMessageErrorEvent, +} from "../src/events"; + +describe("event factories", () => { + it("builds a message event with spec-shaped fields", () => { + const t = {}; + const e = createMessageEvent({ hi: 1 }, t); + expect(e.type).toBe("message"); + expect(e.data).toEqual({ hi: 1 }); + expect(e.target).toBe(t); + expect(e.ports).toEqual([]); + expect(e.origin).toBe(""); + }); + + it("builds an error event from an Error", () => { + const t = {}; + const err = new Error("boom"); + const e = createErrorEvent(err, t); + expect(e.type).toBe("error"); + expect(e.message).toBe("boom"); + expect(e.error).toBe(err); + expect(e.lineno).toBe(0); + }); + + it("builds an error event from a non-Error value", () => { + const e = createErrorEvent("plain", {}); + expect(e.message).toBe("plain"); + }); + + it("builds a messageerror event", () => { + const e = createMessageErrorEvent({}); + expect(e.type).toBe("messageerror"); + expect(e.data).toBe(null); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `npx vitest run test/events.test.ts` +Expected: FAIL — cannot resolve `../src/events`. + +- [ ] **Step 3: Implement `src/events.ts`** + +```ts +// Lightweight event objects. Old browsers may lack the MessageEvent / +// ErrorEvent constructors, so we build plain objects carrying the fields the +// Worker API exposes. +interface PolyfillEvent { + type: string; + target: any; + currentTarget: any; + [key: string]: any; +} + +const createMessageEvent = (data: any, target: any): PolyfillEvent => { + return { + type: "message", + data: data, + target: target, + currentTarget: target, + origin: "", + lastEventId: "", + source: null, + ports: [], + }; +}; + +const createErrorEvent = (error: any, target: any): PolyfillEvent => { + const message = error && error.message ? error.message : String(error); + return { + type: "error", + target: target, + currentTarget: target, + message: message, + filename: "", + lineno: 0, + colno: 0, + error: error, + }; +}; + +const createMessageErrorEvent = (target: any): PolyfillEvent => { + return { + type: "messageerror", + target: target, + currentTarget: target, + data: null, + }; +}; + +export { + PolyfillEvent, + createMessageEvent, + createErrorEvent, + createMessageErrorEvent, +}; +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx vitest run test/events.test.ts` +Expected: PASS (4 tests). + +- [ ] **Step 5: Commit** + +```bash +git add src/events.ts test/events.test.ts +git commit -m "feat: add message/error event factories" +``` + +--- + +## Task 4: `installEventTarget` mixin + +**Files:** +- Create: `src/event-target.ts` +- Create: `test/event-target.test.ts` + +**Interfaces:** +- Consumes: `isFunction` from `./utils`; `PolyfillEvent` from `./events`. +- Produces: + - `EventTargetLike` — interface: `{ addEventListener(type,cb): void; removeEventListener(type,cb): void; dispatchEvent(event): boolean }`. + - `installEventTarget(host: any): EventTargetLike` — attaches `addEventListener`/`removeEventListener`/`dispatchEvent` to `host`; `dispatchEvent` invokes both the `host["on"+type]` handler (if a function) and every registered listener, each called with `host` as `this`. + +- [ ] **Step 1: Write the failing test `test/event-target.test.ts`** + +```ts +import { describe, it, expect } from "vitest"; +import { installEventTarget } from "../src/event-target"; + +describe("installEventTarget", () => { + it("dispatches to multiple listeners", () => { + const host: any = {}; + installEventTarget(host); + const calls: string[] = []; + host.addEventListener("message", () => calls.push("a")); + host.addEventListener("message", () => calls.push("b")); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(calls).toEqual(["a", "b"]); + }); + + it("also invokes the on handler property", () => { + const host: any = {}; + installEventTarget(host); + let got = ""; + host.onmessage = () => (got = "handler"); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(got).toBe("handler"); + }); + + it("removeEventListener stops a listener", () => { + const host: any = {}; + installEventTarget(host); + const calls: string[] = []; + const fn = () => calls.push("x"); + host.addEventListener("message", fn); + host.removeEventListener("message", fn); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(calls).toEqual([]); + }); + + it("does not register the same listener twice", () => { + const host: any = {}; + installEventTarget(host); + let n = 0; + const fn = () => n++; + host.addEventListener("message", fn); + host.addEventListener("message", fn); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(n).toBe(1); + }); + + it("sets target/currentTarget on the event", () => { + const host: any = {}; + installEventTarget(host); + let seen: any = null; + host.addEventListener("message", (e: any) => (seen = e)); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(seen.currentTarget).toBe(host); + expect(seen.target).toBe(host); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `npx vitest run test/event-target.test.ts` +Expected: FAIL — cannot resolve `../src/event-target`. + +- [ ] **Step 3: Implement `src/event-target.ts`** + +```ts +import { isFunction } from "./utils"; +import { PolyfillEvent } from "./events"; + +// A minimal EventTarget that also supports legacy `on` handler +// properties. Both the Worker (parent) object and the worker global scope +// use this, giving them spec-style multi-listener behaviour. +interface EventTargetLike { + addEventListener: (type: string, callback: any) => void; + removeEventListener: (type: string, callback: any) => void; + dispatchEvent: (event: PolyfillEvent) => boolean; +} + +const installEventTarget = (host: any): EventTargetLike => { + const listeners: { [type: string]: any[] } = {}; + + host.addEventListener = function (type: string, callback: any) { + if (!isFunction(callback)) { + return; + } + if (!listeners[type]) { + listeners[type] = []; + } + if (listeners[type].indexOf(callback) === -1) { + listeners[type].push(callback); + } + }; + + host.removeEventListener = function (type: string, callback: any) { + const list = listeners[type]; + if (!list) { + return; + } + const idx = list.indexOf(callback); + if (idx !== -1) { + list.splice(idx, 1); + } + }; + + host.dispatchEvent = function (event: PolyfillEvent) { + event.target = event.target || host; + event.currentTarget = host; + + const handler = host["on" + event.type]; + if (isFunction(handler)) { + handler.call(host, event); + } + + const list = listeners[event.type]; + if (list) { + // Snapshot so a listener removing another mid-dispatch is safe. + const snapshot = list.slice(); + for (let i = 0; i < snapshot.length; i++) { + snapshot[i].call(host, event); + } + } + return true; + }; + + return host as EventTargetLike; +}; + +export { EventTargetLike, installEventTarget }; +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx vitest run test/event-target.test.ts` +Expected: PASS (5 tests). + +- [ ] **Step 5: Commit** + +```bash +git add src/event-target.ts test/event-target.test.ts +git commit -m "feat: add EventTarget mixin with multi-listener + on* support" +``` + +--- + +## Task 5: `utils.ts` — global accessor + synchronous fetch + +**Files:** +- Modify: `src/utils.ts` +- Create: `test/utils.test.ts` + +**Interfaces:** +- Consumes: nothing new. +- Produces (additions; keep existing `isFunction`, `getHTTPObject`): + - `getGlobal(): any` — returns the global object (`globalThis` / `self` / `window`), IE-safe. + - `fetchScriptSync(url: string): string` — synchronous GET; returns `responseText` on success, throws `Error` on load failure (no object, non-`200`-ish status, or 404/500). + +- [ ] **Step 1: Write the failing test `test/utils.test.ts`** + +```ts +import { describe, it, expect, beforeEach } from "vitest"; +import { fetchScriptSync, getGlobal } from "../src/utils"; +import { installMockXHR, setScript, failScript, resetScripts } from "./helpers/mockXHR"; + +describe("utils", () => { + beforeEach(() => { + resetScripts(); + installMockXHR(); + }); + + it("getGlobal returns an object with setTimeout", () => { + const g = getGlobal(); + expect(typeof g.setTimeout).toBe("function"); + }); + + it("fetchScriptSync returns the script body", () => { + setScript("a.js", "var a = 1;"); + expect(fetchScriptSync("a.js")).toBe("var a = 1;"); + }); + + it("fetchScriptSync throws on a failed load", () => { + failScript("missing.js"); + expect(() => fetchScriptSync("missing.js")).toThrow(); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `npx vitest run test/utils.test.ts` +Expected: FAIL — `fetchScriptSync`/`getGlobal` are not exported. + +- [ ] **Step 3: Rewrite `src/utils.ts`** + +```ts +const isFunction = (f: any) => { + return typeof f === "function"; +}; + +/* HTTP Request */ +const getHTTPObject = (): any => { + let xmlhttp: any; + try { + xmlhttp = new XMLHttpRequest(); + } catch (e) { + try { + // @ts-ignore - ActiveXObject only exists in old IE + xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + } catch (e2) { + xmlhttp = false; + } + } + return xmlhttp; +}; + +// Resolve the global object across environments (browser, worker, Node, IE). +const getGlobal = (): any => { + if (typeof globalThis !== "undefined") { + return globalThis; + } + if (typeof self !== "undefined") { + return self; + } + // @ts-ignore - window exists in browsers + if (typeof window !== "undefined") { + // @ts-ignore + return window; + } + return {}; +}; + +// Fetch a script synchronously and return its source text. Throws on failure +// so callers can surface an `error` event. +const fetchScriptSync = (url: string): string => { + const http = getHTTPObject(); + if (!http) { + throw new Error("No XMLHttpRequest available to load: " + url); + } + http.open("GET", url, false); + http.send(null); + + const ok = + http.readyState === 4 && + http.status !== 404 && + http.status !== 500; + + if (!ok) { + throw new Error( + "Failed to load worker script: " + url + " (status " + http.status + ")", + ); + } + return http.responseText; +}; + +export { isFunction, getHTTPObject, getGlobal, fetchScriptSync }; +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx vitest run test/utils.test.ts` +Expected: PASS (3 tests). + +- [ ] **Step 5: Commit** + +```bash +git add src/utils.ts test/utils.test.ts +git commit -m "feat: add getGlobal and fetchScriptSync helpers" +``` + +--- + +## Task 6: `createWorkerScope` (worker-side global) + +**Files:** +- Create: `src/worker-scope.ts` +- Create: `test/worker-scope.test.ts` + +**Interfaces:** +- Consumes: `fetchScriptSync` from `./utils`; `installEventTarget` from `./event-target`; `createMessageEvent` from `./events`; `structuredCloneShim` from `./clone`. +- Produces: + - `WorkerScope` — interface with `self`, `name`, `onmessage`, `onmessageerror`, `onerror`, `postMessage(data)`, `importScripts(...urls)`, `close()`, `addEventListener`, `removeEventListener`, `dispatchEvent`, `__deliver(data)`, `__evalScript(code)`. + - `createWorkerScope(name: string, toParent: (data:any)=>void, onClose: ()=>void): WorkerScope` — builds the scope. `postMessage` clones then calls `toParent`. `__deliver` dispatches a `message` event into the scope. `__evalScript` runs code with the scope as the variable environment (bare `self`/`postMessage`/`onmessage` resolve to scope members). + +- [ ] **Step 1: Write the failing test `test/worker-scope.test.ts`** + +```ts +import { describe, it, expect } from "vitest"; +import { createWorkerScope } from "../src/worker-scope"; + +describe("createWorkerScope", () => { + it("self refers to the scope itself", () => { + const scope = createWorkerScope("", () => {}, () => {}); + expect(scope.self).toBe(scope); + }); + + it("evaluated code can set self.onmessage and receive __deliver", () => { + const out: any[] = []; + const scope = createWorkerScope("", (d) => out.push(d), () => {}); + scope.__evalScript("self.onmessage = function(e){ self.postMessage(e.data); };"); + scope.__deliver("ping"); + expect(out).toEqual(["ping"]); + }); + + it("bare onmessage/postMessage identifiers resolve to the scope", () => { + const out: any[] = []; + const scope = createWorkerScope("", (d) => out.push(d), () => {}); + scope.__evalScript("onmessage = function(e){ postMessage(e.data + '!'); };"); + scope.__deliver("hey"); + expect(out).toEqual(["hey!"]); + }); + + it("postMessage clones the payload", () => { + const out: any[] = []; + const scope = createWorkerScope("", (d) => out.push(d), () => {}); + const obj = { n: 1 }; + scope.postMessage(obj); + obj.n = 2; + expect(out[0].n).toBe(1); + }); + + it("close() invokes the onClose callback", () => { + let closed = false; + const scope = createWorkerScope("", () => {}, () => (closed = true)); + scope.__evalScript("close();"); + expect(closed).toBe(true); + }); + + it("exposes the worker name", () => { + const scope = createWorkerScope("worker-1", () => {}, () => {}); + expect(scope.name).toBe("worker-1"); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `npx vitest run test/worker-scope.test.ts` +Expected: FAIL — cannot resolve `../src/worker-scope`. + +- [ ] **Step 3: Implement `src/worker-scope.ts`** + +```ts +import { fetchScriptSync } from "./utils"; +import { installEventTarget } from "./event-target"; +import { createMessageEvent } from "./events"; +import { structuredCloneShim } from "./clone"; + +interface WorkerScope { + self: WorkerScope; + name: string; + onmessage: any; + onmessageerror: any; + onerror: any; + postMessage: (data: any) => void; + importScripts: (...urls: string[]) => void; + close: () => void; + addEventListener: (type: string, cb: any) => void; + removeEventListener: (type: string, cb: any) => void; + dispatchEvent: (event: any) => boolean; + __deliver: (data: any) => void; + __evalScript: (code: string) => void; +} + +// Evaluate worker code with `scope` as its variable environment. `with` is +// illegal in strict mode, but a Function-constructor body is sloppy mode +// regardless of how the surrounding module is compiled, so bare identifiers +// (self, postMessage, onmessage, importScripts, close, ...) resolve to the +// scope object. Direct `eval` runs in this augmented environment. +// NOTE: the parameter names below leak into worker code as identifiers; they +// are deliberately obscure to avoid collisions. +const runWithScope: (scope: any, __worker_src__: string) => void = new Function( + "__worker_scope__", + "__worker_src__", + "with (__worker_scope__) { eval(__worker_src__); }", +) as any; + +// Builds the worker-side global scope (a DedicatedWorkerGlobalScope-like +// object). `toParent` is called when the worker posts a message out; `onClose` +// is called when the worker calls close(). +const createWorkerScope = ( + name: string, + toParent: (data: any) => void, + onClose: () => void, +): WorkerScope => { + const scope = {} as WorkerScope; + installEventTarget(scope); + + scope.self = scope; + scope.name = name || ""; + scope.onmessage = null; + scope.onmessageerror = null; + scope.onerror = null; + + scope.postMessage = function (data: any) { + toParent(structuredCloneShim(data)); + }; + + scope.importScripts = function () { + const urls = Array.prototype.slice.call(arguments); + for (let i = 0; i < urls.length; i++) { + scope.__evalScript(fetchScriptSync(urls[i])); + } + }; + + scope.close = function () { + onClose(); + }; + + // Deliver a parent->worker message as a `message` event inside the scope. + scope.__deliver = function (data: any) { + scope.dispatchEvent(createMessageEvent(data, scope)); + }; + + scope.__evalScript = function (code: string) { + runWithScope(scope, code); + }; + + return scope; +}; + +export { WorkerScope, createWorkerScope }; +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx vitest run test/worker-scope.test.ts` +Expected: PASS (6 tests). + +- [ ] **Step 5: Commit** + +```bash +git add src/worker-scope.ts test/worker-scope.test.ts +git commit -m "feat: add worker scope with isolated self and sync importScripts" +``` + +--- + +## Task 7: `WorkerPolyfill` constructor (rewrite) + +**Files:** +- Rewrite: `src/worker-polyfill.ts` +- Create: `test/worker-polyfill.test.ts` + +**Interfaces:** +- Consumes: `fetchScriptSync`, `getGlobal` from `./utils`; `installEventTarget` from `./event-target`; `createMessageEvent`, `createErrorEvent` from `./events`; `structuredCloneShim` from `./clone`; `createWorkerScope`, `WorkerScope` from `./worker-scope`. +- Produces: + - `WorkerPolyfill` — constructor `new WorkerPolyfill(scriptFile: string, options?: { type?; name?; credentials? })`. Instance is an `EventTarget` with `postMessage(data)`, `terminate()`, and `on(message|error|messageerror)`. Parent→worker delivery is FIFO and async (`setTimeout`); worker→parent delivery is async. `terminate()` and worker-side `close()` stop all further delivery. Load/eval failures dispatch an async `error` event. + - Side effect on import: installs `WorkerPolyfill` as the global `Worker` **only if no native `Worker` exists**. + +- [ ] **Step 1: Write the failing test `test/worker-polyfill.test.ts`** + +```ts +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { installMockXHR, setScript, failScript, resetScripts } from "./helpers/mockXHR"; +import { WorkerPolyfill } from "../src/worker-polyfill"; + +const makeWorker = (file: string, opts?: any) => + new (WorkerPolyfill as any)(file, opts); + +describe("WorkerPolyfill", () => { + beforeEach(() => { + resetScripts(); + installMockXHR(); + vi.useFakeTimers(); + }); + + it("echoes a message using the self.* idiom", () => { + setScript("echo.js", "self.onmessage = function(e){ self.postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage("hi"); + vi.runAllTimers(); + expect(got).toEqual(["hi"]); + }); + + it("delivers a message event object, not a bare value", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + let evt: any = null; + w.addEventListener("message", (e: any) => (evt = e)); + w.postMessage("x"); + vi.runAllTimers(); + expect(evt.type).toBe("message"); + expect(evt.data).toBe("x"); + expect(evt.target).toBe(w); + }); + + it("preserves message order for rapid posts", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage(1); + w.postMessage(2); + w.postMessage(3); + vi.runAllTimers(); + expect(got).toEqual([1, 2, 3]); + }); + + it("structured-clones outgoing messages", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + let received: any = null; + w.onmessage = (e: any) => (received = e.data); + const payload = { n: 1 }; + w.postMessage(payload); + payload.n = 2; + vi.runAllTimers(); + expect(received.n).toBe(1); + }); + + it("supports multiple message listeners", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const calls: string[] = []; + w.addEventListener("message", () => calls.push("a")); + w.addEventListener("message", () => calls.push("b")); + w.postMessage("x"); + vi.runAllTimers(); + expect(calls).toEqual(["a", "b"]); + }); + + it("fires the error event when a handler throws", () => { + setScript("bad.js", "onmessage = function(){ throw new Error('boom'); };"); + const w = makeWorker("bad.js"); + let err: any = null; + w.onerror = (e: any) => (err = e); + w.postMessage("go"); + vi.runAllTimers(); + expect(err).not.toBe(null); + expect(err.type).toBe("error"); + expect(err.message).toBe("boom"); + }); + + it("fires the error event when the script fails to load", () => { + failScript("missing.js"); + const w = makeWorker("missing.js"); + let err: any = null; + w.onerror = (e: any) => (err = e); + vi.runAllTimers(); + expect(err).not.toBe(null); + expect(err.type).toBe("error"); + }); + + it("fires the error event when top-level worker code throws", () => { + setScript("throws.js", "throw new Error('top-level');"); + const w = makeWorker("throws.js"); + let err: any = null; + w.onerror = (e: any) => (err = e); + vi.runAllTimers(); + expect(err.message).toBe("top-level"); + }); + + it("terminate() stops further delivery", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage("a"); + w.terminate(); + w.postMessage("b"); + vi.runAllTimers(); + expect(got).toEqual([]); + }); + + it("worker close() stops further delivery", () => { + setScript("closer.js", "onmessage = function(){ close(); postMessage('after'); };"); + const w = makeWorker("closer.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage("go"); + vi.runAllTimers(); + expect(got).toEqual([]); + }); + + it("supports importScripts synchronously", () => { + setScript("dep.js", "var DEP_VALUE = 42;"); + setScript("main.js", "importScripts('dep.js'); onmessage = function(){ postMessage(DEP_VALUE); };"); + const w = makeWorker("main.js"); + let got: any = null; + w.onmessage = (e: any) => (got = e.data); + w.postMessage("go"); + vi.runAllTimers(); + expect(got).toBe(42); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `npx vitest run test/worker-polyfill.test.ts` +Expected: FAIL — `WorkerPolyfill` not exported / behaviour mismatch. + +- [ ] **Step 3: Rewrite `src/worker-polyfill.ts`** + +```ts +/* + A single-threaded Worker polyfill for IE and other old browsers. + Dedicated Workers only. The worker script is fetched with synchronous XHR + and eval'd in-process, inside its own scope object so that `self`, + `postMessage`, `onmessage`, etc. behave like a real worker global. + Remember: messages are structured-cloned, but this is NOT a real thread and + provides none of the native security isolation. +*/ +import { fetchScriptSync, getGlobal } from "./utils"; +import { installEventTarget } from "./event-target"; +import { createMessageEvent, createErrorEvent } from "./events"; +import { structuredCloneShim } from "./clone"; +import { createWorkerScope, WorkerScope } from "./worker-scope"; + +interface PolyfillWorkerOptions { + type?: string; + name?: string; + credentials?: string; +} + +const WorkerPolyfill = function ( + this: any, + scriptFile: string, + options?: PolyfillWorkerOptions, +) { + const self = this; + const opts = options || {}; + const glob = getGlobal(); + + installEventTarget(self); + self.onmessage = null; + self.onerror = null; + self.onmessageerror = null; + + let terminated = false; + const inbox: any[] = []; + let scope: WorkerScope | null = null; + + // worker -> parent + const toParent = function (data: any) { + if (terminated) { + return; + } + glob.setTimeout(function () { + if (terminated) { + return; + } + self.dispatchEvent(createMessageEvent(data, self)); + }, 0); + }; + + const stop = function () { + terminated = true; + inbox.length = 0; + }; + + // Drain queued parent->worker messages one at a time, asynchronously, so + // ordering is preserved and delivery never blocks the caller. + const drain = function () { + if (terminated || !scope || inbox.length === 0) { + return; + } + const data = inbox.shift(); + try { + scope.__deliver(data); + } catch (e) { + self.dispatchEvent(createErrorEvent(e, self)); + } + if (!terminated && inbox.length > 0) { + glob.setTimeout(drain, 0); + } + }; + + // parent -> worker + self.postMessage = function (data: any) { + if (terminated) { + return; + } + inbox.push(structuredCloneShim(data)); + glob.setTimeout(drain, 0); + }; + + self.terminate = function () { + stop(); + }; + + // Load and start the worker. Failures (load or top-level eval) dispatch an + // async error event so handlers attached right after construction still fire. + try { + const code = fetchScriptSync(scriptFile); + scope = createWorkerScope(opts.name || "", toParent, stop); + scope.__evalScript(code); + } catch (e) { + glob.setTimeout(function () { + self.dispatchEvent(createErrorEvent(e, self)); + }, 0); + } +}; + +// Install as the global Worker only when there is no native implementation. +const glob = getGlobal(); +if (typeof glob.Worker === "undefined") { + glob.Worker = WorkerPolyfill; +} + +export { WorkerPolyfill }; +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `npx vitest run test/worker-polyfill.test.ts` +Expected: PASS (11 tests). + +- [ ] **Step 5: Run the full suite** + +Run: `npm run test:run` +Expected: PASS — all test files green. + +- [ ] **Step 6: Commit** + +```bash +git add src/worker-polyfill.ts test/worker-polyfill.test.ts +git commit -m "feat: rewrite Worker constructor with queues, error events, terminate" +``` + +--- + +## Task 8: Build config + bundle verification + +**Files:** +- Modify: `webpack.config.js:26` (UMD library name) +- Verify: `lib/` build output + +**Interfaces:** +- Consumes: all `src` modules. +- Produces: `lib/worker-polyfill.js` (+ `.min.js`) UMD bundle that installs the global `Worker` as a side effect and exposes `WorkerPolyfill` as the named UMD export. + +**Rationale:** The current UMD `library: 'Worker'` makes webpack assign `window.Worker = factory()`. Since the module now has a real export, that would set `window.Worker` to the exports object and clobber the guarded side-effect install. Renaming the UMD global to `WorkerPolyfill` lets the in-module guarded install own `window.Worker`. + +- [ ] **Step 1: Update the UMD library name in `webpack.config.js`** + +Change line 26 from: +```js + library: 'Worker', +``` +to: +```js + library: 'WorkerPolyfill', +``` + +- [ ] **Step 2: Build the bundle** + +Run: `npm run build` +Expected: webpack completes with no TypeScript errors; `lib/worker-polyfill.js` and `lib/worker-polyfill.min.js` are regenerated. + +- [ ] **Step 3: Smoke-check the built bundle installs a global Worker** + +Run: +```bash +node -e "var XHR=function(){};XHR.prototype.open=function(){};XHR.prototype.send=function(){this.readyState=4;this.status=200;this.responseText='';};global.XMLHttpRequest=XHR;global.window=global;require('./lib/worker-polyfill.js');console.log(typeof global.Worker);" +``` +Expected output: `function` + +- [ ] **Step 4: Commit** + +```bash +git add webpack.config.js lib +git commit -m "build: expose WorkerPolyfill UMD export without clobbering global Worker" +``` + +--- + +## Task 9: README update + +**Files:** +- Modify: `README.md` + +**Interfaces:** none (docs only). + +- [ ] **Step 1: Update `README.md` to reflect the new behaviour** + +Replace the body of `README.md` with: + +````markdown +# worker-polyfill + +A small polyfill that emulates the Dedicated [Web Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Worker) +in browsers that don't support it (Internet Explorer and other old browsers). +The code is still single-threaded, but it lets you keep one consistent code +path. Messages are structured-cloned and delivered asynchronously, matching +the spec's observable behaviour. + +## Install + +The polyfill installs itself as the global `Worker` **only if the browser has +no native implementation**, so it is safe to include unconditionally: + +```html + +``` + +## Usage + +Workers are created and used as usual: + +```js +var worker = new Worker("your_script.js"); + +worker.onmessage = function (event) { + alert("Got: " + event.data); +}; + +worker.onerror = function (event) { + alert("Worker error: " + event.message); +}; + +worker.postMessage("Hello World"); +``` + +`addEventListener` is supported with full multi-listener semantics: + +```js +worker.addEventListener("message", function (event) { + alert("Got: " + event.data); +}); +worker.addEventListener("error", function (event) { + alert("Worker error: " + event.message); +}); +``` + +Inside the worker script, the usual idioms work because the script runs in its +own scope: + +```js +// your_script.js +self.onmessage = function (event) { + self.postMessage("echo: " + event.data); +}; +// importScripts() is supported and runs synchronously +// close() stops the worker +``` + +## Supported + +`postMessage` (structured-cloned, ordered), `terminate`, `close`, +`addEventListener`/`removeEventListener`/`dispatchEvent`, `message`/`error` +events, `importScripts` (synchronous), `self`/`name`. + +## Not supported + +Module workers (`type: "module"`), transferable objects, `blob:`/`data:` URLs, +`credentials`, and real OS-thread parallelism. Pass plain, cloneable data. + +## Development + +```bash +npm install +npm test # vitest + jsdom conformance suite +npm run build # webpack UMD bundle into lib/ +``` + +- For more on workers see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API +- Originally exported from Google Code (https://code.google.com/p/ie-web-worker/). +```` + +- [ ] **Step 2: Commit** + +```bash +git add README.md +git commit -m "docs: document spec-conformant behaviour and limitations" +``` + +--- + +## Testing Process (summary) + +The suite is **test-first per task** (TDD) and layered: + +1. **Unit tests** for each pure module — `clone`, `events`, `event-target`, `utils` — verify behaviour in isolation against the spec's field shapes and semantics. +2. **Worker-scope tests** verify the hardest fix (the `self` collision) directly: that `self.*` and bare identifiers both resolve to the worker scope, that `postMessage` clones, and that `close()` works. +3. **Integration tests** (`worker-polyfill.test.ts`) drive the public `Worker` API end-to-end through the mock XHR, with **fake timers** (`vi.useFakeTimers()` + `vi.runAllTimers()`) to deterministically flush the async `setTimeout` delivery queues. These cover every bug from the audit: + - error event fires on handler throw / load failure / top-level throw (audit #1, #2) + - message ordering for rapid posts (audit #3) + - multiple `addEventListener` listeners (audit #4) + - `self.*` idiom works (audit #5) + - synchronous `importScripts` (audit #6) + - structured clone, real event objects, `terminate`, worker `close`. +4. **Build verification** (`npm run build`) confirms the TS compiles to ES5 and the UMD bundle installs the global without clobbering a native `Worker`. + +Run everything with `npm run test:run`; run the production build with `npm run build`. + +--- + +## Self-Review + +**Spec coverage** (audit findings → task): +- #1 error event never fires → Task 7 (handler-throw + drain catch dispatch `error`). ✅ +- #2 silent construction failure → Task 5 (`fetchScriptSync` throws) + Task 7 (catch → async `error`). ✅ +- #3 message loss/duplication → Task 7 (FIFO `inbox` queue). ✅ +- #4 single addEventListener listener → Task 4 (`installEventTarget` multi-listener). ✅ +- #5 `self` collision → Task 6 (isolated scope + sloppy-mode `with` evaluator). ✅ +- #6 async importScripts + page pollution → Task 6 (sync XHR eval into scope). ✅ +- Missing surface (real MessageEvent/ErrorEvent → Task 3; structured clone → Task 2; terminate halts → Task 7; messageerror factory → Task 3; close/name/self → Task 6; remove/dispatchEvent → Task 4; feature-detection guard → Task 7). ✅ +- Out-of-scope (module workers, transferables, blob:/data:, credentials) documented as accepted-but-ignored / unsupported in README (Task 9) and Global Constraints. ✅ + +**Placeholder scan:** No `TBD`/`TODO`/"add error handling"/"similar to" — every code and test step contains complete content. ✅ + +**Type consistency:** `WorkerScope` members (`__deliver`, `__evalScript`, `postMessage`, `close`, `name`) are defined in Task 6 and consumed identically in Task 7. `installEventTarget`/`PolyfillEvent`/event factory signatures are consistent across Tasks 3, 4, 6, 7. `fetchScriptSync`/`getGlobal` defined in Task 5 and used in Tasks 6, 7. ✅ From a9f251c1d93f319af09bae4d365431eec17d9dea Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:16:50 -0400 Subject: [PATCH 04/18] test: add vitest + jsdom harness with mock XHR --- package.json | 6 ++++- test/harness.test.ts | 19 +++++++++++++++ test/helpers/mockXHR.ts | 51 +++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 2 +- vitest.config.ts | 8 +++++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 test/harness.test.ts create mode 100644 test/helpers/mockXHR.ts create mode 100644 vitest.config.ts diff --git a/package.json b/package.json index cec803b..f2f278e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "main": "lib/worker-polyfill.js", "scripts": { "prebuild": "rimraf lib", - "build": "webpack --mode=production" + "build": "webpack --mode=production", + "test": "vitest", + "test:run": "vitest run" }, "repository": { "type": "git", @@ -23,9 +25,11 @@ }, "homepage": "https://github.com/TecharoHQ/worker-polyfill#readme", "devDependencies": { + "jsdom": "^25.0.1", "rimraf": "^6.0.1", "ts-loader": "^9.5.4", "typescript": "^6.0.3", + "vitest": "^3.2.6", "webpack": "^5.108.1", "webpack-cli": "^7.1.0" } diff --git a/test/harness.test.ts b/test/harness.test.ts new file mode 100644 index 0000000..91fabdb --- /dev/null +++ b/test/harness.test.ts @@ -0,0 +1,19 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { installMockXHR, setScript, resetScripts } from "./helpers/mockXHR"; + +describe("test harness", () => { + beforeEach(() => { + resetScripts(); + installMockXHR(); + }); + + it("serves a registered script over sync XHR", () => { + setScript("hello.js", "var x = 1;"); + const xhr: any = new (globalThis as any).XMLHttpRequest(); + xhr.open("GET", "hello.js", false); + xhr.send(null); + expect(xhr.readyState).toBe(4); + expect(xhr.status).toBe(200); + expect(xhr.responseText).toBe("var x = 1;"); + }); +}); diff --git a/test/helpers/mockXHR.ts b/test/helpers/mockXHR.ts new file mode 100644 index 0000000..6f2f041 --- /dev/null +++ b/test/helpers/mockXHR.ts @@ -0,0 +1,51 @@ +// A minimal synchronous XMLHttpRequest stand-in. The polyfill fetches +// worker scripts with sync XHR; jsdom can't fetch arbitrary URLs, so tests +// register script bodies here and the mock serves them. +type ScriptMap = { [url: string]: string }; + +let scripts: ScriptMap = {}; +let failUrls: string[] = []; + +class MockXHR { + status = 0; + readyState = 0; + responseText = ""; + private url = ""; + + open(_method: string, url: string, _async?: boolean) { + this.url = url; + } + + send(_body?: any) { + this.readyState = 4; + if (failUrls.indexOf(this.url) !== -1) { + this.status = 404; + this.responseText = ""; + return; + } + if (Object.prototype.hasOwnProperty.call(scripts, this.url)) { + this.status = 200; + this.responseText = scripts[this.url]; + } else { + this.status = 404; + this.responseText = ""; + } + } +} + +export function setScript(url: string, code: string): void { + scripts[url] = code; +} + +export function failScript(url: string): void { + failUrls.push(url); +} + +export function resetScripts(): void { + scripts = {}; + failUrls = []; +} + +export function installMockXHR(): void { + (globalThis as any).XMLHttpRequest = MockXHR as any; +} diff --git a/tsconfig.json b/tsconfig.json index 33c42a1..a498011 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,5 @@ "sourceMap": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "lib"] + "exclude": ["node_modules", "lib", "test"] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..5517232 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "jsdom", + include: ["test/**/*.test.ts"], + }, +}); From 9f8961b5690b78887114f6db52e3e4231e0d337f Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:19:54 -0400 Subject: [PATCH 05/18] feat: add structured-clone shim for postMessage --- src/clone.ts | 39 +++++++++++++++++++++++++++++++++++++++ test/clone.test.ts | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 src/clone.ts create mode 100644 test/clone.test.ts diff --git a/src/clone.ts b/src/clone.ts new file mode 100644 index 0000000..1c7d4cb --- /dev/null +++ b/src/clone.ts @@ -0,0 +1,39 @@ +// Minimal structured-clone approximation for the Worker polyfill. +// Handles primitives, arrays, plain objects, Date, RegExp, and cyclic +// references using paired arrays (no Map/WeakMap, for IE compatibility). +// Non-cloneable values (functions, DOM nodes) are kept by reference. +const structuredCloneShim = (value: any, seen?: any[], copies?: any[]): any => { + if (value === null || typeof value !== "object") { + return value; + } + + seen = seen || []; + copies = copies || []; + + for (let i = 0; i < seen.length; i++) { + if (seen[i] === value) { + return copies[i]; + } + } + + if (value instanceof Date) { + return new Date(value.getTime()); + } + if (value instanceof RegExp) { + return new RegExp(value.source, value.flags); + } + + const out: any = Array.isArray(value) ? [] : {}; + seen.push(value); + copies.push(out); + + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) { + out[key] = structuredCloneShim(value[key], seen, copies); + } + } + + return out; +}; + +export { structuredCloneShim }; diff --git a/test/clone.test.ts b/test/clone.test.ts new file mode 100644 index 0000000..9c810b4 --- /dev/null +++ b/test/clone.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect } from "vitest"; +import { structuredCloneShim } from "../src/clone"; + +describe("structuredCloneShim", () => { + it("returns primitives unchanged", () => { + expect(structuredCloneShim(5)).toBe(5); + expect(structuredCloneShim("a")).toBe("a"); + expect(structuredCloneShim(null)).toBe(null); + }); + + it("deep-copies objects so mutations do not leak", () => { + const src = { a: 1, nested: { b: 2 } }; + const copy = structuredCloneShim(src); + copy.nested.b = 99; + expect(src.nested.b).toBe(2); + expect(copy.nested.b).toBe(99); + }); + + it("deep-copies arrays", () => { + const src = [1, [2, 3]]; + const copy = structuredCloneShim(src); + copy[1][0] = 9; + expect(src[1][0]).toBe(2); + }); + + it("preserves cyclic references", () => { + const src: any = { name: "x" }; + src.me = src; + const copy = structuredCloneShim(src); + expect(copy.me).toBe(copy); + expect(copy).not.toBe(src); + }); + + it("clones Date and RegExp", () => { + const d = structuredCloneShim(new Date(1000)); + expect(d instanceof Date).toBe(true); + expect(d.getTime()).toBe(1000); + }); +}); From 6c7112ca4fc43bfb4eeeb9f760ff7943034bf14c Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:22:59 -0400 Subject: [PATCH 06/18] feat: add message/error event factories --- src/events.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++ test/events.test.ts | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/events.ts create mode 100644 test/events.test.ts diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 0000000..66ea1ec --- /dev/null +++ b/src/events.ts @@ -0,0 +1,52 @@ +// Lightweight event objects. Old browsers may lack the MessageEvent / +// ErrorEvent constructors, so we build plain objects carrying the fields the +// Worker API exposes. +interface PolyfillEvent { + type: string; + target: any; + currentTarget: any; + [key: string]: any; +} + +const createMessageEvent = (data: any, target: any): PolyfillEvent => { + return { + type: "message", + data: data, + target: target, + currentTarget: target, + origin: "", + lastEventId: "", + source: null, + ports: [], + }; +}; + +const createErrorEvent = (error: any, target: any): PolyfillEvent => { + const message = error && error.message ? error.message : String(error); + return { + type: "error", + target: target, + currentTarget: target, + message: message, + filename: "", + lineno: 0, + colno: 0, + error: error, + }; +}; + +const createMessageErrorEvent = (target: any): PolyfillEvent => { + return { + type: "messageerror", + target: target, + currentTarget: target, + data: null, + }; +}; + +export { + PolyfillEvent, + createMessageEvent, + createErrorEvent, + createMessageErrorEvent, +}; diff --git a/test/events.test.ts b/test/events.test.ts new file mode 100644 index 0000000..ad5e976 --- /dev/null +++ b/test/events.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect } from "vitest"; +import { + createMessageEvent, + createErrorEvent, + createMessageErrorEvent, +} from "../src/events"; + +describe("event factories", () => { + it("builds a message event with spec-shaped fields", () => { + const t = {}; + const e = createMessageEvent({ hi: 1 }, t); + expect(e.type).toBe("message"); + expect(e.data).toEqual({ hi: 1 }); + expect(e.target).toBe(t); + expect(e.ports).toEqual([]); + expect(e.origin).toBe(""); + }); + + it("builds an error event from an Error", () => { + const t = {}; + const err = new Error("boom"); + const e = createErrorEvent(err, t); + expect(e.type).toBe("error"); + expect(e.message).toBe("boom"); + expect(e.error).toBe(err); + expect(e.lineno).toBe(0); + }); + + it("builds an error event from a non-Error value", () => { + const e = createErrorEvent("plain", {}); + expect(e.message).toBe("plain"); + }); + + it("builds a messageerror event", () => { + const e = createMessageErrorEvent({}); + expect(e.type).toBe("messageerror"); + expect(e.data).toBe(null); + }); +}); From 2ebf2d2c15a868e45bf37924cda2b154d1386247 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:29:55 -0400 Subject: [PATCH 07/18] feat: add EventTarget mixin with multi-listener + on* support --- src/event-target.ts | 62 +++++++++++++++++++++++++++++++++++++++ test/event-target.test.ts | 55 ++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/event-target.ts create mode 100644 test/event-target.test.ts diff --git a/src/event-target.ts b/src/event-target.ts new file mode 100644 index 0000000..9be9b9c --- /dev/null +++ b/src/event-target.ts @@ -0,0 +1,62 @@ +import { isFunction } from "./utils"; +import { PolyfillEvent } from "./events"; + +// A minimal EventTarget that also supports legacy `on` handler +// properties. Both the Worker (parent) object and the worker global scope +// use this, giving them spec-style multi-listener behaviour. +interface EventTargetLike { + addEventListener: (type: string, callback: any) => void; + removeEventListener: (type: string, callback: any) => void; + dispatchEvent: (event: PolyfillEvent) => boolean; +} + +const installEventTarget = (host: any): EventTargetLike => { + const listeners: { [type: string]: any[] } = {}; + + host.addEventListener = function (type: string, callback: any) { + if (!isFunction(callback)) { + return; + } + if (!listeners[type]) { + listeners[type] = []; + } + if (listeners[type].indexOf(callback) === -1) { + listeners[type].push(callback); + } + }; + + host.removeEventListener = function (type: string, callback: any) { + const list = listeners[type]; + if (!list) { + return; + } + const idx = list.indexOf(callback); + if (idx !== -1) { + list.splice(idx, 1); + } + }; + + host.dispatchEvent = function (event: PolyfillEvent) { + event.target = event.target || host; + event.currentTarget = host; + + const handler = host["on" + event.type]; + if (isFunction(handler)) { + handler.call(host, event); + } + + const list = listeners[event.type]; + if (list) { + // Snapshot so a listener removing another mid-dispatch is safe. + const snapshot = list.slice(); + for (let i = 0; i < snapshot.length; i++) { + snapshot[i].call(host, event); + } + } + return true; + }; + + return host as EventTargetLike; +}; + +export { EventTargetLike, installEventTarget }; diff --git a/test/event-target.test.ts b/test/event-target.test.ts new file mode 100644 index 0000000..312a40e --- /dev/null +++ b/test/event-target.test.ts @@ -0,0 +1,55 @@ +import { describe, it, expect } from "vitest"; +import { installEventTarget } from "../src/event-target"; + +describe("installEventTarget", () => { + it("dispatches to multiple listeners", () => { + const host: any = {}; + installEventTarget(host); + const calls: string[] = []; + host.addEventListener("message", () => calls.push("a")); + host.addEventListener("message", () => calls.push("b")); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(calls).toEqual(["a", "b"]); + }); + + it("also invokes the on handler property", () => { + const host: any = {}; + installEventTarget(host); + let got = ""; + host.onmessage = () => (got = "handler"); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(got).toBe("handler"); + }); + + it("removeEventListener stops a listener", () => { + const host: any = {}; + installEventTarget(host); + const calls: string[] = []; + const fn = () => calls.push("x"); + host.addEventListener("message", fn); + host.removeEventListener("message", fn); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(calls).toEqual([]); + }); + + it("does not register the same listener twice", () => { + const host: any = {}; + installEventTarget(host); + let n = 0; + const fn = () => n++; + host.addEventListener("message", fn); + host.addEventListener("message", fn); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(n).toBe(1); + }); + + it("sets target/currentTarget on the event", () => { + const host: any = {}; + installEventTarget(host); + let seen: any = null; + host.addEventListener("message", (e: any) => (seen = e)); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(seen.currentTarget).toBe(host); + expect(seen.target).toBe(host); + }); +}); From 492a0c9ae7fa6b159148b4180e0e9e2cba28f457 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:40:05 -0400 Subject: [PATCH 08/18] chore: track package-lock.json This is a fork of older code from an era when committing the lockfile was considered a mistake. It is not: the lockfile gives reproducible installs and is required by 'npm ci' in CI. Stop ignoring it and commit the current lockfile. Signed-off-by: Xe Iaso --- .gitignore | 1 - package-lock.json | 3979 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3979 insertions(+), 1 deletion(-) create mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index a3d090e..bdc2f8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ lib/ node_modules/ -package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4edeb09 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3979 @@ +{ + "name": "@techaro/worker-polyfill", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@techaro/worker-polyfill", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "jsdom": "^25.0.1", + "rimraf": "^6.0.1", + "ts-loader": "^9.5.4", + "typescript": "^6.0.3", + "vitest": "^3.2.6", + "webpack": "^5.108.1", + "webpack-cli": "^7.1.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-1.1.0.tgz", + "integrity": "sha512-Xc3VhU02wqZ1HvHRJUwL09HkZSTvidqY5Ya0NXBSYOxAp+Ln9dcJr9fySI+CkONzP3PekQo9WdzCv0PGER/mOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.0.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.1.tgz", + "integrity": "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.6", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.6", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.380", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.380.tgz", + "integrity": "sha512-W6d5AbuEoRayO447cqrg6lKJIlscgRnnxOZl/08kfV71BQDoEBC7Wwis68z87LjyK6f4kWyTaubuDbhHKrZkbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.24.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.1.tgz", + "integrity": "sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimizer-webpack-plugin": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nwsapi": { + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.24.tgz", + "integrity": "sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.5.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", + "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-loader": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.6.2.tgz", + "integrity": "sha512-R4iuczmtgxvtuI556s+hTZ6/7Ee03VCAk/l/M8LY1OAsUgB7YydsCxkgq9D9pKRaD7GJqUi2u8fp9zZP/ufjKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "picomatch": "^4.0.0", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "loader-utils": "*", + "typescript": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "loader-utils": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/watchpack": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", + "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack": { + "version": "5.108.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.1.tgz", + "integrity": "sha512-UUCihHQK3O7483Woa0SulNLDeAiOhHI2PN2PAPU4fVWJqbzhv04EJ8FaWtB9WWh3i8fRt28543U7VfuJTOrpgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.22.2", + "es-module-lexer": "^2.1.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", + "minimizer-webpack-plugin": "^5.6.1", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "watchpack": "^2.5.2", + "webpack-sources": "^3.5.0" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-7.1.0.tgz", + "integrity": "sha512-pSJ5p5PkXRD88sfCq5Wo+coc42QykwRu5Md0DyESj0rT6PPPA2wTNabpHPKgqH8EMkfTDo3IWx3iiNXMu8XDBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^1.1.0", + "commander": "^14.0.3", + "cross-spawn": "^7.0.6", + "envinfo": "^7.21.0", + "import-local": "^3.2.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^6.0.1" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "js-yaml": "^4.0.0 || ^5.0.0", + "json5": "^2.2.3", + "toml": "^3.0.0 || ^4.0.0", + "webpack": "^5.101.0", + "webpack-bundle-analyzer": "^4.0.0 || ^5.0.0", + "webpack-dev-server": "^5.0.0" + }, + "peerDependenciesMeta": { + "js-yaml": { + "optional": true + }, + "json5": { + "optional": true + }, + "toml": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + } + } +} From 0ad525f5e4f8fd47f37b323bb82b2d67ffd8a274 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:41:18 -0400 Subject: [PATCH 09/18] ci: add node_tests workflow and local act runner --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ package.json | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..08a52c7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI + +on: + push: + pull_request: + +jobs: + node_tests: + name: Node tests + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build + + - name: Test + run: npm run test:run diff --git a/package.json b/package.json index f2f278e..af8184f 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "prebuild": "rimraf lib", "build": "webpack --mode=production", "test": "vitest", - "test:run": "vitest run" + "test:run": "vitest run", + "ci": "act -P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04 -j node_tests" }, "repository": { "type": "git", From c84a4a41f3035d0c20a82d5a99145af59e28e4a3 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 12:48:55 -0400 Subject: [PATCH 10/18] feat: add getGlobal and fetchScriptSync helpers --- src/utils.ts | 54 ++++++++++++++++++++++++++++++++++++++++------ test/utils.test.ts | 25 +++++++++++++++++++++ 2 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 test/utils.test.ts diff --git a/src/utils.ts b/src/utils.ts index 2b0e27c..57089b1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,20 +1,60 @@ -const isFunction = (f: () => any) => { - return typeof f === 'function'; +const isFunction = (f: any) => { + return typeof f === "function"; }; -/* HTTP Request*/ -const getHTTPObject = () => { - let xmlhttp; +/* HTTP Request */ +const getHTTPObject = (): any => { + let xmlhttp: any; try { xmlhttp = new XMLHttpRequest(); } catch (e) { try { + // @ts-ignore - ActiveXObject only exists in old IE xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); - } catch (e) { + } catch (e2) { xmlhttp = false; } } return xmlhttp; }; -export { isFunction, getHTTPObject }; +// Resolve the global object across environments (browser, worker, Node, IE). +const getGlobal = (): any => { + if (typeof globalThis !== "undefined") { + return globalThis; + } + if (typeof self !== "undefined") { + return self; + } + // @ts-ignore - window exists in browsers + if (typeof window !== "undefined") { + // @ts-ignore + return window; + } + return {}; +}; + +// Fetch a script synchronously and return its source text. Throws on failure +// so callers can surface an `error` event. +const fetchScriptSync = (url: string): string => { + const http = getHTTPObject(); + if (!http) { + throw new Error("No XMLHttpRequest available to load: " + url); + } + http.open("GET", url, false); + http.send(null); + + const ok = + http.readyState === 4 && + http.status !== 404 && + http.status !== 500; + + if (!ok) { + throw new Error( + "Failed to load worker script: " + url + " (status " + http.status + ")", + ); + } + return http.responseText; +}; + +export { isFunction, getHTTPObject, getGlobal, fetchScriptSync }; diff --git a/test/utils.test.ts b/test/utils.test.ts new file mode 100644 index 0000000..9a8f1fb --- /dev/null +++ b/test/utils.test.ts @@ -0,0 +1,25 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { fetchScriptSync, getGlobal } from "../src/utils"; +import { installMockXHR, setScript, failScript, resetScripts } from "./helpers/mockXHR"; + +describe("utils", () => { + beforeEach(() => { + resetScripts(); + installMockXHR(); + }); + + it("getGlobal returns an object with setTimeout", () => { + const g = getGlobal(); + expect(typeof g.setTimeout).toBe("function"); + }); + + it("fetchScriptSync returns the script body", () => { + setScript("a.js", "var a = 1;"); + expect(fetchScriptSync("a.js")).toBe("var a = 1;"); + }); + + it("fetchScriptSync throws on a failed load", () => { + failScript("missing.js"); + expect(() => fetchScriptSync("missing.js")).toThrow(); + }); +}); From 8300b08ce2eb10a1dfd9c9120eafded822d038cc Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 13:06:48 -0400 Subject: [PATCH 11/18] feat: add worker scope with isolated self and sync importScripts --- src/worker-scope.ts | 79 +++++++++++++++++++++++++++++++++++++++ test/worker-scope.test.ts | 46 +++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/worker-scope.ts create mode 100644 test/worker-scope.test.ts diff --git a/src/worker-scope.ts b/src/worker-scope.ts new file mode 100644 index 0000000..4458920 --- /dev/null +++ b/src/worker-scope.ts @@ -0,0 +1,79 @@ +import { fetchScriptSync } from "./utils"; +import { installEventTarget } from "./event-target"; +import { createMessageEvent } from "./events"; +import { structuredCloneShim } from "./clone"; + +interface WorkerScope { + self: WorkerScope; + name: string; + onmessage: any; + onmessageerror: any; + onerror: any; + postMessage: (data: any) => void; + importScripts: (...urls: string[]) => void; + close: () => void; + addEventListener: (type: string, cb: any) => void; + removeEventListener: (type: string, cb: any) => void; + dispatchEvent: (event: any) => boolean; + __deliver: (data: any) => void; + __evalScript: (code: string) => void; +} + +// Evaluate worker code with `scope` as its variable environment. `with` is +// illegal in strict mode, but a Function-constructor body is sloppy mode +// regardless of how the surrounding module is compiled, so bare identifiers +// (self, postMessage, onmessage, importScripts, close, ...) resolve to the +// scope object. Direct `eval` runs in this augmented environment. +// NOTE: the parameter names below leak into worker code as identifiers; they +// are deliberately obscure to avoid collisions. +const runWithScope: (scope: any, __worker_src__: string) => void = new Function( + "__worker_scope__", + "__worker_src__", + "with (__worker_scope__) { eval(__worker_src__); }", +) as any; + +// Builds the worker-side global scope (a DedicatedWorkerGlobalScope-like +// object). `toParent` is called when the worker posts a message out; `onClose` +// is called when the worker calls close(). +const createWorkerScope = ( + name: string, + toParent: (data: any) => void, + onClose: () => void, +): WorkerScope => { + const scope = {} as WorkerScope; + installEventTarget(scope); + + scope.self = scope; + scope.name = name || ""; + scope.onmessage = null; + scope.onmessageerror = null; + scope.onerror = null; + + scope.postMessage = function (data: any) { + toParent(structuredCloneShim(data)); + }; + + scope.importScripts = function () { + const urls = Array.prototype.slice.call(arguments); + for (let i = 0; i < urls.length; i++) { + scope.__evalScript(fetchScriptSync(urls[i])); + } + }; + + scope.close = function () { + onClose(); + }; + + // Deliver a parent->worker message as a `message` event inside the scope. + scope.__deliver = function (data: any) { + scope.dispatchEvent(createMessageEvent(data, scope)); + }; + + scope.__evalScript = function (code: string) { + runWithScope(scope, code); + }; + + return scope; +}; + +export { WorkerScope, createWorkerScope }; diff --git a/test/worker-scope.test.ts b/test/worker-scope.test.ts new file mode 100644 index 0000000..304ebd9 --- /dev/null +++ b/test/worker-scope.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from "vitest"; +import { createWorkerScope } from "../src/worker-scope"; + +describe("createWorkerScope", () => { + it("self refers to the scope itself", () => { + const scope = createWorkerScope("", () => {}, () => {}); + expect(scope.self).toBe(scope); + }); + + it("evaluated code can set self.onmessage and receive __deliver", () => { + const out: any[] = []; + const scope = createWorkerScope("", (d) => out.push(d), () => {}); + scope.__evalScript("self.onmessage = function(e){ self.postMessage(e.data); };"); + scope.__deliver("ping"); + expect(out).toEqual(["ping"]); + }); + + it("bare onmessage/postMessage identifiers resolve to the scope", () => { + const out: any[] = []; + const scope = createWorkerScope("", (d) => out.push(d), () => {}); + scope.__evalScript("onmessage = function(e){ postMessage(e.data + '!'); };"); + scope.__deliver("hey"); + expect(out).toEqual(["hey!"]); + }); + + it("postMessage clones the payload", () => { + const out: any[] = []; + const scope = createWorkerScope("", (d) => out.push(d), () => {}); + const obj = { n: 1 }; + scope.postMessage(obj); + obj.n = 2; + expect(out[0].n).toBe(1); + }); + + it("close() invokes the onClose callback", () => { + let closed = false; + const scope = createWorkerScope("", () => {}, () => (closed = true)); + scope.__evalScript("close();"); + expect(closed).toBe(true); + }); + + it("exposes the worker name", () => { + const scope = createWorkerScope("worker-1", () => {}, () => {}); + expect(scope.name).toBe("worker-1"); + }); +}); From fa04d8829b8e3cfe8896e591373b1d8db4c5a0ab Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 13:10:40 -0400 Subject: [PATCH 12/18] feat: rewrite Worker constructor with queues, error events, terminate --- src/worker-polyfill.ts | 174 +++++++++++++++++------------------ test/worker-polyfill.test.ts | 135 +++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 91 deletions(-) create mode 100644 test/worker-polyfill.test.ts diff --git a/src/worker-polyfill.ts b/src/worker-polyfill.ts index 3fd56a4..a219db5 100644 --- a/src/worker-polyfill.ts +++ b/src/worker-polyfill.ts @@ -1,114 +1,106 @@ /* - Create a fake worker thread of IE and other browsers - Remember: Only pass in primitives, and there is none of the native security happening - Only Supports Dedicated Web Workers + A single-threaded Worker polyfill for IE and other old browsers. + Dedicated Workers only. The worker script is fetched with synchronous XHR + and eval'd in-process, inside its own scope object so that `self`, + `postMessage`, `onmessage`, etc. behave like a real worker global. + Remember: messages are structured-cloned, but this is NOT a real thread and + provides none of the native security isolation. */ -import {getHTTPObject, isFunction} from "./utils"; - -// @ts-ignore -Worker = function (scriptFile: any) { - let self = this; - let __timer: number = null; - let __text: any = null; - let __fileContent: any = null; - - // External methods (worker.METHOD) +import { fetchScriptSync, getGlobal } from "./utils"; +import { installEventTarget } from "./event-target"; +import { createMessageEvent, createErrorEvent } from "./events"; +import { structuredCloneShim } from "./clone"; +import { createWorkerScope, WorkerScope } from "./worker-scope"; + +interface PolyfillWorkerOptions { + type?: string; + name?: string; + credentials?: string; +} + +const WorkerPolyfill = function ( + this: any, + scriptFile: string, + options?: PolyfillWorkerOptions, +) { + const self = this; + const opts = options || {}; + const glob = getGlobal(); + + installEventTarget(self); self.onmessage = null; self.onerror = null; + self.onmessageerror = null; - // Child methods - let onmessage; - let onerror; + let terminated = false; + const inbox: any[] = []; + let scope: WorkerScope | null = null; - // Child runs this itself and calls for it's parent to be notified - const postMessage = function (data: any) { - if ( isFunction(self.onmessage) ) { - return self.onmessage({ data }); + // worker -> parent + const toParent = function (data: any) { + if (terminated) { + return; } - return false; - }; - - // Method that starts the threading - self.postMessage = function (text: any) { - __text = text; - __iterate(); - return true; + glob.setTimeout(function () { + if (terminated) { + return; + } + self.dispatchEvent(createMessageEvent(data, self)); + }, 0); }; - // Child can call this method instead of assigning methods directly - const addEventListener = function (type, callback) { - switch(type) { - case 'message': - onmessage = callback; - break; - case 'error': - onerror = callback; - break; - } + const stop = function () { + terminated = true; + inbox.length = 0; }; - // Parent can call this method instead of assigning methods directly - self.addEventListener = function (type, callback) { - switch(type) { - case 'message': - self.onmessage = callback; - break; - case 'error': - self.onerror = callback; - break; + // Drain queued parent->worker messages one at a time, asynchronously, so + // ordering is preserved and delivery never blocks the caller. + const drain = function () { + if (terminated || !scope || inbox.length === 0) { + return; } - }; - - const __iterate = function () { - // Execute on a timer so we don't block (well as good as we can get in a single thread) - __timer = setTimeout(__onIterate, 1); - return true; - }; - - const __onIterate = function () { + const data = inbox.shift(); try { - if ( isFunction(onmessage) ) { - onmessage({ data: __text }); - } - return true; + scope.__deliver(data); } catch (e) { - if ( isFunction(onerror) ) { - return onerror(e); - } + self.dispatchEvent(createErrorEvent(e, self)); + } + if (!terminated && inbox.length > 0) { + glob.setTimeout(drain, 0); } - return false; - }; - - self.terminate = function () { - clearTimeout(__timer); - return true; }; - const importScripts = function () { - // Turn arguments from pseudo-array in to array in order to iterate it - const params = Array.prototype.slice.call(arguments); - - for (let i = 0, j = params.length; i < j; i++) { - const script = document.createElement('script'); - script.src = params[i]; - script.setAttribute('type', 'text/javascript'); - document.getElementsByTagName('head')[0].appendChild(script) + // parent -> worker + self.postMessage = function (data: any) { + if (terminated) { + return; } + inbox.push(structuredCloneShim(data)); + glob.setTimeout(drain, 0); }; - const http = getHTTPObject(); - http.open("GET", scriptFile, false); - http.send(null); - - if (http.readyState == 4) { - const strResponse = http.responseText; + self.terminate = function () { + stop(); + }; - if (http.status !== 404 && http.status !== 500) { - __fileContent = strResponse; - // IE functions will become delagates of the instance of Worker - eval(__fileContent); - } + // Load and start the worker. Failures (load or top-level eval) dispatch an + // async error event so handlers attached right after construction still fire. + try { + const code = fetchScriptSync(scriptFile); + scope = createWorkerScope(opts.name || "", toParent, stop); + scope.__evalScript(code); + } catch (e) { + glob.setTimeout(function () { + self.dispatchEvent(createErrorEvent(e, self)); + }, 0); } - - return true; }; + +// Install as the global Worker only when there is no native implementation. +const glob = getGlobal(); +if (typeof glob.Worker === "undefined") { + glob.Worker = WorkerPolyfill; +} + +export { WorkerPolyfill }; diff --git a/test/worker-polyfill.test.ts b/test/worker-polyfill.test.ts new file mode 100644 index 0000000..935eb8c --- /dev/null +++ b/test/worker-polyfill.test.ts @@ -0,0 +1,135 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { installMockXHR, setScript, failScript, resetScripts } from "./helpers/mockXHR"; +import { WorkerPolyfill } from "../src/worker-polyfill"; + +const makeWorker = (file: string, opts?: any) => + new (WorkerPolyfill as any)(file, opts); + +describe("WorkerPolyfill", () => { + beforeEach(() => { + resetScripts(); + installMockXHR(); + vi.useFakeTimers(); + }); + + it("echoes a message using the self.* idiom", () => { + setScript("echo.js", "self.onmessage = function(e){ self.postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage("hi"); + vi.runAllTimers(); + expect(got).toEqual(["hi"]); + }); + + it("delivers a message event object, not a bare value", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + let evt: any = null; + w.addEventListener("message", (e: any) => (evt = e)); + w.postMessage("x"); + vi.runAllTimers(); + expect(evt.type).toBe("message"); + expect(evt.data).toBe("x"); + expect(evt.target).toBe(w); + }); + + it("preserves message order for rapid posts", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage(1); + w.postMessage(2); + w.postMessage(3); + vi.runAllTimers(); + expect(got).toEqual([1, 2, 3]); + }); + + it("structured-clones outgoing messages", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + let received: any = null; + w.onmessage = (e: any) => (received = e.data); + const payload = { n: 1 }; + w.postMessage(payload); + payload.n = 2; + vi.runAllTimers(); + expect(received.n).toBe(1); + }); + + it("supports multiple message listeners", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const calls: string[] = []; + w.addEventListener("message", () => calls.push("a")); + w.addEventListener("message", () => calls.push("b")); + w.postMessage("x"); + vi.runAllTimers(); + expect(calls).toEqual(["a", "b"]); + }); + + it("fires the error event when a handler throws", () => { + setScript("bad.js", "onmessage = function(){ throw new Error('boom'); };"); + const w = makeWorker("bad.js"); + let err: any = null; + w.onerror = (e: any) => (err = e); + w.postMessage("go"); + vi.runAllTimers(); + expect(err).not.toBe(null); + expect(err.type).toBe("error"); + expect(err.message).toBe("boom"); + }); + + it("fires the error event when the script fails to load", () => { + failScript("missing.js"); + const w = makeWorker("missing.js"); + let err: any = null; + w.onerror = (e: any) => (err = e); + vi.runAllTimers(); + expect(err).not.toBe(null); + expect(err.type).toBe("error"); + }); + + it("fires the error event when top-level worker code throws", () => { + setScript("throws.js", "throw new Error('top-level');"); + const w = makeWorker("throws.js"); + let err: any = null; + w.onerror = (e: any) => (err = e); + vi.runAllTimers(); + expect(err.message).toBe("top-level"); + }); + + it("terminate() stops further delivery", () => { + setScript("echo.js", "onmessage = function(e){ postMessage(e.data); };"); + const w = makeWorker("echo.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage("a"); + w.terminate(); + w.postMessage("b"); + vi.runAllTimers(); + expect(got).toEqual([]); + }); + + it("worker close() stops further delivery", () => { + setScript("closer.js", "onmessage = function(){ close(); postMessage('after'); };"); + const w = makeWorker("closer.js"); + const got: any[] = []; + w.onmessage = (e: any) => got.push(e.data); + w.postMessage("go"); + vi.runAllTimers(); + expect(got).toEqual([]); + }); + + it("supports importScripts synchronously", () => { + setScript("dep.js", "self.DEP_VALUE = 42;"); + setScript("main.js", "importScripts('dep.js'); onmessage = function(){ postMessage(DEP_VALUE); };"); + const w = makeWorker("main.js"); + let got: any = null; + w.onmessage = (e: any) => (got = e.data); + w.postMessage("go"); + vi.runAllTimers(); + expect(got).toBe(42); + }); +}); From 59ba6a521935da86ae8247049fdd5d94ab7924f4 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 13:15:49 -0400 Subject: [PATCH 13/18] build: expose WorkerPolyfill UMD export without clobbering global Worker --- webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.config.js b/webpack.config.js index 76d4686..e75d771 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -23,7 +23,7 @@ const config = { path: PATHS.bundles, filename: '[name].js', libraryTarget: 'umd', - library: 'Worker', + library: 'WorkerPolyfill', umdNamedDefine: true }, From 89f4216acbae0c0d587a8300d13641604f90756c Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 13:43:45 -0400 Subject: [PATCH 14/18] docs: document spec-conformant behaviour and limitations --- README.md | 91 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index bc759b7..26484f1 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,87 @@ # worker-polyfill -A simple script that emulates web worker threads in non compatible browsers. -The code will still be slow (single threaded) but you can keep you code consistent. +A small polyfill that emulates the Dedicated [Web Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Worker) +in browsers that don't support it (Internet Explorer and other old browsers). +The code is still single-threaded, but it lets you keep one consistent code +path. Messages are structured-cloned and delivered asynchronously, matching +the spec's observable behaviour. -Usage: -```js -// You must check for compatibility before loading the polyfill -if ( !Worker ) { require('worker-loader'); } +## Install + +The polyfill installs itself as the global `Worker` **only if the browser has +no native implementation**, so it is safe to include unconditionally: + +```html + ``` -Workers can be loaded and used as usual: +## Usage + +Workers are created and used as usual: + ```js -var worker = new Worker("your_script.js"); +var worker = new Worker("your_script.js"); -worker.onmessage = function(event) { - alert("Got: " + event.data); -}; +worker.onmessage = function (event) { + alert("Got: " + event.data); +}; -worker.onerror = function(error) { - alert("Worker error: " + error); +worker.onerror = function (event) { + alert("Worker error: " + event.message); }; -worker.postMessage("Hello World"); +worker.postMessage("Hello World"); ``` -'addEventListener' methods are also supported: +`addEventListener` is supported with full multi-listener semantics: ```js -var worker = new Worker("your_script.js"); - -worker.addEventListener("message", function(event) { - alert("Got: " + event.data); +worker.addEventListener("message", function (event) { + alert("Got: " + event.data); }); - -worker.addEventListener("error", function(error) { - alert("Worker error: " + error); +worker.addEventListener("error", function (event) { + alert("Worker error: " + event.message); }); +``` -worker.postMessage("Hello World"); +Inside the worker script, the usual idioms work because the script runs in its +own scope: + +```js +// your_script.js +self.onmessage = function (event) { + self.postMessage("echo: " + event.data); +}; +// importScripts() is supported and runs synchronously +// close() stops the worker ``` -- For more info on worker threads see -https://developer.mozilla.org/En/Using_web_workers +## Supported + +`postMessage` (structured-cloned, ordered), `terminate`, `close`, +`addEventListener`/`removeEventListener`/`dispatchEvent`, `message`/`error` +events, `importScripts` (synchronous), `self`/`name`. + +## Not supported + +Module workers (`type: "module"`), transferable objects, `blob:`/`data:` URLs, +`credentials`, and real OS-thread parallelism. Pass plain, cloneable data. + +## Limitations + +`importScripts()` is synchronous and executes imported scripts immediately, +but top-level `var`/`function` declarations in an imported script are NOT +visible to the main worker script (or vice versa). Use `self.X = ...` +assignments (which land on the worker scope) to share values across scripts +loaded via `importScripts()`. + +## Development + +```bash +npm install +npm test # vitest + jsdom conformance suite +npm run build # webpack UMD bundle into lib/ +``` +- For more on workers see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API - Originally exported from Google Code (https://code.google.com/p/ie-web-worker/). From c1e73a82d311a82a10c6f0979241c7ed12d362b3 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 14:03:05 -0400 Subject: [PATCH 15/18] fix: prevent queue stranding when listeners throw Wrap each listener invocation and on handler in try/catch to prevent errors from propagating out of dispatchEvent. This fixes two issues: 1. Queue stranding: When parent's onerror throws, the error no longer escapes the drain loop's catch block, so message processing continues. 2. Spec divergence: postMessage is now fire-and-forget; listener throws never propagate to the caller. Uses conditional error catching (catchErrors option) to allow worker scope errors to propagate to the parent's error dispatch, while parent scope errors are swallowed. Listener errors are intentionally swallowed rather than re-thrown to maintain fire-and-forget semantics. Added regression tests proving: - Multiple listeners continue executing after one throws - No queue stranding when both worker onmessage and parent onerror throw --- src/event-target.ts | 30 +++++++++++++++++++++++++----- test/event-target.test.ts | 13 +++++++++++++ test/worker-polyfill.test.ts | 23 +++++++++++++++++++++++ 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/event-target.ts b/src/event-target.ts index 9be9b9c..d263328 100644 --- a/src/event-target.ts +++ b/src/event-target.ts @@ -1,5 +1,5 @@ -import { isFunction } from "./utils"; -import { PolyfillEvent } from "./events"; +import { isFunction, getGlobal } from "./utils"; +import { PolyfillEvent, createErrorEvent } from "./events"; // A minimal EventTarget that also supports legacy `on` handler // properties. Both the Worker (parent) object and the worker global scope @@ -10,8 +10,10 @@ interface EventTargetLike { dispatchEvent: (event: PolyfillEvent) => boolean; } -const installEventTarget = (host: any): EventTargetLike => { +const installEventTarget = (host: any, options?: { catchErrors: boolean }): EventTargetLike => { const listeners: { [type: string]: any[] } = {}; + const catchErrors = options?.catchErrors !== false; // default to true + let inErrorDispatch = false; host.addEventListener = function (type: string, callback: any) { if (!isFunction(callback)) { @@ -42,7 +44,16 @@ const installEventTarget = (host: any): EventTargetLike => { const handler = host["on" + event.type]; if (isFunction(handler)) { - handler.call(host, event); + if (catchErrors) { + try { + handler.call(host, event); + } catch (e) { + // Swallow handler errors to prevent queue stranding and spec violations. + // Listener errors are intentionally not re-thrown to maintain fire-and-forget semantics. + } + } else { + handler.call(host, event); + } } const list = listeners[event.type]; @@ -50,7 +61,16 @@ const installEventTarget = (host: any): EventTargetLike => { // Snapshot so a listener removing another mid-dispatch is safe. const snapshot = list.slice(); for (let i = 0; i < snapshot.length; i++) { - snapshot[i].call(host, event); + if (catchErrors) { + try { + snapshot[i].call(host, event); + } catch (e) { + // Swallow listener errors to prevent queue stranding and spec violations. + // Listener errors are intentionally not re-thrown to maintain fire-and-forget semantics. + } + } else { + snapshot[i].call(host, event); + } } } return true; diff --git a/test/event-target.test.ts b/test/event-target.test.ts index 312a40e..1136f6f 100644 --- a/test/event-target.test.ts +++ b/test/event-target.test.ts @@ -52,4 +52,17 @@ describe("installEventTarget", () => { expect(seen.currentTarget).toBe(host); expect(seen.target).toBe(host); }); + + it("continues dispatching after a listener throws", () => { + const host: any = {}; + installEventTarget(host); + const calls: string[] = []; + host.addEventListener("message", () => { + calls.push("first"); + throw new Error("boom"); + }); + host.addEventListener("message", () => calls.push("second")); + host.dispatchEvent({ type: "message", target: null, currentTarget: null }); + expect(calls).toEqual(["first", "second"]); + }); }); diff --git a/test/worker-polyfill.test.ts b/test/worker-polyfill.test.ts index 935eb8c..d6986b5 100644 --- a/test/worker-polyfill.test.ts +++ b/test/worker-polyfill.test.ts @@ -79,6 +79,8 @@ describe("WorkerPolyfill", () => { expect(err).not.toBe(null); expect(err.type).toBe("error"); expect(err.message).toBe("boom"); + // Verify the error event was dispatched even though we swallow listener throws + expect(err.error).toBeDefined(); }); it("fires the error event when the script fails to load", () => { @@ -132,4 +134,25 @@ describe("WorkerPolyfill", () => { vi.runAllTimers(); expect(got).toBe(42); }); + + it("does not strand messages when both onmessage and onerror throw", () => { + setScript("thrower.js", "onmessage = function(){ throw new Error('worker boom'); };"); + const w = makeWorker("thrower.js"); + const errors: any[] = []; + const messages: any[] = []; + w.onerror = (e: any) => { + errors.push(e.message); + throw new Error("parent boom"); + }; + w.onmessage = (e: any) => messages.push(e.data); + w.postMessage("first"); + w.postMessage("second"); + vi.runAllTimers(); + // First message should trigger error path (swallowed, no propagation) + expect(errors.length).toBeGreaterThanOrEqual(1); + expect(errors[0]).toBe("worker boom"); + // Second message should also be processed (not stranded) + expect(errors.length).toBeGreaterThanOrEqual(2); + expect(errors[1]).toBe("worker boom"); + }); }); From 9776a615725bf9190b12458f588d110482772a89 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 14:03:23 -0400 Subject: [PATCH 16/18] docs: document arguments shadowing in worker code The Function constructor wrapper shadows the bare identifier 'arguments' and internal parameter names (__worker_scope__, __worker_src__) inside top-level worker code. Added note to README Limitations section warning users to avoid using 'arguments' as an identifier in worker scripts. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 26484f1..664fac1 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,11 @@ visible to the main worker script (or vice versa). Use `self.X = ...` assignments (which land on the worker scope) to share values across scripts loaded via `importScripts()`. +The bare identifier `arguments` (and the internal parameter names +`__worker_scope__` and `__worker_src__`) are shadowed inside top-level +worker code due to the Function constructor wrapper—avoid using `arguments` +as an identifier in worker scripts. + ## Development ```bash From d43d4b7f2082a0a1ad9b987020fe5e482e7583f9 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 14:03:41 -0400 Subject: [PATCH 17/18] fix: tighten HTTP status check and add RegExp assertions - Tighten fetchScriptSync to only accept 2xx status codes (and 0 for local/file URLs), rejecting non-2xx responses like 502 that were incorrectly treated as success. - Add test proving non-2xx responses now throw correctly. - Add RegExp assertions (source and flags) to the clone test to match the test name 'clones Date and RegExp'. --- src/utils.ts | 3 +-- test/clone.test.ts | 5 +++++ test/helpers/mockXHR.ts | 13 ++++++++++++- test/utils.test.ts | 7 ++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 57089b1..0d2bfbe 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -46,8 +46,7 @@ const fetchScriptSync = (url: string): string => { const ok = http.readyState === 4 && - http.status !== 404 && - http.status !== 500; + (http.status === 0 || (http.status >= 200 && http.status < 300)); if (!ok) { throw new Error( diff --git a/test/clone.test.ts b/test/clone.test.ts index 9c810b4..abdb612 100644 --- a/test/clone.test.ts +++ b/test/clone.test.ts @@ -35,5 +35,10 @@ describe("structuredCloneShim", () => { const d = structuredCloneShim(new Date(1000)); expect(d instanceof Date).toBe(true); expect(d.getTime()).toBe(1000); + + const re = structuredCloneShim(/foo/gi); + expect(re instanceof RegExp).toBe(true); + expect(re.source).toBe("foo"); + expect(re.flags).toBe("gi"); }); }); diff --git a/test/helpers/mockXHR.ts b/test/helpers/mockXHR.ts index 6f2f041..235865c 100644 --- a/test/helpers/mockXHR.ts +++ b/test/helpers/mockXHR.ts @@ -2,8 +2,10 @@ // worker scripts with sync XHR; jsdom can't fetch arbitrary URLs, so tests // register script bodies here and the mock serves them. type ScriptMap = { [url: string]: string }; +type ScriptWithStatusMap = { [url: string]: { code: string; status: number } }; let scripts: ScriptMap = {}; +let scriptsWithStatus: ScriptWithStatusMap = {}; let failUrls: string[] = []; class MockXHR { @@ -23,7 +25,11 @@ class MockXHR { this.responseText = ""; return; } - if (Object.prototype.hasOwnProperty.call(scripts, this.url)) { + if (Object.prototype.hasOwnProperty.call(scriptsWithStatus, this.url)) { + const entry = scriptsWithStatus[this.url]; + this.status = entry.status; + this.responseText = entry.code; + } else if (Object.prototype.hasOwnProperty.call(scripts, this.url)) { this.status = 200; this.responseText = scripts[this.url]; } else { @@ -37,12 +43,17 @@ export function setScript(url: string, code: string): void { scripts[url] = code; } +export function setScriptWithStatus(url: string, code: string, status: number): void { + scriptsWithStatus[url] = { code, status }; +} + export function failScript(url: string): void { failUrls.push(url); } export function resetScripts(): void { scripts = {}; + scriptsWithStatus = {}; failUrls = []; } diff --git a/test/utils.test.ts b/test/utils.test.ts index 9a8f1fb..07e7899 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach } from "vitest"; import { fetchScriptSync, getGlobal } from "../src/utils"; -import { installMockXHR, setScript, failScript, resetScripts } from "./helpers/mockXHR"; +import { installMockXHR, setScript, failScript, resetScripts, setScriptWithStatus } from "./helpers/mockXHR"; describe("utils", () => { beforeEach(() => { @@ -22,4 +22,9 @@ describe("utils", () => { failScript("missing.js"); expect(() => fetchScriptSync("missing.js")).toThrow(); }); + + it("fetchScriptSync throws on non-2xx status", () => { + setScriptWithStatus("bad.js", "var a = 1;", 502); + expect(() => fetchScriptSync("bad.js")).toThrow("Failed to load worker script: bad.js (status 502)"); + }); }); From dace367ad1afcaea8f1751f30f8b18f7620c1994 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 28 Jun 2026 14:06:26 -0400 Subject: [PATCH 18/18] fix: let worker scope propagate handler throws to error events Companion to the dispatchEvent catchErrors change (c1e73a8): the worker scope must dispatch with catchErrors=false so that a worker onmessage throw propagates up to drain()'s try/catch and surfaces as an 'error' event. With catchErrors defaulted to true here, handler throws were swallowed inside the scope, regressing the error-event-on-throw behavior (audit #1) and breaking the no-stranding regression test. Signed-off-by: Xe Iaso --- src/worker-scope.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worker-scope.ts b/src/worker-scope.ts index 4458920..5ef8d33 100644 --- a/src/worker-scope.ts +++ b/src/worker-scope.ts @@ -41,7 +41,7 @@ const createWorkerScope = ( onClose: () => void, ): WorkerScope => { const scope = {} as WorkerScope; - installEventTarget(scope); + installEventTarget(scope, { catchErrors: false }); scope.self = scope; scope.name = name || "";