diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5ab8cc36..ab57ef66 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,6 +34,8 @@ jobs:
run: pnpm --filter @mdbase-reader/app exec playwright install --with-deps chromium
- name: Verify PDF gestures and mobile highlight persistence
run: pnpm --filter @mdbase-reader/app test:pdf-touch
+ - name: Verify imported SVG rendering in the HTML sandbox
+ run: pnpm --filter @mdbase-reader/app test:html-svg
- name: Verify private feedback with sample data and intercepted delivery
env:
VITE_MDBASE_FEEDBACK_URL: http://127.0.0.1:8891/v1/feedback
diff --git a/apps/reader/package.json b/apps/reader/package.json
index a6bb2713..3832ba88 100644
--- a/apps/reader/package.json
+++ b/apps/reader/package.json
@@ -18,6 +18,7 @@
"preview": "vite preview --host 127.0.0.1",
"test": "pnpm manifest && pnpm manifest:verify && node --test scripts/*.test.mjs && vitest run src capture --maxWorkers=2 --testTimeout=15000",
"test:browser": "node scripts/audit-reader.mjs",
+ "test:html-svg": "node scripts/audit-html-svg.mjs",
"test:feedback": "node scripts/feedback-browser-test.mjs",
"test:pdf-touch": "node scripts/run-pdf-touch-audits.mjs",
"typecheck": "tsc -p tsconfig.json",
diff --git a/apps/reader/scripts/audit-html-svg.mjs b/apps/reader/scripts/audit-html-svg.mjs
new file mode 100644
index 00000000..52614c0c
--- /dev/null
+++ b/apps/reader/scripts/audit-html-svg.mjs
@@ -0,0 +1,76 @@
+import { readFile } from "node:fs/promises";
+import { resolve } from "node:path";
+
+import { chromium, expect } from "@playwright/test";
+import { createServer } from "vite";
+
+// The production reproduction, rendered in Reader's script-disabled HTML sandbox.
+const root = resolve(import.meta.dirname, "..");
+const fixture = await readFile(
+ resolve(root, "../../packages/renderer-html/src/fixtures/imported-svg.html"),
+ "utf8",
+);
+const server = await createServer({
+ root,
+ server: { host: "127.0.0.1", port: 0, strictPort: true },
+});
+let browser;
+try {
+ await server.listen();
+ const address = server.httpServer.address();
+ const origin = `http://127.0.0.1:${address.port}`;
+ browser = await chromium.launch({ headless: true });
+ const page = await browser.newPage();
+ const externalRequests = [];
+ await page.route("**/*", (route) => {
+ if (new URL(route.request().url()).origin === origin) return route.continue();
+ externalRequests.push(route.request().url());
+ return route.abort();
+ });
+ // No app, collection, daemon or production network access is needed.
+ await page.route(`${origin}/svg-test`, (route) =>
+ route.fulfill({
+ contentType: "text/html",
+ body: "
SVG regression",
+ }),
+ );
+ await page.goto(`${origin}/svg-test`);
+ const moduleUrl = `/@fs${resolve(root, "../../packages/renderer-html/src/html-document.ts")}`;
+ for (const passes of [0, 1, 2]) {
+ await page.evaluate(
+ async ({ fixture, moduleUrl, passes }) => {
+ const { prepareHtmlDocument } = await import(moduleUrl);
+ let source = fixture;
+ for (let pass = 0; pass < passes; pass++) source = prepareHtmlDocument(source);
+ const frame = globalThis.document.createElement("iframe");
+ frame.sandbox = "allow-same-origin";
+ frame.title = "HTML reading document";
+ globalThis.document.body.replaceChildren(frame);
+ await new Promise((resolveLoad) => {
+ frame.onload = resolveLoad;
+ frame.srcdoc = source;
+ });
+ },
+ { fixture, moduleUrl, passes },
+ );
+ const frame = page.frameLocator("iframe");
+ const image = frame.getByAltText("Test image");
+ await expect
+ .poll(() => image.evaluate((image) => [image.naturalWidth, image.naturalHeight]))
+ .toEqual([30, 30]);
+ await expect(frame.locator("code")).toHaveText("const example = 42;");
+ if (passes) {
+ await expect(frame.locator('meta[http-equiv="Content-Security-Policy"]')).toHaveAttribute(
+ "content",
+ "default-src 'none'; img-src data: blob:; style-src 'unsafe-inline'; font-src data:; base-uri 'none'; form-action 'none'",
+ );
+ }
+ }
+ expect(externalRequests).toEqual([]);
+ console.log(
+ "Imported SVG: 30×30 in Chrome and after both Reader sanitization passes; CSP unchanged.",
+ );
+} finally {
+ await browser?.close();
+ await server.close();
+}
diff --git a/packages/renderer-html/package.json b/packages/renderer-html/package.json
index 6f151198..dfd4d59b 100644
--- a/packages/renderer-html/package.json
+++ b/packages/renderer-html/package.json
@@ -15,10 +15,12 @@
"@lingui/react": "6.9.0",
"@mdbase-reader/core": "workspace:*",
"@mdbase-reader/reading-surface": "workspace:*",
+ "dompurify": "^3.4.17",
"react": "^19.2.8"
},
"devDependencies": {
"@types/react": "^19.2.14",
- "happy-dom": "^20.11.2"
+ "happy-dom": "^20.11.2",
+ "jsdom": "28.1.0"
}
}
diff --git a/packages/renderer-html/src/fixtures/imported-svg.html b/packages/renderer-html/src/fixtures/imported-svg.html
new file mode 100644
index 00000000..c4be4349
--- /dev/null
+++ b/packages/renderer-html/src/fixtures/imported-svg.html
@@ -0,0 +1,26 @@
+
+
+
+ [test] agent-20261029T030716Z-R2-1a2 reader
+
+
+
+ [test] agent-20261029T030716Z-R2-1a2 reader
+ Unicode: café 漢字 🐨
+
+
+ | Item |
+ Value |
+
+
+ | Alpha |
+ 42 |
+
+
+ const example = 42;
+
+
+
diff --git a/packages/renderer-html/src/html-document.test.ts b/packages/renderer-html/src/html-document.test.ts
index 3c02a6e3..ba0625c3 100644
--- a/packages/renderer-html/src/html-document.test.ts
+++ b/packages/renderer-html/src/html-document.test.ts
@@ -1,9 +1,22 @@
-// @vitest-environment happy-dom
+// @vitest-environment jsdom
+import { readFileSync } from "node:fs";
+import { resolve } from "node:path";
+
import { describe, expect, it } from "vitest";
import { extractArchivedHtmlText, prepareHtmlDocument } from "./html-document.js";
describe("prepareHtmlDocument", () => {
+ it("retains the embedded SVG image from the production import fixture", () => {
+ const source = readFileSync(resolve(import.meta.dirname, "fixtures/imported-svg.html"), "utf8");
+ const rendered = new DOMParser().parseFromString(prepareHtmlDocument(source), "text/html");
+ const image = rendered.querySelector("img");
+ expect(image?.getAttribute("src")).toMatch(/^data:image\/svg\+xml,/u);
+ expect(image?.getAttribute("alt")).toBe("Test image");
+ expect(rendered.querySelector("td")?.textContent).toBe("Alpha");
+ expect(rendered.querySelector("code")?.textContent).toBe("const example = 42;");
+ expect(rendered.body.textContent).toContain("Unicode: café 漢字 🐨");
+ });
it("shares background index text with the rendered document, without executing markup", () => {
const source =
"Not body text";
diff --git a/packages/renderer-html/src/html-document.ts b/packages/renderer-html/src/html-document.ts
index 2fc57a3a..4470b207 100644
--- a/packages/renderer-html/src/html-document.ts
+++ b/packages/renderer-html/src/html-document.ts
@@ -1,6 +1,7 @@
import { highlightPalette } from "@mdbase-reader/core";
import { annotationHighlightCss } from "./html-css-highlights.js";
+import { sanitizedSvgImage } from "./svg-image.js";
const blockedElements = [
"script",
@@ -60,12 +61,19 @@ export function prepareHtmlDocument(source: string): string {
function sanitizeAttributes(element: Element): void {
for (const attribute of [...element.attributes]) {
const name = attribute.name.toLocaleLowerCase();
- if (name.startsWith("on") || name === "srcdoc" || name === "style") {
+ if (name.startsWith("on") || name === "srcdoc" || name === "srcset" || name === "style") {
element.removeAttribute(attribute.name);
}
}
for (const name of urlAttributes) {
const value = element.getAttribute(name)?.trim();
+ if (name === "src" && element.localName === "img" && value) {
+ const svg = sanitizedSvgImage(value);
+ if (svg) {
+ element.setAttribute(name, svg);
+ continue;
+ }
+ }
if (value && !safeResource(name, value)) {
element.removeAttribute(name);
}
diff --git a/packages/renderer-html/src/svg-image.test.ts b/packages/renderer-html/src/svg-image.test.ts
new file mode 100644
index 00000000..ad0b9993
--- /dev/null
+++ b/packages/renderer-html/src/svg-image.test.ts
@@ -0,0 +1,140 @@
+// @vitest-environment jsdom
+import { describe, expect, it } from "vitest";
+
+import { prepareHtmlDocument } from "./html-document.js";
+import { sanitizedSvgImage } from "./svg-image.js";
+
+const drawing = ``;
+
+function decodedImage(url: string | null): Document {
+ expect(url).toMatch(/^data:image\/svg\+xml,/u);
+ return new DOMParser().parseFromString(decodeURIComponent(url!.split(",")[1]!), "image/svg+xml");
+}
+
+describe("sanitizedSvgImage", () => {
+ it.each(["percent", "base64"])("preserves geometry and Unicode in %s images", (encoding) => {
+ const url =
+ encoding === "percent"
+ ? `data:image/svg+xml,${encodeURIComponent(drawing)}`
+ : `data:image/svg+xml;charset=utf-8;base64,${btoa(String.fromCharCode(...new TextEncoder().encode(drawing)))}`;
+ const svg = decodedImage(sanitizedSvgImage(url));
+ expect(svg.documentElement.getAttribute("width")).toBe("30");
+ expect(svg.querySelector("rect")?.getAttribute("fill")).toBe("blue");
+ expect(svg.querySelector("title")?.textContent).toBe("café 漢字 🐨");
+ });
+
+ it("strips scripts, event handlers, foreign content, animation, CSS and external references", () => {
+ const source = ``;
+ const svg = decodedImage(sanitizedSvgImage(`data:image/svg+xml,${encodeURIComponent(source)}`));
+ const clean = new XMLSerializer().serializeToString(svg);
+ expect(clean).not.toMatch(
+ /script|onload|onclick|foreignObject|iframe|",
+ ])("rejects malformed or non-SVG input: %s", (url) => {
+ expect(sanitizedSvgImage(url)).toBeNull();
+ const html = new DOMParser().parseFromString(
+ prepareHtmlDocument(`
`),
+ "text/html",
+ );
+ expect(html.querySelector("img")?.hasAttribute("src")).toBe(false);
+ });
+
+ it("preserves non-breaking spaces, local reuse and quoted paints without the source doctype", () => {
+ const source = `
+ `;
+ const svg = decodedImage(
+ sanitizedSvgImage(`data:image/svg+xml;utf8,${encodeURIComponent(source)}`),
+ );
+ expect(svg.doctype).toBeNull();
+ expect(svg.querySelector("text")?.textContent).toBe("a\u00a0b");
+ expect(svg.querySelector("text")?.getAttribute("aria-label")).toBe("a\u00a0b");
+ expect(svg.querySelectorAll("use")).toHaveLength(2);
+ expect(svg.querySelectorAll("use")[0]?.getAttribute("href")).toBe("#shape");
+ expect(svg.querySelectorAll("use")[1]?.getAttribute("xlink:href")).toBe("#shape");
+ expect(svg.querySelectorAll("use")[0]?.getAttribute("fill")).toBe("url('#g')");
+ expect(svg.querySelectorAll("use")[1]?.getAttribute("fill")).toBe('url("#g")');
+ });
+
+ it.each([';charset="utf-8"', ";charset=US-ASCII", ";utf8", ""])(
+ "accepts %s parameters and literal percent signs as Chrome does",
+ (parameters) => {
+ const source = '';
+ const svg = decodedImage(sanitizedSvgImage(`data:image/svg+xml${parameters},${source}`));
+ expect(svg.querySelector("rect")?.getAttribute("width")).toBe("100%");
+ },
+ );
+
+ it("keeps embedded raster images and local paint fallbacks, while rejecting external fallbacks", () => {
+ const raster = "data:image/png;base64,iVBORw0KGgo=";
+ const source = ``;
+ const svg = decodedImage(sanitizedSvgImage(`data:image/svg+xml,${encodeURIComponent(source)}`));
+ expect(svg.querySelectorAll("image")[0]?.getAttribute("xlink:href")).toBe(raster);
+ expect(svg.querySelectorAll("image")[1]?.hasAttribute("href")).toBe(false);
+ expect(svg.querySelector("rect")?.getAttribute("fill")).toBe("url(#missing) blue");
+ expect(svg.querySelector("circle")?.hasAttribute("fill")).toBe(false);
+ });
+
+ it("removes responsive image candidates so they cannot bypass SVG sanitization", () => {
+ const url = `data:image/svg+xml,${encodeURIComponent(drawing)}`;
+ const html = new DOMParser().parseFromString(
+ prepareHtmlDocument(
+ `
`,
+ ),
+ "text/html",
+ );
+ expect(html.querySelector("[srcset]")).toBeNull();
+ decodedImage(html.querySelector("img")!.getAttribute("src"));
+ });
+
+ it("is stable across capture and rendering passes and keeps the restrictive document CSP", () => {
+ const once = prepareHtmlDocument(
+ `
`,
+ );
+ const twice = prepareHtmlDocument(once);
+ const parsed = new DOMParser().parseFromString(twice, "text/html");
+ expect(parsed.querySelector("img")?.getAttribute("src")).toBe(
+ new DOMParser().parseFromString(once, "text/html").querySelector("img")?.getAttribute("src"),
+ );
+ expect(
+ parsed.querySelector('meta[http-equiv="Content-Security-Policy"]')?.getAttribute("content"),
+ ).toBe(
+ "default-src 'none'; img-src data: blob:; style-src 'unsafe-inline'; font-src data:; base-uri 'none'; form-action 'none'",
+ );
+ const unsafeLocation = new DOMParser().parseFromString(
+ prepareHtmlDocument(
+ ``,
+ ),
+ "text/html",
+ );
+ expect(unsafeLocation.querySelector("iframe")).toBeNull();
+ expect(unsafeLocation.querySelector("video")?.hasAttribute("poster")).toBe(false);
+ });
+});
diff --git a/packages/renderer-html/src/svg-image.ts b/packages/renderer-html/src/svg-image.ts
new file mode 100644
index 00000000..8ffdce41
--- /dev/null
+++ b/packages/renderer-html/src/svg-image.ts
@@ -0,0 +1,61 @@
+import purify from "dompurify";
+
+/** Keep embedded images static and self-contained before putting them back in a data URL. */
+export function sanitizedSvgImage(value: string): string | null {
+ const match = /^data:image\/svg\+xml((?:;[^,]*)?),([\s\S]*)$/iu.exec(value);
+ if (!match || !purify.isSupported) {
+ return null;
+ }
+ try {
+ const payload = decodeURIComponent((match[2] ?? "").replace(/%(?![\da-f]{2})/giu, "%25"));
+ const source = /(?:^|;)base64(?:;|$)/iu.test(match[1] ?? "")
+ ? new TextDecoder("utf-8", { fatal: true }).decode(
+ Uint8Array.from(atob(payload), (character) => character.charCodeAt(0)),
+ )
+ : payload;
+ const parsed = new DOMParser().parseFromString(source, "image/svg+xml");
+ if (
+ parsed.querySelector("parsererror") ||
+ parsed.documentElement.localName !== "svg" ||
+ parsed.documentElement.namespaceURI !== "http://www.w3.org/2000/svg"
+ ) {
+ return null;
+ }
+ // Only the root is kept; source doctypes and processing instructions never reach the image.
+ const clean = purify.sanitize(parsed.documentElement, {
+ USE_PROFILES: { svg: true, svgFilters: true },
+ ADD_TAGS: ["use"],
+ FORBID_TAGS: ["style", "animate", "animatemotion", "animatetransform", "set", "discard"],
+ FORBID_ATTR: ["style"],
+ RETURN_DOM_FRAGMENT: true,
+ });
+ const svg = clean.firstElementChild;
+ if (svg?.localName !== "svg") {
+ return null;
+ }
+ sanitizeSvgReferences(svg);
+ return `data:image/svg+xml,${encodeURIComponent(new XMLSerializer().serializeToString(svg))}`;
+ } catch {
+ return null;
+ }
+}
+
+function sanitizeSvgReferences(svg: Element): void {
+ for (const element of [svg, ...svg.querySelectorAll("*")]) {
+ for (const attribute of [...element.attributes]) {
+ // Presentation attributes can also load resources; permit only local fragment paints.
+ const references = attribute.value.replace(/url\(\s*(['"]?)#[\w.-]+\1\s*\)/giu, "");
+ const embeddedRaster =
+ element.localName === "image" &&
+ /^data:image\/(?:png|gif|jpeg|webp|avif);base64,/iu.test(attribute.value);
+ if (
+ (attribute.localName === "href" &&
+ !attribute.value.trim().startsWith("#") &&
+ !embeddedRaster) ||
+ /\\|url\s*\(/iu.test(references)
+ ) {
+ element.removeAttribute(attribute.name);
+ }
+ }
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d72ab404..e69e7d85 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -82,7 +82,7 @@ importers:
version: 8.66.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)
vitest:
specifier: ^4.1.10
- version: 4.1.10(@types/node@22.20.1)(happy-dom@20.11.2)(vite@8.3.4(@types/node@22.20.1)(jiti@2.7.0)(yaml@2.9.0))
+ version: 4.1.10(@types/node@22.20.1)(happy-dom@20.11.2)(jsdom@28.1.0(@noble/hashes@2.4.0))(vite@8.3.4(@types/node@22.20.1)(jiti@2.7.0)(yaml@2.9.0))
yaml:
specifier: ^2.9.0
version: 2.9.0
@@ -494,6 +494,9 @@ importers:
'@mdbase-reader/reading-surface':
specifier: workspace:*
version: link:../reading-surface
+ dompurify:
+ specifier: ^3.4.17
+ version: 3.4.17
react:
specifier: ^19.2.8
version: 19.2.8
@@ -504,6 +507,9 @@ importers:
happy-dom:
specifier: ^20.11.2
version: 20.11.2
+ jsdom:
+ specifier: 28.1.0
+ version: 28.1.0(@noble/hashes@2.4.0)
packages/renderer-pdf:
dependencies:
@@ -608,6 +614,23 @@ importers:
packages:
+ '@acemir/cssom@0.9.32':
+ resolution: {integrity: sha512-OijrAUu7rrJhSIoHNg6LMPS5e344nwUHA+1EFYYjrh64D+GmytUsfBQjci45TjT+rd5Spsp8B5xsZDT+TgyXXQ==}
+
+ '@asamuzakjp/css-color@5.1.11':
+ resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/dom-selector@6.8.1':
+ resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==}
+
+ '@asamuzakjp/generational-cache@1.0.1':
+ resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
+
'@babel/code-frame@7.29.7':
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
engines: {node: '>=6.9.0'}
@@ -679,6 +702,10 @@ packages:
resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==}
engines: {node: '>=6.9.0'}
+ '@bramus/specificity@2.4.3':
+ resolution: {integrity: sha512-0GEz8qJWokkUVYQYRukmkSHIFNoBH8QTreeHrAFbvz1XFYc3Y+puhMs8PQ5x8GNugiC2l5jvDBXKLbBIByeSBw==}
+ hasBin: true
+
'@callumalpass/mdbase@0.3.0-rc.9':
resolution: {integrity: sha512-bXYhTqRqd928j9osTFGQTmzKG59W1pelmBV+UaEF1WOL+E5WEQVl4sBKvvdGvBVD9VMAq7IF1zJTkr3gqNb4Mw==}
hasBin: true
@@ -767,6 +794,42 @@ packages:
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
engines: {node: '>=0.1.90'}
+ '@csstools/color-helpers@6.1.2':
+ resolution: {integrity: sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==}
+ engines: {node: '>=20.19.0'}
+
+ '@csstools/css-calc@3.4.3':
+ resolution: {integrity: sha512-iex20d8CHVkyvg6B7UKV7uHnI2Bqo9g+EFfT9E0y+GvTvhZ/DwONJ+9aKb1dlqm0ZiGsL5RXjp0fCoJYnkeDjA==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.2
+ '@csstools/css-tokenizer': ^4.0.2
+
+ '@csstools/css-color-parser@4.2.6':
+ resolution: {integrity: sha512-iiPQ3iRWwnJkeEn6RIu6SJPr7hYrLz6XZ9s/QZl+2/LI5KQVjpl2fdmDSZKuD4xP6GMmMPgHFFXg6k1Wkz0Trg==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.2
+ '@csstools/css-tokenizer': ^4.0.2
+
+ '@csstools/css-parser-algorithms@4.0.2':
+ resolution: {integrity: sha512-40cSKyMvK+tq4qz6Awrlye2WGuOKt3FwPgtGg6KTfbHOWNw+Rk1rzbAtZnZ6IBhsY491HLRnDXwoyBAijmmILA==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^4.0.2
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.15':
+ resolution: {integrity: sha512-J0u7HkVl2nzSlhsiTOp4AmwcUQ3D+mGEEKfBy/7To5/y7F2OHwyLrXfrhR0SMgr4p5Lo+eaMVSeai24zUcBIxA==}
+ peerDependencies:
+ css-tree: ^3.2.1
+ peerDependenciesMeta:
+ css-tree:
+ optional: true
+
+ '@csstools/css-tokenizer@4.0.2':
+ resolution: {integrity: sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==}
+ engines: {node: '>=20.19.0'}
+
'@electron-internal/extract-zip@1.0.4':
resolution: {integrity: sha512-Zr1Vs7E9tpCNhZHDAbFVXc2gEVCG9RqPDjrno5+bdgB6LRAuvgyMHJut4NCVyYwtAieapMzc3fiQ3CSTi75ARg==}
engines: {node: '>=22.12.0'}
@@ -1193,6 +1256,15 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@exodus/bytes@1.16.0':
+ resolution: {integrity: sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ '@noble/hashes': ^1.8.0 || ^2.0.0
+ peerDependenciesMeta:
+ '@noble/hashes':
+ optional: true
+
'@fontsource-variable/atkinson-hyperlegible-next@5.3.0':
resolution: {integrity: sha512-UnLzNUy1RWoLDfydAatP4NaRm99X/WbQEph7q/PymJnCFIOOwKOx3pBmp5ys8trO0dM+CKGuJgeZP9fAR4mQpA==}
@@ -1476,22 +1548,22 @@ packages:
'@lingui/react': 6.9.0
react: ^19.2.0
- '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-lab.tgz':
- resolution: {integrity: sha512-9z3vnOUNkKJHB0PGFNjoT7DJJmwcJs0k/GADCKESN/1YTcgEZJH5w0G746HTVBsC/RhX5h15ABkV9ifNDU9Hyw==, tarball: file:packages/connect/vendor/sdk-dev-eaa4e697-lab.tgz}
+ '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dce61ff5-production-beta141.tgz':
+ resolution: {integrity: sha512-qBmdxJVMeKh3nv4lWl6fOcwurW57BjxBESQHyhSpcFvgLCTBzpZwFayRXoCilIYC9H9tZXc7L+DhwelmEgxlzA==, tarball: file:packages/connect/vendor/sdk-dce61ff5-production-beta141.tgz}
version: 0.0.0
engines: {node: '>=20'}
bundledDependencies:
- '@mdbase-dev/connect-protocol'
- '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-staging.tgz':
- resolution: {integrity: sha512-OZcexDhkjwROq0pSf/rSV1aU9H2AArhB5S2/UQU4ZTYMqJz7mpOhSFznZKSjDh6nb4EVROvBS926O3+HUePbjA==, tarball: file:packages/connect/vendor/sdk-dev-eaa4e697-staging.tgz}
+ '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-lab.tgz':
+ resolution: {integrity: sha512-9z3vnOUNkKJHB0PGFNjoT7DJJmwcJs0k/GADCKESN/1YTcgEZJH5w0G746HTVBsC/RhX5h15ABkV9ifNDU9Hyw==, tarball: file:packages/connect/vendor/sdk-dev-eaa4e697-lab.tgz}
version: 0.0.0
engines: {node: '>=20'}
bundledDependencies:
- '@mdbase-dev/connect-protocol'
- '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dce61ff5-production-beta141.tgz':
- resolution: {integrity: sha512-qBmdxJVMeKh3nv4lWl6fOcwurW57BjxBESQHyhSpcFvgLCTBzpZwFayRXoCilIYC9H9tZXc7L+DhwelmEgxlzA==, tarball: file:packages/connect/vendor/sdk-dce61ff5-production-beta141.tgz}
+ '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-staging.tgz':
+ resolution: {integrity: sha512-OZcexDhkjwROq0pSf/rSV1aU9H2AArhB5S2/UQU4ZTYMqJz7mpOhSFznZKSjDh6nb4EVROvBS926O3+HUePbjA==, tarball: file:packages/connect/vendor/sdk-dev-eaa4e697-staging.tgz}
version: 0.0.0
engines: {node: '>=20'}
bundledDependencies:
@@ -2066,6 +2138,10 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
ajv-formats@3.0.1:
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
peerDependencies:
@@ -2179,6 +2255,9 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
+ bidi-js@1.1.0:
+ resolution: {integrity: sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==}
+
big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
engines: {node: '>=0.6'}
@@ -2323,6 +2402,10 @@ packages:
resolution: {integrity: sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==}
engines: {node: '>=20.19.0'}
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
css-what@8.0.0:
resolution: {integrity: sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==}
engines: {node: '>=20.19.0'}
@@ -2330,6 +2413,10 @@ packages:
cssom@0.5.0:
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
+ cssstyle@6.2.0:
+ resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==}
+ engines: {node: '>=20'}
+
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -2340,6 +2427,10 @@ packages:
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
engines: {node: '>= 12'}
+ data-urls@7.0.0:
+ resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@@ -2364,6 +2455,9 @@ packages:
supports-color:
optional: true
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -2424,6 +2518,9 @@ packages:
resolution: {integrity: sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==}
engines: {node: '>=20.19.0'}
+ dompurify@3.4.17:
+ resolution: {integrity: sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==}
+
domutils@3.2.2:
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
@@ -2829,12 +2926,24 @@ packages:
hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
+ html-encoding-sniffer@6.0.0:
+ resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
html-escaper@3.0.3:
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
htmlparser2@10.1.0:
resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==}
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -2946,6 +3055,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-reference@3.0.3:
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
@@ -3028,6 +3140,15 @@ packages:
resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==}
hasBin: true
+ jsdom@28.1.0:
+ resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -3193,6 +3314,10 @@ packages:
resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==}
engines: {node: 20 || >=22}
+ lru-cache@11.5.3:
+ resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==}
+ engines: {node: 20 || >=22}
+
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@@ -3206,6 +3331,9 @@ packages:
mathml-to-latex@1.8.0:
resolution: {integrity: sha512-gQ0uK3zqB8HwlfaXJkEL5rgaZNbKUiBMmBP/B/W+b+t6KcseLSuYb1b0BjLgS9ZiQa24ePkqTX8/6FaQuDL7wQ==}
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
@@ -3336,6 +3464,9 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parse5@8.0.1:
+ resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -3515,6 +3646,10 @@ packages:
resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==}
engines: {node: '>=11.0.0'}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
@@ -3688,6 +3823,9 @@ packages:
resolution: {integrity: sha512-PY8LOw7xP6c8IOiVqdo0sbbZVYhXRSfklOQLAUyGBKqjTX0wx/z4l/9J+PmBpmlLnxzEb1NqltxQ5/wZme/Cmg==}
engines: {node: '>=18'}
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
sync-fetch@0.6.0:
resolution: {integrity: sha512-IELLEvzHuCfc1uTsshPK58ViSdNqXxlml1U+fmwJIKLYKOr/rAtBrorE2RYm5IHaMpDNlmC0fr1LAvdXvyheEQ==}
engines: {node: '>=18'}
@@ -3729,10 +3867,25 @@ packages:
resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==}
engines: {node: '>=14.0.0'}
+ tldts-core@7.4.20:
+ resolution: {integrity: sha512-C630TWXZCZmLq0F2bW4QqwnaaxCQ/svpAqvJwnC4JvgEM5ohhBnGsEzTLSOXcN+xjz+kEaHS5uoWIw2klnqd0A==}
+
+ tldts@7.4.19:
+ resolution: {integrity: sha512-48dH6aSpQnpbzDUc4vIQZ1VjB8tkK+e8c1yx05/SZK+rkssgjEOlxDd/yU8/a4vGYQ9vRgJr9dwMq9TJ0b3X2Q==}
+ hasBin: true
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ tough-cookie@6.0.2:
+ resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==}
+ engines: {node: '>=16'}
+
+ tr46@6.0.0:
+ resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
+ engines: {node: '>=20'}
+
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -3942,10 +4095,18 @@ packages:
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
web-streams-polyfill@3.3.3:
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
engines: {node: '>= 8'}
+ webidl-conversions@8.0.1:
+ resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
+ engines: {node: '>=20'}
+
whatwg-mimetype@3.0.0:
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
engines: {node: '>=12'}
@@ -3954,6 +4115,14 @@ packages:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
+ whatwg-mimetype@5.0.0:
+ resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
+ engines: {node: '>=20'}
+
+ whatwg-url@16.0.1:
+ resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -4004,6 +4173,10 @@ packages:
resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==}
engines: {node: '>=10.0.0'}
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
xml-naming@0.3.0:
resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==}
engines: {node: '>=16.0.0'}
@@ -4020,6 +4193,9 @@ packages:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
@@ -4062,6 +4238,28 @@ packages:
snapshots:
+ '@acemir/cssom@0.9.32': {}
+
+ '@asamuzakjp/css-color@5.1.11':
+ dependencies:
+ '@asamuzakjp/generational-cache': 1.0.1
+ '@csstools/css-calc': 3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)
+ '@csstools/css-color-parser': 4.2.6(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)
+ '@csstools/css-parser-algorithms': 4.0.2(@csstools/css-tokenizer@4.0.2)
+ '@csstools/css-tokenizer': 4.0.2
+
+ '@asamuzakjp/dom-selector@6.8.1':
+ dependencies:
+ '@asamuzakjp/nwsapi': 2.3.9
+ bidi-js: 1.1.0
+ css-tree: 3.2.1
+ is-potential-custom-element-name: 1.0.1
+ lru-cache: 11.5.3
+
+ '@asamuzakjp/generational-cache@1.0.1': {}
+
+ '@asamuzakjp/nwsapi@2.3.9': {}
+
'@babel/code-frame@7.29.7':
dependencies:
'@babel/helper-validator-identifier': 7.29.7
@@ -4193,6 +4391,10 @@ snapshots:
'@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7
+ '@bramus/specificity@2.4.3':
+ dependencies:
+ css-tree: 3.2.1
+
'@callumalpass/mdbase@0.3.0-rc.9':
dependencies:
'@marcbachmann/cel-js': 8.0.0
@@ -4359,6 +4561,30 @@ snapshots:
'@colors/colors@1.5.0':
optional: true
+ '@csstools/color-helpers@6.1.2': {}
+
+ '@csstools/css-calc@3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 4.0.2(@csstools/css-tokenizer@4.0.2)
+ '@csstools/css-tokenizer': 4.0.2
+
+ '@csstools/css-color-parser@4.2.6(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)':
+ dependencies:
+ '@csstools/color-helpers': 6.1.2
+ '@csstools/css-calc': 3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)
+ '@csstools/css-parser-algorithms': 4.0.2(@csstools/css-tokenizer@4.0.2)
+ '@csstools/css-tokenizer': 4.0.2
+
+ '@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2)':
+ dependencies:
+ '@csstools/css-tokenizer': 4.0.2
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.15(css-tree@3.2.1)':
+ optionalDependencies:
+ css-tree: 3.2.1
+
+ '@csstools/css-tokenizer@4.0.2': {}
+
'@electron-internal/extract-zip@1.0.4': {}
'@electron/get@5.0.0':
@@ -4854,6 +5080,10 @@ snapshots:
'@eslint/core': 0.17.0
levn: 0.4.1
+ '@exodus/bytes@1.16.0(@noble/hashes@2.4.0)':
+ optionalDependencies:
+ '@noble/hashes': 2.4.0
+
'@fontsource-variable/atkinson-hyperlegible-next@5.3.0': {}
'@fontsource-variable/source-serif-4@5.3.1': {}
@@ -5245,19 +5475,19 @@ snapshots:
- rolldown
- supports-color
- '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-lab.tgz':
+ '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dce61ff5-production-beta141.tgz':
dependencies:
'@noble/ciphers': 2.4.0
'@noble/curves': 2.4.0
'@noble/hashes': 2.4.0
- '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-staging.tgz':
+ '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-lab.tgz':
dependencies:
'@noble/ciphers': 2.4.0
'@noble/curves': 2.4.0
'@noble/hashes': 2.4.0
- '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dce61ff5-production-beta141.tgz':
+ '@mdbase-dev/sdk@file:packages/connect/vendor/sdk-dev-eaa4e697-staging.tgz':
dependencies:
'@noble/ciphers': 2.4.0
'@noble/curves': 2.4.0
@@ -5788,6 +6018,8 @@ snapshots:
acorn@8.18.0: {}
+ agent-base@7.1.4: {}
+
ajv-formats@3.0.1(ajv@8.20.0):
optionalDependencies:
ajv: 8.20.0
@@ -5894,6 +6126,10 @@ snapshots:
baseline-browser-mapping@2.11.13: {}
+ bidi-js@1.1.0:
+ dependencies:
+ require-from-string: 2.0.2
+
big-integer@1.6.52: {}
boolbase@2.0.0:
@@ -6027,18 +6263,37 @@ snapshots:
nth-check: 3.0.1
optional: true
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.2
+
css-what@8.0.0:
optional: true
cssom@0.5.0:
optional: true
+ cssstyle@6.2.0:
+ dependencies:
+ '@asamuzakjp/css-color': 5.1.11
+ '@csstools/css-syntax-patches-for-csstree': 1.1.15(css-tree@3.2.1)
+ css-tree: 3.2.1
+ lru-cache: 11.5.3
+
csstype@3.2.3: {}
damerau-levenshtein@1.0.8: {}
data-uri-to-buffer@4.0.1: {}
+ data-urls@7.0.0(@noble/hashes@2.4.0):
+ dependencies:
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1(@noble/hashes@2.4.0)
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -6063,6 +6318,8 @@ snapshots:
dependencies:
ms: 2.1.3
+ decimal.js@10.6.0: {}
+
deep-is@0.1.4: {}
define-data-property@1.1.4:
@@ -6136,6 +6393,10 @@ snapshots:
domelementtype: 3.0.0
optional: true
+ dompurify@3.4.17:
+ optionalDependencies:
+ '@types/trusted-types': 2.0.7
+
domutils@3.2.2:
dependencies:
dom-serializer: 2.0.0
@@ -6650,6 +6911,12 @@ snapshots:
dependencies:
hermes-estree: 0.25.1
+ html-encoding-sniffer@6.0.0(@noble/hashes@2.4.0):
+ dependencies:
+ '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0)
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
html-escaper@3.0.3:
optional: true
@@ -6661,6 +6928,20 @@ snapshots:
entities: 7.0.1
optional: true
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
ignore@5.3.2: {}
ignore@7.0.6: {}
@@ -6763,6 +7044,8 @@ snapshots:
is-number@7.0.0: {}
+ is-potential-custom-element-name@1.0.1: {}
+
is-reference@3.0.3:
dependencies:
'@types/estree': 1.0.9
@@ -6844,6 +7127,33 @@ snapshots:
dependencies:
argparse: 2.0.1
+ jsdom@28.1.0(@noble/hashes@2.4.0):
+ dependencies:
+ '@acemir/cssom': 0.9.32
+ '@asamuzakjp/dom-selector': 6.8.1
+ '@bramus/specificity': 2.4.3
+ '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0)
+ cssstyle: 6.2.0
+ data-urls: 7.0.0(@noble/hashes@2.4.0)
+ decimal.js: 10.6.0
+ html-encoding-sniffer: 6.0.0(@noble/hashes@2.4.0)
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ is-potential-custom-element-name: 1.0.1
+ parse5: 8.0.1
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 6.0.2
+ undici: 7.29.0
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 8.0.1
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1(@noble/hashes@2.4.0)
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - '@noble/hashes'
+ - supports-color
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
@@ -6971,6 +7281,8 @@ snapshots:
lru-cache@11.5.2: {}
+ lru-cache@11.5.3: {}
+
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
@@ -6985,6 +7297,8 @@ snapshots:
dependencies:
'@xmldom/xmldom': 0.9.10
+ mdn-data@2.27.1: {}
+
micromatch@4.0.8:
dependencies:
braces: 3.0.3
@@ -7131,6 +7445,10 @@ snapshots:
dependencies:
callsites: 3.1.0
+ parse5@8.0.1:
+ dependencies:
+ entities: 8.1.0
+
path-exists@4.0.0: {}
path-expression-matcher@1.6.2: {}
@@ -7309,6 +7627,10 @@ snapshots:
sax@1.6.1: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
scheduler@0.27.0: {}
section-matter@1.0.0:
@@ -7515,6 +7837,8 @@ snapshots:
transitivePeerDependencies:
- '@typescript-eslint/types'
+ symbol-tree@3.2.4: {}
+
sync-fetch@0.6.0:
dependencies:
node-fetch: 3.3.2
@@ -7553,10 +7877,24 @@ snapshots:
tinyrainbow@3.1.1: {}
+ tldts-core@7.4.20: {}
+
+ tldts@7.4.19:
+ dependencies:
+ tldts-core: 7.4.20
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
+ tough-cookie@6.0.2:
+ dependencies:
+ tldts: 7.4.19
+
+ tr46@6.0.0:
+ dependencies:
+ punycode: 2.3.1
+
tree-kill@1.2.2: {}
ts-api-utils@2.5.0(typescript@5.9.3):
@@ -7720,7 +8058,7 @@ snapshots:
jiti: 2.7.0
yaml: 2.9.1
- vitest@4.1.10(@types/node@22.20.1)(happy-dom@20.11.2)(vite@8.3.4(@types/node@22.20.1)(jiti@2.7.0)(yaml@2.9.0)):
+ vitest@4.1.10(@types/node@22.20.1)(happy-dom@20.11.2)(jsdom@28.1.0(@noble/hashes@2.4.0))(vite@8.3.4(@types/node@22.20.1)(jiti@2.7.0)(yaml@2.9.0)):
dependencies:
'@vitest/expect': 4.1.10
'@vitest/mocker': 4.1.10(vite@8.3.4(@types/node@22.20.1)(jiti@2.7.0)(yaml@2.9.0))
@@ -7745,6 +8083,7 @@ snapshots:
optionalDependencies:
'@types/node': 22.20.1
happy-dom: 20.11.2
+ jsdom: 28.1.0(@noble/hashes@2.4.0)
transitivePeerDependencies:
- msw
@@ -7760,12 +8099,28 @@ snapshots:
w3c-keyname@2.2.8: {}
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
web-streams-polyfill@3.3.3: {}
+ webidl-conversions@8.0.1: {}
+
whatwg-mimetype@3.0.0: {}
whatwg-mimetype@4.0.0: {}
+ whatwg-mimetype@5.0.0: {}
+
+ whatwg-url@16.0.1(@noble/hashes@2.4.0):
+ dependencies:
+ '@exodus/bytes': 1.16.0(@noble/hashes@2.4.0)
+ tr46: 6.0.0
+ webidl-conversions: 8.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
@@ -7831,6 +8186,8 @@ snapshots:
simple-plist: 1.3.1
uuid: 7.0.3
+ xml-name-validator@5.0.0: {}
+
xml-naming@0.3.0: {}
xml2js@0.6.2:
@@ -7842,6 +8199,8 @@ snapshots:
xmlbuilder@15.1.1: {}
+ xmlchars@2.2.0: {}
+
yallist@3.1.1: {}
yallist@5.0.0: {}