Compare commits

..

7 Commits

Author SHA1 Message Date
Philipinho d2b8d2077a fix 2026-03-15 18:21:39 +00:00
Philipinho d7d14c2acf Merge branch 'main' into feature-flag 2026-03-15 17:16:08 +00:00
Philipinho 6e5efc3757 Merge branch 'main' into feature-flag 2026-03-14 13:45:35 +00:00
Philipinho bf692e8b08 fix 2026-03-13 23:06:19 +00:00
Philipinho ff01355ec3 refactor 2026-03-09 00:51:14 +00:00
Philipinho 78c3839ae7 fix translations 2026-03-07 23:22:46 +00:00
Philipinho 73ed0c54e5 feat: feature flag upgrade 2026-03-07 21:57:14 +00:00
15 changed files with 114 additions and 277 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "client", "name": "client",
"private": true, "private": true,
"version": "0.70.3", "version": "0.70.1",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
@@ -10,5 +10,3 @@ export const readOnlyEditorAtom = atom<Editor | null>(null);
export const yjsConnectionStatusAtom = atom<string>(""); export const yjsConnectionStatusAtom = atom<string>("");
export const showAiMenuAtom = atom(false); export const showAiMenuAtom = atom(false);
export const showLinkMenuAtom = atom(false);
@@ -26,7 +26,7 @@ import { v7 as uuid7 } from "uuid";
import { isCellSelection, isTextSelected } from "@docmost/editor-ext"; import { isCellSelection, isTextSelected } from "@docmost/editor-ext";
import { LinkSelector } from "@/features/editor/components/bubble-menu/link-selector.tsx"; import { LinkSelector } from "@/features/editor/components/bubble-menu/link-selector.tsx";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { showAiMenuAtom, showLinkMenuAtom } from "@/features/editor/atoms/editor-atoms"; import { showAiMenuAtom } from "@/features/editor/atoms/editor-atoms";
import { workspaceAtom } from "@/features/user/atoms/current-user-atom"; import { workspaceAtom } from "@/features/user/atoms/current-user-atom";
export interface BubbleMenuItem { export interface BubbleMenuItem {
@@ -49,8 +49,6 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
const [, setDraftCommentId] = useAtom(draftCommentIdAtom); const [, setDraftCommentId] = useAtom(draftCommentIdAtom);
const showCommentPopupRef = useRef(showCommentPopup); const showCommentPopupRef = useRef(showCommentPopup);
const showAiMenuRef = useRef(showAiMenu); const showAiMenuRef = useRef(showAiMenu);
const [showLinkMenu] = useAtom(showLinkMenuAtom);
const showLinkMenuRef = useRef(showLinkMenu);
useEffect(() => { useEffect(() => {
showCommentPopupRef.current = showCommentPopup; showCommentPopupRef.current = showCommentPopup;
@@ -60,10 +58,6 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
showAiMenuRef.current = showAiMenu; showAiMenuRef.current = showAiMenu;
}, [showAiMenu]); }, [showAiMenu]);
useEffect(() => {
showLinkMenuRef.current = showLinkMenu;
}, [showLinkMenu]);
const editorState = useEditorState({ const editorState = useEditorState({
editor: props.editor, editor: props.editor,
selector: (ctx) => { selector: (ctx) => {
@@ -141,7 +135,6 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
isNodeSelection(selection) || isNodeSelection(selection) ||
isCellSelection(selection) || isCellSelection(selection) ||
showAiMenuRef.current || showAiMenuRef.current ||
showLinkMenuRef.current ||
showCommentPopupRef?.current showCommentPopupRef?.current
) { ) {
return false; return false;
@@ -154,6 +147,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
onHide: () => { onHide: () => {
setIsNodeSelectorOpen(false); setIsNodeSelectorOpen(false);
setIsTextAlignmentOpen(false); setIsTextAlignmentOpen(false);
setIsLinkSelectorOpen(false);
setIsColorSelectorOpen(false); setIsColorSelectorOpen(false);
}, },
}, },
@@ -161,10 +155,11 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false); const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false);
const [isTextAlignmentSelectorOpen, setIsTextAlignmentOpen] = useState(false); const [isTextAlignmentSelectorOpen, setIsTextAlignmentOpen] = useState(false);
const [isLinkSelectorOpen, setIsLinkSelectorOpen] = useState(false);
const [isColorSelectorOpen, setIsColorSelectorOpen] = useState(false); const [isColorSelectorOpen, setIsColorSelectorOpen] = useState(false);
// Hide the bubble menu immediately when AI menu is shown // Hide the bubble menu immediately when AI menu is shown
if (showAiMenu || showLinkMenu) return; if (showAiMenu) return;
return ( return (
<BubbleMenu <BubbleMenu
@@ -194,6 +189,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
setIsOpen={() => { setIsOpen={() => {
setIsNodeSelectorOpen(!isNodeSelectorOpen); setIsNodeSelectorOpen(!isNodeSelectorOpen);
setIsTextAlignmentOpen(false); setIsTextAlignmentOpen(false);
setIsLinkSelectorOpen(false);
setIsColorSelectorOpen(false); setIsColorSelectorOpen(false);
}} }}
/> />
@@ -204,6 +200,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
setIsOpen={() => { setIsOpen={() => {
setIsTextAlignmentOpen(!isTextAlignmentSelectorOpen); setIsTextAlignmentOpen(!isTextAlignmentSelectorOpen);
setIsNodeSelectorOpen(false); setIsNodeSelectorOpen(false);
setIsLinkSelectorOpen(false);
setIsColorSelectorOpen(false); setIsColorSelectorOpen(false);
}} }}
/> />
@@ -227,7 +224,16 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
))} ))}
</ActionIcon.Group> </ActionIcon.Group>
<LinkSelector /> <LinkSelector
editor={props.editor}
isOpen={isLinkSelectorOpen}
setIsOpen={(value) => {
setIsLinkSelectorOpen(value);
setIsNodeSelectorOpen(false);
setIsTextAlignmentOpen(false);
setIsColorSelectorOpen(false);
}}
/>
<ColorSelector <ColorSelector
editor={props.editor} editor={props.editor}
@@ -236,6 +242,7 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
setIsColorSelectorOpen(!isColorSelectorOpen); setIsColorSelectorOpen(!isColorSelectorOpen);
setIsNodeSelectorOpen(false); setIsNodeSelectorOpen(false);
setIsTextAlignmentOpen(false); setIsTextAlignmentOpen(false);
setIsLinkSelectorOpen(false);
}} }}
/> />
@@ -1,25 +1,68 @@
import { FC } from "react"; import { Dispatch, FC, SetStateAction, useCallback } from "react";
import { IconLink } from "@tabler/icons-react"; import { IconLink } from "@tabler/icons-react";
import { ActionIcon, Tooltip } from "@mantine/core"; import { ActionIcon, Popover, Tooltip } from "@mantine/core";
import { useSetAtom } from "jotai"; import { useEditor } from "@tiptap/react";
import { TextSelection } from "@tiptap/pm/state";
import { LinkEditorPanel } from "@/features/editor/components/link/link-editor-panel.tsx";
import { normalizeUrl } from "@/features/editor/components/link/link-view";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { showLinkMenuAtom } from "@/features/editor/atoms/editor-atoms";
export const LinkSelector: FC = () => { interface LinkSelectorProps {
editor: ReturnType<typeof useEditor>;
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
}
export const LinkSelector: FC<LinkSelectorProps> = ({
editor,
isOpen,
setIsOpen,
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const setShowLinkMenu = useSetAtom(showLinkMenuAtom); const onLink = useCallback(
(url: string, internal?: boolean) => {
setIsOpen(false);
editor
.chain()
.focus()
.setLink({ href: internal ? url : normalizeUrl(url), internal: !!internal } as any)
.command(({ tr }) => {
tr.setSelection(TextSelection.create(tr.doc, tr.selection.to));
return true;
})
.run();
},
[editor, setIsOpen],
);
return ( return (
<Tooltip label={t("Add link")} withArrow> <Popover
<ActionIcon width={320}
variant="default" opened={isOpen}
size="lg" trapFocus
radius="0" offset={{ mainAxis: 35, crossAxis: 0 }}
style={{ border: "none" }} withArrow
onClick={() => setShowLinkMenu(true)} shadow="md"
> >
<IconLink size={16} /> <Popover.Target>
</ActionIcon> <Tooltip label={t("Add link")} withArrow>
</Tooltip> <ActionIcon
variant="default"
size="lg"
radius="0"
style={{
border: "none",
}}
onClick={() => setIsOpen(!isOpen)}
>
<IconLink size={16} />
</ActionIcon>
</Tooltip>
</Popover.Target>
<Popover.Dropdown p="sm">
<LinkEditorPanel onSetLink={onLink} />
</Popover.Dropdown>
</Popover>
); );
}; };
@@ -36,7 +36,7 @@ export const LinkEditorPanel = ({
includeUsers: false, includeUsers: false,
includePages: true, includePages: true,
spaceId: space?.id, spaceId: space?.id,
limit: state.isSearchQuery ? 10 : 3, limit: state.isSearchQuery ? 10 : 5,
preload: true, preload: true,
}); });
@@ -105,7 +105,6 @@ export const LinkEditorPanel = ({
value={state.url} value={state.url}
onChange={state.onChange} onChange={state.onChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
data-autofocus
autoFocus autoFocus
/> />
</form> </form>
@@ -1,114 +0,0 @@
import { FC, useCallback, useEffect, useRef } from "react";
import { BubbleMenu } from "@tiptap/react/menus";
import type { Editor } from "@tiptap/react";
import { useAtom } from "jotai";
import { isTextSelected } from "@docmost/editor-ext";
import { showLinkMenuAtom } from "@/features/editor/atoms/editor-atoms";
import { LinkEditorPanel } from "@/features/editor/components/link/link-editor-panel";
import { normalizeUrl } from "@/features/editor/components/link/link-view";
import { TextSelection } from "@tiptap/pm/state";
import { Paper } from "@mantine/core";
type EditorLinkMenuProps = {
editor: Editor;
};
export const EditorLinkMenu: FC<EditorLinkMenuProps> = ({ editor }) => {
const [showLinkMenu, setShowLinkMenu] = useAtom(showLinkMenuAtom);
const showLinkMenuRef = useRef(showLinkMenu);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
showLinkMenuRef.current = showLinkMenu;
if (showLinkMenu) {
editor.commands.focus();
}
}, [showLinkMenu, editor]);
const focusInput = useCallback(() => {
requestAnimationFrame(() => {
containerRef.current
?.querySelector<HTMLInputElement>("input")
?.focus({ preventScroll: true });
});
}, []);
const onSetLink = useCallback(
(url: string, internal?: boolean) => {
editor
.chain()
.focus()
.setLink({
href: internal ? url : normalizeUrl(url),
internal: !!internal,
} as any)
.command(({ tr }) => {
tr.setSelection(TextSelection.create(tr.doc, tr.selection.to));
return true;
})
.run();
setShowLinkMenu(false);
},
[editor, setShowLinkMenu],
);
useEffect(() => {
if (!showLinkMenu) return;
const dismiss = () => {
setShowLinkMenu(false);
editor.commands.focus();
editor.commands.setTextSelection(editor.state.selection.to);
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") {
dismiss();
}
};
const handleMouseDown = (e: MouseEvent) => {
if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
dismiss();
}
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("mousedown", handleMouseDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener("mousedown", handleMouseDown);
};
}, [showLinkMenu, setShowLinkMenu]);
if (!showLinkMenu) return null;
return (
<BubbleMenu
editor={editor}
shouldShow={({ editor, state }) => {
const { empty } = state.selection;
return (
showLinkMenuRef.current &&
editor.isEditable &&
!empty &&
isTextSelected(editor)
);
}}
options={{
placement: "bottom",
offset: 8,
onShow: focusInput,
onHide: () => {
setShowLinkMenu(false);
},
}}
style={{ zIndex: 198, position: "relative" }}
>
<Paper ref={containerRef} w={320} p="sm" shadow="md" radius={6} withBorder>
<LinkEditorPanel onSetLink={onSetLink} />
</Paper>
</BubbleMenu>
);
};
@@ -66,7 +66,6 @@ import { jwtDecode } from "jwt-decode";
import { searchSpotlight } from "@/features/search/constants.ts"; import { searchSpotlight } from "@/features/search/constants.ts";
import { useEditorScroll } from "./hooks/use-editor-scroll"; import { useEditorScroll } from "./hooks/use-editor-scroll";
import { EditorAiMenu } from "@/ee/ai/components/editor/ai-menu/ai-menu"; import { EditorAiMenu } from "@/ee/ai/components/editor/ai-menu/ai-menu";
import { EditorLinkMenu } from "@/features/editor/components/link/link-menu";
import ColumnsMenu from "@/features/editor/components/columns/columns-menu.tsx"; import ColumnsMenu from "@/features/editor/components/columns/columns-menu.tsx";
interface PageEditorProps { interface PageEditorProps {
@@ -408,7 +407,6 @@ export default function PageEditor({
{editor && editorIsEditable && ( {editor && editorIsEditable && (
<div> <div>
<EditorAiMenu editor={editor} /> <EditorAiMenu editor={editor} />
<EditorLinkMenu editor={editor} />
<EditorBubbleMenu editor={editor} /> <EditorBubbleMenu editor={editor} />
<TableMenu editor={editor} /> <TableMenu editor={editor} />
<TableCellMenu editor={editor} appendTo={menuContainerRef} /> <TableCellMenu editor={editor} appendTo={menuContainerRef} />
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "server", "name": "server",
"version": "0.70.3", "version": "0.70.1",
"description": "", "description": "",
"author": "", "author": "",
"private": true, "private": true,
@@ -91,15 +91,9 @@ export class SearchService {
return { items: [] }; return { items: [] };
} }
const isRestricted =
await this.pagePermissionRepo.hasRestrictedAncestor(share.pageId);
if (isRestricted) {
return { items: [] };
}
const pageIdsToSearch = []; const pageIdsToSearch = [];
if (share.includeSubPages) { if (share.includeSubPages) {
const pageList = await this.pageRepo.getPageAndDescendantsExcludingRestricted( const pageList = await this.pageRepo.getPageAndDescendants(
share.pageId, share.pageId,
{ {
includeContent: false, includeContent: false,
@@ -25,7 +25,6 @@ import {
buildAttachmentCandidates, buildAttachmentCandidates,
collectMarkdownAndHtmlFiles, collectMarkdownAndHtmlFiles,
encodeFilePath, encodeFilePath,
extractNotionPartialId,
readDocmostMetadata, readDocmostMetadata,
stripNotionID, stripNotionID,
} from '../utils/import.utils'; } from '../utils/import.utils';
@@ -161,7 +160,6 @@ export class FileImportTaskService {
fileTask: FileTask; fileTask: FileTask;
}): Promise<void> { }): Promise<void> {
const { extractDir, fileTask } = opts; const { extractDir, fileTask } = opts;
const isNotion = fileTask.source === FileImportSource.Notion;
const allFiles = await collectMarkdownAndHtmlFiles(extractDir); const allFiles = await collectMarkdownAndHtmlFiles(extractDir);
const attachmentCandidates = await buildAttachmentCandidates(extractDir); const attachmentCandidates = await buildAttachmentCandidates(extractDir);
const docmostMetadata = await readDocmostMetadata(extractDir); const docmostMetadata = await readDocmostMetadata(extractDir);
@@ -232,17 +230,7 @@ export class FileImportTaskService {
} }
// For each folder with content, create a placeholder page if no corresponding .md or .html exists // For each folder with content, create a placeholder page if no corresponding .md or .html exists
// Process folders with partial UUIDs first so they claim their specific files foldersWithContent.forEach((folderPath) => {
// before plain folders (without partial UUIDs) take whatever remains.
const sortedFolders = isNotion
? [...foldersWithContent].sort((a, b) => {
const aHasPartial = extractNotionPartialId(path.basename(a)) ? 0 : 1;
const bHasPartial = extractNotionPartialId(path.basename(b)) ? 0 : 1;
return aHasPartial - bHasPartial;
})
: [...foldersWithContent];
sortedFolders.forEach((folderPath) => {
if ( if (
skipRootFolder && skipRootFolder &&
folderPath?.toLowerCase() === skipRootFolder?.toLowerCase() folderPath?.toLowerCase() === skipRootFolder?.toLowerCase()
@@ -255,54 +243,18 @@ export class FileImportTaskService {
if (!pagesMap.has(mdPath) && !pagesMap.has(htmlPath)) { if (!pagesMap.has(mdPath) && !pagesMap.has(htmlPath)) {
const folderName = path.basename(folderPath); const folderName = path.basename(folderPath);
const parentDir = path.dirname(folderPath); const encodedMdPath = encodeFilePath(mdPath);
const placeholderMetadata = docmostMetadata?.pages[encodedMdPath];
// Notion no longer adds UUIDs to folder names, but still adds them to files. pagesMap.set(mdPath, {
// For duplicate names, Notion adds a partial UUID "{first4}-{last4}" to the folder. id: v7(),
let matched = false; slugId: generateSlugId(),
if (isNotion) { name: stripNotionID(folderName),
const partialId = extractNotionPartialId(folderName); content: '',
const strippedFolderName = stripNotionID(folderName); parentPageId: null,
const isSameDir = (fileDir: string) => fileExtension: '.md',
fileDir === parentDir || (parentDir === '.' && !fileDir.includes('/')); filePath: mdPath,
icon: placeholderMetadata?.icon ?? null,
for (const [filePath, page] of pagesMap.entries()) { });
if (!isSameDir(path.dirname(filePath))) continue;
if (page.name !== strippedFolderName) continue;
if (partialId) {
// Match partial UUID against the full UUID in the filename
const fileBase = path.basename(filePath, path.extname(filePath));
const fullIdMatch = fileBase.match(/[a-f0-9]{32}$/i);
if (!fullIdMatch) continue;
const fullId = fullIdMatch[0].toLowerCase();
if (!fullId.startsWith(partialId.prefix) || !fullId.endsWith(partialId.suffix)) {
continue;
}
}
pagesMap.delete(filePath);
page.filePath = mdPath;
pagesMap.set(mdPath, page);
matched = true;
break;
}
}
if (!matched) {
const encodedMdPath = encodeFilePath(mdPath);
const placeholderMetadata = docmostMetadata?.pages[encodedMdPath];
pagesMap.set(mdPath, {
id: v7(),
slugId: generateSlugId(),
name: stripNotionID(folderName),
content: '',
parentPageId: null,
fileExtension: '.md',
filePath: mdPath,
icon: placeholderMetadata?.icon ?? null,
});
}
} }
}); });
@@ -1,7 +1,6 @@
import { getEmbedUrlAndProvider } from '@docmost/editor-ext'; import { getEmbedUrlAndProvider } from '@docmost/editor-ext';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import * as path from 'path'; import * as path from 'path';
import { v7 } from 'uuid';
import { InsertableBacklink } from '@docmost/db/types/entity.types'; import { InsertableBacklink } from '@docmost/db/types/entity.types';
import { Cheerio, CheerioAPI, load } from 'cheerio'; import { Cheerio, CheerioAPI, load } from 'cheerio';
// eslint-disable-next-line @typescript-eslint/no-require-imports // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -345,35 +344,14 @@ export async function rewriteInternalLinksToMentionHtml(
const meta = filePathToPageMetaMap.get(resolved); const meta = filePathToPageMetaMap.get(resolved);
if (!meta) return; if (!meta) return;
const linkText = $a.text().trim(); const titleSlug = slugify(meta.title?.substring(0, 70) || 'untitled');
const titleMatch = const pageSlug = `${titleSlug}-${meta.slugId}`;
linkText === meta.title || const internalHref = spaceSlug
linkText === meta.title?.trim(); ? `/s/${spaceSlug}/p/${pageSlug}`
: `/p/${pageSlug}`;
if (titleMatch) { $a.attr('href', internalHref);
const mentionId = v7(); $a.attr('data-internal', 'true');
const $mention = $('<span>')
.attr({
'data-type': 'mention',
'data-id': mentionId,
'data-entity-type': 'page',
'data-entity-id': meta.id,
'data-label': meta.title,
'data-slug-id': meta.slugId,
'data-creator-id': creatorId,
})
.text(meta.title);
$a.replaceWith($mention);
} else {
const titleSlug = slugify(meta.title?.substring(0, 70) || 'untitled');
const pageSlug = `${titleSlug}-${meta.slugId}`;
const internalHref = spaceSlug
? `/s/${spaceSlug}/p/${pageSlug}`
: `/p/${pageSlug}`;
$a.attr('href', internalHref);
$a.attr('data-internal', 'true');
}
backlinks.push({ sourcePageId, targetPageId: meta.id, workspaceId }); backlinks.push({ sourcePageId, targetPageId: meta.id, workspaceId });
}); });
@@ -81,25 +81,7 @@ export async function collectMarkdownAndHtmlFiles(
export function stripNotionID(fileName: string): string { export function stripNotionID(fileName: string): string {
// Handle optional separator (space or dash) + 32 alphanumeric chars at end // Handle optional separator (space or dash) + 32 alphanumeric chars at end
const notionIdPattern = /[ -]?[a-z0-9]{32}$/i; const notionIdPattern = /[ -]?[a-z0-9]{32}$/i;
// Handle partial UUID format used for duplicate names: "Name abcd-ef12" return fileName.replace(notionIdPattern, '').trim();
const partialIdPattern = / [a-f0-9]{4}-[a-f0-9]{4}$/i;
return fileName
.replace(notionIdPattern, '')
.replace(partialIdPattern, '')
.trim();
}
/**
* Extract a partial Notion UUID suffix from a folder name.
* Notion adds "{first4}-{last4}" when multiple pages share the same title.
* e.g. "Cool 324d-35ab" → { prefix: "324d", suffix: "35ab" }
*/
export function extractNotionPartialId(
folderName: string,
): { prefix: string; suffix: string } | null {
const match = folderName.match(/ ([a-f0-9]{4})-([a-f0-9]{4})$/i);
if (!match) return null;
return { prefix: match[1].toLowerCase(), suffix: match[2].toLowerCase() };
} }
export function encodeFilePath(filePath: string): string { export function encodeFilePath(filePath: string): string {
+3 -3
View File
@@ -1,7 +1,7 @@
{ {
"name": "docmost", "name": "docmost",
"homepage": "https://docmost.com", "homepage": "https://docmost.com",
"version": "0.70.3", "version": "0.70.1",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "nx run-many -t build", "build": "nx run-many -t build",
@@ -62,7 +62,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"diff": "8.0.3", "diff": "8.0.3",
"dompurify": "^3.3.3", "dompurify": "^3.3.1",
"fractional-indexing-jittered": "^1.0.0", "fractional-indexing-jittered": "^1.0.0",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"image-dimensions": "^2.5.0", "image-dimensions": "^2.5.0",
@@ -109,7 +109,7 @@
"lodash": "4.17.23", "lodash": "4.17.23",
"ws": "8.19.0", "ws": "8.19.0",
"cross-spawn": "7.0.5", "cross-spawn": "7.0.5",
"dompurify": "3.3.3", "dompurify": "3.3.1",
"tmp": "0.2.5", "tmp": "0.2.5",
"lodash-es": "4.17.23", "lodash-es": "4.17.23",
"markdown-it": "14.1.1", "markdown-it": "14.1.1",
+8 -8
View File
@@ -14,7 +14,7 @@ overrides:
lodash: 4.17.23 lodash: 4.17.23
ws: 8.19.0 ws: 8.19.0
cross-spawn: 7.0.5 cross-spawn: 7.0.5
dompurify: 3.3.3 dompurify: 3.3.1
tmp: 0.2.5 tmp: 0.2.5
lodash-es: 4.17.23 lodash-es: 4.17.23
markdown-it: 14.1.1 markdown-it: 14.1.1
@@ -170,8 +170,8 @@ importers:
specifier: 8.0.3 specifier: 8.0.3
version: 8.0.3 version: 8.0.3
dompurify: dompurify:
specifier: 3.3.3 specifier: 3.3.1
version: 3.3.3 version: 3.3.1
fractional-indexing-jittered: fractional-indexing-jittered:
specifier: ^1.0.0 specifier: ^1.0.0
version: 1.0.0 version: 1.0.0
@@ -6510,8 +6510,8 @@ packages:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
dompurify@3.3.3: dompurify@3.3.1:
resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==}
domutils@3.2.2: domutils@3.2.2:
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
@@ -17205,7 +17205,7 @@ snapshots:
dependencies: dependencies:
domelementtype: 2.3.0 domelementtype: 2.3.0
dompurify@3.3.3: dompurify@3.3.1:
optionalDependencies: optionalDependencies:
'@types/trusted-types': 2.0.7 '@types/trusted-types': 2.0.7
@@ -19251,7 +19251,7 @@ snapshots:
d3-sankey: 0.12.3 d3-sankey: 0.12.3
dagre-d3-es: 7.0.13 dagre-d3-es: 7.0.13
dayjs: 1.11.19 dayjs: 1.11.19
dompurify: 3.3.3 dompurify: 3.3.1
katex: 0.16.27 katex: 0.16.27
khroma: 2.1.0 khroma: 2.1.0
lodash-es: 4.17.23 lodash-es: 4.17.23
@@ -20004,7 +20004,7 @@ snapshots:
'@posthog/core': 1.22.0 '@posthog/core': 1.22.0
'@posthog/types': 1.345.5 '@posthog/types': 1.345.5
core-js: 3.43.0 core-js: 3.43.0
dompurify: 3.3.3 dompurify: 3.3.1
fflate: 0.4.8 fflate: 0.4.8
preact: 10.28.3 preact: 10.28.3
query-selector-shadow-dom: 1.0.1 query-selector-shadow-dom: 1.0.1