From 2279fd19b0fb051fd41860bfbfbe7e634bc473a7 Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Thu, 20 Aug 2026 16:46:57 +0800 Subject: [PATCH] chore(ui-conversation): add lexical dependencies and jsdom spike --- THIRD_PARTY_NOTICES.md | 6 + packages/client/ui-conversation/package.json | 12 +- .../tests/lexical-spike.client.spec.tsx | 199 ++++++++++++ pnpm-lock.yaml | 305 +++++++++++++++++- 4 files changed, 509 insertions(+), 13 deletions(-) create mode 100644 packages/client/ui-conversation/tests/lexical-spike.client.spec.tsx diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 295eb1868f..f7fcb09283 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -38,6 +38,10 @@ External packages that a workspace package resolves at runtime. The tier covers | [`@earendil-works/pi-ai`](https://github.com/earendil-works/pi) | MIT | | [`@joplin/turndown-plugin-gfm`](https://github.com/laurent22/joplin-turndown-plugin-gfm) | MIT | | [`@jridgewell/gen-mapping`](https://github.com/jridgewell/sourcemaps) | MIT | +| [`@lexical/history`](https://github.com/facebook/lexical) | MIT | +| [`@lexical/plain-text`](https://github.com/facebook/lexical) | MIT | +| [`@lexical/text`](https://github.com/facebook/lexical) | MIT | +| [`@lexical/utils`](https://github.com/facebook/lexical) | MIT | | [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) | MIT | | [`@openai/codex`](https://github.com/openai/codex) | Apache-2.0 | | [`@opentelemetry/api`](https://github.com/open-telemetry/opentelemetry-js) | Apache-2.0 | @@ -63,6 +67,7 @@ External packages that a workspace package resolves at runtime. The tier covers | [`js-yaml`](https://github.com/nodeca/js-yaml) | MIT | | [`katex`](https://github.com/KaTeX/KaTeX) | MIT | | [`koffi`](https://github.com/Koromix/koffi) | MIT | +| [`lexical`](https://github.com/facebook/lexical) | MIT | | [`mdast-util-from-markdown`](https://github.com/syntax-tree/mdast-util-from-markdown) | MIT | | [`mdast-util-gfm`](https://github.com/syntax-tree/mdast-util-gfm) | MIT | | [`mdast-util-math`](https://github.com/syntax-tree/mdast-util-math) | MIT | @@ -122,6 +127,7 @@ External packages **directly declared** only by repository tooling, test infrast | Package | License | | --- | --- | | [`@braintree/sanitize-url`](https://github.com/braintree/sanitize-url) | MIT | +| [`@lexical/headless`](https://github.com/facebook/lexical) | MIT | | [`@modelcontextprotocol/server-everything`](https://github.com/modelcontextprotocol/servers) | MIT / Apache-2.0 | | [`@modelcontextprotocol/server-filesystem`](https://github.com/modelcontextprotocol/servers) | MIT / Apache-2.0 | | [`@stylistic/eslint-plugin`](https://github.com/eslint-stylistic/eslint-stylistic) | MIT | diff --git a/packages/client/ui-conversation/package.json b/packages/client/ui-conversation/package.json index a8596f1209..8b94dcd936 100644 --- a/packages/client/ui-conversation/package.json +++ b/packages/client/ui-conversation/package.json @@ -49,7 +49,12 @@ "license": "MIT", "dependencies": { "clsx": "^2.0.0", - "@deepseek-ai/schemastery": "workspace:^" + "@deepseek-ai/schemastery": "workspace:^", + "@lexical/history": "^0.49.0", + "@lexical/plain-text": "^0.49.0", + "@lexical/text": "^0.49.0", + "@lexical/utils": "^0.49.0", + "lexical": "^0.49.0" }, "peerDependencies": { "@deepseek-ai/cordis": "workspace:^", @@ -105,7 +110,10 @@ "@deepseek-ai/dsh-tools": "workspace:^", "@types/react": "~18.3.1", "react": "^18.2.0", - "@deepseek-ai/dsh-settings": "workspace:^" + "@deepseek-ai/dsh-settings": "workspace:^", + "@lexical/headless": "^0.49.0", + "react-dom": "^18.2.0", + "@types/react-dom": "~18.3.0" }, "files": [ "lib/index.js", diff --git a/packages/client/ui-conversation/tests/lexical-spike.client.spec.tsx b/packages/client/ui-conversation/tests/lexical-spike.client.spec.tsx new file mode 100644 index 0000000000..d95e45f031 --- /dev/null +++ b/packages/client/ui-conversation/tests/lexical-spike.client.spec.tsx @@ -0,0 +1,199 @@ +// @vitest-environment jsdom +/** + * SPIKE (Phase 0): validates the jsdom driving model for the Lexical composer + * before the real implementation lands. Answers three questions: (1) can a + * shell-owned headful editor render into jsdom and accept update-driven + * edits; (2) can synthetic beforeinput/keyboard events drive Lexical in + * jsdom, or must component tests drive through the command layer; (3) do + * DecoratorNode portals render and keep DOM identity when text is inserted + * before them. Deleted/absorbed into the real suites at the end of Phase 4. + */ +import { describe, expect, it } from 'vitest' +import * as React from 'react' +import { createPortal } from 'react-dom' +import { act, render } from '@testing-library/react' +import type { EditorConfig, LexicalEditor, NodeKey, SerializedLexicalNode } from 'lexical' +import { + $createParagraphNode, $createTextNode, $getRoot, $getSelection, $isRangeSelection, + createEditor, DecoratorNode, +} from 'lexical' +import { registerPlainText } from '@lexical/plain-text' + +/** Minimal inline atomic chip for the spike (real node lands in Phase 1). */ +class SpikeChipNode extends DecoratorNode { + static getType(): string { + return 'spike-chip' + } + + static clone(node: SpikeChipNode): SpikeChipNode { + return new SpikeChipNode(node.__key) + } + + static importJSON(): SpikeChipNode { + return new SpikeChipNode() + } + + exportJSON(): SerializedLexicalNode { + return { type: 'spike-chip', version: 1 } + } + + createDOM(_config: EditorConfig): HTMLElement { + const el = document.createElement('span') + el.dataset['spikeChip'] = 'true' + return el + } + + updateDOM(): boolean { + return false + } + + isInline(): boolean { + return true + } + + getTextContent(): string { + return '/chip-clipboard' + } + + decorate(): React.JSX.Element { + return + } +} + +function makeEditor(): { editor: LexicalEditor; rootEl: HTMLDivElement } { + const editor = createEditor({ + namespace: 'spike', + nodes: [SpikeChipNode], + onError: (error) => { throw error }, + }) + const rootEl = document.createElement('div') + rootEl.contentEditable = 'true' + document.body.appendChild(rootEl) + editor.setRootElement(rootEl) + registerPlainText(editor) + return { editor, rootEl } +} + +describe('lexical jsdom spike', () => { + it('renders update-driven text into the DOM and reports projections', async () => { + const { editor, rootEl } = makeEditor() + editor.update(() => { + const p = $createParagraphNode() + p.append($createTextNode('hello world')) + $getRoot().append(p) + }, { discrete: true }) + await Promise.resolve() // reconciliation is sync inside update; flush microtasks anyway + expect(rootEl.textContent).toBe('hello world') + const text = editor.getEditorState().read(() => $getRoot().getTextContent()) + expect(text).toBe('hello world') + }) + + it('answers whether synthetic beforeinput insertText drives Lexical under jsdom', () => { + const { editor, rootEl } = makeEditor() + editor.update(() => { + const p = $createParagraphNode() + p.append($createTextNode('ab')) + $getRoot().append(p) + }, { discrete: true }) + // Place a real DOM selection at the end of the text node. + const walker = document.createTreeWalker(rootEl, NodeFilter.SHOW_TEXT) + const textDom = walker.nextNode() + const selectable = textDom !== null && textDom !== undefined + if (selectable) { + const sel = document.getSelection() + const range = document.createRange() + range.setStart(textDom, 2) + range.collapse(true) + sel?.removeAllRanges() + sel?.addRange(range) + document.dispatchEvent(new Event('selectionchange')) + } + const event = new InputEvent('beforeinput', { + inputType: 'insertText', data: 'X', bubbles: true, cancelable: true, + }) + rootEl.dispatchEvent(event) + const after = editor.getEditorState().read(() => $getRoot().getTextContent()) + // Record the verdict either way — the spike's job is the answer, not a pass. + console.log(`SPIKE beforeinput verdict: selectable=${selectable} after=${JSON.stringify(after)}`) + expect(typeof after).toBe('string') + }) + + it('keeps decorator DOM identity when text is inserted before the chip', async () => { + const { editor, rootEl } = makeEditor() + // Decorator portal loop (what the real DecoratorPortals component will do). + function Portals(): React.JSX.Element { + const [decorators, setDecorators] = React.useState>( + () => editor.getDecorators(), + ) + React.useLayoutEffect( + () => editor.registerDecoratorListener((next) => { setDecorators(next) }), + [], + ) + return ( + <> + {Object.entries(decorators).map(([key, jsx]) => { + const el = editor.getElementByKey(key) + return el === null ? null : createPortal(jsx, el, key) + })} + + ) + } + render() + + let chipKey = '' + act(() => { + editor.update(() => { + const p = $createParagraphNode() + const chip = new SpikeChipNode() + chipKey = chip.getKey() + p.append($createTextNode('before '), chip, $createTextNode(' after')) + $getRoot().append(p) + }, { discrete: true }) + }) + await Promise.resolve() + const chipButton = rootEl.querySelector('[data-chip-button]') + expect(chipButton).not.toBeNull() + const chipSpan = rootEl.querySelector('[data-spike-chip]') + + // Insert text before the chip through the node API (the transaction path). + act(() => { + editor.update(() => { + const p = $getRoot().getFirstChild() + if (p === null) throw new Error('paragraph missing') + const first = (p as ReturnType).getFirstChild() + if (first === null) throw new Error('text missing') + ;(first as ReturnType).spliceText(0, 0, '@') + }, { discrete: true }) + }) + await Promise.resolve() + // Chip DOM node identity survives (bug #2793's structural fix). + expect(rootEl.querySelector('[data-spike-chip]')).toBe(chipSpan) + expect(rootEl.querySelector('[data-chip-button]')).toBe(chipButton) + // Chip node identity survives in the tree (bug #2813's structural fix). + const stillThere = editor.getEditorState().read(() => { + const node = editor.getEditorState()._nodeMap.get(chipKey) + return node !== undefined + }) + expect(stillThere).toBe(true) + // Text content projection sees the clipboard form. + const text = editor.getEditorState().read(() => $getRoot().getTextContent()) + expect(text).toBe('@before /chip-clipboard after') + }) + + it('reports whether selection APIs let update-driven caret placement work', () => { + const { editor } = makeEditor() + editor.update(() => { + const p = $createParagraphNode() + const t = $createTextNode('abc') + p.append(t) + $getRoot().append(p) + t.select(1, 1) + }, { discrete: true }) + const verdict = editor.getEditorState().read(() => { + const sel = $getSelection() + return $isRangeSelection(sel) ? `range@${sel.anchor.offset}` : String(sel) + }) + console.log(`SPIKE selection verdict: ${verdict}`) + expect(verdict).toBe('range@1') + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74c628dd01..2237b86d9d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -122,7 +122,7 @@ importers: version: 6.1.1(typescript@6.0.3)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) vitest: specifier: ^4.1.8 - version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) apps/cli: dependencies: @@ -411,7 +411,7 @@ importers: version: 6.4.3(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0) vitest: specifier: ^4.1.8 - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@6.4.3(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@6.4.3(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) examples: dependencies: @@ -1858,9 +1858,24 @@ importers: '@deepseek-ai/schemastery': specifier: link:../../../vendor/schemastery version: link:../../../vendor/schemastery + '@lexical/history': + specifier: ^0.49.0 + version: 0.49.0(typescript@6.0.3) + '@lexical/plain-text': + specifier: ^0.49.0 + version: 0.49.0(typescript@6.0.3) + '@lexical/text': + specifier: ^0.49.0 + version: 0.49.0(typescript@6.0.3) + '@lexical/utils': + specifier: ^0.49.0 + version: 0.49.0(typescript@6.0.3) clsx: specifier: ^2.0.0 version: 2.1.1 + lexical: + specifier: ^0.49.0 + version: 0.49.0(typescript@6.0.3) devDependencies: '@deepseek-ai/cordis': specifier: workspace:^ @@ -1943,12 +1958,21 @@ importers: '@deepseek-ai/dsh-tools': specifier: workspace:^ version: link:../../core/tools + '@lexical/headless': + specifier: ^0.49.0 + version: 0.49.0(typescript@6.0.3) '@types/react': specifier: ~18.3.1 version: 18.3.31 + '@types/react-dom': + specifier: ~18.3.0 + version: 18.3.7(@types/react@18.3.31) react: specifier: ^18.2.0 version: 18.3.1 + react-dom: + specifier: ^18.2.0 + version: 18.3.1(react@18.3.1) packages/client/ui-deliverables: devDependencies: @@ -7982,7 +8006,7 @@ importers: version: link:../loader-smoke vitest: specifier: ^4.1.8 - version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) devDependencies: '@deepseek-ai/cordis': specifier: workspace:^ @@ -8031,7 +8055,7 @@ importers: version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) vitest: specifier: ^4.1.8 - version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) devDependencies: '@deepseek-ai/cordis': specifier: workspace:^ @@ -10450,6 +10474,102 @@ packages: cpu: [x64] os: [win32] + '@lexical/clipboard@0.49.0': + resolution: {integrity: sha512-AVKj21xH1qU7JAFA/v0hCoafa+Yti1I7cHG+JQIgc/EqCtP8ePeJyIfTPNN/tXskoCdq++HewQoiSXRwwlocVg==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/dragon@0.49.0': + resolution: {integrity: sha512-62/4DP5qyX/l4Yf5qRyyQrs9BV725eRU3OmLUW6g7T5xrcHXxAo7tia/NvqjqvXdpvQzyHjWgsy7dMitGITUsw==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/extension@0.49.0': + resolution: {integrity: sha512-Wv0VsuqxorbxHCK4ms1PwAu6cXIGNLtflq66auF+zwxOtBprkSFV8VzzzdKLOYD2admP0VK6EqVCeGXFK1GggA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/headless@0.49.0': + resolution: {integrity: sha512-3fQiKMAZ+K5/YlnGli9MId4LM8TPuOdLXIy1eUszfA/8hTZyPMcAxLjG99940UClgcoW9XxP03T37PJpFvpqIA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/history@0.49.0': + resolution: {integrity: sha512-uQdtEd34gIJklXNSdHS2Wko1zxx1xUMVXbiodcLO6a3GeFTE5bKnx6af1zGX78KpYhUQYnHWorKuUvtdZlJPaA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/html@0.49.0': + resolution: {integrity: sha512-NQqAydKzRjQl7Jx+bTTyC2iuz5uhuDaQX0SSPrdfgaFDCPjqQEejcBkCt1QXnu1CkbVHutZKVGVzljx40Y6y+Q==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/internal@0.49.0': + resolution: {integrity: sha512-s+XjPC7Qb39A/Xx9ahcz1s69CPix4ultaqyW+MDG0AXYW2quDr7m0USqReKIAiuoLIWtGN5HW8BwV2Y6t4qr6Q==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/list@0.49.0': + resolution: {integrity: sha512-zs6wYkxakDRcJO0KmwrPPHgeLLIxzjD+P2CRu+scJCHRuA5e2iSw2iFjH5n/LlWBrlnPMSjeQse4QqsRy9nnqA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/plain-text@0.49.0': + resolution: {integrity: sha512-l7IuUj9n9CtFfz4Fz6zU6mmO+VkcnvyyebABx+lHevvTa7B6YI5PPVgABFfzdyPanyW/FGs7qpKBf59inAqbkg==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/selection@0.49.0': + resolution: {integrity: sha512-08Vd1+VoC6YnztWOFWVsqF/Hxw5EP8qeL1c7t3+rVCV8revLzXxdQw+vbPX3tgM4fmjOBDUXk6Ws1+rTtsqjcQ==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/text@0.49.0': + resolution: {integrity: sha512-mowedvbvx0HDaW+ymVdYmWVhueqgauhhqIWaCtbJj33tPk8pOu1BB0pZuJQbOB+1bDnFiZhkJV8W/CvR2M9lEA==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + + '@lexical/utils@0.49.0': + resolution: {integrity: sha512-Jaa6DERBqxiFOFa49VPRV1WOb7mzRbMZ5U+v+RFagjzTmBhfxDmEkbQQ9nYTU3n3DPfdT8Hkyffextmw04etXg==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + '@mermaid-js/mermaid-mindmap@9.3.0': resolution: {integrity: sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==} @@ -11003,6 +11123,9 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@preact/signals-core@1.14.4': + resolution: {integrity: sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA==} + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -11716,6 +11839,9 @@ packages: '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -12068,6 +12194,10 @@ packages: buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-image-size@0.6.4: + resolution: {integrity: sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==} + engines: {node: '>=4.0'} + builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -12811,6 +12941,10 @@ packages: hachure-fill@0.5.2: resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + happy-dom@20.11.2: + resolution: {integrity: sha512-7MB+bJLkxu3SowAfBJbjW+c55kNz5tkR45gu2qzrxznezhLeN5YIlJbwUgSzlGc+qWoZ8Ykg71H5ezz69xixrw==} + engines: {node: '>=20.0.0'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -13180,6 +13314,14 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lexical@0.49.0: + resolution: {integrity: sha512-9V1ZIzGpJEd8rIN+nN7veL4fW4fFWbS66Un4JNqSZB4D5t9euzN9+3+jEXy83FjNjNy0MiiUI3+DQaGCLYko0w==} + peerDependencies: + typescript: '>=5.2' + peerDependenciesMeta: + typescript: + optional: true + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -14566,6 +14708,10 @@ packages: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + whatwg-mimetype@5.0.0: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} @@ -15853,6 +15999,111 @@ snapshots: '@koromix/koffi-win32-x64@3.1.1': optional: true + '@lexical/clipboard@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/extension': 0.49.0(typescript@6.0.3) + '@lexical/html': 0.49.0(typescript@6.0.3) + '@lexical/internal': 0.49.0(typescript@6.0.3) + '@lexical/list': 0.49.0(typescript@6.0.3) + '@lexical/selection': 0.49.0(typescript@6.0.3) + '@lexical/utils': 0.49.0(typescript@6.0.3) + '@types/trusted-types': 2.0.7 + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/dragon@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/extension': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/extension@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/internal': 0.49.0(typescript@6.0.3) + '@lexical/utils': 0.49.0(typescript@6.0.3) + '@preact/signals-core': 1.14.4 + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/headless@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/internal': 0.49.0(typescript@6.0.3) + happy-dom: 20.11.2 + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@lexical/history@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/extension': 0.49.0(typescript@6.0.3) + '@lexical/utils': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/html@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/extension': 0.49.0(typescript@6.0.3) + '@lexical/internal': 0.49.0(typescript@6.0.3) + '@lexical/selection': 0.49.0(typescript@6.0.3) + '@lexical/utils': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/internal@0.49.0(typescript@6.0.3)': + optionalDependencies: + typescript: 6.0.3 + + '@lexical/list@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/extension': 0.49.0(typescript@6.0.3) + '@lexical/html': 0.49.0(typescript@6.0.3) + '@lexical/internal': 0.49.0(typescript@6.0.3) + '@lexical/utils': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/plain-text@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/clipboard': 0.49.0(typescript@6.0.3) + '@lexical/dragon': 0.49.0(typescript@6.0.3) + '@lexical/extension': 0.49.0(typescript@6.0.3) + '@lexical/selection': 0.49.0(typescript@6.0.3) + '@lexical/utils': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/selection@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/internal': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/text@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/internal': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + + '@lexical/utils@0.49.0(typescript@6.0.3)': + dependencies: + '@lexical/internal': 0.49.0(typescript@6.0.3) + '@lexical/selection': 0.49.0(typescript@6.0.3) + lexical: 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + '@mermaid-js/mermaid-mindmap@9.3.0': dependencies: '@braintree/sanitize-url': 6.0.4 @@ -16254,6 +16505,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@preact/signals-core@1.14.4': {} + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -16863,8 +17116,7 @@ snapshots: '@types/tough-cookie@4.0.5': {} - '@types/trusted-types@2.0.7': - optional: true + '@types/trusted-types@2.0.7': {} '@types/turndown@5.0.6': {} @@ -16872,6 +17124,8 @@ snapshots: '@types/web-bluetooth@0.0.21': {} + '@types/whatwg-mimetype@3.0.2': {} + '@types/ws@8.18.1': dependencies: '@types/node': 22.20.0 @@ -16914,7 +17168,7 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) '@vitest/expect@4.1.8': dependencies: @@ -17263,6 +17517,10 @@ snapshots: buffer-equal-constant-time@1.0.1: {} + buffer-image-size@0.6.4: + dependencies: + '@types/node': 22.20.0 + builtin-modules@3.3.0: {} bundle-name@4.1.0: @@ -18124,6 +18382,19 @@ snapshots: hachure-fill@0.5.2: {} + happy-dom@20.11.2: + dependencies: + '@types/node': 22.20.0 + '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 + buffer-image-size: 0.6.4 + entities: 7.0.1 + whatwg-mimetype: 3.0.0 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -18483,6 +18754,12 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lexical@0.49.0(typescript@6.0.3): + dependencies: + '@lexical/internal': 0.49.0(typescript@6.0.3) + optionalDependencies: + typescript: 6.0.3 + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -20042,7 +20319,7 @@ snapshots: - typescript - universal-cookie - vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@6.4.3(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)): + vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@6.4.3(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.8 '@vitest/mocker': 4.1.8(vite@6.4.3(@types/node@22.20.0)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -20068,11 +20345,12 @@ snapshots: '@opentelemetry/api': 1.9.0 '@types/node': 22.20.0 '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) + happy-dom: 20.11.2 jsdom: 29.1.1 transitivePeerDependencies: - msw - vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): + vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.8 '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -20098,11 +20376,12 @@ snapshots: '@opentelemetry/api': 1.9.0 '@types/node': 25.9.3 '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) + happy-dom: 20.11.2 jsdom: 29.1.1 transitivePeerDependencies: - msw - vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): + vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.20.0)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.8 '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.20.0)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -20128,11 +20407,12 @@ snapshots: '@opentelemetry/api': 1.9.1 '@types/node': 22.20.0 '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) + happy-dom: 20.11.2 jsdom: 29.1.1 transitivePeerDependencies: - msw - vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): + vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(@vitest/coverage-v8@4.1.8)(happy-dom@20.11.2)(jsdom@29.1.1)(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.8 '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -20158,6 +20438,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@types/node': 25.9.3 '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) + happy-dom: 20.11.2 jsdom: 29.1.1 transitivePeerDependencies: - msw @@ -20195,6 +20476,8 @@ snapshots: webidl-conversions@8.0.1: {} + whatwg-mimetype@3.0.0: {} + whatwg-mimetype@5.0.0: {} whatwg-url@16.0.1: