refactor: sanitize HTML function (#8307)

* refactor: replace isomorphic-dompurify with sanitize-html

* dompurify fixes

* more fixes with fallback and title

* build

---------

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
This commit is contained in:
M. Palanikannan 2025-12-11 13:30:31 +05:30 committed by GitHub
parent 76ebf395e6
commit e0c97c5471
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 235 additions and 260 deletions

View file

@ -45,7 +45,6 @@
"express-ws": "^5.0.2",
"helmet": "^7.1.0",
"ioredis": "5.7.0",
"isomorphic-dompurify": "^1.8.0",
"uuid": "catalog:",
"ws": "^8.18.3",
"y-prosemirror": "^1.3.7",

View file

@ -20,24 +20,32 @@ const fetchDocument = async ({ context, documentName: pageId, instance }: FetchP
try {
const service = getPageService(context.documentType, context);
// fetch details
const response = await service.fetchDescriptionBinary(pageId);
const response = (await service.fetchDescriptionBinary(pageId)) as Buffer;
const binaryData = new Uint8Array(response);
// if binary data is empty, convert HTML to binary data
if (binaryData.byteLength === 0) {
const pageDetails = await service.fetchDetails(pageId);
const convertedBinaryData = getBinaryDataFromDocumentEditorHTMLString(pageDetails.description_html ?? "<p></p>");
const convertedBinaryData = getBinaryDataFromDocumentEditorHTMLString(
pageDetails.description_html ?? "<p></p>",
pageDetails.name
);
if (convertedBinaryData) {
// save the converted binary data back to the database
const { contentBinaryEncoded, contentHTML, contentJSON } = getAllDocumentFormatsFromDocumentEditorBinaryData(
convertedBinaryData,
true
);
const payload = {
description_binary: contentBinaryEncoded,
description_html: contentHTML,
description: contentJSON,
};
await service.updateDescriptionBinary(pageId, payload);
try {
const { contentBinaryEncoded, contentHTML, contentJSON } = getAllDocumentFormatsFromDocumentEditorBinaryData(
convertedBinaryData,
true
);
const payload = {
description_binary: contentBinaryEncoded,
description_html: contentHTML,
description: contentJSON,
};
await service.updateDescriptionBinary(pageId, payload);
} catch (e) {
const error = new AppError(e);
logger.error("Failed to save binary after first convertion from html:", error);
}
return convertedBinaryData;
}
}

View file

@ -1,5 +1,13 @@
import { Database } from "./database";
import { ForceCloseHandler } from "./force-close-handler";
import { Logger } from "./logger";
import { Redis } from "./redis";
import { TitleSyncExtension } from "./title-sync";
export const getExtensions = () => [new Logger(), new Database(), new Redis()];
export const getExtensions = () => [
new Logger(),
new Database(),
new Redis(),
new TitleSyncExtension(),
new ForceCloseHandler(), // Must be after Redis to receive broadcasts
];

View file

@ -1,18 +1,22 @@
// hocuspocus
import type { Extension, Hocuspocus, Document } from "@hocuspocus/server";
import { TiptapTransformer } from "@hocuspocus/transformer";
import type { AnyExtension, JSONContent } from "@tiptap/core";
import type * as Y from "yjs";
// editor extensions
import { TITLE_EDITOR_EXTENSIONS, createRealtimeEvent } from "@plane/editor";
import {
TITLE_EDITOR_EXTENSIONS,
createRealtimeEvent,
extractTextFromHTML,
generateTitleProsemirrorJson,
} from "@plane/editor";
import { logger } from "@plane/logger";
import { AppError } from "@/lib/errors";
// helpers
import { getPageService } from "@/services/page/handler";
import type { HocusPocusServerContext, OnLoadDocumentPayloadWithContext } from "@/types";
import { generateTitleProsemirrorJson } from "@/utils";
import { broadcastMessageToPage } from "@/utils/broadcast-message";
import { TitleUpdateManager } from "./title-update/title-update-manager";
import { extractTextFromHTML } from "./title-update/title-utils";
/**
* Hocuspocus extension for synchronizing document titles
@ -41,15 +45,11 @@ export class TitleSyncExtension implements Extension {
// in the yjs binary
if (document.isEmpty("title")) {
const service = getPageService(context.documentType, context);
// const title = await service.fe
const title = (await service.fetchDetails?.(documentName)).name;
const pageDetails = await service.fetchDetails(documentName);
const title = pageDetails.name;
if (title == null) return;
const titleField = TiptapTransformer.toYdoc(
generateTitleProsemirrorJson(title),
"title",
// editor
TITLE_EDITOR_EXTENSIONS as any
);
const titleJson = (generateTitleProsemirrorJson as (text: string) => JSONContent)(title);
const titleField = TiptapTransformer.toYdoc(titleJson, "title", TITLE_EDITOR_EXTENSIONS as AnyExtension[]);
document.merge(titleField);
}
} catch (error) {

View file

@ -1,21 +0,0 @@
import DOMPurify from "isomorphic-dompurify";
/**
* Sanitizes HTML by removing all HTML tags, leaving only text content
* @param htmlString - The HTML string to sanitize
* @returns The sanitized text with all HTML tags removed
*/
const sanitizeHTML = (htmlString: string): string => {
const sanitizedText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: [] }); // sanitize the string to remove all HTML tags
return sanitizedText.trim(); // trim the string to remove leading and trailing whitespaces
};
/**
* Utility function to extract text from HTML content
*/
export const extractTextFromHTML = (html: string): string => {
// Use sanitizeHTML to safely extract text and remove all HTML tags
// This is more secure than regex as it handles edge cases and prevents injection
// Note: sanitizeHTML trims whitespace, which is acceptable for title extraction
return sanitizeHTML(html) || "";
};

View file

@ -1,21 +0,0 @@
export const generateTitleProsemirrorJson = (text: string) => {
return {
type: "doc",
content: [
{
type: "heading",
attrs: { level: 1 },
...(text
? {
content: [
{
type: "text",
text,
},
],
}
: {}),
},
],
};
};

View file

@ -1 +0,0 @@
export * from "./document";

View file

@ -69,6 +69,7 @@ export const PageRoot = observer((props: TPageRootProps) => {
const { isFetchingFallbackBinary } = usePageFallback({
editorRef,
fetchPageDescription: handlers.fetchDescriptionBinary,
page,
collaborationState,
updatePageDescription: handlers.updateDescription,
});

View file

@ -2,22 +2,22 @@ import { useCallback, useEffect, useRef, useState } from "react";
import type { EditorRefApi, CollaborationState } from "@plane/editor";
// plane editor
import { convertBinaryDataToBase64String, getBinaryDataFromDocumentEditorHTMLString } from "@plane/editor";
// plane propel
import { setToast, TOAST_TYPE } from "@plane/propel/toast";
// plane types
import type { TDocumentPayload } from "@plane/types";
// hooks
import useAutoSave from "@/hooks/use-auto-save";
import type { TPageInstance } from "@/store/pages/base-page";
type TArgs = {
editorRef: React.RefObject<EditorRefApi>;
fetchPageDescription: () => Promise<ArrayBuffer>;
collaborationState: CollaborationState | null;
updatePageDescription: (data: TDocumentPayload) => Promise<void>;
page: TPageInstance;
};
export const usePageFallback = (args: TArgs) => {
const { editorRef, fetchPageDescription, collaborationState, updatePageDescription } = args;
const { editorRef, fetchPageDescription, collaborationState, updatePageDescription, page } = args;
const hasShownFallbackToast = useRef(false);
const [isFetchingFallbackBinary, setIsFetchingFallbackBinary] = useState(false);
@ -32,12 +32,7 @@ export const usePageFallback = (args: TArgs) => {
// Show toast notification when fallback mechanism kicks in (only once)
if (!hasShownFallbackToast.current) {
// setToast({
// type: TOAST_TYPE.WARNING,
// title: "Connection lost",
// message: "Your changes are being saved using backup mechanism. ",
// });
console.log("Connection lost");
console.warn("Websocket Connection lost, your changes are being saved using backup mechanism.");
hasShownFallbackToast.current = true;
}
@ -49,7 +44,11 @@ export const usePageFallback = (args: TArgs) => {
if (latestEncodedDescription && latestEncodedDescription.byteLength > 0) {
latestDecodedDescription = new Uint8Array(latestEncodedDescription);
} else {
latestDecodedDescription = getBinaryDataFromDocumentEditorHTMLString("<p></p>");
const pageDescriptionHtml = page.description_html;
latestDecodedDescription = getBinaryDataFromDocumentEditorHTMLString(
pageDescriptionHtml ?? "<p></p>",
page.name
);
}
editor.setProviderDocument(latestDecodedDescription);
@ -64,15 +63,10 @@ export const usePageFallback = (args: TArgs) => {
});
} catch (error: any) {
console.error(error);
// setToast({
// type: TOAST_TYPE.ERROR,
// title: "Error",
// message: `Failed to update description using backup mechanism, ${error?.message}`,
// });
} finally {
setIsFetchingFallbackBinary(false);
}
}, [editorRef, fetchPageDescription, hasConnectionFailed, updatePageDescription]);
}, [editorRef, fetchPageDescription, hasConnectionFailed, updatePageDescription, page.description_html, page.name]);
useEffect(() => {
if (hasConnectionFailed) {

View file

@ -66,7 +66,6 @@
"emoji-regex": "^10.3.0",
"highlight.js": "^11.8.0",
"is-emoji-supported": "^0.0.5",
"isomorphic-dompurify": "^1.8.0",
"jsx-dom-cjs": "^8.0.3",
"linkifyjs": "^4.3.2",
"lowlight": "^3.0.0",

View file

@ -1,5 +1,5 @@
import { Buffer } from "buffer";
import type { Extensions } from "@tiptap/core";
import type { Extensions, JSONContent } from "@tiptap/core";
import { getSchema } from "@tiptap/core";
import { generateHTML, generateJSON } from "@tiptap/html";
import { prosemirrorJSONToYDoc, yXmlFragmentToProseMirrorRootNode } from "y-prosemirror";
@ -11,7 +11,7 @@ import {
DocumentEditorExtensionsWithoutProps,
} from "@/extensions/core-without-props";
import { TitleExtensions } from "@/extensions/title-extension";
import DOMPurify from "isomorphic-dompurify";
import { sanitizeHTML } from "@plane/utils";
// editor extension configs
const RICH_TEXT_EDITOR_EXTENSIONS = CoreEditorExtensionsWithoutProps;
@ -69,16 +69,49 @@ export const getBinaryDataFromRichTextEditorHTMLString = (descriptionHTML: strin
return encodedData;
};
export const generateTitleProsemirrorJson = (text: string): JSONContent => {
return {
type: "doc",
content: [
{
type: "heading",
attrs: { level: 1 },
...(text
? {
content: [
{
type: "text",
text,
},
],
}
: {}),
},
],
};
};
/**
* @description this function generates the binary equivalent of html content for the document editor
* @param {string} descriptionHTML
* @param {string} descriptionHTML - The HTML content to convert
* @param {string} [title] - Optional title to append to the document
* @returns {Uint8Array}
*/
export const getBinaryDataFromDocumentEditorHTMLString = (descriptionHTML: string): Uint8Array => {
export const getBinaryDataFromDocumentEditorHTMLString = (descriptionHTML: string, title?: string): Uint8Array => {
// convert HTML to JSON
const contentJSON = generateJSON(descriptionHTML ?? "<p></p>", DOCUMENT_EDITOR_EXTENSIONS);
// convert JSON to Y.Doc format
const transformedData = prosemirrorJSONToYDoc(documentEditorSchema, contentJSON, "default");
// If title is provided, merge it into the document
if (title != null) {
const titleJSON = generateTitleProsemirrorJson(title);
const titleField = prosemirrorJSONToYDoc(documentEditorSchema, titleJSON, "title");
// Encode the title YDoc to updates and apply them to the main document
const titleUpdates = Y.encodeStateAsUpdate(titleField);
Y.applyUpdate(transformedData, titleUpdates);
}
// convert Y.Doc to Uint8Array format
const encodedData = Y.encodeStateAsUpdate(transformedData);
return encodedData;
@ -210,6 +243,6 @@ export const extractTextFromHTML = (html: string): string => {
// Use DOMPurify to safely extract text and remove all HTML tags
// This is more secure than regex as it handles edge cases and prevents injection
// Note: sanitizeHTML trims whitespace, which is acceptable for title extraction
const sanitizedText = DOMPurify.sanitize(html, { ALLOWED_TAGS: [] }); // sanitize the string to remove all HTML tags
const sanitizedText = sanitizeHTML(html); // sanitize the string to remove all HTML tags
return sanitizedText.trim() || ""; // trim the string to remove leading and trailing whitespaces
};

View file

@ -27,7 +27,6 @@
"@plane/types": "workspace:*",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"dompurify": "3.2.7",
"hast": "^1.0.0",
"hast-util-to-mdast": "^10.1.2",
"lodash-es": "catalog:",
@ -38,6 +37,7 @@
"rehype-remark": "^10.0.1",
"remark-gfm": "^4.0.1",
"remark-stringify": "^11.0.0",
"sanitize-html": "2.17.0",
"tailwind-merge": "^2.5.5",
"unified": "^11.0.5",
"uuid": "catalog:"
@ -49,6 +49,7 @@
"@types/mdast": "^4.0.4",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/sanitize-html": "2.16.0",
"tsdown": "catalog:",
"typescript": "catalog:"
},

View file

@ -1,4 +1,4 @@
import DOMPurify from "dompurify";
import sanitizeHtml from "sanitize-html";
import type { Content, JSONContent } from "@plane/types";
/**
@ -120,7 +120,7 @@ const text = stripHTML(html);
console.log(text); // Some text
*/
export const sanitizeHTML = (htmlString: string) => {
const sanitizedText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: [] }); // sanitize the string to remove all HTML tags
const sanitizedText = sanitizeHtml(htmlString, { allowedTags: [] }); // sanitize the string to remove all HTML tags
return sanitizedText.trim(); // trim the string to remove leading and trailing whitespaces
};
@ -155,8 +155,8 @@ export const checkEmailValidity = (email: string): boolean => {
};
export const isEmptyHtmlString = (htmlString: string, allowedHTMLTags: string[] = []) => {
// Remove HTML tags using DOMPurify
const cleanText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: allowedHTMLTags });
// Remove HTML tags using sanitize-html
const cleanText = sanitizeHtml(htmlString, { allowedTags: allowedHTMLTags });
// Trim the string and check if it's empty
return cleanText.trim() === "";
};

305
pnpm-lock.yaml generated
View file

@ -129,7 +129,7 @@ importers:
version: 0.1.3
'@vitest/eslint-plugin':
specifier: 1.5.1
version: 1.5.1(eslint@9.39.1(jiti@2.5.1))(typescript@5.8.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@23.2.0)(terser@5.43.1)(yaml@2.8.1))
version: 1.5.1(eslint@9.39.1(jiti@2.5.1))(typescript@5.8.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@25.0.1)(terser@5.43.1)(yaml@2.8.1))
eslint:
specifier: 9.39.1
version: 9.39.1(jiti@2.5.1)
@ -371,9 +371,6 @@ importers:
ioredis:
specifier: 5.7.0
version: 5.7.0
isomorphic-dompurify:
specifier: ^1.8.0
version: 1.13.0
uuid:
specifier: 'catalog:'
version: 13.0.0
@ -784,7 +781,7 @@ importers:
version: 17.3.0
vitest:
specifier: ^4.0.8
version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@23.2.0)(terser@5.43.1)(yaml@2.8.1)
version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@25.0.1)(terser@5.43.1)(yaml@2.8.1)
packages/constants:
dependencies:
@ -942,9 +939,6 @@ importers:
is-emoji-supported:
specifier: ^0.0.5
version: 0.0.5
isomorphic-dompurify:
specifier: ^1.8.0
version: 1.13.0
jsx-dom-cjs:
specifier: ^8.0.3
version: 8.1.6
@ -1457,9 +1451,6 @@ importers:
date-fns:
specifier: ^4.1.0
version: 4.1.0
dompurify:
specifier: 3.2.7
version: 3.2.7
hast:
specifier: ^1.0.0
version: 1.0.0
@ -1490,6 +1481,9 @@ importers:
remark-stringify:
specifier: ^11.0.0
version: 11.0.0
sanitize-html:
specifier: 2.17.0
version: 2.17.0
tailwind-merge:
specifier: ^2.5.5
version: 2.6.0
@ -1518,6 +1512,9 @@ importers:
'@types/react':
specifier: 'catalog:'
version: 18.3.11
'@types/sanitize-html':
specifier: 2.16.0
version: 2.16.0
tsdown:
specifier: 'catalog:'
version: 0.16.0(typescript@5.8.3)
@ -1547,9 +1544,6 @@ packages:
'@asamuzakjp/css-color@3.2.0':
resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
'@asamuzakjp/dom-selector@2.0.2':
resolution: {integrity: sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==}
'@atlaskit/pragmatic-drag-and-drop-auto-scroll@1.4.0':
resolution: {integrity: sha512-5GoikoTSW13UX76F9TDeWB8x3jbbGlp/Y+3aRkHe1MOBMkrWkwNpJ42MIVhhX/6NSeaZiPumP0KbGJVs2tOWSQ==}
@ -1836,8 +1830,8 @@ packages:
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
engines: {node: '>=0.1.90'}
'@csstools/color-helpers@5.1.0':
resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==}
'@csstools/color-helpers@5.0.2':
resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
engines: {node: '>=18'}
'@csstools/css-calc@2.1.4':
@ -1847,8 +1841,8 @@ packages:
'@csstools/css-parser-algorithms': ^3.0.5
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-color-parser@3.1.0':
resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==}
'@csstools/css-color-parser@3.0.10':
resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-parser-algorithms': ^3.0.5
@ -4031,10 +4025,6 @@ packages:
'@types/dom4@2.0.4':
resolution: {integrity: sha512-PD+wqNhrjWFjAlSVd18jvChZvOXB2SOwAILBmuYev5zswBats5qmzs/QFoooLKd2omj9BT05a8MeSeRmXLGY+Q==}
'@types/dompurify@3.2.0':
resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==}
deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.
'@types/eslint-scope@3.7.7':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
@ -4159,6 +4149,9 @@ packages:
'@types/resolve@1.20.6':
resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==}
'@types/sanitize-html@2.16.0':
resolution: {integrity: sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==}
'@types/semver@7.7.1':
resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==}
@ -4882,9 +4875,6 @@ packages:
resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==}
engines: {node: '>=14.16'}
caniuse-lite@1.0.30001743:
resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==}
caniuse-lite@1.0.30001759:
resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==}
@ -5169,10 +5159,6 @@ packages:
resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
engines: {node: '>=8.0.0'}
css-tree@2.3.1:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
css-what@6.2.2:
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
engines: {node: '>= 6'}
@ -5277,15 +5263,6 @@ packages:
supports-color:
optional: true
debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
@ -5447,12 +5424,6 @@ packages:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
dompurify@3.2.6:
resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==}
dompurify@3.2.7:
resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==}
domutils@2.8.0:
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
@ -6315,6 +6286,9 @@ packages:
htmlparser2@6.1.0:
resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
@ -6527,6 +6501,10 @@ packages:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
is-plain-object@5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
is-port-reachable@4.0.0:
resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -6599,10 +6577,6 @@ packages:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}
isomorphic-dompurify@1.13.0:
resolution: {integrity: sha512-9qOYGngy9ZR9JB/iLmr7SViPSZ7uWGvepdnLaXYznbTxvJOCuONneKajJ54f+IRQpvL8608ylUy9EK1iPtL3Ag==}
engines: {node: '>=18'}
isomorphic.js@0.2.5:
resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==}
@ -6650,8 +6624,8 @@ packages:
resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==}
engines: {node: '>=12.0.0'}
jsdom@23.2.0:
resolution: {integrity: sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==}
jsdom@25.0.1:
resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@ -6955,9 +6929,6 @@ packages:
mdn-data@2.0.14:
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
mdn-data@2.0.30:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
@ -7374,6 +7345,9 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
nwsapi@2.2.21:
resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@ -7529,6 +7503,9 @@ packages:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
parse-srcset@1.0.2:
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
parse-svg-path@0.1.2:
resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==}
@ -7914,9 +7891,6 @@ packages:
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
psl@1.15.0:
resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@ -7939,9 +7913,6 @@ packages:
quansync@0.2.11:
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -8236,9 +8207,6 @@ packages:
resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==}
engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'}
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
@ -8313,8 +8281,8 @@ packages:
rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
rrweb-cssom@0.7.1:
resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==}
rrweb-cssom@0.8.0:
resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
@ -8351,6 +8319,9 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sanitize-html@2.17.0:
resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
@ -8814,6 +8785,13 @@ packages:
peerDependencies:
'@tiptap/core': ^2.0.3
tldts-core@6.1.86:
resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==}
tldts@6.1.86:
resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==}
hasBin: true
tmp@0.2.5:
resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
engines: {node: '>=14.14'}
@ -8830,9 +8808,9 @@ packages:
resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==}
engines: {node: '>=14.16'}
tough-cookie@4.1.4:
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
engines: {node: '>=6'}
tough-cookie@5.1.2:
resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
engines: {node: '>=16'}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@ -9070,10 +9048,6 @@ packages:
unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@ -9110,9 +9084,6 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
url@0.11.4:
resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==}
engines: {node: '>= 0.4'}
@ -9583,16 +9554,11 @@ snapshots:
'@asamuzakjp/css-color@3.2.0':
dependencies:
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
lru-cache: 10.4.3
'@asamuzakjp/dom-selector@2.0.2':
dependencies:
bidi-js: 1.0.3
css-tree: 2.3.1
is-potential-custom-element-name: 1.0.1
optional: true
'@atlaskit/pragmatic-drag-and-drop-auto-scroll@1.4.0':
dependencies:
@ -10010,25 +9976,30 @@ snapshots:
'@colors/colors@1.6.0': {}
'@csstools/color-helpers@5.1.0': {}
'@csstools/color-helpers@5.0.2':
optional: true
'@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
optional: true
'@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
'@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/color-helpers': 5.1.0
'@csstools/color-helpers': 5.0.2
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
optional: true
'@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/css-tokenizer': 3.0.4
optional: true
'@csstools/css-tokenizer@3.0.4': {}
'@csstools/css-tokenizer@3.0.4':
optional: true
'@dabh/diagnostics@2.0.3':
dependencies:
@ -12433,10 +12404,6 @@ snapshots:
'@types/dom4@2.0.4': {}
'@types/dompurify@3.2.0':
dependencies:
dompurify: 3.2.6
'@types/eslint-scope@3.7.7':
dependencies:
'@types/eslint': 9.6.1
@ -12581,6 +12548,10 @@ snapshots:
'@types/resolve@1.20.6': {}
'@types/sanitize-html@2.16.0':
dependencies:
htmlparser2: 8.0.2
'@types/semver@7.7.1': {}
'@types/send@0.17.5':
@ -12818,14 +12789,14 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
'@vitest/eslint-plugin@1.5.1(eslint@9.39.1(jiti@2.5.1))(typescript@5.8.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@23.2.0)(terser@5.43.1)(yaml@2.8.1))':
'@vitest/eslint-plugin@1.5.1(eslint@9.39.1(jiti@2.5.1))(typescript@5.8.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@25.0.1)(terser@5.43.1)(yaml@2.8.1))':
dependencies:
'@typescript-eslint/scope-manager': 8.49.0
'@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.5.1))(typescript@5.8.3)
eslint: 9.39.1(jiti@2.5.1)
optionalDependencies:
typescript: 5.8.3
vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@23.2.0)(terser@5.43.1)(yaml@2.8.1)
vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@25.0.1)(terser@5.43.1)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
@ -13035,11 +13006,12 @@ snapshots:
agent-base@6.0.2:
dependencies:
debug: 4.4.1
debug: 4.4.3
transitivePeerDependencies:
- supports-color
agent-base@7.1.4: {}
agent-base@7.1.4:
optional: true
ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
@ -13399,8 +13371,6 @@ snapshots:
camelcase@7.0.1: {}
caniuse-lite@1.0.30001743: {}
caniuse-lite@1.0.30001759: {}
capital-case@1.0.4:
@ -13706,11 +13676,6 @@ snapshots:
mdn-data: 2.0.14
source-map: 0.6.1
css-tree@2.3.1:
dependencies:
mdn-data: 2.0.30
source-map-js: 1.2.1
css-what@6.2.2: {}
css.escape@1.5.1: {}
@ -13721,6 +13686,7 @@ snapshots:
dependencies:
'@asamuzakjp/css-color': 3.2.0
rrweb-cssom: 0.8.0
optional: true
csstype@3.1.3: {}
@ -13768,6 +13734,7 @@ snapshots:
dependencies:
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
optional: true
data-view-buffer@1.0.2:
dependencies:
@ -13799,10 +13766,6 @@ snapshots:
dependencies:
ms: 2.1.3
debug@4.4.1:
dependencies:
ms: 2.1.3
debug@4.4.3:
dependencies:
ms: 2.1.3
@ -13933,14 +13896,6 @@ snapshots:
dependencies:
domelementtype: 2.3.0
dompurify@3.2.6:
optionalDependencies:
'@types/trusted-types': 2.0.7
dompurify@3.2.7:
optionalDependencies:
'@types/trusted-types': 2.0.7
domutils@2.8.0:
dependencies:
dom-serializer: 1.4.1
@ -15006,6 +14961,7 @@ snapshots:
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
optional: true
html-entities@2.6.0: {}
@ -15038,6 +14994,13 @@ snapshots:
domutils: 2.8.0
entities: 2.2.0
htmlparser2@8.0.2:
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
domutils: 3.2.2
entities: 4.5.0
http-errors@2.0.0:
dependencies:
depd: 2.0.0
@ -15049,23 +15012,25 @@ snapshots:
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
debug: 4.4.1
debug: 4.4.3
transitivePeerDependencies:
- supports-color
optional: true
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
debug: 4.4.1
debug: 4.4.3
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
debug: 4.4.1
debug: 4.4.3
transitivePeerDependencies:
- supports-color
optional: true
human-signals@2.1.0: {}
@ -15080,6 +15045,7 @@ snapshots:
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
optional: true
icss-utils@5.1.0(postcss@8.5.6):
dependencies:
@ -15267,9 +15233,12 @@ snapshots:
dependencies:
isobject: 3.0.1
is-plain-object@5.0.0: {}
is-port-reachable@4.0.0: {}
is-potential-custom-element-name@1.0.1: {}
is-potential-custom-element-name@1.0.1:
optional: true
is-regex@1.2.1:
dependencies:
@ -15328,17 +15297,6 @@ snapshots:
isobject@3.0.1: {}
isomorphic-dompurify@1.13.0:
dependencies:
'@types/dompurify': 3.2.0
dompurify: 3.2.6
jsdom: 23.2.0
transitivePeerDependencies:
- bufferutil
- canvas
- supports-color
- utf-8-validate
isomorphic.js@0.2.5: {}
iterator.prototype@1.1.5:
@ -15399,9 +15357,8 @@ snapshots:
jsdoc-type-pratt-parser@4.8.0: {}
jsdom@23.2.0:
jsdom@25.0.1:
dependencies:
'@asamuzakjp/dom-selector': 2.0.2
cssstyle: 4.6.0
data-urls: 5.0.0
decimal.js: 10.6.0
@ -15410,11 +15367,12 @@ snapshots:
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.21
parse5: 7.3.0
rrweb-cssom: 0.6.0
rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 4.1.4
tough-cookie: 5.1.2
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
@ -15426,6 +15384,7 @@ snapshots:
- bufferutil
- supports-color
- utf-8-validate
optional: true
jsesc@3.0.2: {}
@ -15613,7 +15572,8 @@ snapshots:
devlop: 1.1.0
highlight.js: 11.11.1
lru-cache@10.4.3: {}
lru-cache@10.4.3:
optional: true
lru-cache@11.2.1: {}
@ -15813,8 +15773,6 @@ snapshots:
mdn-data@2.0.14: {}
mdn-data@2.0.30: {}
mdurl@2.0.0: {}
media-engine@1.0.3: {}
@ -16287,7 +16245,7 @@ snapshots:
'@next/env': 14.2.32
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001743
caniuse-lite: 1.0.30001759
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
@ -16313,7 +16271,7 @@ snapshots:
'@next/env': 14.2.32
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001743
caniuse-lite: 1.0.30001759
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
@ -16401,6 +16359,9 @@ snapshots:
dependencies:
boolbase: 1.0.0
nwsapi@2.2.21:
optional: true
object-assign@4.1.1: {}
object-hash@3.0.0: {}
@ -16583,6 +16544,8 @@ snapshots:
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
parse-srcset@1.0.2: {}
parse-svg-path@0.1.2: {}
parse5@7.3.0:
@ -16956,10 +16919,6 @@ snapshots:
proxy-from-env@1.1.0: {}
psl@1.15.0:
dependencies:
punycode: 2.3.1
punycode.js@2.3.1: {}
punycode@1.4.1: {}
@ -16976,8 +16935,6 @@ snapshots:
quansync@0.2.11: {}
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
queue@6.0.2:
@ -17385,8 +17342,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
requires-port@1.0.0: {}
reselect@5.1.1: {}
resolve-from@4.0.0: {}
@ -17489,9 +17444,11 @@ snapshots:
rope-sequence@1.3.4: {}
rrweb-cssom@0.6.0: {}
rrweb-cssom@0.7.1:
optional: true
rrweb-cssom@0.8.0: {}
rrweb-cssom@0.8.0:
optional: true
run-parallel@1.2.0:
dependencies:
@ -17528,9 +17485,19 @@ snapshots:
safer-buffer@2.1.2: {}
sanitize-html@2.17.0:
dependencies:
deepmerge: 4.3.1
escape-string-regexp: 4.0.0
htmlparser2: 8.0.2
is-plain-object: 5.0.0
parse-srcset: 1.0.2
postcss: 8.5.6
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
optional: true
scheduler@0.17.0:
dependencies:
@ -17973,7 +17940,8 @@ snapshots:
react: 18.3.1
use-sync-external-store: 1.5.0(react@18.3.1)
symbol-tree@3.2.4: {}
symbol-tree@3.2.4:
optional: true
tabbable@6.2.0: {}
@ -18084,6 +18052,14 @@ snapshots:
markdown-it-task-lists: 2.1.1
prosemirror-markdown: 1.13.2
tldts-core@6.1.86:
optional: true
tldts@6.1.86:
dependencies:
tldts-core: 6.1.86
optional: true
tmp@0.2.5: {}
to-regex-range@5.0.1:
@ -18098,18 +18074,17 @@ snapshots:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
tough-cookie@4.1.4:
tough-cookie@5.1.2:
dependencies:
psl: 1.15.0
punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
tldts: 6.1.86
optional: true
tr46@0.0.3: {}
tr46@5.1.1:
dependencies:
punycode: 2.3.1
optional: true
tree-kill@1.2.2: {}
@ -18367,8 +18342,6 @@ snapshots:
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
universalify@0.2.0: {}
universalify@2.0.1: {}
unpipe@1.0.0: {}
@ -18432,11 +18405,6 @@ snapshots:
dependencies:
punycode: 2.3.1
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
url@0.11.4:
dependencies:
punycode: 1.4.1
@ -18603,7 +18571,7 @@ snapshots:
terser: 5.43.1
yaml: 2.8.1
vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@23.2.0)(terser@5.43.1)(yaml@2.8.1):
vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.12.0)(jiti@2.5.1)(jsdom@25.0.1)(terser@5.43.1)(yaml@2.8.1):
dependencies:
'@vitest/expect': 4.0.15
'@vitest/mocker': 4.0.15(vite@7.1.11(@types/node@22.12.0)(jiti@2.5.1)(terser@5.43.1)(yaml@2.8.1))
@ -18628,7 +18596,7 @@ snapshots:
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@types/node': 22.12.0
jsdom: 23.2.0
jsdom: 25.0.1
transitivePeerDependencies:
- jiti
- less
@ -18647,6 +18615,7 @@ snapshots:
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
optional: true
warning@4.0.3:
dependencies:
@ -18663,7 +18632,8 @@ snapshots:
webidl-conversions@3.0.1: {}
webidl-conversions@7.0.0: {}
webidl-conversions@7.0.0:
optional: true
webpack-dev-middleware@6.1.3(webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))(esbuild@0.25.0)):
dependencies:
@ -18722,13 +18692,16 @@ snapshots:
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
optional: true
whatwg-mimetype@4.0.0: {}
whatwg-mimetype@4.0.0:
optional: true
whatwg-url@14.2.0:
dependencies:
tr46: 5.1.1
webidl-conversions: 7.0.0
optional: true
whatwg-url@5.0.0:
dependencies:
@ -18846,9 +18819,11 @@ snapshots:
ws@8.18.3: {}
xml-name-validator@5.0.0: {}
xml-name-validator@5.0.0:
optional: true
xmlchars@2.2.0: {}
xmlchars@2.2.0:
optional: true
xtend@4.0.2: {}