diff --git a/packages/react/src/SuperDocEditor.test.tsx b/packages/react/src/SuperDocEditor.test.tsx index 6c469273ea..c93b3af722 100644 --- a/packages/react/src/SuperDocEditor.test.tsx +++ b/packages/react/src/SuperDocEditor.test.tsx @@ -175,6 +175,213 @@ describe('SuperDocEditor', () => { }); }); + describe('prop stability (SD-2635)', () => { + it('does not destroy/re-init when user prop is a new object literal with identical content', async () => { + const ref = createRef(); + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + + const { rerender } = render( + , + ); + + await waitFor(() => expect(onReady).toHaveBeenCalled(), { timeout: 5000 }); + const instanceBefore = ref.current?.getInstance(); + expect(instanceBefore).toBeTruthy(); + + // Re-render with a *new* object literal carrying the same content — + // this is the idiomatic React pattern that used to trigger a full + // destroy + re-init loop before SD-2635. + rerender( + , + ); + + // Same underlying instance proves no destroy+rebuild happened. + expect(ref.current?.getInstance()).toBe(instanceBefore); + expect(onEditorDestroy).not.toHaveBeenCalled(); + }); + + it('does not destroy/re-init when users prop is a new array literal with identical content', async () => { + const ref = createRef(); + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + + const { rerender } = render( + , + ); + + await waitFor(() => expect(onReady).toHaveBeenCalled(), { timeout: 5000 }); + const instanceBefore = ref.current?.getInstance(); + + rerender( + , + ); + + expect(ref.current?.getInstance()).toBe(instanceBefore); + expect(onEditorDestroy).not.toHaveBeenCalled(); + }); + + it('rebuilds and remounts a new instance when user prop value actually changes', async () => { + const ref = createRef(); + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + + const { rerender } = render( + , + ); + + await waitFor(() => expect(onReady).toHaveBeenCalled(), { timeout: 5000 }); + const instanceBefore = ref.current?.getInstance(); + + rerender( + , + ); + + // Old instance torn down, new instance ready. + await waitFor(() => expect(onEditorDestroy).toHaveBeenCalled(), { timeout: 5000 }); + await waitFor(() => expect(onReady).toHaveBeenCalledTimes(2), { timeout: 5000 }); + expect(ref.current?.getInstance()).not.toBe(instanceBefore); + }); + + it('stays stable under StrictMode double-invocation on rerender', async () => { + const ref = createRef(); + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + + const { rerender } = render( + + + , + ); + + await waitFor(() => expect(onReady).toHaveBeenCalled(), { timeout: 5000 }); + const instanceBefore = ref.current?.getInstance(); + const destroysBefore = onEditorDestroy.mock.calls.length; + + rerender( + + + , + ); + + expect(ref.current?.getInstance()).toBe(instanceBefore); + expect(onEditorDestroy.mock.calls.length).toBe(destroysBefore); + }); + + it('still rebuilds under StrictMode when user prop value actually changes', async () => { + // The same-content StrictMode test above proves memoization survives + // double-invocation. This test proves the positive path — a real + // value change under StrictMode still tears down and remounts. + const ref = createRef(); + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + + const { rerender } = render( + + + , + ); + + await waitFor(() => expect(onReady).toHaveBeenCalled(), { timeout: 5000 }); + const instanceBefore = ref.current?.getInstance(); + + rerender( + + + , + ); + + await waitFor(() => expect(onEditorDestroy).toHaveBeenCalled(), { timeout: 5000 }); + await waitFor(() => expect(ref.current?.getInstance()).not.toBe(instanceBefore), { timeout: 5000 }); + }); + + it('rebuilds when a new modules object is passed, even if content looks equal', async () => { + // `modules` is intentionally kept on reference identity in the dep + // array because it can carry functions and live objects that a + // structural compare would miss. This test pins that contract — + // if a future refactor wraps `modules` in useStructuralMemo, this + // test will fail and flag the regression. + const ref = createRef(); + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + + const { rerender } = render( + , + ); + + await waitFor(() => expect(onReady).toHaveBeenCalled(), { timeout: 5000 }); + const instanceBefore = ref.current?.getInstance(); + + rerender( + , + ); + + await waitFor(() => expect(onEditorDestroy).toHaveBeenCalled(), { timeout: 5000 }); + await waitFor(() => expect(onReady).toHaveBeenCalledTimes(2), { timeout: 5000 }); + expect(ref.current?.getInstance()).not.toBe(instanceBefore); + }); + }); + describe('unique IDs', () => { it('should generate unique container IDs for multiple instances', () => { const { container: container1 } = render(); diff --git a/packages/react/src/SuperDocEditor.tsx b/packages/react/src/SuperDocEditor.tsx index 33662a5555..b215bdacc0 100644 --- a/packages/react/src/SuperDocEditor.tsx +++ b/packages/react/src/SuperDocEditor.tsx @@ -7,7 +7,7 @@ import { type CSSProperties, type ForwardedRef, } from 'react'; -import { useStableId } from './utils'; +import { useStableId, useMemoByValue } from './utils'; import type { CallbackProps, DocumentMode, @@ -50,8 +50,8 @@ function SuperDocEditorInner(props: SuperDocEditorProps, ref: ForwardedRef(null); const toolbarContainerRef = useRef(null); @@ -223,8 +230,8 @@ function SuperDocEditorInner(props: SuperDocEditorProps, ref: ForwardedRef>[0]; +/** Surface where an editor event originated. */ +export type EditorSurface = 'body' | 'header' | 'footer'; -/** Event passed to onTransaction callback */ -export type SuperDocTransactionEvent = Parameters>[0]; +/** Event passed to onEditorUpdate callback. Mirrors superdoc's EditorUpdateEvent. */ +export interface SuperDocEditorUpdateEvent { + /** The primary editor associated with the update. For header/footer edits, this is the main body editor. */ + editor: Editor; + /** The editor instance that emitted the update. For body edits, this matches `editor`. */ + sourceEditor: Editor; + /** The surface where the edit originated. */ + surface: EditorSurface; + /** Relationship ID for header/footer edits. */ + headerId?: string | null; + /** Header/footer variant (`default`, `first`, `even`, `odd`) when available. */ + sectionType?: string | null; +} /** Event passed to onContentError callback */ export interface SuperDocContentErrorEvent { diff --git a/packages/react/src/utils.test.ts b/packages/react/src/utils.test.ts new file mode 100644 index 0000000000..6e651fb7d3 --- /dev/null +++ b/packages/react/src/utils.test.ts @@ -0,0 +1,75 @@ +import { describe, it, expect } from 'vitest'; +import { renderHook } from '@testing-library/react'; +import { useMemoByValue } from './utils'; + +describe('useMemoByValue', () => { + it('returns the same reference across renders when content is unchanged', () => { + const initial = { name: 'Alex', email: 'alex@example.com' }; + const { result, rerender } = renderHook(({ value }) => useMemoByValue(value), { + initialProps: { value: initial }, + }); + + const first = result.current; + expect(first).toBe(initial); + + // Parent passes a fresh object literal with identical content + rerender({ value: { name: 'Alex', email: 'alex@example.com' } }); + expect(result.current).toBe(first); // same reference — critical for effect deps + + // And again, still stable + rerender({ value: { name: 'Alex', email: 'alex@example.com' } }); + expect(result.current).toBe(first); + }); + + it('returns a new reference when the content actually changes', () => { + const { result, rerender } = renderHook(({ value }) => useMemoByValue(value), { + initialProps: { value: { name: 'Alex' } }, + }); + + const first = result.current; + rerender({ value: { name: 'Jamie' } }); + expect(result.current).not.toBe(first); + expect(result.current.name).toBe('Jamie'); + }); + + it('handles undefined and null stably', () => { + const { result, rerender } = renderHook(({ value }) => useMemoByValue(value as unknown), { + initialProps: { value: undefined }, + }); + + const first = result.current; + rerender({ value: undefined }); + expect(result.current).toBe(first); + + rerender({ value: null }); + expect(result.current).toBe(null); + }); + + it('stabilizes arrays the same way as objects', () => { + const { result, rerender } = renderHook(({ value }) => useMemoByValue(value), { + initialProps: { value: [{ id: 1 }, { id: 2 }] }, + }); + + const first = result.current; + rerender({ value: [{ id: 1 }, { id: 2 }] }); + expect(result.current).toBe(first); + + rerender({ value: [{ id: 1 }, { id: 3 }] }); + expect(result.current).not.toBe(first); + }); + + it('adopts a new reference on circular input (JSON.stringify throws)', () => { + const circularA: { self?: unknown; name: string } = { name: 'a' }; + circularA.self = circularA; + + const { result, rerender } = renderHook(({ value }) => useMemoByValue(value), { + initialProps: { value: circularA }, + }); + + const circularB: { self?: unknown; name: string } = { name: 'a' }; + circularB.self = circularB; + rerender({ value: circularB }); + // The compare throws; the hook falls back to adopting the new reference. + expect(result.current).toBe(circularB); + }); +}); diff --git a/packages/react/src/utils.ts b/packages/react/src/utils.ts index 6162d2b8f1..782e8fe7af 100644 --- a/packages/react/src/utils.ts +++ b/packages/react/src/utils.ts @@ -25,3 +25,42 @@ function useIdPolyfill(): string { */ export const useStableId: () => string = typeof (React as any).useId === 'function' ? (React as any).useId : useIdPolyfill; + +/** + * Returns a reference-stable version of `value` — identity only changes + * when the serialized content changes. + * + * Use for plain-data object/array props that feed into `useEffect` / + * `useMemo` dependency arrays when the consumer is likely to pass inline + * literals. Without this, every parent re-render produces a fresh + * reference and causes the effect to re-run even when the content is + * identical. + * + * Not suitable for values containing functions, class instances (Yjs + * Doc, Maps, Sets, Dates), or circular references — JSON.stringify + * drops or collapses those. The compare only runs when the incoming + * reference differs, so the steady-state cost is a single pointer check. + */ +export function useMemoByValue(value: T): T { + const lastRawRef = React.useRef(value); + const stableRef = React.useRef(value); + + if (lastRawRef.current !== value) { + if (!shallowJsonEqual(stableRef.current, value)) { + stableRef.current = value; + } + lastRawRef.current = value; + } + + return stableRef.current; +} + +function shallowJsonEqual(a: T, b: T): boolean { + if (a === b) return true; + if (a == null || b == null) return a === b; + try { + return JSON.stringify(a) === JSON.stringify(b); + } catch { + return false; + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46e0c792ab..69c691e95d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -549,7 +549,7 @@ importers: version: 14.0.3 mintlify: specifier: 4.2.446 - version: 4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.6.0)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) remark-mdx: specifier: ^3.1.1 version: 3.1.1 @@ -26333,16 +26333,6 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/checkbox@4.3.2(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/checkbox@4.3.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26368,13 +26358,6 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 - '@inquirer/confirm@5.1.21(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/confirm@5.1.21(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26389,19 +26372,6 @@ snapshots: optionalDependencies: '@types/node': 18.19.130 - '@inquirer/core@10.3.2(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - cli-width: 4.1.0 - mute-stream: 2.0.0 - signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/core@10.3.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26468,14 +26438,6 @@ snapshots: chalk: 4.1.2 external-editor: 3.1.0 - '@inquirer/editor@4.2.23(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/external-editor': 1.0.3(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/editor@4.2.23(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26499,14 +26461,6 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/expand@4.0.23(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/expand@4.0.23(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26515,13 +26469,6 @@ snapshots: optionalDependencies: '@types/node': 25.6.0 - '@inquirer/external-editor@1.0.3(@types/node@22.19.2)': - dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/external-editor@1.0.3(@types/node@25.6.0)': dependencies: chardet: 2.1.1 @@ -26546,13 +26493,6 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 - '@inquirer/input@4.3.1(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/input@4.3.1(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26567,13 +26507,6 @@ snapshots: optionalDependencies: '@types/node': 18.19.130 - '@inquirer/number@3.0.23(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/number@3.0.23(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26588,14 +26521,6 @@ snapshots: ansi-escapes: 4.3.2 chalk: 4.1.2 - '@inquirer/password@4.0.23(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/password@4.0.23(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26616,21 +26541,6 @@ snapshots: '@inquirer/rawlist': 1.2.16 '@inquirer/select': 1.3.3 - '@inquirer/prompts@7.10.1(@types/node@22.19.2)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) - '@inquirer/confirm': 5.1.21(@types/node@22.19.2) - '@inquirer/editor': 4.2.23(@types/node@22.19.2) - '@inquirer/expand': 4.0.23(@types/node@22.19.2) - '@inquirer/input': 4.3.1(@types/node@22.19.2) - '@inquirer/number': 3.0.23(@types/node@22.19.2) - '@inquirer/password': 4.0.23(@types/node@22.19.2) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) - '@inquirer/search': 3.2.2(@types/node@22.19.2) - '@inquirer/select': 4.4.2(@types/node@22.19.2) - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/prompts@7.10.1(@types/node@25.6.0)': dependencies: '@inquirer/checkbox': 4.3.2(@types/node@25.6.0) @@ -26646,20 +26556,20 @@ snapshots: optionalDependencies: '@types/node': 25.6.0 - '@inquirer/prompts@7.9.0(@types/node@22.19.2)': + '@inquirer/prompts@7.9.0(@types/node@25.6.0)': dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.2) - '@inquirer/confirm': 5.1.21(@types/node@22.19.2) - '@inquirer/editor': 4.2.23(@types/node@22.19.2) - '@inquirer/expand': 4.0.23(@types/node@22.19.2) - '@inquirer/input': 4.3.1(@types/node@22.19.2) - '@inquirer/number': 3.0.23(@types/node@22.19.2) - '@inquirer/password': 4.0.23(@types/node@22.19.2) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.2) - '@inquirer/search': 3.2.2(@types/node@22.19.2) - '@inquirer/select': 4.4.2(@types/node@22.19.2) + '@inquirer/checkbox': 4.3.2(@types/node@25.6.0) + '@inquirer/confirm': 5.1.21(@types/node@25.6.0) + '@inquirer/editor': 4.2.23(@types/node@25.6.0) + '@inquirer/expand': 4.0.23(@types/node@25.6.0) + '@inquirer/input': 4.3.1(@types/node@25.6.0) + '@inquirer/number': 3.0.23(@types/node@25.6.0) + '@inquirer/password': 4.0.23(@types/node@25.6.0) + '@inquirer/rawlist': 4.1.11(@types/node@25.6.0) + '@inquirer/search': 3.2.2(@types/node@25.6.0) + '@inquirer/select': 4.4.2(@types/node@25.6.0) optionalDependencies: - '@types/node': 22.19.2 + '@types/node': 25.6.0 '@inquirer/rawlist@1.2.16': dependencies: @@ -26667,14 +26577,6 @@ snapshots: '@inquirer/type': 1.5.5 chalk: 4.1.2 - '@inquirer/rawlist@4.1.11(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/rawlist@4.1.11(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26683,15 +26585,6 @@ snapshots: optionalDependencies: '@types/node': 25.6.0 - '@inquirer/search@3.2.2(@types/node@22.19.2)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/search@3.2.2(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -26709,16 +26602,6 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/select@4.4.2(@types/node@22.19.2)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.2) - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/select@4.4.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -26742,10 +26625,6 @@ snapshots: dependencies: mute-stream: 1.0.0 - '@inquirer/type@3.0.10(@types/node@22.19.2)': - optionalDependencies: - '@types/node': 22.19.2 - '@inquirer/type@3.0.10(@types/node@25.6.0)': optionalDependencies: '@types/node': 25.6.0 @@ -27310,11 +27189,11 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@mintlify/cli@4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@mintlify/cli@4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.6.0)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: - '@inquirer/prompts': 7.9.0(@types/node@22.19.2) + '@inquirer/prompts': 7.9.0(@types/node@25.6.0) '@mintlify/common': 1.0.813(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@mintlify/link-rot': 3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@mintlify/link-rot': 3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/models': 0.0.286 '@mintlify/prebuild': 1.0.954(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/previewing': 4.0.1012(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) @@ -27327,7 +27206,7 @@ snapshots: front-matter: 4.0.2 fs-extra: 11.2.0 ink: 6.3.0(@types/react@19.2.14)(react@19.2.3) - inquirer: 12.3.0(@types/node@22.19.2) + inquirer: 12.3.0(@types/node@25.6.0) js-yaml: 4.1.0 mdast-util-mdx-jsx: 3.2.0 react: 19.2.3 @@ -27353,7 +27232,7 @@ snapshots: - utf-8-validate - yaml - '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@asyncapi/parser': 3.4.0 '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) @@ -27393,7 +27272,7 @@ snapshots: remark-parse: 11.0.0 remark-rehype: 11.1.1 remark-stringify: 11.0.0 - tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3)) + tailwindcss: 3.4.4(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3)) unified: 11.0.5 unist-builder: 4.0.0 unist-util-map: 4.0.0 @@ -27477,12 +27356,12 @@ snapshots: - typescript - yaml - '@mintlify/link-rot@3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': + '@mintlify/link-rot@3.0.983(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@mintlify/common': 1.0.813(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/prebuild': 1.0.954(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) '@mintlify/previewing': 4.0.1012(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) - '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/validation': 0.1.640(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) fs-extra: 11.1.0 unist-util-visit: 4.1.2 @@ -27626,9 +27505,9 @@ snapshots: - utf-8-validate - yaml - '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3)': + '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(typescript@5.9.3) + '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 fs-extra: 11.1.1 hast-util-to-mdast: 10.1.0 @@ -38850,12 +38729,12 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - inquirer@12.3.0(@types/node@22.19.2): + inquirer@12.3.0(@types/node@25.6.0): dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.2) - '@inquirer/prompts': 7.10.1(@types/node@22.19.2) - '@inquirer/type': 3.0.10(@types/node@22.19.2) - '@types/node': 22.19.2 + '@inquirer/core': 10.3.2(@types/node@25.6.0) + '@inquirer/prompts': 7.10.1(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@types/node': 25.6.0 ansi-escapes: 4.3.2 mute-stream: 2.0.0 run-async: 3.0.0 @@ -41227,9 +41106,9 @@ snapshots: dependencies: minipass: 7.1.3 - mintlify@4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): + mintlify@4.2.446(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.6.0)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: - '@mintlify/cli': 4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.2)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@mintlify/cli': 4.0.1049(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@25.6.0)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.3))(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3))(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) transitivePeerDependencies: - '@radix-ui/react-popover' - '@types/node' @@ -43188,13 +43067,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.8 - postcss-load-config@4.0.2(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.3 optionalDependencies: postcss: 8.5.10 - ts-node: 10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3) + ts-node: 10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3) postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3): dependencies: @@ -46397,7 +46276,7 @@ snapshots: - tsx - yaml - tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3)): + tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -46416,7 +46295,7 @@ snapshots: postcss: 8.5.10 postcss-import: 15.1.0(postcss@8.5.10) postcss-js: 4.1.0(postcss@8.5.10) - postcss-load-config: 4.0.2(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3)) + postcss-load-config: 4.0.2(postcss@8.5.10)(ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3)) postcss-nested: 6.2.0(postcss@8.5.10) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -46786,14 +46665,14 @@ snapshots: '@swc/core': 1.15.21 optional: true - ts-node@10.9.2(@swc/core@1.15.21)(@types/node@22.19.2)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.21)(@types/node@25.6.0)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.19.2 + '@types/node': 25.6.0 acorn: 8.16.0 acorn-walk: 8.3.5 arg: 4.1.3