From 797f2b968c0b27087f65f493e731a318549b462a Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 16:04:15 +0330 Subject: [PATCH 1/7] fix(image): export nested/inline images to markdown (#13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Image markdown export only worked for top-level images. Lexical applies `element` transformers only to direct children of the root during export; images nested inside another element (e.g. inside a paragraph after HTML import or when placed inline with text) were routed through `exportChildren`, which only runs `text-match` transformers and otherwise falls back to a decorator's empty `getTextContent()` — so the image was silently dropped. - Add IMAGE_TEXT_MATCH_TRANSFORMER (text-match) to handle nested/inline images, alongside the existing element transformer for block images. - Share the export + node-creation logic between both transformers so output is identical regardless of tree position. - Inline images can now also be imported from markdown (e.g. "text ![](x) text"). - Export ImageNode, $createImageNode, $isImageNode, ImageTranslator and the image transformers from the package root for discoverability. Co-Authored-By: Claude Opus 4.8 --- .../src/extensions/export/transformers.ts | 13 +- packages/editor/src/extensions/index.ts | 11 +- .../src/extensions/media/ImageExtension.tsx | 161 ++++++++++++------ 3 files changed, 129 insertions(+), 56 deletions(-) diff --git a/packages/editor/src/extensions/export/transformers.ts b/packages/editor/src/extensions/export/transformers.ts index 74183c3..c830d4d 100644 --- a/packages/editor/src/extensions/export/transformers.ts +++ b/packages/editor/src/extensions/export/transformers.ts @@ -8,11 +8,20 @@ import { HTML_EMBED_MARKDOWN_TRANSFORMER } from "../media/HTMLEmbedExtension"; import { HORIZONTAL_RULE_TRANSFORMER } from "../formatting/HorizontalRuleExtension"; import { UNDERLINE_TRANSFORMER } from "../formatting/UnderlineExtension"; import { TABLE_MARKDOWN_TRANSFORMER } from "../formatting/TableExtension"; -import { IMAGE_MARKDOWN_TRANSFORMER } from "../media/ImageExtension"; +import { + IMAGE_MARKDOWN_TRANSFORMER, + IMAGE_TEXT_MATCH_TRANSFORMER, +} from "../media/ImageExtension"; /** * All markdown transformers collected in one place * Import this array to get all available transformers + * + * Note: images ship two transformers. The element transformer handles + * top-level (block) images, while the text-match transformer handles images + * nested inside other elements (e.g. inside a paragraph after HTML import or + * when placed inline with text). Both are required for images to survive a + * markdown export in every position. */ export const ALL_MARKDOWN_TRANSFORMERS = [ HTML_EMBED_MARKDOWN_TRANSFORMER, @@ -20,6 +29,7 @@ export const ALL_MARKDOWN_TRANSFORMERS = [ UNDERLINE_TRANSFORMER, TABLE_MARKDOWN_TRANSFORMER, IMAGE_MARKDOWN_TRANSFORMER, + IMAGE_TEXT_MATCH_TRANSFORMER, ]; /** @@ -31,4 +41,5 @@ export { UNDERLINE_TRANSFORMER, TABLE_MARKDOWN_TRANSFORMER, IMAGE_MARKDOWN_TRANSFORMER, + IMAGE_TEXT_MATCH_TRANSFORMER, }; diff --git a/packages/editor/src/extensions/index.ts b/packages/editor/src/extensions/index.ts index ba9bc96..843f8aa 100644 --- a/packages/editor/src/extensions/index.ts +++ b/packages/editor/src/extensions/index.ts @@ -60,7 +60,16 @@ export { } from "./export/MarkdownExtension"; // Media Extensions -export { ImageExtension, imageExtension } from "./media/ImageExtension"; +export { + ImageExtension, + imageExtension, + ImageNode, + $createImageNode, + $isImageNode, + IMAGE_MARKDOWN_TRANSFORMER, + IMAGE_TEXT_MATCH_TRANSFORMER, +} from "./media/ImageExtension"; +export { ImageTranslator } from "./media/ImageTranslator"; export { HTMLEmbedExtension, htmlEmbedExtension, diff --git a/packages/editor/src/extensions/media/ImageExtension.tsx b/packages/editor/src/extensions/media/ImageExtension.tsx index 57ab9da..3e79101 100644 --- a/packages/editor/src/extensions/media/ImageExtension.tsx +++ b/packages/editor/src/extensions/media/ImageExtension.tsx @@ -1088,9 +1088,82 @@ export class ImageExtension extends BaseExtension< export const imageExtension = new ImageExtension(); /** - * Image Markdown Transformer - * Supports standard markdown image syntax with optional alignment - * + * Shared markdown pattern for images. + * + * Matches standard markdown image syntax with an optional title (used as the + * caption) and an optional trailing alignment HTML comment. + * + * Capture groups: 1=alt, 2=src, 3=caption (title), 4=alignment. + */ +const IMAGE_MARKDOWN_PATTERN = + String.raw`!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)(?:\s*)?`; + +/** + * Serialize an ImageNode to markdown. + * Shared by both the element and text-match transformers so the output is + * always identical regardless of where the image lives in the tree. + */ +function $exportImageToMarkdown(node: LexicalNode): string | null { + if (!$isImageNode(node)) { + return null; + } + + const imageNode = node as ImageNode; + const src = imageNode.__src || ""; + const alt = imageNode.__alt || ""; + const caption = imageNode.__caption || ""; + const alignment = imageNode.__alignment || "none"; + + if (!src) { + return null; + } + + // Build markdown image syntax + let markdown = `![${alt}](${src}`; + + // Add caption as title if present + if (caption) { + markdown += ` "${caption}"`; + } + + markdown += ")"; + + // Add alignment as HTML comment if not 'none' + if (alignment && alignment !== "none") { + markdown += ` `; + } + + return markdown; +} + +/** + * Build an ImageNode from a markdown match produced by IMAGE_MARKDOWN_PATTERN. + */ +function $createImageNodeFromMatch(match: string[]): ImageNode | null { + const [, alt, src, caption, alignment] = match; + + if (!src) return null; + + return $createImageNode( + src, + alt || "", + caption || undefined, + (alignment as "left" | "center" | "right" | "none") || "none", + undefined, + undefined, + undefined, + undefined, + false, + ); +} + +/** + * Image Markdown Transformer (block / element level) + * + * Handles images that sit at the top level of the document (their own block). + * Element transformers are the only ones Lexical applies to direct children of + * the root during export, so this is required for standalone images. + * * Syntax examples: * - ![alt text](url) * - ![alt text](url "caption") @@ -1100,66 +1173,46 @@ export const imageExtension = new ImageExtension(); */ export const IMAGE_MARKDOWN_TRANSFORMER = { dependencies: [ImageNode], - export: (node: LexicalNode) => { - if (!$isImageNode(node)) { - return null; - } - - const imageNode = node as ImageNode; - const src = imageNode.__src || ""; - const alt = imageNode.__alt || ""; - const caption = imageNode.__caption || ""; - const alignment = imageNode.__alignment || "none"; - - if (!src) { - return null; - } - - // Build markdown image syntax - let markdown = `![${alt}](${src}`; - - // Add caption as title if present - if (caption) { - markdown += ` "${caption}"`; - } - - markdown += ")"; - - // Add alignment as HTML comment if not 'none' - if (alignment && alignment !== "none") { - markdown += ` `; - } - - return markdown; - }, - regExp: /^!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)(?:\s*)?\s*$/, + export: $exportImageToMarkdown, + regExp: new RegExp(`^${IMAGE_MARKDOWN_PATTERN}\\s*$`), replace: ( parentNode: ElementNode, _children: LexicalNode[], match: string[], - isImport: boolean, + _isImport: boolean, ) => { - const [, alt, src, caption, alignment] = match; - - if (!src) return; - - const imageNode = $createImageNode( - src, - alt || "", - caption || undefined, - (alignment as "left" | "center" | "right" | "none") || "none", - undefined, - undefined, - undefined, - undefined, - false, - ); - - parentNode.replace(imageNode); + const imageNode = $createImageNodeFromMatch(match); + if (imageNode) { + parentNode.replace(imageNode); + } }, type: "element" as const, }; +/** + * Image Markdown Transformer (inline / text-match level) + * + * Handles images nested inside another element (e.g. inside a paragraph, which + * is where they end up after HTML import or when inserted inline with text). + * Element transformers never reach those nodes during export — only text-match + * transformers do — so without this transformer such images are silently + * dropped from the markdown output. See issue #13. + */ +export const IMAGE_TEXT_MATCH_TRANSFORMER = { + dependencies: [ImageNode], + export: $exportImageToMarkdown, + importRegExp: new RegExp(IMAGE_MARKDOWN_PATTERN), + regExp: new RegExp(`${IMAGE_MARKDOWN_PATTERN}$`), + replace: (textNode: LexicalNode, match: string[]) => { + const imageNode = $createImageNodeFromMatch(match); + if (imageNode) { + textNode.replace(imageNode); + } + }, + trigger: ")", + type: "text-match" as const, +}; + /** * Helper function to check if a node is an ImageNode */ From 52c2d896e5beb532576b48c3e41503f3eae84673 Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 16:04:25 +0330 Subject: [PATCH 2/7] fix(image): preserve width/height and alignment on HTML import (#10, #11) ImageTranslator.importDOM dropped intrinsic dimensions and mis-read alignment, so an HTML round-trip (getHTML -> injectHTML) lost image size and reset alignment to center. - #10: the `img` conversion now reads width/height from the `width`/`height` attributes and from `px` inline styles (percentage/auto are ignored as they can't be a numeric pixel size). - #11: the `figure` conversion no longer hardcodes "center"; it reads the alignment back from the `align-*` class / `text-align` style the editor emits, and pulls dimensions, className and inline style from the inner img. - Add shared extractAlignment() and extractDimension() helpers used by both the img and figure conversions. Verified with a real-DOM (jsdom) export->serialize->parse->import round-trip across left/center/right/none alignments and sized/unsized images. Co-Authored-By: Claude Opus 4.8 --- .../src/extensions/media/ImageTranslator.ts | 113 ++++++++++++++---- 1 file changed, 90 insertions(+), 23 deletions(-) diff --git a/packages/editor/src/extensions/media/ImageTranslator.ts b/packages/editor/src/extensions/media/ImageTranslator.ts index d61a339..d6ec669 100644 --- a/packages/editor/src/extensions/media/ImageTranslator.ts +++ b/packages/editor/src/extensions/media/ImageTranslator.ts @@ -81,27 +81,12 @@ export class ImageTranslator { } const img = domNode; - // Extract alignment from various possible sources - let alignment: "left" | "center" | "right" | "none" = "none"; - - // Check style attribute - const computedStyle = img.style; - if (computedStyle.textAlign) { - alignment = computedStyle.textAlign as any; - } else if (computedStyle.float) { - alignment = - computedStyle.float === "left" - ? "left" - : computedStyle.float === "right" - ? "right" - : "none"; - } + // Extract alignment from style, float, or class names + const alignment = this.extractAlignment(img); - // Check class names for alignment - if (img.classList.contains("align-left")) alignment = "left"; - else if (img.classList.contains("align-center")) - alignment = "center"; - else if (img.classList.contains("align-right")) alignment = "right"; + // Extract intrinsic dimensions (attribute or inline style) + const width = this.extractDimension(img, "width"); + const height = this.extractDimension(img, "height"); // Extract caption from figure/figcaption if present let caption: string | undefined; @@ -121,6 +106,8 @@ export class ImageTranslator { alignment, img.className || undefined, this.extractStyleObject(img), + width, + height, ); return { node }; @@ -153,14 +140,25 @@ export class ImageTranslator { const figcaption = figure.querySelector("figcaption"); const caption = figcaption?.textContent || undefined; + // Preserve the figure's alignment instead of assuming "center". + // The editor exports alignment as an `align-*` class / text-align + // style on the figure, so a round-trip must read it back. (#11) + const alignment = this.extractAlignment(figure); + + // Dimensions and presentation live on the inner . (#10) + const width = this.extractDimension(img, "width"); + const height = this.extractDimension(img, "height"); + try { const node = $createImageNode( img.src, img.alt || "", caption, - "center", // Figures are typically centered - figure.className || undefined, - this.extractStyleObject(figure), + alignment, + img.className || undefined, + this.extractStyleObject(img), + width, + height, ); return { node }; @@ -176,6 +174,75 @@ export class ImageTranslator { }; } + /** + * Extract the alignment of an image-bearing element. + * Class names (`align-left|center|right|none`) take precedence, then the + * `text-align` style, then `float`. Defaults to "none". + * @param element - The DOM element to read alignment from + */ + private static extractAlignment( + element: HTMLElement, + ): "left" | "center" | "right" | "none" { + try { + if (element.classList) { + if (element.classList.contains("align-left")) return "left"; + if (element.classList.contains("align-center")) return "center"; + if (element.classList.contains("align-right")) return "right"; + if (element.classList.contains("align-none")) return "none"; + } + + const style = element.style; + if (style) { + const textAlign = style.textAlign; + if ( + textAlign === "left" || + textAlign === "center" || + textAlign === "right" + ) { + return textAlign; + } + if (style.float === "left") return "left"; + if (style.float === "right") return "right"; + } + } catch (error) { + // fall through to default + } + return "none"; + } + + /** + * Extract a pixel dimension (width/height) from a DOM element. + * Reads the HTML attribute first (e.g. `width="300"`), then a `px` inline + * style (e.g. `style="width: 300px"`). Percentage / auto values are ignored + * since they cannot be represented as a numeric pixel size. + * @param element - The DOM element to read from + * @param dimension - Which dimension to read + */ + private static extractDimension( + element: HTMLElement, + dimension: "width" | "height", + ): number | undefined { + try { + // Attribute form: width="300" or width="300px" + const attr = element.getAttribute(dimension); + if (attr && /^\d+(?:px)?$/.test(attr.trim())) { + const value = parseInt(attr, 10); + if (!isNaN(value) && value > 0) return value; + } + + // Inline style form: style="width: 300px" + const styleValue = + dimension === "width" ? element.style?.width : element.style?.height; + if (styleValue && /^\d+(?:\.\d+)?px$/.test(styleValue.trim())) { + const value = parseInt(styleValue, 10); + if (!isNaN(value) && value > 0) return value; + } + } catch (error) { + // ignore and fall through + } + return undefined; + } + /** * Export an ImageNode to DOM elements * @param node - The ImageNode to export From b7cb67e154c03d7414f92066bd3105da27c6c331 Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 16:04:29 +0330 Subject: [PATCH 3/7] chore: ignore .claude directory Co-Authored-By: Claude Opus 4.8 --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2f22806..c73e295 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,5 @@ npm-debug.log* *_NOTES.* .vscode -**/.vscode \ No newline at end of file +**/.vscode +.claude \ No newline at end of file From 6f8d8a4c496fa94d0ac024d7a8044dc5e50123fe Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 16:08:47 +0330 Subject: [PATCH 4/7] chore(editor): add files allowlist + publishConfig, bump to 0.0.39 - Add `files: ["dist"]` so the published tarball contents are explicit and deterministic (only the build output ships). - Add `publishConfig.access: public` so the scoped package always publishes publicly. - Bump version to 0.0.39 to ship the image markdown/HTML round-trip fixes (#10, #11, #13). Co-Authored-By: Claude Opus 4.8 --- packages/editor/package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/editor/package.json b/packages/editor/package.json index b492ae5..7539265 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@lexkit/editor", - "version": "0.0.38", + "version": "0.0.39", "description": "LexKit Editor - A headless, extensible rich text editor built on Lexical", "type": "module", "private": false, @@ -15,6 +15,12 @@ } }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, "scripts": { "build": "tsup", "lint": "eslint . --max-warnings 0", From a912dc8e4416529f74544dca2e92c312230527b6 Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 16:08:48 +0330 Subject: [PATCH 5/7] ci: add npm release workflow with provenance + build CI release.yml publishes @lexkit/editor to npm whenever its version changes on main: it builds, checks whether the version is already on npm, and if not publishes with provenance (id-token: write) and cuts a GitHub release. Requires an npm automation token in the `NPM_TOKEN` repo secret. ci.yml builds the workspace on PRs and pushes to main. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 36 ++++++++++++++ .github/workflows/release.yml | 92 +++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..abddaec --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +# Builds the workspace on every PR and push to main so broken builds are caught +# before a release is attempted. + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9cc9492 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,92 @@ +name: Release @lexkit/editor + +# Publishes @lexkit/editor to npm whenever its version changes on main. +# +# Flow ("release as you sync"): +# 1. Bump the version in packages/editor/package.json +# (e.g. `pnpm --filter @lexkit/editor version patch`). +# 2. Commit & push to main. +# 3. This workflow builds the package, checks whether that exact version is +# already on npm, and if not, publishes it (with provenance) and cuts a +# GitHub release. Pushes that don't change the version are no-ops. +# +# Setup required once: +# - Add an npm "Automation" access token as the repo secret `NPM_TOKEN` +# (Settings -> Secrets and variables -> Actions -> New repository secret). + +on: + push: + branches: [main] + paths: + - "packages/editor/**" + - ".github/workflows/release.yml" + workflow_dispatch: {} # allow manual runs from the Actions tab + +concurrency: + group: release-editor + cancel-in-progress: false + +permissions: + contents: write # create tags + GitHub releases + id-token: write # REQUIRED for npm provenance (the "Published from GitHub" badge) + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 # version comes from "packageManager" in package.json + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: "https://registry.npmjs.org" + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build package + run: pnpm --filter @lexkit/editor build + + - name: Check whether this version is already published + id: check + working-directory: packages/editor + run: | + NAME=$(node -p "require('./package.json').name") + VERSION=$(node -p "require('./package.json').version") + echo "name=$NAME" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + if npm view "$NAME@$VERSION" version >/dev/null 2>&1; then + echo "published=true" >> "$GITHUB_OUTPUT" + echo "::notice::$NAME@$VERSION is already on npm — skipping publish." + else + echo "published=false" >> "$GITHUB_OUTPUT" + echo "::notice::$NAME@$VERSION is not on npm — publishing." + fi + + - name: Publish to npm (with provenance) + if: steps.check.outputs.published == 'false' + working-directory: packages/editor + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: "true" + run: pnpm publish --no-git-checks --access public + + - name: Tag release and create GitHub Release + if: steps.check.outputs.published == 'false' + env: + GH_TOKEN: ${{ github.token }} + run: | + TAG="editor-v${{ steps.check.outputs.version }}" + git tag "$TAG" + git push origin "$TAG" + gh release create "$TAG" \ + --title "@lexkit/editor v${{ steps.check.outputs.version }}" \ + --generate-notes From bab25b24ddc1c645607a468f58cfb4eaf57e01bb Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 23:16:14 +0330 Subject: [PATCH 6/7] test(editor): add vitest regression tests for image markdown + HTML round-trip Covers the three fixed issues so they can't silently regress: - #13: markdown export of top-level, nested, and inline images; inline import. - #10: width/height imported from img attributes and px inline styles. - #11: alignment preserved (left/center/right/none) across an HTML round-trip. Adds vitest + jsdom, a `test` script, and gates both CI and the release workflow on the suite so a broken build can never be published. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 3 + .github/workflows/release.yml | 3 + packages/editor/package.json | 10 +- .../media/__tests__/image-html.test.ts | 135 +++ .../media/__tests__/image-markdown.test.ts | 133 +++ packages/editor/vitest.config.ts | 17 + pnpm-lock.yaml | 1024 ++++++++++++++++- 7 files changed, 1313 insertions(+), 12 deletions(-) create mode 100644 packages/editor/src/extensions/media/__tests__/image-html.test.ts create mode 100644 packages/editor/src/extensions/media/__tests__/image-markdown.test.ts create mode 100644 packages/editor/vitest.config.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abddaec..81a86d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,3 +34,6 @@ jobs: - name: Build run: pnpm build + + - name: Test + run: pnpm --filter @lexkit/editor test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9cc9492..db852dc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,6 +55,9 @@ jobs: - name: Build package run: pnpm --filter @lexkit/editor build + - name: Test + run: pnpm --filter @lexkit/editor test + - name: Check whether this version is already published id: check working-directory: packages/editor diff --git a/packages/editor/package.json b/packages/editor/package.json index 7539265..9e82f90 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -13,7 +13,6 @@ "require": "./dist/index.js", "default": "./dist/index.js" } - }, "files": [ "dist" @@ -24,7 +23,9 @@ "scripts": { "build": "tsup", "lint": "eslint . --max-warnings 0", - "dev": "tsup --watch" + "dev": "tsup --watch", + "test": "vitest run", + "test:watch": "vitest" }, "keywords": [ "editor", @@ -45,15 +46,16 @@ "url": "https://github.com/novincode/lexkit/issues" }, "homepage": "https://github.com/novincode/lexkit#readme", - "dependencies": {}, "devDependencies": { "@repo/eslint-config": "workspace:*", "@repo/typescript-config": "workspace:*", "@types/react": "^19.1.1", "@types/react-dom": "^19.1.1", "eslint": "^9.32.0", + "jsdom": "^29.1.1", "tsup": "^8.0.0", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "vitest": "^4.1.8" }, "peerDependencies": { "@lexical/code": ">=0.34.0", diff --git a/packages/editor/src/extensions/media/__tests__/image-html.test.ts b/packages/editor/src/extensions/media/__tests__/image-html.test.ts new file mode 100644 index 0000000..fd16079 --- /dev/null +++ b/packages/editor/src/extensions/media/__tests__/image-html.test.ts @@ -0,0 +1,135 @@ +import { describe, it, expect } from "vitest"; +import { + createEditor, + $getRoot, + type LexicalEditor, +} from "lexical"; +import { $generateHtmlFromNodes, $generateNodesFromDOM } from "@lexical/html"; +import { ImageNode, $createImageNode } from "../../../index"; + +function makeEditor(): LexicalEditor { + return createEditor({ + nodes: [ImageNode], + onError: (e) => { + throw e; + }, + }); +} + +function exportHtml(editor: LexicalEditor): string { + return editor + .getEditorState() + .read(() => $generateHtmlFromNodes(editor)); +} + +function importHtml(editor: LexicalEditor, html: string): void { + editor.update( + () => { + const root = $getRoot(); + root.clear(); + const dom = new DOMParser().parseFromString(html, "text/html"); + const nodes = $generateNodesFromDOM(editor, dom); + nodes.forEach((n) => root.append(n)); + }, + { discrete: true }, + ); +} + +function firstImage(editor: LexicalEditor): ImageNode | null { + return editor.getEditorState().read(() => { + const found = $getRoot() + .getChildren() + .flatMap((n) => (n instanceof ImageNode ? [n] : [])); + if (found.length) return found[0]; + // also look one level down (image nested in a paragraph) + for (const child of $getRoot().getChildren()) { + const grandchildren = (child as any).getChildren?.() ?? []; + for (const gc of grandchildren) if (gc instanceof ImageNode) return gc; + } + return null; + }); +} + +describe("image HTML round-trip (#10, #11)", () => { + it("preserves right alignment and dimensions across export -> import (#11, #10)", () => { + const editor = makeEditor(); + editor.update( + () => { + $getRoot().clear(); + $getRoot().append( + $createImageNode( + "a.png", + "cat", + undefined, + "right", + undefined, + undefined, + 300, + 200, + ), + ); + }, + { discrete: true }, + ); + + const html = exportHtml(editor); + importHtml(editor, html); + + const img = firstImage(editor); + expect(img).not.toBeNull(); + expect(img!.__alignment).toBe("right"); + expect(img!.__width).toBe(300); + expect(img!.__height).toBe(200); + }); + + it.each(["left", "center", "right", "none"] as const)( + "round-trips %s alignment without resetting to center (#11)", + (alignment) => { + const editor = makeEditor(); + editor.update( + () => { + $getRoot().clear(); + $getRoot().append($createImageNode("a.png", "x", undefined, alignment)); + }, + { discrete: true }, + ); + + const html = exportHtml(editor); + importHtml(editor, html); + + expect(firstImage(editor)!.__alignment).toBe(alignment); + }, + ); + + it("imports width/height from img attributes (#10)", () => { + const editor = makeEditor(); + importHtml(editor, ''); + const img = firstImage(editor); + expect(img).not.toBeNull(); + expect(img!.__width).toBe(300); + expect(img!.__height).toBe(200); + }); + + it("imports width/height from px inline styles (#10)", () => { + const editor = makeEditor(); + importHtml(editor, ''); + const img = firstImage(editor); + expect(img!.__width).toBe(300); + expect(img!.__height).toBe(200); + }); + + it("ignores non-pixel (percentage) dimensions (#10)", () => { + const editor = makeEditor(); + importHtml(editor, ''); + const img = firstImage(editor); + expect(img!.__width).toBeUndefined(); + }); + + it("derives alignment from a float style on a bare img", () => { + const editor = makeEditor(); + importHtml(editor, ''); + const img = firstImage(editor); + expect(img!.__alignment).toBe("right"); + expect(img!.__width).toBe(120); + }); +}); diff --git a/packages/editor/src/extensions/media/__tests__/image-markdown.test.ts b/packages/editor/src/extensions/media/__tests__/image-markdown.test.ts new file mode 100644 index 0000000..02d637d --- /dev/null +++ b/packages/editor/src/extensions/media/__tests__/image-markdown.test.ts @@ -0,0 +1,133 @@ +import { describe, it, expect } from "vitest"; +import { + createEditor, + $getRoot, + $createParagraphNode, + $createTextNode, + type LexicalEditor, +} from "lexical"; +import { + $convertToMarkdownString, + $convertFromMarkdownString, + TRANSFORMERS, +} from "@lexical/markdown"; +import { + ImageNode, + $createImageNode, + ALL_MARKDOWN_TRANSFORMERS, +} from "../../../index"; + +const TRANSFORMERS_WITH_IMAGES = [...ALL_MARKDOWN_TRANSFORMERS, ...TRANSFORMERS]; + +function makeEditor(): LexicalEditor { + return createEditor({ + nodes: [ImageNode], + onError: (e) => { + throw e; + }, + }); +} + +function exportMarkdown(editor: LexicalEditor): string { + return editor + .getEditorState() + .read(() => $convertToMarkdownString(TRANSFORMERS_WITH_IMAGES)); +} + +describe("image markdown transformers (#13)", () => { + it("exports a top-level (block) image", () => { + const editor = makeEditor(); + editor.update( + () => { + const root = $getRoot(); + root.clear(); + root.append($createImageNode("https://cdn/top.png", "top", "", "left")); + }, + { discrete: true }, + ); + + expect(exportMarkdown(editor)).toBe( + "![top](https://cdn/top.png) ", + ); + }); + + it("exports an image nested as the only child of a paragraph (the #13 regression)", () => { + const editor = makeEditor(); + editor.update( + () => { + const root = $getRoot(); + root.clear(); + const p = $createParagraphNode(); + p.append( + $createImageNode("https://cdn/x.png", "My alt", "My caption", "right"), + ); + root.append(p); + }, + { discrete: true }, + ); + + // Before the fix this produced "" because element transformers never reach + // nodes nested inside a paragraph. + expect(exportMarkdown(editor)).toBe( + '![My alt](https://cdn/x.png "My caption") ', + ); + }); + + it("exports an image placed inline between text nodes", () => { + const editor = makeEditor(); + editor.update( + () => { + const root = $getRoot(); + root.clear(); + const p = $createParagraphNode(); + p.append($createTextNode("before ")); + p.append($createImageNode("https://cdn/mid.png", "m")); + p.append($createTextNode(" after")); + root.append(p); + }, + { discrete: true }, + ); + + expect(exportMarkdown(editor)).toBe("before ![m](https://cdn/mid.png) after"); + }); + + it("imports a standalone image line as a top-level image and round-trips", () => { + const editor = makeEditor(); + const md = '![cat](pic.png "cap") '; + editor.update( + () => { + $getRoot().clear(); + $convertFromMarkdownString(md, TRANSFORMERS_WITH_IMAGES); + }, + { discrete: true }, + ); + + const node = editor.getEditorState().read(() => { + const first = $getRoot().getFirstChild(); + return first instanceof ImageNode ? first : null; + }); + expect(node).not.toBeNull(); + expect(node!.__alignment).toBe("right"); + expect(exportMarkdown(editor)).toBe(md); + }); + + it("imports an inline image within text and round-trips", () => { + const editor = makeEditor(); + const md = "Look: ![cat](c.png) here"; + editor.update( + () => { + $getRoot().clear(); + $convertFromMarkdownString(md, TRANSFORMERS_WITH_IMAGES); + }, + { discrete: true }, + ); + + expect(exportMarkdown(editor)).toBe(md); + }); + + it("ships both an element and a text-match image transformer", () => { + const types = ALL_MARKDOWN_TRANSFORMERS.map((t) => t.type); + expect(types).toContain("element"); + expect(types).toContain("text-match"); + }); +}); diff --git a/packages/editor/vitest.config.ts b/packages/editor/vitest.config.ts new file mode 100644 index 0000000..b24f904 --- /dev/null +++ b/packages/editor/vitest.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vitest/config"; +import { resolve } from "node:path"; + +export default defineConfig({ + resolve: { + alias: { + // Mirror the tsconfig path "@lexkit/editor/*" -> "./src/*" so tests can + // import the source the same way the source imports itself. + "@lexkit/editor": resolve(__dirname, "src"), + }, + }, + test: { + // jsdom gives us document/DOMParser for the HTML import/export round-trips. + environment: "jsdom", + include: ["src/**/*.{test,spec}.{ts,tsx}"], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8506cdd..987dba5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -184,12 +184,18 @@ importers: eslint: specifier: ^9.32.0 version: 9.32.0(jiti@2.5.1) + jsdom: + specifier: ^29.1.1 + version: 29.1.1 tsup: specifier: ^8.0.0 - version: 8.5.0(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2) + version: 8.5.0(jiti@2.5.1)(postcss@8.5.15)(tsx@4.20.5)(typescript@5.9.2) typescript: specifier: ^5.7.3 version: 5.9.2 + vitest: + specifier: ^4.1.8 + version: 4.1.8(@edge-runtime/vm@3.2.0)(@types/node@20.19.9)(jsdom@29.1.1)(vite@8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5)) packages/eslint-config: devDependencies: @@ -286,7 +292,7 @@ importers: version: 9.32.0(jiti@2.5.1) tsup: specifier: ^8.0.0 - version: 8.5.0(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2) + version: 8.5.0(jiti@2.5.1)(postcss@8.5.15)(tsx@4.20.5)(typescript@5.9.2) typescript: specifier: ^5.7.3 version: 5.9.2 @@ -451,6 +457,21 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@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@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@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/runtime-corejs3@7.28.2': resolution: {integrity: sha512-FVFaVs2/dZgD3Y9ZD+AKNKjyGKzwu0C54laAXWUXgLcVXcCX6YZ6GhK2cp7FogSN2OA0Fu+QT8dP3FUdo9ShSQ==} engines: {node: '>=6.9.0'} @@ -459,12 +480,17 @@ packages: resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} engines: {node: '>=6.9.0'} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@cloudflare/kv-asset-handler@0.4.0': resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} engines: {node: '>=18.0.0'} '@cloudflare/next-on-pages@1.13.15': resolution: {integrity: sha512-HTLgU4S6ESRz79E6a5iTKLk7J/i0/5DL+3q8WfG47muH/dQpSl98ZpZh4R3qPf77HGghZUX934Mt5zwHle8uDw==} + deprecated: 'Please use the OpenNext adapter instead: https://opennext.js.org/cloudflare' hasBin: true peerDependencies: '@cloudflare/workers-types': ^4.20240208.0 @@ -547,6 +573,42 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.1': + resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.7': + resolution: {integrity: sha512-CmjJFQTFQx/U/xNJhSjCQ0ilpesPmNQ8+eOUeM/+kDOVW33qsIjeOXc27vrQDdWVkf83ZSWwtg7kXSUvKDJ8cQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@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.1.5': + resolution: {integrity: sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@dnd-kit/accessibility@3.1.1': resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} peerDependencies: @@ -583,9 +645,18 @@ packages: resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==} engines: {node: '>=16'} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.4.5': resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.25.4': resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} engines: {node: '>=18'} @@ -942,6 +1013,15 @@ packages: resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} 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 + '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -1237,6 +1317,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} @@ -1336,6 +1419,12 @@ packages: engines: {node: '>=18'} hasBin: true + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@next/env@15.4.5': resolution: {integrity: sha512-ruM+q2SCOVCepUiERoxOmZY9ZVoecR3gcXNwCYZRvQQWRjhOiPJGmQ2fAiLR6YKWXcSAh7G79KEFxN3rwhs4LQ==} @@ -1402,6 +1491,9 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2001,6 +2093,98 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/pluginutils@5.2.0': resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} engines: {node: '>=14.0.0'} @@ -2149,6 +2333,9 @@ packages: '@speed-highlight/core@1.2.7': resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} @@ -2273,6 +2460,15 @@ packages: resolution: {integrity: sha512-Gye68+szmOp96xMvmondTRQYcYvevDqUP9JuN9jC6kqzFel7U1pJ/hoPvyD3WGQNxyKsdF+wJ5fvNaYXkzr6tQ==} hasBin: true + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -2379,6 +2575,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@vercel/blob@1.0.2': resolution: {integrity: sha512-Im/KeFH4oPx7UsM+QiteimnE07bIUD7JK6CBafI9Z0jRFogaialTBMiZj8EKk/30ctUYsrpIIyP9iIY1YxWnUQ==} @@ -2444,6 +2641,35 @@ packages: '@vercel/static-config@3.1.2': resolution: {integrity: sha512-2d+TXr6K30w86a+WbMbGm2W91O0UzO5VeemZYBBUJbCjk/5FLLGIi8aV6RS2+WmaRvtcqNTn2pUA7nCOK3bGcQ==} + '@vitest/expect@4.1.8': + resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + + '@vitest/mocker@4.1.8': + resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.8': + resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + + '@vitest/runner@4.1.8': + resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + + '@vitest/snapshot@4.1.8': + resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + + '@vitest/spy@4.1.8': + resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + + '@vitest/utils@4.1.8': + resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -2569,6 +2795,10 @@ packages: as-table@1.0.55: resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types@0.13.4: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} @@ -2615,6 +2845,9 @@ packages: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -2683,6 +2916,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2829,6 +3066,9 @@ packages: resolution: {integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==} engines: {node: '>=8'} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -2851,6 +3091,10 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -2861,6 +3105,10 @@ packages: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} + 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'} @@ -2891,6 +3139,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -2986,6 +3237,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} @@ -3008,6 +3263,9 @@ packages: es-module-lexer@1.4.1: resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -3371,6 +3629,9 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -3390,6 +3651,10 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + exsolve@1.0.7: resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} @@ -3546,11 +3811,12 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} @@ -3642,6 +3908,10 @@ packages: header-case@1.0.1: resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==} + 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-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -3828,6 +4098,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -3919,6 +4192,15 @@ packages: jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jsdom@29.1.1: + resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -3960,70 +4242,140 @@ packages: engines: {node: '>=16'} hasBin: true + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.30.1: resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.30.1: resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.30.1: resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.30.1: resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.30.1: resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.30.1: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} engines: {node: '>= 12.0.0'} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -4073,6 +4425,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -4089,6 +4445,9 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -4099,6 +4458,9 @@ packages: mdast-util-to-hast@13.2.0: resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -4224,6 +4586,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4243,6 +4610,7 @@ packages: next@15.4.5: resolution: {integrity: sha512-nJ4v+IO9CPmbmcvsPebIoX3Q+S7f6Fu08/dEWu0Ttfa+wVwQRh9epcmsyCPjmL2b8MxC+CkBR97jgDhUUztI3g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -4331,6 +4699,10 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} @@ -4417,6 +4789,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + pascal-case@2.0.1: resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==} @@ -4487,6 +4862,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -4520,6 +4899,10 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -4718,6 +5101,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.50.0: resolution: {integrity: sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4755,6 +5143,10 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} @@ -4833,6 +5225,9 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -4891,6 +5286,9 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stacktracey@2.1.8: resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} @@ -4901,6 +5299,9 @@ packages: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -5005,6 +5406,9 @@ packages: swap-case@1.1.2: resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} @@ -5021,10 +5425,12 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me tar@7.4.3: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -5044,22 +5450,44 @@ packages: resolution: {integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==} engines: {node: '>=10'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + tinygradient@1.1.5: resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + title-case@2.1.1: resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} + tldts-core@7.4.2: + resolution: {integrity: sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==} + + tldts@7.4.2: + resolution: {integrity: sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==} + hasBin: true + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -5072,12 +5500,20 @@ packages: resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} engines: {node: '>=0.6'} + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + 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 @@ -5274,6 +5710,10 @@ packages: resolution: {integrity: sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ==} engines: {node: '>=20.18.1'} + undici@7.27.2: + resolution: {integrity: sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==} + engines: {node: '>=20.18.1'} + unenv@2.0.0-rc.19: resolution: {integrity: sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA==} @@ -5370,6 +5810,94 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.8: + resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.8 + '@vitest/browser-preview': 4.1.8 + '@vitest/browser-webdriverio': 4.1.8 + '@vitest/coverage-istanbul': 4.1.8 + '@vitest/coverage-v8': 4.1.8 + '@vitest/ui': 4.1.8 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -5385,6 +5913,18 @@ packages: webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + 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} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5412,6 +5952,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -5474,6 +6019,13 @@ packages: resolution: {integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==} engines: {node: '>= 6.0'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -5549,12 +6101,36 @@ snapshots: '@jridgewell/gen-mapping': 0.3.12 '@jridgewell/trace-mapping': 0.3.29 + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@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.7(@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@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} + '@babel/runtime-corejs3@7.28.2': dependencies: core-js-pure: 3.45.0 '@babel/runtime@7.28.3': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + '@cloudflare/kv-asset-handler@0.4.0': dependencies: mime: 3.0.0 @@ -5619,6 +6195,30 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.2.1(@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@4.1.7(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.1(@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@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.5(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + '@dnd-kit/accessibility@3.1.1(react@19.1.1)': dependencies: react: 19.1.1 @@ -5649,11 +6249,27 @@ snapshots: dependencies: '@edge-runtime/primitives': 4.1.0 + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.4.5': dependencies: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.4': optional: true @@ -5857,6 +6473,8 @@ snapshots: '@eslint/core': 0.15.1 levn: 0.4.1 + '@exodus/bytes@1.15.1': {} + '@fastify/busboy@2.1.1': {} '@floating-ui/core@1.7.3': @@ -6085,6 +6703,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.4': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.29': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -6270,6 +6890,13 @@ snapshots: - encoding - supports-color + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + '@next/env@15.4.5': {} '@next/eslint-plugin-next@15.4.5': @@ -6312,6 +6939,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@oxc-project/types@0.133.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -6941,6 +7570,57 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + '@rollup/pluginutils@5.2.0(rollup@4.50.0)': dependencies: '@types/estree': 1.0.8 @@ -7060,6 +7740,8 @@ snapshots: '@speed-highlight/core@1.2.7': {} + '@standard-schema/spec@1.1.0': {} + '@standard-schema/utils@0.3.0': {} '@swc/helpers@0.5.15': @@ -7191,6 +7873,18 @@ snapshots: semver: 7.6.2 update-check: 1.5.4 + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + '@types/estree@1.0.8': {} '@types/glob@7.2.0': @@ -7513,6 +8207,47 @@ snapshots: json-schema-to-ts: 1.6.4 ts-morph: 12.0.0 + '@vitest/expect@4.1.8': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5))': + dependencies: + '@vitest/spy': 4.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5) + + '@vitest/pretty-format@4.1.8': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.8': + dependencies: + '@vitest/utils': 4.1.8 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + '@vitest/utils': 4.1.8 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.8': {} + + '@vitest/utils@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + abbrev@3.0.1: {} acorn-import-attributes@1.9.5(acorn@8.15.0): @@ -7652,6 +8387,8 @@ snapshots: dependencies: printable-characters: 1.0.42 + assertion-error@2.0.1: {} + ast-types@0.13.4: dependencies: tslib: 2.8.1 @@ -7686,6 +8423,10 @@ snapshots: basic-ftp@5.0.5: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + binary-extensions@2.3.0: {} bindings@1.5.0: @@ -7757,6 +8498,8 @@ snapshots: ccount@2.0.1: {} + chai@6.2.2: {} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -7907,6 +8650,8 @@ snapshots: convert-hrtime@3.0.0: {} + convert-source-map@2.0.0: {} + cookie@0.5.0: {} cookie@0.7.2: {} @@ -7923,12 +8668,24 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + csstype@3.1.3: {} data-uri-to-buffer@2.0.2: {} data-uri-to-buffer@6.0.2: {} + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -7955,6 +8712,8 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + deep-extend@0.6.0: {} deep-is@0.1.4: {} @@ -8057,6 +8816,8 @@ snapshots: entities@6.0.1: {} + entities@8.0.0: {} + error-stack-parser-es@1.0.5: {} es-abstract@1.24.0: @@ -8141,6 +8902,8 @@ snapshots: es-module-lexer@1.4.1: {} + es-module-lexer@2.1.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -8508,6 +9271,10 @@ snapshots: estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} etag@1.8.1: {} @@ -8528,6 +9295,8 @@ snapshots: exit-hook@2.2.1: {} + expect-type@1.3.0: {} + exsolve@1.0.7: {} extend@3.0.2: {} @@ -8572,6 +9341,10 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -8845,6 +9618,12 @@ snapshots: no-case: 2.3.2 upper-case: 1.1.3 + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + html-void-elements@3.0.0: {} http-errors@1.4.0: @@ -9048,6 +9827,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -9134,6 +9915,32 @@ snapshots: jsbn@1.1.0: {} + jsdom@29.1.1: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) + '@exodus/bytes': 1.15.1 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.1 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.27.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + json-buffer@3.0.1: {} json-schema-to-ts@1.6.4: @@ -9177,36 +9984,69 @@ snapshots: dependencies: isomorphic.js: 0.2.5 + lightningcss-android-arm64@1.32.0: + optional: true + lightningcss-darwin-arm64@1.30.1: optional: true + lightningcss-darwin-arm64@1.32.0: + optional: true + lightningcss-darwin-x64@1.30.1: optional: true + lightningcss-darwin-x64@1.32.0: + optional: true + lightningcss-freebsd-x64@1.30.1: optional: true + lightningcss-freebsd-x64@1.32.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.30.1: optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + lightningcss-linux-arm64-gnu@1.30.1: optional: true + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + lightningcss-linux-arm64-musl@1.30.1: optional: true + lightningcss-linux-arm64-musl@1.32.0: + optional: true + lightningcss-linux-x64-gnu@1.30.1: optional: true + lightningcss-linux-x64-gnu@1.32.0: + optional: true + lightningcss-linux-x64-musl@1.30.1: optional: true + lightningcss-linux-x64-musl@1.32.0: + optional: true + lightningcss-win32-arm64-msvc@1.30.1: optional: true + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + lightningcss-win32-x64-msvc@1.30.1: optional: true + lightningcss-win32-x64-msvc@1.32.0: + optional: true + lightningcss@1.30.1: dependencies: detect-libc: 2.0.4 @@ -9222,6 +10062,22 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1 + lightningcss@1.32.0: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -9261,6 +10117,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.1: {} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 @@ -9275,6 +10133,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + make-error@1.3.6: {} math-intrinsics@1.1.0: {} @@ -9291,6 +10153,8 @@ snapshots: unist-util-visit: 5.0.0 vfile: 6.0.3 + mdn-data@2.27.1: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -9424,6 +10288,8 @@ snapshots: nanoid@3.3.11: {} + nanoid@3.3.12: {} + natural-compare@1.4.0: {} neo-async@2.6.2: {} @@ -9532,6 +10398,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + obug@2.1.3: {} + ohash@2.0.11: {} once@1.3.3: @@ -9649,6 +10517,10 @@ snapshots: dependencies: entities: 6.0.1 + parse5@8.0.1: + dependencies: + entities: 8.0.0 + pascal-case@2.0.1: dependencies: camel-case: 3.0.0 @@ -9704,6 +10576,8 @@ snapshots: picomatch@4.0.3: {} + picomatch@4.0.4: {} + pirates@4.0.7: {} pkg-types@1.3.1: @@ -9714,12 +10588,12 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5): + postcss-load-config@6.0.1(jiti@2.5.1)(postcss@8.5.15)(tsx@4.20.5): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.5.1 - postcss: 8.5.6 + postcss: 8.5.15 tsx: 4.20.5 postcss@8.4.31: @@ -9728,6 +10602,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -9936,6 +10816,27 @@ snapshots: dependencies: glob: 7.2.3 + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + rollup@4.50.0: dependencies: '@types/estree': 1.0.8 @@ -10000,6 +10901,10 @@ snapshots: safer-buffer@2.1.2: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.26.0: {} semver@6.3.1: {} @@ -10146,6 +11051,8 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} signal-exit@4.0.2: {} @@ -10194,6 +11101,8 @@ snapshots: sprintf-js@1.1.3: {} + stackback@0.0.2: {} + stacktracey@2.1.8: dependencies: as-table: 1.0.55 @@ -10203,6 +11112,8 @@ snapshots: statuses@1.5.0: {} + std-env@4.1.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -10331,6 +11242,8 @@ snapshots: lower-case: 1.1.4 upper-case: 1.1.3 + symbol-tree@3.2.4: {} + tabbable@6.2.0: {} tailwind-merge@3.3.1: {} @@ -10373,25 +11286,42 @@ snapshots: dependencies: convert-hrtime: 3.0.0 + tinybench@2.9.0: {} + tinycolor2@1.6.0: {} tinyexec@0.3.2: {} + tinyexec@1.2.4: {} + tinyglobby@0.2.14: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinygradient@1.1.5: dependencies: '@types/tinycolor2': 1.4.6 tinycolor2: 1.6.0 + tinyrainbow@3.1.0: {} + title-case@2.1.1: dependencies: no-case: 2.3.2 upper-case: 1.1.3 + tldts-core@7.4.2: {} + + tldts@7.4.2: + dependencies: + tldts-core: 7.4.2 + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -10402,12 +11332,20 @@ snapshots: toidentifier@1.0.0: {} + tough-cookie@6.0.1: + dependencies: + tldts: 7.4.2 + tr46@0.0.3: {} tr46@1.0.1: dependencies: punycode: 2.3.1 + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -10467,7 +11405,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.0(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2): + tsup@8.5.0(jiti@2.5.1)(postcss@8.5.15)(tsx@4.20.5)(typescript@5.9.2): dependencies: bundle-require: 5.1.0(esbuild@0.25.9) cac: 6.7.14 @@ -10478,7 +11416,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.5.1)(postcss@8.5.6)(tsx@4.20.5) + postcss-load-config: 6.0.1(jiti@2.5.1)(postcss@8.5.15)(tsx@4.20.5) resolve-from: 5.0.0 rollup: 4.50.0 source-map: 0.8.0-beta.0 @@ -10487,7 +11425,7 @@ snapshots: tinyglobby: 0.2.14 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.5.6 + postcss: 8.5.15 typescript: 5.9.2 transitivePeerDependencies: - jiti @@ -10613,6 +11551,8 @@ snapshots: undici@7.15.0: {} + undici@7.27.2: {} + unenv@2.0.0-rc.19: dependencies: defu: 6.1.4 @@ -10748,6 +11688,53 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + vite@8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 20.19.9 + esbuild: 0.25.9 + fsevents: 2.3.3 + jiti: 2.5.1 + tsx: 4.20.5 + + vitest@4.1.8(@edge-runtime/vm@3.2.0)(@types/node@20.19.9)(jsdom@29.1.1)(vite@8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5)): + dependencies: + '@vitest/expect': 4.1.8 + '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5)) + '@vitest/pretty-format': 4.1.8 + '@vitest/runner': 4.1.8 + '@vitest/snapshot': 4.1.8 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@20.19.9)(esbuild@0.25.9)(jiti@2.5.1)(tsx@4.20.5) + why-is-node-running: 2.3.0 + optionalDependencies: + '@edge-runtime/vm': 3.2.0 + '@types/node': 20.19.9 + jsdom: 29.1.1 + transitivePeerDependencies: + - msw + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -10760,6 +11747,18 @@ snapshots: webidl-conversions@4.0.2: {} + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -10816,6 +11815,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} wordwrap@1.0.0: {} @@ -10882,6 +11886,10 @@ snapshots: dependencies: os-paths: 4.4.0 + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + yallist@4.0.0: {} yallist@5.0.0: {} From 7deeecb7b89585c33e2148a33a22396c848b9443 Mon Sep 17 00:00:00 2001 From: Shayan Date: Sun, 14 Jun 2026 23:20:14 +0330 Subject: [PATCH 7/7] fix(editor): use ReturnType instead of NodeJS.Timeout NodeJS.Timeout requires @types/node, which isn't a dependency of this browser library. It only resolved locally via hoisting and broke the DTS build on a clean CI install (TS2694: Namespace 'NodeJS' has no exported member 'Timeout'). ReturnType is environment-agnostic and the correct type for a browser timer handle. Co-Authored-By: Claude Opus 4.8 --- .../editor/src/extensions/core/DraggableBlockExtension.tsx | 6 +++--- .../editor/src/extensions/core/FloatingToolbarExtension.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/editor/src/extensions/core/DraggableBlockExtension.tsx b/packages/editor/src/extensions/core/DraggableBlockExtension.tsx index 5016426..bb36bd7 100644 --- a/packages/editor/src/extensions/core/DraggableBlockExtension.tsx +++ b/packages/editor/src/extensions/core/DraggableBlockExtension.tsx @@ -26,7 +26,7 @@ function debounce any>( func: T, wait: number, ): (...args: Parameters) => void { - let timeout: NodeJS.Timeout; + let timeout: ReturnType; return (...args: Parameters) => { clearTimeout(timeout); timeout = setTimeout(() => func(...args), wait); @@ -462,7 +462,7 @@ function DraggableBlockPlugin({ // Mouse tracking for handle visibility with smooth positioning useEffect(() => { - let hideTimeout: NodeJS.Timeout; + let hideTimeout: ReturnType; const handleMouseMove = (e: MouseEvent) => { if (isDragging) return; @@ -1001,7 +1001,7 @@ function DraggableBlockPlugin({ const editorElement = editor.getRootElement(); if (!editorElement) return; - let pressTimeout: NodeJS.Timeout | null = null; + let pressTimeout: ReturnType | null = null; let startX = 0; let startY = 0; diff --git a/packages/editor/src/extensions/core/FloatingToolbarExtension.tsx b/packages/editor/src/extensions/core/FloatingToolbarExtension.tsx index 72a75a1..88f75d7 100644 --- a/packages/editor/src/extensions/core/FloatingToolbarExtension.tsx +++ b/packages/editor/src/extensions/core/FloatingToolbarExtension.tsx @@ -235,7 +235,7 @@ function FloatingToolbarPlugin({ func: T, wait: number, ) => { - let timeout: NodeJS.Timeout; + let timeout: ReturnType; return (...args: Parameters) => { clearTimeout(timeout); timeout = setTimeout(() => func(() => args), wait);