diff --git a/.changeset/auto-transform-bible-html.md b/.changeset/auto-transform-bible-html.md new file mode 100644 index 00000000..49ba44e9 --- /dev/null +++ b/.changeset/auto-transform-bible-html.md @@ -0,0 +1,7 @@ +--- +"@youversion/platform-core": minor +"@youversion/platform-react-hooks": minor +"@youversion/platform-react-ui": minor +--- + +Auto-transform Bible HTML in `getPassage` — verse wrapping, footnote extraction, sanitization, and table fixes now happen automatically. Consumers no longer need to call `transformBibleHtml` manually. Uses native DOMParser in browser, dynamic `import('jsdom')` on server. `jsdom` is now declared as an optional peer dependency so install logs surface it for server consumers. Added `data-yv-transformed` idempotency marker so double-transforms are a no-op. Pass `transform: false` to receive raw, untransformed HTML (useful for simple display or when `jsdom` is unavailable); `usePassage` accepts the same `transform` option and forwards it. Bible reader CSS now handles verse label spacing for untransformed HTML automatically. diff --git a/packages/core/AGENTS.md b/packages/core/AGENTS.md index 3772860d..e2cb043b 100644 --- a/packages/core/AGENTS.md +++ b/packages/core/AGENTS.md @@ -7,9 +7,45 @@ Foundation package providing pure TypeScript API clients for YouVersion services - For React hooks wrapping these clients → see `packages/hooks/AGENTS.md` - For pre-built UI components → see `packages/ui/AGENTS.md` -The public API is whatever `src/index.ts`, `src/browser.ts`, and `src/server.ts` -export. Read those rather than a list here. Browser CSS ships from `src/styles/` -and is exported via `./browser/styles/*`. +## STRUCTURE +``` +schemas/ # Zod schemas for all data types (schema-first design) +styles/ # Browser CSS (exported via ./browser/styles/*) + fonts.css # Google Fonts import (Inter, Source Serif 4) + theme.css # --yv-* design tokens on :root, dark mode, scoped preflight + bible-reader.css # USFM/Bible typography for [data-slot='yv-bible-renderer'] + index.css # Barrel: imports fonts + theme + bible-reader +client.ts # ApiClient - main HTTP client +bible.ts # BibleClient - Bible data operations +languages.ts # LanguagesClient - language data +highlights.ts # HighlightsClient - user highlights +YouVersionAPI.ts # Base YouVersion API client +SignInWithYouVersionPKCE.ts # PKCE auth implementation +StorageStrategy.ts # Storage interface (SessionStorage, MemoryStorage) +bible-html-transformer.ts # Runtime-agnostic transformer (also contains browser convenience fn) +bible-html-transformer-server.ts # Server convenience wrapper (uses jsdom) +browser.ts # Browser entry point +server.ts # Server entry point +index.ts # Main entry point (runtime-agnostic) +``` + +## PUBLIC API + +### TypeScript (`@youversion/platform-core`) +- `ApiClient`: Main HTTP client with auth handling +- `BibleClient`: Fetch Bibles, chapters, verses, versions +- `LanguagesClient`: Get available languages +- `HighlightsClient`: Manage user highlights +- `SignInWithYouVersionPKCE()`: PKCE auth flow function +- `SessionStorage`, `MemoryStorage`: Storage strategies +- `transformBibleHtml`: Runtime-agnostic Bible HTML transformer (requires DOM adapters) +- `TransformBibleHtmlOptions`: Options for DOM parsing and serialization + +### Browser CSS (`@youversion/platform-core/browser/styles/*`) +- `index.css`: All-in-one import (fonts + theme + bible-reader) +- `theme.css`: `--yv-*` design tokens on `:root` + dark mode (`[data-yv-theme='dark']`) + scoped preflight +- `bible-reader.css`: USFM typography for `[data-slot='yv-bible-renderer']` or `[data-yv-sdk-bible-reader]` +- `fonts.css`: Google Fonts import (Inter, Source Serif 4) ## DOs / DON'Ts @@ -26,12 +62,35 @@ and is exported via `./browser/styles/*`. Three entry points, deliberately separate: -- `@youversion/platform-core` → runtime-agnostic `transformBibleHtml`, requires DOM adapters -- `@youversion/platform-core/browser` → convenience wrapper using native `DOMParser` -- `@youversion/platform-core/server` → convenience wrapper using `linkedom` +- `@youversion/platform-core` → Runtime-agnostic `transformBibleHtml` (requires DOM adapters) +- `@youversion/platform-core/browser` → Browser convenience wrapper (uses native DOMParser) +- `@youversion/platform-core/server` → Server convenience wrapper (uses jsdom) -The split keeps the main export runtime-agnostic and keeps `linkedom` out of -browser bundles. New DOM-touching code follows the same pattern. +**Examples:** + +```ts +// Runtime-agnostic (works anywhere with custom adapters) +import { transformBibleHtml } from '@youversion/platform-core'; + +const result = transformBibleHtml(html, { + parseHtml: (h) => new DOMParser().parseFromString(h, 'text/html'), + serializeHtml: (doc) => doc.body.innerHTML, +}); + +// Browser convenience (uses native DOMParser) +import { transformBibleHtml } from '@youversion/platform-core/browser'; + +const result = transformBibleHtml(html); + +// Server convenience (uses jsdom, requires: npm install jsdom) +import { transformBibleHtml } from '@youversion/platform-core/server'; + +const result = transformBibleHtml(html); +``` + +**Why separate entry points?** + +This architecture keeps the main export truly runtime-agnostic while providing ergonomic convenience wrappers for common environments. The separate `/browser` and `/server` entry points ensure optimal bundle sizes. `package.json` also maps `"browser": { "jsdom": false }` so Vite/Rollup client builds stub jsdom even when the main entry's dynamic `import('jsdom')` is present (Node-only path; browsers use native `DOMParser`). ## ADDING A NEW ENDPOINT OR CLIENT diff --git a/packages/core/package.json b/packages/core/package.json index e22a6cf2..4051b17d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -16,6 +16,9 @@ "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", + "browser": { + "jsdom": false + }, "exports": { ".": { "types": "./dist/index.d.ts", @@ -48,20 +51,21 @@ "devDependencies": { "@internal/eslint-config": "workspace:*", "@internal/tsconfig": "workspace:*", + "@types/jsdom": "^28.0.1", "@vitest/coverage-v8": "4.0.4", "dotenv-cli": "7.4.2", "eslint": "9.38.0", - "jsdom": "24.0.0", + "jsdom": "28.1.0", "msw": "2.11.6", "tsup": "8.5.0", "typescript": "5.9.3", "vitest": "4.0.4" }, "peerDependencies": { - "linkedom": "^0.18.12" + "jsdom": "^24.0.0 || ^28.0.0" }, "peerDependenciesMeta": { - "linkedom": { + "jsdom": { "optional": true } }, diff --git a/packages/core/src/__tests__/bible.test.ts b/packages/core/src/__tests__/bible.test.ts index 7f3b961f..38834f0f 100644 --- a/packages/core/src/__tests__/bible.test.ts +++ b/packages/core/src/__tests__/bible.test.ts @@ -507,18 +507,16 @@ describe('BibleClient', () => { }); describe('getPassage', () => { - it('should fetch a passage for a verse', async () => { + it('should fetch a passage for a verse and auto-transform HTML', async () => { const passage = await bibleClient.getPassage(111, 'GEN.1.1'); const { success } = BiblePassageSchema.safeParse(passage); expect(success).toBe(true); - expect(passage).toEqual({ - id: 'GEN.1.1', - content: - '
1In the beginning God created the heavens and the earth.
', - reference: 'Genesis 1:1', - }); + expect(passage.id).toBe('GEN.1.1'); + expect(passage.reference).toBe('Genesis 1:1'); + expect(passage.content).toContain('data-yv-transformed'); + expect(passage.content).toContain('In the beginning God created'); }); it('should fetch a passage for a chapter', async () => { @@ -534,13 +532,29 @@ describe('BibleClient', () => { it('should fetch a passage with html format by default', async () => { const passage = await bibleClient.getPassage(111, 'GEN.1.1'); - expect(passage.content).toContain('
'); + expect(passage.content).toContain(' { + it('should not transform text format', async () => { const passage = await bibleClient.getPassage(111, 'GEN.1.1', 'text'); expect(passage.content).not.toContain('
'); + expect(passage.content).not.toContain('data-yv-transformed'); + }); + + it('should skip transformation when transform is false', async () => { + const passage = await bibleClient.getPassage( + 111, + 'GEN.1.1', + 'html', + undefined, + undefined, + false, + ); + + expect(passage.content).toContain(' { @@ -548,14 +562,15 @@ describe('BibleClient', () => { expect(passage.id).toBe('ROM.1'); expect(passage.content).toContain('yv-h'); - expect(passage.content).not.toContain('yv-n'); + expect(passage.content).not.toContain('data-verse-footnote'); }); - it('should fetch a passage with include_notes', async () => { + it('should fetch a passage with include_notes and transform footnotes', async () => { const passage = await bibleClient.getPassage(111, 'ROM.1', 'html', undefined, true); expect(passage.id).toBe('ROM.1'); - expect(passage.content).toContain('yv-n'); + // Footnotes are transformed into data-verse-footnote anchors + expect(passage.content).toContain('data-verse-footnote'); expect(passage.content).not.toContain('yv-h'); }); @@ -563,7 +578,7 @@ describe('BibleClient', () => { const passage = await bibleClient.getPassage(111, 'ROM.1', 'html', true, true); expect(passage.id).toBe('ROM.1'); - expect(passage.content).toContain('yv-n'); + expect(passage.content).toContain('data-verse-footnote'); expect(passage.content).toContain('yv-h'); }); diff --git a/packages/core/src/bible-html-transformer-server.ts b/packages/core/src/bible-html-transformer-server.ts index e7e25911..6b42819c 100644 --- a/packages/core/src/bible-html-transformer-server.ts +++ b/packages/core/src/bible-html-transformer-server.ts @@ -1,4 +1,4 @@ -import { DOMParser } from 'linkedom'; +import { JSDOM } from 'jsdom'; import { transformBibleHtml as transformBibleHtmlWithAdapters, @@ -6,14 +6,11 @@ import { } from './bible-html-transformer'; /** - * Transforms Bible HTML for server environments using linkedom. + * Transforms Bible HTML for server environments using jsdom. * - * Import from `@youversion/platform-core/server` to avoid bundling linkedom + * Import from `@youversion/platform-core/server` to avoid bundling jsdom * in client-side builds. * - * linkedom requires HTML to be wrapped in body tags for `doc.body.innerHTML` - * to work correctly, so this function handles that wrapping automatically. - * * @param html - The raw Bible HTML from the YouVersion API * @returns The transformed HTML * @@ -28,10 +25,7 @@ import { export function transformBibleHtml(html: string): TransformedBibleHtml { return transformBibleHtmlWithAdapters(html, { parseHtml: (h: string) => - new DOMParser().parseFromString( - `${h}`, - 'text/html', - ) as unknown as Document, + new JSDOM(`${h}`).window.document, serializeHtml: (doc: Document) => doc.body.innerHTML, }); } diff --git a/packages/core/src/bible-html-transformer.server.test.ts b/packages/core/src/bible-html-transformer.server.test.ts index 3d4dc69a..1df9f0b6 100644 --- a/packages/core/src/bible-html-transformer.server.test.ts +++ b/packages/core/src/bible-html-transformer.server.test.ts @@ -5,7 +5,7 @@ import { describe, it, expect } from 'vitest'; import { transformBibleHtml } from './bible-html-transformer-server'; describe('transformBibleHtml', () => { - it('should transform HTML using linkedom', () => { + it('should transform HTML using jsdom', () => { const html = `
@@ -58,7 +58,7 @@ describe('transformBibleHtml', () => { const result = transformBibleHtml(html); - // linkedom may serialize attributes in different order than browsers + // jsdom may serialize attributes in different order than browsers expect(result.html).toContain('class="yv-v"'); expect(result.html).toContain('v="1"'); expect(result.html).toContain('v="2"'); @@ -77,8 +77,8 @@ describe('transformBibleHtml', () => { const result = transformBibleHtml(html); - // linkedom encodes non-breaking space as   instead of the raw character - expect(result.html).toMatch(/1(\u00A0| )/); + // jsdom may encode non-breaking space as   instead of the raw character + expect(result.html).toMatch(/1(\u00A0| | )/); }); it('should handle intro chapter footnotes', () => { @@ -137,7 +137,7 @@ describe('transformBibleHtml', () => { expect(result.html).toContain('Click me'); }); - it('should preserve safe Bible HTML through linkedom', () => { + it('should preserve safe Bible HTML through jsdom', () => { const html = `
Jesus said diff --git a/packages/core/src/bible-html-transformer.test.ts b/packages/core/src/bible-html-transformer.test.ts index fee794b1..01a6630f 100644 --- a/packages/core/src/bible-html-transformer.test.ts +++ b/packages/core/src/bible-html-transformer.test.ts @@ -308,8 +308,8 @@ describe('transformBibleHtml - sanitization', () => { const result = transformBibleHtml(html, createAdapters()); expect(result.html).not.toContain('onclick'); - expect(result.html).toContain('

'); - expect(result.html).toContain('Click me'); + // Tag-boundary match so we don't accept a false positive like `]*)?>Click me<\/p>/); }); it('should unwrap anchor tags (not in allowlist) preserving text', () => { @@ -336,7 +336,7 @@ describe('transformBibleHtml - sanitization', () => { const result = transformBibleHtml(html, createAdapters()); expect(result.html).not.toContain('style'); - expect(result.html).toContain('

'); + expect(result.html).toContain(' { expect(result.html).toContain('class="p"'); expect(result.html).toContain('class="wj"'); expect(result.html).toContain('colspan="2"'); - expect(result.html).toContain(''); + expect(result.html).toMatch(/]*)?>/); }); it('should unwrap unknown custom elements preserving text', () => { @@ -387,6 +387,68 @@ describe('transformBibleHtml - sanitization', () => { }); }); +describe('transformBibleHtml - idempotency', () => { + it('should add data-yv-transformed marker after transforming', () => { + const html = + '
1Text.
'; + const result = transformBibleHtml(html, createAdapters()); + + expect(result.html).toContain('data-yv-transformed'); + }); + + it('should short-circuit when HTML is already transformed', () => { + const html = + '
1Text.
'; + const first = transformBibleHtml(html, createAdapters()); + const second = transformBibleHtml(first.html, createAdapters()); + + expect(second.html).toBe(first.html); + }); + + it('should produce identical output when transformed twice (idempotent)', () => { + const html = + '
1Verse textA note.
'; + const first = transformBibleHtml(html, createAdapters()); + const second = transformBibleHtml(first.html, createAdapters()); + + expect(second.html).toBe(first.html); + }); + + it('should not short-circuit on untrusted nested data-yv-transformed', () => { + const html = + '
1TextA note.
'; + const result = transformBibleHtml(html, createAdapters()); + + expect(result.html).toContain('data-verse-footnote'); + expect(result.html).toMatch(/^]*\bdata-yv-transformed\b/); + }); + + it('should transform raw siblings when only the first top-level element is marked', () => { + const raw = + '
2SecondSibling note.
'; + const transformed = transformBibleHtml( + '
1First.
', + createAdapters(), + ); + + const result = transformBibleHtml(transformed.html + raw, createAdapters()); + + expect(result.html).toContain('data-verse-footnote'); + expect(result.html).toContain('Sibling note'); + }); + + it('should mark every top-level element so a multi-root fragment stays idempotent', () => { + const html = + '
1One.
' + + '
2Two.
'; + const first = transformBibleHtml(html, createAdapters()); + const second = transformBibleHtml(first.html, createAdapters()); + + expect(first.html.match(/data-yv-transformed/g)).toHaveLength(2); + expect(second.html).toBe(first.html); + }); +}); + describe('transformBibleHtmlForBrowser - DOMParser fallback', () => { it('should throw when DOMParser is unavailable', () => { const original = globalThis.DOMParser; diff --git a/packages/core/src/bible-html-transformer.ts b/packages/core/src/bible-html-transformer.ts index 448a26cc..826ee3b9 100644 --- a/packages/core/src/bible-html-transformer.ts +++ b/packages/core/src/bible-html-transformer.ts @@ -2,6 +2,8 @@ const NON_BREAKING_SPACE = '\u00A0'; const FOOTNOTE_KEY_ATTR = 'data-footnote-key'; +const TRANSFORMED_ATTR = 'data-yv-transformed'; + const NEEDS_SPACE_BEFORE = /^[^\s.,;:!?)}\]'"'»›]/; const ALLOWED_TAGS = new Set([ @@ -47,6 +49,10 @@ const DROP_ENTIRELY_TAGS = new Set([ const ALLOWED_ATTRS = new Set(['class', 'v', 'colspan', 'rowspan', 'dir', 'usfm']); +function topLevelElements(doc: Document): Element[] { + return doc.body ? Array.from(doc.body.children) : []; +} + function sanitizeBibleHtmlDocument(doc: Document): void { const root = doc.body ?? doc.documentElement; for (const el of Array.from(root.querySelectorAll('*'))) { @@ -339,6 +345,16 @@ export function transformBibleHtml( const doc = options.parseHtml(html); sanitizeBibleHtmlDocument(doc); + + // Only trust the marker when every top-level element carries it. A nested or + // partially-marked fragment (transformed HTML concatenated with raw HTML, or + // an untrusted data-yv-transformed preserved by the data-* allowlist) must + // still run verse wrapping and footnote extraction. + const roots = topLevelElements(doc); + if (roots.length > 0 && roots.every((el) => el.hasAttribute(TRANSFORMED_ATTR))) { + return { html: options.serializeHtml(doc) }; + } + wrapVerseContent(doc); assignFootnoteKeys(doc); @@ -348,6 +364,12 @@ export function transformBibleHtml( addNbspToVerseLabels(doc); fixIrregularTables(doc); + // Mark every top-level element so a later re-transform can tell the whole + // fragment came from here, not just its first sibling. + for (const el of topLevelElements(doc)) { + el.setAttribute(TRANSFORMED_ATTR, ''); + } + const transformedHtml = options.serializeHtml(doc); return { html: transformedHtml }; } diff --git a/packages/core/src/bible.ts b/packages/core/src/bible.ts index 918fdf3a..6cf1fa16 100644 --- a/packages/core/src/bible.ts +++ b/packages/core/src/bible.ts @@ -1,5 +1,6 @@ import { z } from 'zod'; import type { ApiClient } from './client'; +import { transformBibleHtml, type TransformBibleHtmlOptions } from './bible-html-transformer'; import { BibleVersionSchema } from './schemas'; import type { BibleBook, @@ -13,6 +14,36 @@ import type { VOTD, } from './types'; +async function getHtmlAdapters(): Promise { + if (typeof globalThis.DOMParser !== 'undefined') { + return { + parseHtml: (h) => + new globalThis.DOMParser().parseFromString(h, 'text/html') as unknown as Document, + serializeHtml: (doc) => doc.body.innerHTML, + }; + } + let jsdom; + try { + // Literal dynamic import is fine in Node. Client bundlers must not pull + // jsdom into browser graphs — see package.json "browser": { "jsdom": false }. + jsdom = await import('jsdom'); + } catch (err) { + const detail = err instanceof Error ? err.message : String(err); + throw new Error( + 'Server-side HTML transformation requires "jsdom". ' + + 'Install it as a dependency or pass transform: false to skip transformation. ' + + `Original error: ${detail}`, + { cause: err }, + ); + } + return { + parseHtml: (h) => + new jsdom.JSDOM(`${h}`).window + .document as unknown as Document, + serializeHtml: (doc) => doc.body.innerHTML, + }; +} + /** * Client for interacting with Bible API endpoints. */ @@ -234,18 +265,23 @@ export class BibleClient { /** * Fetches a passage (range of verses) from the Bible using the passages endpoint. - * This is the new API format that returns HTML-formatted content. * - * Note: The HTML returned from the API contains inline footnote content that should - * be transformed before rendering. Use `transformBibleHtml()` or - * `transformBibleHtmlForBrowser()` to clean up the HTML and extract footnotes. + * When format is "html" (the default), the returned content is automatically + * sanitized and transformed — verse content is wrapped for CSS targeting, + * footnotes are extracted into data attributes, and verse labels get + * non-breaking spaces. No manual call to `transformBibleHtml` is needed. * * @param versionId The version ID. * @param usfm The USFM reference (e.g., "JHN.3.1-2", "GEN.1", "JHN.3.16"). * @param format The format to return ("html" or "text", default: "html"). * @param include_headings Whether to include headings in the content. * @param include_notes Whether to include notes in the content. - * @returns The requested BiblePassage object with HTML content. + * @param transform Whether to auto-transform HTML content (default: `true`). + * Set to `false` to receive the original, untransformed HTML from the API. + * Raw HTML is sufficient for simple display (e.g., verse-of-the-day) where + * verse-level interactivity like highlighting or footnote popovers isn't + * needed. Also avoids the `jsdom` dependency on the server. + * @returns The requested BiblePassage object. * * @example * ```ts @@ -258,9 +294,11 @@ export class BibleClient { * // Get an entire chapter * const chapter = await bibleClient.getPassage(3034, "GEN.1"); * - * // Transform HTML before rendering - * const passage = await bibleClient.getPassage(3034, "JHN.3.16", "html", true, true); - * const transformed = transformBibleHtmlForBrowser(passage.content); + * // Get plain text (no transformation applied) + * const text = await bibleClient.getPassage(3034, "JHN.3.16", "text"); + * + * // Get raw, untransformed HTML (no jsdom needed on server) + * const raw = await bibleClient.getPassage(3034, "JHN.3.16", "html", undefined, undefined, false); * ``` */ async getPassage( @@ -269,6 +307,7 @@ export class BibleClient { format: 'html' | 'text' = 'html', include_headings?: boolean, include_notes?: boolean, + transform?: boolean, ): Promise { BibleClient.versionIdSchema.parse(versionId); if (include_headings !== undefined) { @@ -286,7 +325,18 @@ export class BibleClient { if (include_notes !== undefined) { params.include_notes = include_notes; } - return this.client.get(`/v1/bibles/${versionId}/passages/${usfm}`, params); + const passage = await this.client.get( + `/v1/bibles/${versionId}/passages/${usfm}`, + params, + ); + + if (format === 'html' && transform !== false) { + const adapters = await getHtmlAdapters(); + const { html } = transformBibleHtml(passage.content, adapters); + return { ...passage, content: html }; + } + + return passage; } /** diff --git a/packages/core/src/styles/bible-reader.css b/packages/core/src/styles/bible-reader.css index abeb637d..27d90016 100644 --- a/packages/core/src/styles/bible-reader.css +++ b/packages/core/src/styles/bible-reader.css @@ -89,6 +89,12 @@ font-family: var(--yv-font-sans); } + /* When content hasn't been JS-transformed, add spacing after verse labels via CSS. + Transformed HTML already has a \u00A0 inserted by addNbspToVerseLabels(). */ + &:not(:has([data-yv-transformed])) .yv-vlbl::after { + content: "\00A0"; + } + /* \f - Footnote container (YouVersion wrapper) */ & .yv-n { display: none; diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts index 617608e2..a2e8c7da 100644 --- a/packages/core/tsup.config.ts +++ b/packages/core/tsup.config.ts @@ -17,6 +17,8 @@ export default defineConfig({ entry: ['src/index.ts', 'src/browser.ts', 'src/server.ts'], format: ['cjs', 'esm'], dts: true, + // Keep Node-only peer out of published bundles; loaded at runtime on server. + external: ['jsdom'], env: { YVP_PUBLISH_BUILD: isPublishBuild ? 'true' : '', }, diff --git a/packages/hooks/src/usePassage.test.tsx b/packages/hooks/src/usePassage.test.tsx index 88e81290..11b0b074 100644 --- a/packages/hooks/src/usePassage.test.tsx +++ b/packages/hooks/src/usePassage.test.tsx @@ -46,7 +46,25 @@ describe('usePassage', () => { expect(result.current.loading).toBe(false); }); - expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', false, false); + expect + .soft(mockGetPassage) + .toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', false, false, true); + }); + + it('should forward transform: false so callers can opt out of HTML transformation', async () => { + const wrapper = createYVWrapper(); + const { result } = renderHook( + () => usePassage({ versionId: 3034, usfm: 'JHN.3.16', transform: false }), + { wrapper }, + ); + + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + expect + .soft(mockGetPassage) + .toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', false, false, false); }); }); @@ -76,7 +94,9 @@ describe('usePassage', () => { expect(result.current.loading).toBe(false); }); - expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3.16', 'text', false, false); + expect + .soft(mockGetPassage) + .toHaveBeenCalledWith(3034, 'JHN.3.16', 'text', false, false, true); }); }); @@ -92,7 +112,7 @@ describe('usePassage', () => { expect(result.current.loading).toBe(false); }); - expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', true, false); + expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', true, false, true); }); it('should pass include_notes=true', async () => { @@ -106,7 +126,7 @@ describe('usePassage', () => { expect(result.current.loading).toBe(false); }); - expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', false, true); + expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3.16', 'html', false, true, true); }); it('should pass all options combined', async () => { @@ -127,7 +147,7 @@ describe('usePassage', () => { expect(result.current.loading).toBe(false); }); - expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3', 'text', true, true); + expect.soft(mockGetPassage).toHaveBeenCalledWith(3034, 'JHN.3', 'text', true, true, true); }); }); @@ -139,8 +159,8 @@ describe('usePassage', () => { usePassage({ versionId: val as number, usfm: 'JHN.3.16' }), initial: { val: 1 }, updated: { val: 3034 }, - expectedInitial: [1, 'JHN.3.16', 'html', false, false], - expectedUpdated: [3034, 'JHN.3.16', 'html', false, false], + expectedInitial: [1, 'JHN.3.16', 'html', false, false, true], + expectedUpdated: [3034, 'JHN.3.16', 'html', false, false, true], }, { param: 'usfm', @@ -148,8 +168,8 @@ describe('usePassage', () => { usePassage({ versionId: 3034, usfm: val as string }), initial: { val: 'JHN.3.16' }, updated: { val: 'GEN.1.1' }, - expectedInitial: [3034, 'JHN.3.16', 'html', false, false], - expectedUpdated: [3034, 'GEN.1.1', 'html', false, false], + expectedInitial: [3034, 'JHN.3.16', 'html', false, false, true], + expectedUpdated: [3034, 'GEN.1.1', 'html', false, false, true], }, { param: 'format', @@ -157,8 +177,8 @@ describe('usePassage', () => { usePassage({ versionId: 3034, usfm: 'JHN.3.16', format: val as 'html' | 'text' }), initial: { val: 'html' }, updated: { val: 'text' }, - expectedInitial: [3034, 'JHN.3.16', 'html', false, false], - expectedUpdated: [3034, 'JHN.3.16', 'text', false, false], + expectedInitial: [3034, 'JHN.3.16', 'html', false, false, true], + expectedUpdated: [3034, 'JHN.3.16', 'text', false, false, true], }, ])( 'should refetch when $param changes', diff --git a/packages/hooks/src/usePassage.ts b/packages/hooks/src/usePassage.ts index 1be29191..bbdaf6e4 100644 --- a/packages/hooks/src/usePassage.ts +++ b/packages/hooks/src/usePassage.ts @@ -10,6 +10,12 @@ type usePassageProps = { format?: 'html' | 'text'; include_headings?: boolean; include_notes?: boolean; + /** + * Whether to auto-transform HTML content (default: `true`). Set to `false` + * to receive the original, untransformed HTML from the API — useful when + * running outside a DOM environment without the optional `jsdom` peer. + */ + transform?: boolean; options?: UseApiDataOptions; }; @@ -19,6 +25,7 @@ export function usePassage({ format = 'html', include_headings = false, include_notes = false, + transform = true, options, }: usePassageProps): { passage: BiblePassage | null; @@ -32,8 +39,9 @@ export function usePassage({ const isValidUsfm = Boolean(usfm) && usfm !== 'undefined' && usfm !== 'null'; const { data, loading, error, refetch } = useApiData( - () => bibleClient.getPassage(versionId, usfm, format, include_headings, include_notes), - [bibleClient, versionId, usfm, format, include_headings, include_notes], + () => + bibleClient.getPassage(versionId, usfm, format, include_headings, include_notes, transform), + [bibleClient, versionId, usfm, format, include_headings, include_notes, transform], { enabled: options?.enabled !== false && isValidUsfm }, ); diff --git a/packages/ui/package.json b/packages/ui/package.json index b9797d86..3ab2dd8e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -18,6 +18,9 @@ "module": "./dist/index.js", "style": "./dist/tailwind.css", "types": "./dist/index.d.ts", + "browser": { + "jsdom": false + }, "files": [ "dist", "README.md", diff --git a/packages/ui/src/components/verse.tsx b/packages/ui/src/components/verse.tsx index d0f36068..94471036 100644 --- a/packages/ui/src/components/verse.tsx +++ b/packages/ui/src/components/verse.tsx @@ -477,9 +477,8 @@ export const Verse = { }: VerseHtmlProps, ref, ): ReactNode => { - // transformBibleHtml uses the browser's native DOMParser, which doesn't - // exist during SSR. Return raw html on the server; the client-side - // useLayoutEffect in BibleTextHtml will handle it after hydration. + // SSR safety: DOMParser doesn't exist during server render. + // Idempotent — already-transformed HTML from getPassage is a no-op. const transformedHtml = useMemo( () => (typeof window === 'undefined' ? html : transformBibleHtml(html).html), [html], diff --git a/packages/ui/src/i18n/index.ts b/packages/ui/src/i18n/index.ts index 600470b9..24275595 100644 --- a/packages/ui/src/i18n/index.ts +++ b/packages/ui/src/i18n/index.ts @@ -5,7 +5,6 @@ import { resources, supportedLngs } from './resources.generated'; export { resources, supportedLngs }; - const defaultNS = 'translation'; const BRAND_NAME = 'YouVersion'; /** Used when a key/locale is missing or browser language is unsupported — not the active UI language. */ diff --git a/packages/ui/tsup.config.ts b/packages/ui/tsup.config.ts index 0880d7ec..21c59b5e 100644 --- a/packages/ui/tsup.config.ts +++ b/packages/ui/tsup.config.ts @@ -20,8 +20,9 @@ export default defineConfig({ // building here, and why the env var is scoped to that command alone. See // packages/core/tsup.config.ts. noExternal: ['@youversion/platform-core'], - // Consumers provide these: - external: ['react', 'react/jsx-runtime', 'react-dom'], + // Consumers provide these. jsdom is Node-only (optional peer of platform-core); + // never inline it into the UI browser bundle. + external: ['react', 'react/jsx-runtime', 'react-dom', 'jsdom'], dts: false, // types come from `tsc` + API Extractor // Embed built Tailwind CSS as a global constant for runtime injection // Users don't need to manually import the CSS file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52c43ee8..06c9e1bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -148,9 +148,6 @@ importers: packages/core: dependencies: - linkedom: - specifier: ^0.18.12 - version: 0.18.12 zod: specifier: 4.1.12 version: 4.1.12 @@ -161,6 +158,9 @@ importers: '@internal/tsconfig': specifier: workspace:* version: link:../../tools/tsconfig + '@types/jsdom': + specifier: ^28.0.1 + version: 28.0.3 '@vitest/coverage-v8': specifier: 4.0.4 version: 4.0.4(@vitest/browser@4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1))(vitest@4.0.4))(vitest@4.0.4) @@ -171,8 +171,8 @@ importers: specifier: 9.38.0 version: 9.38.0(jiti@2.6.1) jsdom: - specifier: 24.0.0 - version: 24.0.0 + specifier: 28.1.0 + version: 28.1.0(@noble/hashes@1.8.0) msw: specifier: 2.11.6 version: 2.11.6(@types/node@24.11.0)(typescript@5.9.3) @@ -184,7 +184,7 @@ importers: version: 5.9.3 vitest: specifier: 4.0.4 - version: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@24.0.0)(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) + version: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) packages/hooks: dependencies: @@ -426,6 +426,9 @@ importers: packages: + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} @@ -433,15 +436,23 @@ packages: resolution: {integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==} hasBin: true - '@asamuzakjp/css-color@3.2.0': - resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - '@asamuzakjp/css-color@4.0.5': resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==} + '@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.7.3': resolution: {integrity: sha512-kiGFeY+Hxf5KbPpjRLf+ffWbkos1aGo8MBfd91oxS3O57RgU3XhZrt/6UzoVF9VMpWbC3v87SRc9jxGrc9qHtQ==} + '@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==} @@ -678,6 +689,10 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@changesets/apply-release-plan@7.0.13': resolution: {integrity: sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg==} @@ -806,6 +821,10 @@ packages: resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} + '@csstools/color-helpers@6.1.0': + resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} + engines: {node: '>=20.19.0'} + '@csstools/css-calc@2.1.4': resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} engines: {node: '>=18'} @@ -813,6 +832,13 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-calc@3.3.0': + resolution: {integrity: sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-color-parser@3.1.0': resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} engines: {node: '>=18'} @@ -820,22 +846,47 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-color-parser@4.1.10': + resolution: {integrity: sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms@3.0.5': resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} engines: {node: '>=18'} peerDependencies: '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-syntax-patches-for-csstree@1.0.14': resolution: {integrity: sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==} engines: {node: '>=18'} peerDependencies: postcss: ^8.4 + '@csstools/css-syntax-patches-for-csstree@1.1.7': + resolution: {integrity: sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@dotenvx/dotenvx@1.52.0': resolution: {integrity: sha512-CaQcc8JvtzQhUSm9877b6V4Tb7HCotkcyud9X2YwdqtQKwgljkMRwU96fVYKnzN3V0Hj74oP7Es+vZ0mS+Aa1w==} hasBin: true @@ -1231,6 +1282,15 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + 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 + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -2993,6 +3053,9 @@ packages: '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + '@types/jsdom@28.0.3': + resolution: {integrity: sha512-/HQ2uFoetFTXuye8vzIcHw2z6Fwi7Hi/qcgC+RoS9NCyewiqxhVGqlG+ViGB6lkax481R6dmhf1I7lIGlzJStQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -3025,6 +3088,9 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/validate-npm-package-name@4.0.2': resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} @@ -3335,9 +3401,6 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -3371,9 +3434,6 @@ packages: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -3516,10 +3576,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -3621,17 +3677,10 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - css-tree@3.1.0: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} - css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} @@ -3640,17 +3689,14 @@ packages: engines: {node: '>=4'} hasBin: true - cssom@0.5.0: - resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} - - cssstyle@4.6.0: - resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} - engines: {node: '>=18'} - cssstyle@5.3.1: resolution: {integrity: sha512-g5PC9Aiph9eiczFpcgUhd9S4UUO3F+LHGRIi5NUMZ+4xtoIYbHNZwZnWA2JsFGe8OU8nl4WyaEFiZuGuxlutJQ==} engines: {node: '>=20'} + cssstyle@6.2.0: + resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==} + engines: {node: '>=20'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -3662,14 +3708,14 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} - data-urls@6.0.0: resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} engines: {node: '>=20'} + 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'} @@ -3742,10 +3788,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -3792,19 +3834,6 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -3878,18 +3907,10 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} - entities@7.0.1: - resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} - engines: {node: '>=0.12'} - env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -4191,10 +4212,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.4: - resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} - engines: {node: '>= 6'} - formatly@0.3.0: resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} engines: {node: '>=18.3.0'} @@ -4412,18 +4429,16 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + 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@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - html-escaper@3.0.3: - resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} - html-parse-stringify@3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} - htmlparser2@10.1.0: - resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -4778,18 +4793,18 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsdom@24.0.0: - resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==} - engines: {node: '>=18'} + jsdom@27.0.1: + resolution: {integrity: sha512-SNSQteBL1IlV2zqhwwolaG9CwhIhTvVHWg3kTss/cLE7H/X4644mtPQqYvCfsSrGQWt9hSZcgOXX8bOZaMN+kA==} + engines: {node: '>=20'} peerDependencies: - canvas: ^2.11.2 + canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true - jsdom@27.0.1: - resolution: {integrity: sha512-SNSQteBL1IlV2zqhwwolaG9CwhIhTvVHWg3kTss/cLE7H/X4644mtPQqYvCfsSrGQWt9hSZcgOXX8bOZaMN+kA==} - engines: {node: '>=20'} + 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: @@ -5016,15 +5031,6 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - linkedom@0.18.12: - resolution: {integrity: sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==} - engines: {node: '>=16'} - peerDependencies: - canvas: '>= 2' - peerDependenciesMeta: - canvas: - optional: true - lint-staged@16.2.5: resolution: {integrity: sha512-o36wH3OX0jRWqDw5dOa8a8x6GXTKaLM+LvhRaucZxez0IxA+KNDUCiyjBfNgsMNmchwSX6urLSL7wShcUqAang==} engines: {node: '>=20.17'} @@ -5113,6 +5119,10 @@ packages: resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -5193,18 +5203,10 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - mime-db@1.54.0: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mime-types@3.0.2: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} @@ -5339,12 +5341,6 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - nwsapi@2.2.22: - resolution: {integrity: sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -5478,9 +5474,6 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - parse5@8.0.0: resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} @@ -5659,9 +5652,6 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -5673,9 +5663,6 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -5814,9 +5801,6 @@ packages: resolution: {integrity: sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==} engines: {node: '>=0.10.5'} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -5870,9 +5854,6 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} - rrweb-cssom@0.6.0: - resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -6268,10 +6249,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@4.1.4: - resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} - engines: {node: '>=6'} - tough-cookie@6.0.0: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} @@ -6283,10 +6260,6 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} - tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} @@ -6426,9 +6399,6 @@ packages: ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - uhyphen@0.2.0: - resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} - unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -6436,6 +6406,13 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.29.0: + resolution: {integrity: sha512-vamA8dGlzMwhpyYpQp9d8vka3o4D/yn5I7ez7Or+msDA4bZ8Uh+Zy91WvWf3I73gDAkFha9JcYRqm2li0Npfgg==} + + undici@7.29.0: + resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} + engines: {node: '>=20.18.1'} + unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} @@ -6448,10 +6425,6 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -6482,9 +6455,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -6642,14 +6612,14 @@ packages: webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - webidl-conversions@8.0.0: resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} engines: {node: '>=20'} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} @@ -6662,14 +6632,18 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} whatwg-url@15.1.0: resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} engines: {node: '>=20'} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} @@ -6815,6 +6789,8 @@ packages: snapshots: + '@acemir/cssom@0.9.31': {} + '@adobe/css-tools@4.4.4': {} '@antfu/ni@25.0.0': @@ -6824,14 +6800,6 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 - '@asamuzakjp/css-color@3.2.0': - dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 - '@asamuzakjp/css-color@4.0.5': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -6840,6 +6808,14 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 11.2.1 + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.10(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@asamuzakjp/dom-selector@6.7.3': dependencies: '@asamuzakjp/nwsapi': 2.3.9 @@ -6848,6 +6824,16 @@ snapshots: is-potential-custom-element-name: 1.0.1 lru-cache: 11.2.2 + '@asamuzakjp/dom-selector@6.8.1': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.2 + + '@asamuzakjp/generational-cache@1.0.1': {} + '@asamuzakjp/nwsapi@2.3.9': {} '@babel/code-frame@7.27.1': @@ -7216,6 +7202,10 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.1.0 + '@changesets/apply-release-plan@7.0.13': dependencies: '@changesets/config': 3.1.1 @@ -7472,11 +7462,18 @@ snapshots: '@csstools/color-helpers@5.1.0': {} + '@csstools/color-helpers@6.1.0': {} + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/color-helpers': 5.1.0 @@ -7484,16 +7481,33 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-color-parser@4.1.10(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.1.0 + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-syntax-patches-for-csstree@1.0.14(postcss@8.5.6)': dependencies: postcss: 8.5.6 + '@csstools/css-syntax-patches-for-csstree@1.1.7(css-tree@3.1.0)': + optionalDependencies: + css-tree: 3.1.0 + '@csstools/css-tokenizer@3.0.4': {} + '@csstools/css-tokenizer@4.0.0': {} + '@dotenvx/dotenvx@1.52.0': dependencies: commander: 11.1.0 @@ -7760,6 +7774,10 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@exodus/bytes@1.15.1(@noble/hashes@1.8.0)': + optionalDependencies: + '@noble/hashes': 1.8.0 + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -9535,6 +9553,13 @@ snapshots: '@types/istanbul-lib-coverage@2.0.6': {} + '@types/jsdom@28.0.3': + dependencies: + '@types/node': 24.11.0 + '@types/tough-cookie': 4.0.5 + parse5: 8.0.0 + undici-types: 7.29.0 + '@types/json-schema@7.0.15': {} '@types/mdx@2.0.13': {} @@ -9565,6 +9590,8 @@ snapshots: '@types/statuses@2.0.6': {} + '@types/tough-cookie@4.0.5': {} + '@types/validate-npm-package-name@4.0.2': {} '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': @@ -9751,7 +9778,7 @@ snapshots: '@vitest/mocker': 4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1)) playwright: 1.56.1 tinyrainbow: 3.0.3 - vitest: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@24.0.0)(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) + vitest: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) transitivePeerDependencies: - bufferutil - msw @@ -9781,7 +9808,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@24.0.0)(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) + vitest: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) ws: 8.18.3 transitivePeerDependencies: - bufferutil @@ -9820,7 +9847,7 @@ snapshots: magicast: 0.3.5 std-env: 3.9.0 tinyrainbow: 3.0.3 - vitest: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@24.0.0)(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) + vitest: 4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1) optionalDependencies: '@vitest/browser': 4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1))(vitest@4.0.4) transitivePeerDependencies: @@ -10103,8 +10130,6 @@ snapshots: async-function@1.0.0: {} - asynckit@0.4.0: {} - available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -10141,8 +10166,6 @@ snapshots: transitivePeerDependencies: - supports-color - boolbase@1.0.0: {} - brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -10278,10 +10301,6 @@ snapshots: colorette@2.0.20: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@11.1.0: {} commander@14.0.1: {} @@ -10369,32 +10388,15 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-select@5.2.2: - dependencies: - boolbase: 1.0.0 - css-what: 6.2.2 - domhandler: 5.0.3 - domutils: 3.2.2 - nth-check: 2.1.1 - css-tree@3.1.0: dependencies: mdn-data: 2.12.2 source-map-js: 1.2.1 - css-what@6.2.2: {} - css.escape@1.5.1: {} cssesc@3.0.0: {} - cssom@0.5.0: {} - - cssstyle@4.6.0: - dependencies: - '@asamuzakjp/css-color': 3.2.0 - rrweb-cssom: 0.8.0 - cssstyle@5.3.1(postcss@8.5.6): dependencies: '@asamuzakjp/css-color': 4.0.5 @@ -10403,22 +10405,31 @@ snapshots: transitivePeerDependencies: - postcss + cssstyle@6.2.0: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@csstools/css-syntax-patches-for-csstree': 1.1.7(css-tree@3.1.0) + css-tree: 3.1.0 + lru-cache: 11.5.2 + csstype@3.1.3: {} dargs@8.1.0: {} data-uri-to-buffer@4.0.1: {} - data-urls@5.0.0: - dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - data-urls@6.0.0: dependencies: whatwg-mimetype: 4.0.0 whatwg-url: 15.1.0 + data-urls@7.0.0(@noble/hashes@1.8.0): + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@1.8.0) + transitivePeerDependencies: + - '@noble/hashes' + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -10476,8 +10487,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - delayed-stream@1.0.0: {} - depd@2.0.0: {} dequal@2.0.3: {} @@ -10508,24 +10517,6 @@ snapshots: dom-accessibility-api@0.6.3: {} - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - dot-prop@5.3.0: dependencies: is-obj: 2.0.0 @@ -10591,12 +10582,8 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - entities@4.5.0: {} - entities@6.0.1: {} - entities@7.0.1: {} - env-paths@2.2.1: {} environment@1.1.0: {} @@ -11145,14 +11132,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.4: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - formatly@0.3.0: dependencies: fd-package-json: 2.0.0 @@ -11369,21 +11348,18 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 - html-escaper@2.0.2: {} + html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0): + dependencies: + '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) + transitivePeerDependencies: + - '@noble/hashes' - html-escaper@3.0.3: {} + html-escaper@2.0.2: {} html-parse-stringify@3.0.1: dependencies: void-elements: 3.1.0 - htmlparser2@10.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 7.0.1 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -11395,7 +11371,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -11711,61 +11687,60 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@24.0.0: + jsdom@27.0.1(postcss@8.5.6): dependencies: - cssstyle: 4.6.0 - data-urls: 5.0.0 + '@asamuzakjp/dom-selector': 6.7.3 + cssstyle: 5.3.1(postcss@8.5.6) + data-urls: 6.0.0 decimal.js: 10.6.0 - form-data: 4.0.4 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.22 - parse5: 7.3.0 - rrweb-cssom: 0.6.0 + parse5: 8.0.0 + rrweb-cssom: 0.8.0 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 4.1.4 + tough-cookie: 6.0.0 w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 + webidl-conversions: 8.0.0 whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 + whatwg-url: 15.1.0 ws: 8.18.3 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil + - postcss - supports-color - utf-8-validate - jsdom@27.0.1(postcss@8.5.6): + jsdom@28.1.0(@noble/hashes@1.8.0): dependencies: - '@asamuzakjp/dom-selector': 6.7.3 - cssstyle: 5.3.1(postcss@8.5.6) - data-urls: 6.0.0 + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.8.1 + '@bramus/specificity': 2.4.2 + '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) + cssstyle: 6.2.0 + data-urls: 7.0.0(@noble/hashes@1.8.0) decimal.js: 10.6.0 - html-encoding-sniffer: 4.0.0 + html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 parse5: 8.0.0 - rrweb-cssom: 0.8.0 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 6.0.0 + tough-cookie: 6.0.1 + undici: 7.29.0 w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.18.3 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@1.8.0) xml-name-validator: 5.0.0 transitivePeerDependencies: - - bufferutil - - postcss + - '@noble/hashes' - supports-color - - utf-8-validate jsesc@3.1.0: {} @@ -11934,14 +11909,6 @@ snapshots: lines-and-columns@1.2.4: {} - linkedom@0.18.12: - dependencies: - css-select: 5.2.2 - cssom: 0.5.0 - html-escaper: 3.0.3 - htmlparser2: 10.1.0 - uhyphen: 0.2.0 - lint-staged@16.2.5: dependencies: commander: 14.0.1 @@ -12028,6 +11995,8 @@ snapshots: lru-cache@11.2.2: {} + lru-cache@11.5.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -12087,14 +12056,8 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.52.0: {} - mime-db@1.54.0: {} - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mime-types@3.0.2: dependencies: mime-db: 1.54.0 @@ -12236,12 +12199,6 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - nwsapi@2.2.22: {} - object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -12418,10 +12375,6 @@ snapshots: parse-ms@4.0.0: {} - parse5@7.3.0: - dependencies: - entities: 6.0.1 - parse5@8.0.0: dependencies: entities: 6.0.1 @@ -12449,7 +12402,7 @@ snapshots: path-scurry@2.0.0: dependencies: - lru-cache: 11.2.1 + lru-cache: 11.2.2 minipass: 7.1.2 path-scurry@2.0.2: @@ -12556,10 +12509,6 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - psl@1.15.0: - dependencies: - punycode: 2.3.1 - punycode@2.3.1: {} qs@6.15.0: @@ -12568,8 +12517,6 @@ snapshots: quansync@0.2.11: {} - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} radix-ui@1.4.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.2(react@19.1.2))(react@19.1.2): @@ -12764,8 +12711,6 @@ snapshots: requireindex@1.1.0: {} - requires-port@1.0.0: {} - resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -12843,8 +12788,6 @@ snapshots: transitivePeerDependencies: - supports-color - rrweb-cssom@0.6.0: {} - rrweb-cssom@0.8.0: {} run-applescript@7.1.0: {} @@ -13310,13 +13253,6 @@ snapshots: totalist@3.0.1: {} - tough-cookie@4.1.4: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tough-cookie@6.0.0: dependencies: tldts: 7.0.17 @@ -13329,10 +13265,6 @@ snapshots: dependencies: punycode: 2.3.1 - tr46@5.1.1: - dependencies: - punycode: 2.3.1 - tr46@6.0.0: dependencies: punycode: 2.3.1 @@ -13526,8 +13458,6 @@ snapshots: ufo@1.6.1: {} - uhyphen@0.2.0: {} - unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -13537,14 +13467,16 @@ snapshots: undici-types@7.16.0: {} + undici-types@7.29.0: {} + + undici@7.29.0: {} + unicorn-magic@0.1.0: {} unicorn-magic@0.3.0: {} universalify@0.1.2: {} - universalify@0.2.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -13574,11 +13506,6 @@ snapshots: dependencies: punycode: 2.3.1 - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - use-callback-ref@1.3.3(@types/react@19.1.2)(react@19.1.2): dependencies: react: 19.1.2 @@ -13647,10 +13574,10 @@ snapshots: '@types/react': 19.1.2 '@types/react-dom': 19.1.2(@types/react@19.1.2) - vitest@4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@24.0.0)(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1): + vitest@4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@27.0.1(postcss@8.5.6))(lightningcss@1.31.1)(msw@2.13.4(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.4 - '@vitest/mocker': 4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1)) + '@vitest/mocker': 4.0.4(msw@2.13.4(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1)) '@vitest/pretty-format': 4.0.4 '@vitest/runner': 4.0.4 '@vitest/snapshot': 4.0.4 @@ -13671,8 +13598,8 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.11.0 - '@vitest/browser-playwright': 4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(playwright@1.56.1)(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1))(vitest@4.0.4) - jsdom: 24.0.0 + '@vitest/browser-playwright': 4.0.4(msw@2.13.4(@types/node@24.11.0)(typescript@5.9.3))(playwright@1.56.1)(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1))(vitest@4.0.4) + jsdom: 27.0.1(postcss@8.5.6) transitivePeerDependencies: - jiti - less @@ -13687,10 +13614,10 @@ snapshots: - tsx - yaml - vitest@4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@27.0.1(postcss@8.5.6))(lightningcss@1.31.1)(msw@2.13.4(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1): + vitest@4.0.4(@types/node@24.11.0)(@vitest/browser-playwright@4.0.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(terser@5.44.0)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.4 - '@vitest/mocker': 4.0.4(msw@2.13.4(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1)) + '@vitest/mocker': 4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1)) '@vitest/pretty-format': 4.0.4 '@vitest/runner': 4.0.4 '@vitest/snapshot': 4.0.4 @@ -13711,8 +13638,8 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.11.0 - '@vitest/browser-playwright': 4.0.4(msw@2.13.4(@types/node@24.11.0)(typescript@5.9.3))(playwright@1.56.1)(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1))(vitest@4.0.4) - jsdom: 27.0.1(postcss@8.5.6) + '@vitest/browser-playwright': 4.0.4(msw@2.11.6(@types/node@24.11.0)(typescript@5.9.3))(playwright@1.56.1)(vite@7.3.3(@types/node@24.11.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.44.0)(yaml@2.8.1))(vitest@4.0.4) + jsdom: 28.1.0(@noble/hashes@1.8.0) transitivePeerDependencies: - jiti - less @@ -13739,10 +13666,10 @@ snapshots: webidl-conversions@4.0.2: {} - webidl-conversions@7.0.0: {} - webidl-conversions@8.0.0: {} + webidl-conversions@8.0.1: {} + webpack-virtual-modules@0.6.2: {} whatwg-encoding@3.1.1: @@ -13751,16 +13678,21 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-url@14.2.0: - dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 + whatwg-mimetype@5.0.0: {} whatwg-url@15.1.0: dependencies: tr46: 6.0.0 webidl-conversions: 8.0.0 + whatwg-url@16.0.1(@noble/hashes@1.8.0): + dependencies: + '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + whatwg-url@7.1.0: dependencies: lodash.sortby: 4.7.0