e.preventDefault()}
diff --git a/apps/client/src/features/editor/components/table/handle/cell-chevron.tsx b/apps/client/src/features/editor/components/table/handle/cell-chevron.tsx
new file mode 100644
index 000000000..db79844e8
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/cell-chevron.tsx
@@ -0,0 +1,126 @@
+import React, { useCallback, useEffect } from "react";
+import type { Editor } from "@tiptap/react";
+import { useEditorState } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { TextSelection } from "@tiptap/pm/state";
+import { columnResizingPluginKey } from "@tiptap/pm/tables";
+import { useFloating, offset, autoUpdate, hide } from "@floating-ui/react";
+import { Menu, UnstyledButton } from "@mantine/core";
+import { IconChevronDown } from "@tabler/icons-react";
+import clsx from "clsx";
+import { useTranslation } from "react-i18next";
+import { isCellSelection } from "@docmost/editor-ext";
+import { CellChevronMenu } from "./menus/cell-chevron-menu";
+import classes from "./handle.module.css";
+
+interface CellChevronProps {
+ editor: Editor;
+ cellPos: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export const CellChevron = React.memo(function CellChevron({
+ editor,
+ cellPos,
+ tableNode,
+ tablePos,
+}: CellChevronProps) {
+ const { t } = useTranslation();
+ const cellDom = editor.view.nodeDOM(cellPos) as HTMLElement | null;
+
+ const { refs, floatingStyles, middlewareData } = useFloating({
+ placement: "top-end",
+ // crossAxis pulls the chevron INWARD from the cell's right edge. We need
+ // enough inset that we don't overlap PM-tables' column-resize hot zone
+ // (~5px wide around the column boundary). Without this, hovering near the
+ // column edge picks up the chevron's `cursor: pointer` instead of
+ // `col-resize`, and a drag near the edge clicks the chevron.
+ middleware: [offset({ mainAxis: -22, crossAxis: -10 }), hide()],
+ whileElementsMounted: autoUpdate,
+ strategy: "absolute",
+ });
+ const isReferenceHidden = !!middlewareData.hide?.referenceHidden;
+
+ useEffect(() => {
+ refs.setReference(cellDom);
+ }, [cellDom, refs]);
+
+ // Hide the chevron while the user is resizing a column. PM-tables sets
+ // `activeHandle > -1` whenever the mouse is near a column boundary OR
+ // actively dragging it. Either way we don't want the chevron in the way.
+ const isResizingColumn = useEditorState({
+ editor,
+ selector: (ctx) => {
+ if (!ctx.editor) return false;
+ const state = columnResizingPluginKey.getState(ctx.editor.state) as
+ | { activeHandle: number }
+ | undefined;
+ return !!state && state.activeHandle > -1;
+ },
+ });
+
+ const onOpen = useCallback(() => {
+ const current = editor.state.selection;
+
+ // Preserve an existing multi-cell CellSelection that already covers
+ // this cell so merge etc. operate on the user's whole range.
+ let preserveExisting = false;
+ if (isCellSelection(current)) {
+ current.forEachCell((_node, pos) => {
+ if (pos === cellPos) preserveExisting = true;
+ });
+ }
+
+ if (!preserveExisting) {
+ // Drop a collapsed cursor inside the cell rather than a single-cell
+ // CellSelection — PM-tables paints the latter as a text-range
+ // highlight on the cell content.
+ try {
+ const $inside = editor.state.doc.resolve(cellPos + 1);
+ const sel = TextSelection.near($inside, 1);
+ editor.view.dispatch(editor.state.tr.setSelection(sel));
+ } catch {}
+ }
+ editor.commands.freezeHandles();
+ }, [editor, cellPos]);
+
+ const onClose = useCallback(() => {
+ editor.commands.unfreezeHandles();
+ }, [editor]);
+
+ if (!cellDom) return null;
+ if (isResizingColumn) return null;
+
+ return (
+
+ );
+});
diff --git a/apps/client/src/features/editor/components/table/handle/column-handle.tsx b/apps/client/src/features/editor/components/table/handle/column-handle.tsx
new file mode 100644
index 000000000..ccc459740
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/column-handle.tsx
@@ -0,0 +1,127 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { useFloating, offset, autoUpdate, hide } from "@floating-ui/react";
+import { Menu } from "@mantine/core";
+import clsx from "clsx";
+import { useTranslation } from "react-i18next";
+import { useTableHandleDrag } from "./hooks/use-table-handle-drag";
+import { useColumnRowMenuLifecycle } from "./hooks/use-column-row-menu-lifecycle";
+import { ColumnHandleMenu } from "./menus/column-handle-menu";
+import classes from "./handle.module.css";
+
+interface ColumnHandleProps {
+ editor: Editor;
+ index: number;
+ anchorPos: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export const ColumnHandle = React.memo(function ColumnHandle({
+ editor,
+ index,
+ anchorPos,
+ tableNode,
+ tablePos,
+}: ColumnHandleProps) {
+ const { t } = useTranslation();
+ // Hold the cell DOM in a ref-backed state so we never unmount the handle
+ // mid-drag. A remote edit can transiently flip `nodeDOM(anchorPos)` to null
+ // (the plugin re-emits `hoveringCell` with the mapped pos a tick later);
+ // unmounting the source element here would make pragmatic-dnd silently
+ // abort the active drag.
+ const lookupCellDom = editor.view.nodeDOM(anchorPos) as HTMLElement | null;
+ const [cellDom, setCellDom] = useState
(lookupCellDom);
+ const lastCellDomRef = useRef(lookupCellDom);
+ useEffect(() => {
+ if (lookupCellDom && lookupCellDom !== lastCellDomRef.current) {
+ lastCellDomRef.current = lookupCellDom;
+ setCellDom(lookupCellDom);
+ }
+ }, [lookupCellDom]);
+
+ const [handleEl, setHandleEl] = useState(null);
+
+ const { refs, floatingStyles, middlewareData } = useFloating({
+ placement: "top",
+ middleware: [offset(-4), hide()],
+ whileElementsMounted: autoUpdate,
+ });
+ const isReferenceHidden = !!middlewareData.hide?.referenceHidden;
+
+ useEffect(() => {
+ refs.setReference(cellDom);
+ }, [cellDom, refs]);
+
+ // `cellDom` is inside the table, so `closest('.tableWrapper')` finds the
+ // wrapper for this drag's auto-scroll. The handle itself lives in a
+ // floating layer outside the editor DOM, so we can't walk up from it.
+ const wrapper = cellDom?.closest(".tableWrapper") ?? null;
+
+ const [menuOpened, setMenuOpened] = useState(false);
+ const closeMenu = useCallback(() => setMenuOpened(false), []);
+ useTableHandleDrag(editor, "col", handleEl, wrapper, closeMenu);
+
+ const { onOpen, onClose } = useColumnRowMenuLifecycle({
+ editor,
+ orientation: "col",
+ index,
+ tableNode,
+ tablePos,
+ });
+
+ if (!cellDom) return null;
+
+ return (
+
+ );
+});
+
+function GripIcon() {
+ return (
+
+ );
+}
diff --git a/apps/client/src/features/editor/components/table/handle/handle.module.css b/apps/client/src/features/editor/components/table/handle/handle.module.css
new file mode 100644
index 000000000..e7d9ac124
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/handle.module.css
@@ -0,0 +1,108 @@
+.handle {
+ position: absolute;
+ z-index: 50;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ color: rgba(55, 53, 47, 0.45);
+ background: var(--mantine-color-body);
+ border: 1px solid rgba(55, 53, 47, 0.12);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
+ cursor: grab;
+ padding: 0;
+ transition: background-color 120ms ease, color 120ms ease;
+
+ @mixin dark {
+ color: rgba(255, 255, 255, 0.55);
+ background: var(--mantine-color-dark-7);
+ border-color: rgba(255, 255, 255, 0.12);
+ }
+}
+
+.handle:hover {
+ background: light-dark(
+ var(--mantine-color-gray-1),
+ var(--mantine-color-dark-5)
+ );
+ color: light-dark(
+ var(--mantine-color-gray-7),
+ var(--mantine-color-dark-0)
+ );
+}
+
+.handle:active {
+ cursor: grabbing;
+}
+
+.columnHandle {
+ width: 28px;
+ height: 16px;
+}
+
+.columnHandle svg {
+ transform: rotate(90deg);
+}
+
+.rowHandle {
+ width: 16px;
+ height: 28px;
+}
+
+@media (max-width: 600px) {
+ .handle {
+ display: none;
+ }
+}
+
+.cellChevron {
+ position: absolute;
+ z-index: 50;
+ width: 18px;
+ height: 18px;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: light-dark(
+ var(--mantine-color-gray-7),
+ var(--mantine-color-dark-1)
+ );
+ background: light-dark(
+ var(--mantine-color-gray-1),
+ var(--mantine-color-dark-5)
+ );
+ border: 1px solid rgba(55, 53, 47, 0.12);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
+ cursor: pointer;
+ padding: 0;
+ transition: background-color 120ms ease, color 120ms ease;
+
+ @mixin dark {
+ border-color: rgba(255, 255, 255, 0.12);
+ }
+}
+
+.cellChevron:hover {
+ background: light-dark(
+ var(--mantine-color-gray-2),
+ var(--mantine-color-dark-4)
+ );
+ color: light-dark(
+ var(--mantine-color-gray-8),
+ var(--mantine-color-dark-0)
+ );
+}
+
+@media (max-width: 600px) {
+ .cellChevron {
+ display: none;
+ }
+}
+
+@media print {
+ .handle,
+ .cellChevron {
+ display: none !important;
+ }
+}
diff --git a/apps/client/src/features/editor/components/table/handle/hooks/use-column-row-menu-lifecycle.ts b/apps/client/src/features/editor/components/table/handle/hooks/use-column-row-menu-lifecycle.ts
new file mode 100644
index 000000000..a30595597
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/hooks/use-column-row-menu-lifecycle.ts
@@ -0,0 +1,40 @@
+import { useCallback } from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { buildRowOrColumnSelection, Orientation } from "../lib/select-row-column";
+
+interface Args {
+ editor: Editor;
+ orientation: Orientation;
+ index: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export function useColumnRowMenuLifecycle({
+ editor,
+ orientation,
+ index,
+ tableNode,
+ tablePos,
+}: Args) {
+ const onOpen = useCallback(() => {
+ const selection = buildRowOrColumnSelection(
+ editor.state,
+ tableNode,
+ tablePos,
+ orientation,
+ index,
+ );
+ const tr = editor.state.tr;
+ if (selection) tr.setSelection(selection);
+ editor.view.dispatch(tr);
+ editor.commands.freezeHandles();
+ }, [editor, orientation, index, tableNode, tablePos]);
+
+ const onClose = useCallback(() => {
+ editor.commands.unfreezeHandles();
+ }, [editor]);
+
+ return { onOpen, onClose };
+}
diff --git a/apps/client/src/features/editor/components/table/handle/hooks/use-table-clear.ts b/apps/client/src/features/editor/components/table/handle/hooks/use-table-clear.ts
new file mode 100644
index 000000000..1bd4cb209
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/hooks/use-table-clear.ts
@@ -0,0 +1,54 @@
+import { useCallback } from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { TableMap } from "@tiptap/pm/tables";
+
+type Scope =
+ | { kind: "col"; index: number }
+ | { kind: "row"; index: number }
+ | { kind: "cell"; cellPos: number };
+
+export function useTableClear(
+ editor: Editor,
+ tableNode: ProseMirrorNode,
+ tablePos: number,
+ scope: Scope,
+) {
+ return useCallback(() => {
+ const tr = editor.state.tr;
+ const tableStart = tablePos + 1;
+ const map = TableMap.get(tableNode);
+ const paragraph = editor.schema.nodes.paragraph;
+ if (!paragraph) return;
+
+ const cellOffsets: number[] = [];
+
+ if (scope.kind === "col") {
+ for (let row = 0; row < map.height; row++) {
+ cellOffsets.push(map.map[row * map.width + scope.index]);
+ }
+ } else if (scope.kind === "row") {
+ for (let col = 0; col < map.width; col++) {
+ cellOffsets.push(map.map[scope.index * map.width + col]);
+ }
+ }
+
+ const targets =
+ scope.kind === "cell"
+ ? [scope.cellPos]
+ : Array.from(new Set(cellOffsets)).map((o) => tableStart + o);
+
+ // Process in reverse position order so earlier replacements don't shift later ones.
+ targets.sort((a, b) => b - a);
+
+ for (const cellPos of targets) {
+ const node = tr.doc.nodeAt(cellPos);
+ if (!node) continue;
+ const start = cellPos + 1;
+ const end = cellPos + node.nodeSize - 1;
+ tr.replaceWith(start, end, paragraph.create());
+ }
+
+ if (tr.docChanged) editor.view.dispatch(tr);
+ }, [editor, tableNode, tablePos, scope]);
+}
diff --git a/apps/client/src/features/editor/components/table/handle/hooks/use-table-handle-drag.ts b/apps/client/src/features/editor/components/table/handle/hooks/use-table-handle-drag.ts
new file mode 100644
index 000000000..30b179689
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/hooks/use-table-handle-drag.ts
@@ -0,0 +1,79 @@
+import { useEffect } from "react";
+import type { Editor } from "@tiptap/react";
+import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
+import { draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
+import { disableNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview";
+import {
+ autoScrollForElements,
+ autoScrollWindowForElements,
+} from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
+import { getTableHandlePluginSpec } from "@docmost/editor-ext";
+
+// Uses pragmatic-drag-and-drop instead of native HTML5 DnD because the native
+// dragstart→dragover→drop lifecycle was being silently cancelled
+export function useTableHandleDrag(
+ editor: Editor,
+ orientation: "col" | "row",
+ element: HTMLElement | null,
+ wrapper: HTMLElement | null,
+ onDragStart?: () => void,
+) {
+ useEffect(() => {
+ if (!element) return;
+
+ return combine(
+ draggable({
+ element,
+ getInitialData: () => ({ type: `table-${orientation}` }),
+ onGenerateDragPreview: ({ nativeSetDragImage }) => {
+ // We render our own floating preview via PreviewController, so hide
+ // the native drag image entirely.
+ disableNativeDragPreview({ nativeSetDragImage });
+ },
+ onDragStart: ({ location }) => {
+ // The menu (if open from a prior click on the handle) won't dismiss
+ // on its own — pragmatic-dnd swallows the events Mantine listens for.
+ onDragStart?.();
+ const spec = getTableHandlePluginSpec(editor);
+ if (!spec) return;
+ const { clientX, clientY } = location.initial.input;
+ spec.startDragFromHandle(orientation, clientX, clientY);
+ },
+ onDrag: ({ location }) => {
+ const spec = getTableHandlePluginSpec(editor);
+ if (!spec) return;
+ const { clientX, clientY } = location.current.input;
+ spec.updateDragPosition(clientX, clientY);
+ },
+ onDrop: ({ location }) => {
+ const spec = getTableHandlePluginSpec(editor);
+ if (!spec) return;
+ const { clientX, clientY } = location.current.input;
+ // Make sure the final position is recorded before committing the drop.
+ spec.updateDragPosition(clientX, clientY);
+ spec.commitDrop();
+ spec.endDrag();
+ },
+ }),
+ // Wrapper owns horizontal auto-scroll (it has `overflow-x: auto`);
+ // window owns vertical. Locking each axis prevents the window's
+ // horizontal auto-scroll from running when the cursor approaches
+ // the viewport edge — without the cap, the preview's `left` follows
+ // the cursor past the viewport, the page widens to contain it, the
+ // plugin scrolls the now-wider page further, and the loop never
+ // ends.
+ // Only the column handle registers wrapper auto-scroll (rows can't
+ // scroll horizontally) — registering twice on the same wrapper
+ // triggers a dev-mode warning from pragmatic-dnd-auto-scroll.
+ orientation === "col" &&
+ wrapper &&
+ !wrapper.classList.contains("tableWrapperNoOverflow")
+ ? autoScrollForElements({
+ element: wrapper,
+ getAllowedAxis: () => "horizontal",
+ })
+ : () => {},
+ autoScrollWindowForElements({ getAllowedAxis: () => "vertical" }),
+ );
+ }, [editor, orientation, element, wrapper, onDragStart]);
+}
diff --git a/apps/client/src/features/editor/components/table/handle/hooks/use-table-handle-state.ts b/apps/client/src/features/editor/components/table/handle/hooks/use-table-handle-state.ts
new file mode 100644
index 000000000..ab8893566
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/hooks/use-table-handle-state.ts
@@ -0,0 +1,23 @@
+import type { Editor } from "@tiptap/react";
+import { useEditorState } from "@tiptap/react";
+import { TableDndKey, TableHandleState } from "@docmost/editor-ext";
+
+const FALLBACK: TableHandleState = {
+ hoveringCell: null,
+ tableNode: null,
+ tablePos: null,
+ dragging: null,
+ frozen: false,
+};
+
+export function useTableHandleState(editor: Editor | null): TableHandleState {
+ const state = useEditorState({
+ editor,
+ selector: (ctx) => {
+ if (!ctx.editor) return null;
+ return TableDndKey.getState(ctx.editor.state) ?? null;
+ },
+ });
+
+ return state ?? FALLBACK;
+}
diff --git a/apps/client/src/features/editor/components/table/handle/hooks/use-table-move-row-column.ts b/apps/client/src/features/editor/components/table/handle/hooks/use-table-move-row-column.ts
new file mode 100644
index 000000000..476c68f8d
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/hooks/use-table-move-row-column.ts
@@ -0,0 +1,50 @@
+import { useCallback, useMemo } from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { TableMap } from "@tiptap/pm/tables";
+import { moveColumn, moveRow } from "@docmost/editor-ext";
+
+export type MoveDirection = "left" | "right" | "up" | "down";
+
+export function useTableMoveRowColumn(
+ editor: Editor,
+ orientation: "col" | "row",
+ index: number,
+ direction: MoveDirection,
+ tableNode: ProseMirrorNode,
+ tablePos: number,
+) {
+ const target =
+ direction === "left" || direction === "up" ? index - 1 : index + 1;
+
+ const maxIndex = useMemo(() => {
+ const map = TableMap.get(tableNode);
+ return orientation === "col" ? map.width - 1 : map.height - 1;
+ }, [tableNode, orientation]);
+
+ const canMove = target >= 0 && target <= maxIndex;
+
+ const handleMove = useCallback(() => {
+ if (!canMove) return;
+ const tr = editor.state.tr;
+ const moved =
+ orientation === "col"
+ ? moveColumn({
+ tr,
+ originIndex: index,
+ targetIndex: target,
+ select: true,
+ pos: tablePos + 1,
+ })
+ : moveRow({
+ tr,
+ originIndex: index,
+ targetIndex: target,
+ select: true,
+ pos: tablePos + 1,
+ });
+ if (moved) editor.view.dispatch(tr);
+ }, [editor, orientation, index, target, tablePos, canMove]);
+
+ return { canMove, handleMove };
+}
diff --git a/apps/client/src/features/editor/components/table/handle/hooks/use-table-sort.ts b/apps/client/src/features/editor/components/table/handle/hooks/use-table-sort.ts
new file mode 100644
index 000000000..afc6a2774
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/hooks/use-table-sort.ts
@@ -0,0 +1,100 @@
+import { useCallback, useMemo } from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import {
+ convertArrayOfRowsToTableNode,
+ convertTableNodeToArrayOfRows,
+ transpose,
+} from "@docmost/editor-ext";
+import {
+ getCellSortText,
+ isCellEmpty,
+ isHeaderCell,
+ type SortDirection,
+ type SortableItem,
+ sortItems,
+ weaveItems,
+} from "../lib/sort-cells";
+
+interface Args {
+ editor: Editor;
+ orientation: "col" | "row";
+ index: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+ direction: SortDirection;
+}
+
+function tableHasMergedCells(tableNode: ProseMirrorNode): boolean {
+ for (let r = 0; r < tableNode.childCount; r++) {
+ const row = tableNode.child(r);
+ for (let c = 0; c < row.childCount; c++) {
+ const { colspan = 1, rowspan = 1 } = row.child(c).attrs;
+ if (colspan > 1 || rowspan > 1) return true;
+ }
+ }
+ return false;
+}
+
+function isAllHeader(cells: (ProseMirrorNode | null)[]): boolean {
+ return cells.every((c) => c !== null && isHeaderCell(c));
+}
+
+export function useTableSort({
+ editor,
+ orientation,
+ index,
+ tableNode,
+ tablePos,
+ direction,
+}: Args) {
+ const canSort = useMemo(() => {
+ if (tableHasMergedCells(tableNode)) return false;
+
+ const rows = convertTableNodeToArrayOfRows(tableNode);
+ const axes = orientation === "col" ? rows : transpose(rows);
+ if (axes.length < 2) return false;
+
+ return axes.some((cells) => {
+ if (isAllHeader(cells)) return false;
+ const sortCell = cells[index];
+ return !!sortCell && !isCellEmpty(sortCell);
+ });
+ }, [tableNode, orientation, index]);
+
+ const handleSort = useCallback(() => {
+ if (!canSort) return;
+
+ const rows = convertTableNodeToArrayOfRows(tableNode);
+ const axes = orientation === "col" ? rows : transpose(rows);
+
+ const items: SortableItem<(ProseMirrorNode | null)[]>[] = axes.map(
+ (cells, originalOrder) => {
+ const sortCell = cells[index];
+ return {
+ payload: cells,
+ text: sortCell ? getCellSortText(sortCell) : "",
+ isHeader: isAllHeader(cells),
+ isEmpty: !sortCell || isCellEmpty(sortCell),
+ originalOrder,
+ };
+ },
+ );
+
+ const dataItems = items.filter((it) => !it.isHeader);
+ const sortedData = sortItems(dataItems, direction);
+ const woven = weaveItems(items, sortedData);
+
+ const newAxes = woven.map((it) => it.payload);
+ const newRows = orientation === "col" ? newAxes : transpose(newAxes);
+
+ const newTable = convertArrayOfRowsToTableNode(tableNode, newRows);
+
+ const tr = editor.state.tr;
+ tr.replaceWith(tablePos, tablePos + tableNode.nodeSize, newTable);
+
+ if (tr.docChanged) editor.view.dispatch(tr);
+ }, [editor, tableNode, tablePos, orientation, index, direction, canSort]);
+
+ return { canSort, handleSort };
+}
diff --git a/apps/client/src/features/editor/components/table/handle/lib/select-row-column.ts b/apps/client/src/features/editor/components/table/handle/lib/select-row-column.ts
new file mode 100644
index 000000000..5ef315cf1
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/lib/select-row-column.ts
@@ -0,0 +1,34 @@
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import type { EditorState } from "@tiptap/pm/state";
+import { CellSelection, TableMap } from "@tiptap/pm/tables";
+
+export type Orientation = "col" | "row";
+
+export function buildRowOrColumnSelection(
+ state: EditorState,
+ tableNode: ProseMirrorNode,
+ tablePos: number,
+ orientation: Orientation,
+ index: number,
+): CellSelection | null {
+ const map = TableMap.get(tableNode);
+ const tableStart = tablePos + 1;
+
+ if (orientation === "col") {
+ if (index < 0 || index >= map.width) return null;
+ const firstCellPos = tableStart + map.map[index];
+ const lastCellPos =
+ tableStart + map.map[(map.height - 1) * map.width + index];
+ const $first = state.doc.resolve(firstCellPos);
+ const $last = state.doc.resolve(lastCellPos);
+ return CellSelection.colSelection($first, $last);
+ }
+
+ if (index < 0 || index >= map.height) return null;
+ const firstCellPos = tableStart + map.map[index * map.width];
+ const lastCellPos =
+ tableStart + map.map[index * map.width + (map.width - 1)];
+ const $first = state.doc.resolve(firstCellPos);
+ const $last = state.doc.resolve(lastCellPos);
+ return CellSelection.rowSelection($first, $last);
+}
diff --git a/apps/client/src/features/editor/components/table/handle/lib/sort-cells.ts b/apps/client/src/features/editor/components/table/handle/lib/sort-cells.ts
new file mode 100644
index 000000000..ffd039c2b
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/lib/sort-cells.ts
@@ -0,0 +1,57 @@
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+
+export type SortDirection = "asc" | "desc";
+
+export interface SortableItem {
+ payload: T;
+ text: string;
+ isHeader: boolean;
+ isEmpty: boolean;
+ originalOrder: number;
+}
+
+const HEADER_TYPE_NAMES = new Set(["tableHeader", "table_header"]);
+
+export function isHeaderCell(node: ProseMirrorNode): boolean {
+ if (HEADER_TYPE_NAMES.has(node.type.name)) return true;
+ return node.attrs?.header === true;
+}
+
+export function getCellSortText(node: ProseMirrorNode): string {
+ let text = "";
+ node.descendants((child) => {
+ if (child.isText) text += child.text ?? "";
+ return true;
+ });
+ return text.trim().toLowerCase();
+}
+
+export function isCellEmpty(node: ProseMirrorNode): boolean {
+ return getCellSortText(node) === "";
+}
+
+export const collator = new Intl.Collator(undefined, {
+ sensitivity: "base",
+ numeric: true,
+});
+
+export function sortItems(
+ data: SortableItem[],
+ direction: SortDirection,
+): SortableItem[] {
+ return [...data].sort((a, b) => {
+ if (a.isEmpty && !b.isEmpty) return 1;
+ if (!a.isEmpty && b.isEmpty) return -1;
+ if (a.isEmpty && b.isEmpty) return a.originalOrder - b.originalOrder;
+ const cmp = collator.compare(a.text, b.text);
+ return direction === "asc" ? cmp : -cmp;
+ });
+}
+
+export function weaveItems(
+ all: SortableItem[],
+ sortedData: SortableItem[],
+): SortableItem[] {
+ const dataQueue = [...sortedData];
+ return all.map((item) => (item.isHeader ? item : dataQueue.shift()!));
+}
diff --git a/apps/client/src/features/editor/components/table/handle/menus/alignment-submenu.tsx b/apps/client/src/features/editor/components/table/handle/menus/alignment-submenu.tsx
new file mode 100644
index 000000000..c58f5a967
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/menus/alignment-submenu.tsx
@@ -0,0 +1,49 @@
+import React from "react";
+import type { Editor } from "@tiptap/react";
+import { Menu } from "@mantine/core";
+import {
+ IconAlignCenter,
+ IconAlignLeft,
+ IconAlignRight,
+} from "@tabler/icons-react";
+import { useTranslation } from "react-i18next";
+
+interface AlignmentSubmenuProps {
+ editor: Editor;
+}
+
+export const AlignmentSubmenu = React.memo(function AlignmentSubmenu({
+ editor,
+}: AlignmentSubmenuProps) {
+ const { t } = useTranslation();
+
+ return (
+
+
+ }>
+ {t("Text alignment")}
+
+
+
+ }
+ onClick={() => editor.chain().focus().setTextAlign("left").run()}
+ >
+ {t("Align left")}
+
+ }
+ onClick={() => editor.chain().focus().setTextAlign("center").run()}
+ >
+ {t("Align center")}
+
+ }
+ onClick={() => editor.chain().focus().setTextAlign("right").run()}
+ >
+ {t("Align right")}
+
+
+
+ );
+});
diff --git a/apps/client/src/features/editor/components/table/handle/menus/cell-chevron-menu.tsx b/apps/client/src/features/editor/components/table/handle/menus/cell-chevron-menu.tsx
new file mode 100644
index 000000000..84f904ca7
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/menus/cell-chevron-menu.tsx
@@ -0,0 +1,154 @@
+import React from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { ColorSwatch, Menu } from "@mantine/core";
+import {
+ IconBoxMargin,
+ IconColumnInsertRight,
+ IconColumnRemove,
+ IconEraser,
+ IconPalette,
+ IconRowInsertBottom,
+ IconRowRemove,
+ IconSquareToggle,
+ IconTableRow,
+} from "@tabler/icons-react";
+import { useTranslation } from "react-i18next";
+import { useTableClear } from "../hooks/use-table-clear";
+import { TABLE_COLORS } from "../../table-background-color";
+import { AlignmentSubmenu } from "./alignment-submenu";
+
+interface CellChevronMenuProps {
+ editor: Editor;
+ cellPos: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export const CellChevronMenu = React.memo(function CellChevronMenu({
+ editor,
+ cellPos,
+ tableNode,
+ tablePos,
+}: CellChevronMenuProps) {
+ const { t } = useTranslation();
+
+ const clearCell = useTableClear(editor, tableNode, tablePos, {
+ kind: "cell",
+ cellPos,
+ });
+
+ const setBackground = (color: string, name: string) => {
+ editor
+ .chain()
+ .focus()
+ .updateAttributes("tableCell", {
+ backgroundColor: color || null,
+ backgroundColorName: color ? name : null,
+ })
+ .updateAttributes("tableHeader", {
+ backgroundColor: color || null,
+ backgroundColorName: color ? name : null,
+ })
+ .run();
+ };
+
+ return (
+ <>
+
+
+ }>
+ {t("Background color")}
+
+
+
+
+ {TABLE_COLORS.map((c) => (
+
+ ))}
+
+
+
+
+
+
+ }
+ onClick={() => editor.chain().focus().mergeCells().run()}
+ disabled={!editor.can().mergeCells()}
+ >
+ {t("Merge cells")}
+
+ }
+ onClick={() => editor.chain().focus().splitCell().run()}
+ disabled={!editor.can().splitCell()}
+ >
+ {t("Split cell")}
+
+ }
+ onClick={() => editor.chain().focus().toggleHeaderCell().run()}
+ >
+ {t("Toggle header cell")}
+
+
+
+
+ }
+ onClick={() => editor.chain().focus().addColumnAfter().run()}
+ >
+ {t("Add column right")}
+
+ }
+ onClick={() => editor.chain().focus().addRowAfter().run()}
+ >
+ {t("Add row below")}
+
+
+ } onClick={clearCell}>
+ {t("Clear cell")}
+
+ }
+ onClick={() => editor.chain().focus().deleteColumn().run()}
+ >
+ {t("Delete column")}
+
+ }
+ onClick={() => editor.chain().focus().deleteRow().run()}
+ >
+ {t("Delete row")}
+
+ >
+ );
+});
diff --git a/apps/client/src/features/editor/components/table/handle/menus/column-handle-menu.tsx b/apps/client/src/features/editor/components/table/handle/menus/column-handle-menu.tsx
new file mode 100644
index 000000000..8dbe9d326
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/menus/column-handle-menu.tsx
@@ -0,0 +1,177 @@
+import React from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { ColorSwatch, Menu } from "@mantine/core";
+import { TABLE_COLORS } from "../../table-background-color";
+import {
+ IconArrowLeft,
+ IconArrowRight,
+ IconColumnInsertLeft,
+ IconColumnInsertRight,
+ IconColumnRemove,
+ IconEraser,
+ IconPalette,
+ IconSortAscendingLetters,
+ IconSortDescendingLetters,
+} from "@tabler/icons-react";
+import { useTranslation } from "react-i18next";
+import { useTableMoveRowColumn } from "../hooks/use-table-move-row-column";
+import { useTableClear } from "../hooks/use-table-clear";
+import { useTableSort } from "../hooks/use-table-sort";
+import { AlignmentSubmenu } from "./alignment-submenu";
+
+interface ColumnHandleMenuProps {
+ editor: Editor;
+ index: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export const ColumnHandleMenu = React.memo(function ColumnHandleMenu({
+ editor,
+ index,
+ tableNode,
+ tablePos,
+}: ColumnHandleMenuProps) {
+ const { t } = useTranslation();
+
+ const moveLeft = useTableMoveRowColumn(editor, "col", index, "left", tableNode, tablePos);
+ const moveRight = useTableMoveRowColumn(editor, "col", index, "right", tableNode, tablePos);
+ const clearCol = useTableClear(editor, tableNode, tablePos, {
+ kind: "col",
+ index,
+ });
+
+ const setBackground = (color: string, name: string) => {
+ editor
+ .chain()
+ .focus()
+ .updateAttributes("tableCell", {
+ backgroundColor: color || null,
+ backgroundColorName: color ? name : null,
+ })
+ .updateAttributes("tableHeader", {
+ backgroundColor: color || null,
+ backgroundColorName: color ? name : null,
+ })
+ .run();
+ };
+
+ const sortAsc = useTableSort({
+ editor,
+ orientation: "col",
+ index,
+ tableNode,
+ tablePos,
+ direction: "asc",
+ });
+ const sortDesc = useTableSort({
+ editor,
+ orientation: "col",
+ index,
+ tableNode,
+ tablePos,
+ direction: "desc",
+ });
+
+ return (
+ <>
+ }
+ onClick={sortAsc.handleSort}
+ disabled={!sortAsc.canSort}
+ >
+ {t("Sort A → Z")}
+
+ }
+ onClick={sortDesc.handleSort}
+ disabled={!sortDesc.canSort}
+ >
+ {t("Sort Z → A")}
+
+
+
+
+
+ }>
+ {t("Background color")}
+
+
+
+
+ {TABLE_COLORS.map((c) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ }
+ onClick={() => editor.chain().focus().addColumnBefore().run()}
+ >
+ {t("Add column left")}
+
+ }
+ onClick={() => editor.chain().focus().addColumnAfter().run()}
+ >
+ {t("Add column right")}
+
+
+
+
+ }
+ onClick={clearCol}
+ >
+ {t("Clear cells")}
+
+ }
+ onClick={() => editor.chain().focus().deleteColumn().run()}
+ >
+ {t("Delete column")}
+
+
+
+
+ }
+ onClick={moveLeft.handleMove}
+ disabled={!moveLeft.canMove}
+ >
+ {t("Move column left")}
+
+ }
+ onClick={moveRight.handleMove}
+ disabled={!moveRight.canMove}
+ >
+ {t("Move column right")}
+
+ >
+ );
+});
diff --git a/apps/client/src/features/editor/components/table/handle/menus/row-handle-menu.tsx b/apps/client/src/features/editor/components/table/handle/menus/row-handle-menu.tsx
new file mode 100644
index 000000000..13b968b76
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/menus/row-handle-menu.tsx
@@ -0,0 +1,138 @@
+import React from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { ColorSwatch, Menu } from "@mantine/core";
+import { TABLE_COLORS } from "../../table-background-color";
+import {
+ IconArrowDown,
+ IconArrowUp,
+ IconEraser,
+ IconPalette,
+ IconRowInsertBottom,
+ IconRowInsertTop,
+ IconRowRemove,
+} from "@tabler/icons-react";
+import { useTranslation } from "react-i18next";
+import { useTableMoveRowColumn } from "../hooks/use-table-move-row-column";
+import { useTableClear } from "../hooks/use-table-clear";
+import { AlignmentSubmenu } from "./alignment-submenu";
+
+interface RowHandleMenuProps {
+ editor: Editor;
+ index: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export const RowHandleMenu = React.memo(function RowHandleMenu({
+ editor,
+ index,
+ tableNode,
+ tablePos,
+}: RowHandleMenuProps) {
+ const { t } = useTranslation();
+
+ const setBackground = (color: string, name: string) => {
+ editor
+ .chain()
+ .focus()
+ .updateAttributes("tableCell", {
+ backgroundColor: color || null,
+ backgroundColorName: color ? name : null,
+ })
+ .updateAttributes("tableHeader", {
+ backgroundColor: color || null,
+ backgroundColorName: color ? name : null,
+ })
+ .run();
+ };
+
+ const moveUp = useTableMoveRowColumn(editor, "row", index, "up", tableNode, tablePos);
+ const moveDown = useTableMoveRowColumn(editor, "row", index, "down", tableNode, tablePos);
+ const clearRow = useTableClear(editor, tableNode, tablePos, {
+ kind: "row",
+ index,
+ });
+
+ return (
+ <>
+
+
+ }>
+ {t("Background color")}
+
+
+
+
+ {TABLE_COLORS.map((c) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ }
+ onClick={() => editor.chain().focus().addRowBefore().run()}
+ >
+ {t("Add row above")}
+
+ }
+ onClick={() => editor.chain().focus().addRowAfter().run()}
+ >
+ {t("Add row below")}
+
+
+
+
+ } onClick={clearRow}>
+ {t("Clear cells")}
+
+ }
+ onClick={() => editor.chain().focus().deleteRow().run()}
+ >
+ {t("Delete row")}
+
+
+
+
+ }
+ onClick={moveUp.handleMove}
+ disabled={!moveUp.canMove}
+ >
+ {t("Move row up")}
+
+ }
+ onClick={moveDown.handleMove}
+ disabled={!moveDown.canMove}
+ >
+ {t("Move row down")}
+
+ >
+ );
+});
diff --git a/apps/client/src/features/editor/components/table/handle/row-handle.tsx b/apps/client/src/features/editor/components/table/handle/row-handle.tsx
new file mode 100644
index 000000000..7a5483558
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/row-handle.tsx
@@ -0,0 +1,122 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import type { Editor } from "@tiptap/react";
+import type { Node as ProseMirrorNode } from "@tiptap/pm/model";
+import { useFloating, offset, autoUpdate, hide } from "@floating-ui/react";
+import { Menu } from "@mantine/core";
+import clsx from "clsx";
+import { useTranslation } from "react-i18next";
+import { useTableHandleDrag } from "./hooks/use-table-handle-drag";
+import { useColumnRowMenuLifecycle } from "./hooks/use-column-row-menu-lifecycle";
+import { RowHandleMenu } from "./menus/row-handle-menu";
+import classes from "./handle.module.css";
+
+interface RowHandleProps {
+ editor: Editor;
+ index: number;
+ anchorPos: number;
+ tableNode: ProseMirrorNode;
+ tablePos: number;
+}
+
+export const RowHandle = React.memo(function RowHandle({
+ editor,
+ index,
+ anchorPos,
+ tableNode,
+ tablePos,
+}: RowHandleProps) {
+ const { t } = useTranslation();
+ // See ColumnHandle for the rationale: keep the last valid cell DOM cached
+ // so the handle div stays mounted across stale-anchor renders, otherwise
+ // pragmatic-dnd silently aborts an in-flight drag.
+ const lookupCellDom = editor.view.nodeDOM(anchorPos) as HTMLElement | null;
+ const [cellDom, setCellDom] = useState(lookupCellDom);
+ const lastCellDomRef = useRef(lookupCellDom);
+ useEffect(() => {
+ if (lookupCellDom && lookupCellDom !== lastCellDomRef.current) {
+ lastCellDomRef.current = lookupCellDom;
+ setCellDom(lookupCellDom);
+ }
+ }, [lookupCellDom]);
+
+ const [handleEl, setHandleEl] = useState(null);
+
+ const { refs, floatingStyles, middlewareData } = useFloating({
+ placement: "left",
+ middleware: [offset(-4), hide()],
+ whileElementsMounted: autoUpdate,
+ });
+ const isReferenceHidden = !!middlewareData.hide?.referenceHidden;
+
+ useEffect(() => {
+ refs.setReference(cellDom);
+ }, [cellDom, refs]);
+
+ const wrapper = cellDom?.closest(".tableWrapper") ?? null;
+
+ const [menuOpened, setMenuOpened] = useState(false);
+ const closeMenu = useCallback(() => setMenuOpened(false), []);
+ useTableHandleDrag(editor, "row", handleEl, wrapper, closeMenu);
+
+ const { onOpen, onClose } = useColumnRowMenuLifecycle({
+ editor,
+ orientation: "row",
+ index,
+ tableNode,
+ tablePos,
+ });
+
+ if (!cellDom) return null;
+
+ return (
+
+ );
+});
+
+function GripIcon() {
+ return (
+
+ );
+}
diff --git a/apps/client/src/features/editor/components/table/handle/table-handles-layer.tsx b/apps/client/src/features/editor/components/table/handle/table-handles-layer.tsx
new file mode 100644
index 000000000..e40c7baac
--- /dev/null
+++ b/apps/client/src/features/editor/components/table/handle/table-handles-layer.tsx
@@ -0,0 +1,44 @@
+import React from "react";
+import type { Editor } from "@tiptap/react";
+import { useTableHandleState } from "./hooks/use-table-handle-state";
+import { ColumnHandle } from "./column-handle";
+import { RowHandle } from "./row-handle";
+import { CellChevron } from "./cell-chevron";
+
+interface TableHandlesLayerProps {
+ editor: Editor | null;
+}
+
+export const TableHandlesLayer = React.memo(function TableHandlesLayer({
+ editor,
+}: TableHandlesLayerProps) {
+ const state = useTableHandleState(editor);
+
+ if (!editor || !editor.isEditable) return null;
+ if (!state.hoveringCell || !state.tableNode || state.tablePos == null) return null;
+
+ return (
+ <>
+
+
+
+ >
+ );
+});
diff --git a/apps/client/src/features/editor/components/table/table-background-color.tsx b/apps/client/src/features/editor/components/table/table-background-color.tsx
index 3e4ce6168..c0df52d81 100644
--- a/apps/client/src/features/editor/components/table/table-background-color.tsx
+++ b/apps/client/src/features/editor/components/table/table-background-color.tsx
@@ -22,7 +22,7 @@ interface TableBackgroundColorProps {
editor: Editor | null;
}
-const TABLE_COLORS: TableColorItem[] = [
+export const TABLE_COLORS: TableColorItem[] = [
{ name: "Default", color: "" },
{ name: "Blue", color: "#b4d5ff" },
{ name: "Green", color: "#acf5d2" },
diff --git a/apps/client/src/features/editor/components/table/table-menu.tsx b/apps/client/src/features/editor/components/table/table-menu.tsx
index 4adafb206..3be7ec539 100644
--- a/apps/client/src/features/editor/components/table/table-menu.tsx
+++ b/apps/client/src/features/editor/components/table/table-menu.tsx
@@ -104,12 +104,12 @@ export const TableMenu = React.memo(
element.style.zIndex = "99";
}}
options={{
- placement: "top",
+ placement: "bottom",
offset: {
mainAxis: 15,
},
flip: {
- fallbackPlacements: ["top", "bottom"],
+ fallbackPlacements: ["bottom", "top"],
padding: { top: 35 + 15, left: 8, right: 8, bottom: -Infinity },
boundary: editor.options.element as HTMLElement,
},
diff --git a/apps/client/src/features/editor/components/table/table-text-alignment.tsx b/apps/client/src/features/editor/components/table/table-text-alignment.tsx
index 4d4646cf5..17ef7c42e 100644
--- a/apps/client/src/features/editor/components/table/table-text-alignment.tsx
+++ b/apps/client/src/features/editor/components/table/table-text-alignment.tsx
@@ -86,11 +86,11 @@ export const TableTextAlignment: FC = ({ editor }) => {
transitionProps={{ transition: "pop" }}
>
-
+
setOpened(!opened)}
>
diff --git a/apps/client/src/features/editor/extensions/drag-handle.ts b/apps/client/src/features/editor/extensions/drag-handle.ts
index a4843ed67..6b10678a1 100644
--- a/apps/client/src/features/editor/extensions/drag-handle.ts
+++ b/apps/client/src/features/editor/extensions/drag-handle.ts
@@ -60,6 +60,23 @@ function nodeDOMAtCoords(
options: GlobalDragHandleOptions,
view: EditorView,
) {
+ // Custom nodes (transclusion, …) render via tiptap's React node-view
+ // renderer, which emits `class="react-renderer node-${name}"` on the
+ // live wrapper — the `data-type` attribute is for static HTML
+ // serialization only. Match both so we cover live and parsed DOM.
+ // Inside a custom node, also match plain `p` so the first paragraph
+ // (which doesn't match `:not(:first-child)`) still gets its own
+ // handle; only hovers on the custom node's padding/border fall
+ // through to the wrapper.
+ const customSelectors = options.customNodes.flatMap((node) => [
+ `[data-type=${node}]`,
+ `.node-${node}`,
+ ]);
+ const customParagraphSelectors = options.customNodes.flatMap((node) => [
+ `[data-type=${node}] p`,
+ `.node-${node} p`,
+ ]);
+
const selectors = [
"li",
"p:not(:first-child)",
@@ -71,7 +88,13 @@ function nodeDOMAtCoords(
"h4",
"h5",
"h6",
- ...options.customNodes.map((node) => `[data-type=${node}]`),
+ // Tables nested in another block (toggle, transclusion, …) have a
+ // wrapper that isn't a direct child of .ProseMirror, so the
+ // parent-check below skips it. Match the wrapper explicitly so the
+ // handle shows up even with empty cells.
+ ".tableWrapper",
+ ...customParagraphSelectors,
+ ...customSelectors,
].join(", ");
return document
.elementsFromPoint(coords.x, coords.y)
@@ -99,6 +122,22 @@ function nodePosAtDOM(
})?.inside;
}
+function isCustomNodeDOM(
+ elem: Element | null | undefined,
+ options: GlobalDragHandleOptions,
+): boolean {
+ if (!elem) return false;
+ for (const name of options.customNodes) {
+ if (
+ elem.getAttribute("data-type") === name ||
+ elem.classList.contains(`node-${name}`)
+ ) {
+ return true;
+ }
+ }
+ return false;
+}
+
function calcNodePos(pos: number, view: EditorView) {
const $pos = view.state.doc.resolve(pos);
if ($pos.depth > 1) return $pos.before($pos.depth);
@@ -137,7 +176,6 @@ export function DragHandlePlugin(
const nodePos = view.state.doc.resolve(fromSelectionPos);
- // Check if nodePos points to the top level node
if (nodePos.node().type.name === "doc") differentNodeSelected = true;
else {
const nodeSelection = NodeSelection.create(
@@ -166,14 +204,46 @@ export function DragHandlePlugin(
} else {
selection = NodeSelection.create(view.state.doc, draggedNodePos);
- // if inline node is selected, e.g mention -> go to the parent node to select the whole node
- // if table row is selected, go to the parent node to select the whole node
- if (
- (selection as NodeSelection).node.type.isInline ||
- (selection as NodeSelection).node.type.name === "tableRow"
- ) {
- let $pos = view.state.doc.resolve(selection.from);
- selection = NodeSelection.create(view.state.doc, $pos.before());
+ const $sel = view.state.doc.resolve(selection.from);
+
+ if (isCustomNodeDOM(node, options)) {
+ // The drag landed on a custom-node container (transclusion etc.).
+ // Walk up to the matching node so the drag moves the whole
+ // container, not whatever inner element the click landed on.
+ const customTypes = new Set(options.customNodes);
+ for (let d = $sel.depth; d > 0; d--) {
+ if (customTypes.has($sel.node(d).type.name)) {
+ selection = NodeSelection.create(
+ view.state.doc,
+ $sel.before(d),
+ );
+ break;
+ }
+ }
+ } else {
+ // If the selected node lives inside a table (at any nesting
+ // depth), promote to the whole table — the global drag handle is
+ // meant to move the table as a single block, not a row/cell. The
+ // earlier tableRow-only check only worked when the table sat at
+ // the doc root; once wrapped in another node (toggle, layout,
+ // etc.) the selection lands on a cell/paragraph and that check
+ // never fired.
+ let tableDepth = -1;
+ for (let d = $sel.depth; d > 0; d--) {
+ if ($sel.node(d).type.name === "table") {
+ tableDepth = d;
+ break;
+ }
+ }
+ if (tableDepth > 0) {
+ selection = NodeSelection.create(
+ view.state.doc,
+ $sel.before(tableDepth),
+ );
+ } else if ((selection as NodeSelection).node.type.isInline) {
+ // Inline node (e.g. mention): walk up to the parent block.
+ selection = NodeSelection.create(view.state.doc, $sel.before());
+ }
}
}
view.dispatch(view.state.tr.setSelection(selection));
@@ -313,6 +383,27 @@ export function DragHandlePlugin(
return;
}
+ const isCustomNode = isCustomNodeDOM(node, options);
+
+ // Custom nodes pin the handle to the inner NodeViewWrapper's top-left:
+ // the natural anchor sits in transient/empty space outside the visible block.
+ if (isCustomNode) {
+ // tiptap React node-views emit an outer `.react-renderer` whose first
+ // child is the visible NodeViewWrapper; walk to that outer first since
+ // `node` may be either the outer or an inner element with data-type.
+ const rendererOuter =
+ (node.closest(".react-renderer") as HTMLElement | null) ?? node;
+ const inner =
+ (rendererOuter.firstElementChild as HTMLElement | null) ??
+ rendererOuter;
+ const innerRect = absoluteRect(inner);
+ if (!dragHandleElement) return;
+ dragHandleElement.style.left = `${innerRect.left + 4}px`;
+ dragHandleElement.style.top = `${innerRect.top + 4}px`;
+ showDragHandle();
+ return;
+ }
+
const compStyle = window.getComputedStyle(node);
const parsedLineHeight = parseInt(compStyle.lineHeight, 10);
const lineHeight = isNaN(parsedLineHeight)
@@ -328,6 +419,13 @@ export function DragHandlePlugin(
if (node.matches("ul:not([data-type=taskList]) li, ol li")) {
rect.left -= options.dragHandleWidth;
}
+ // Tables: clear the table's own row-drag handle so the two
+ // grips don't stack on each other. `nodeDOMAtCoords` returns
+ // the wrapper for top-level hovers (wrapper is direct child of
+ // .ProseMirror) and a descendant for deeper hovers — cover both.
+ if (node.closest(".tableWrapper")) {
+ rect.left -= options.dragHandleWidth;
+ }
rect.width = options.dragHandleWidth;
if (!dragHandleElement) return;
diff --git a/apps/client/src/features/editor/extensions/extensions.ts b/apps/client/src/features/editor/extensions/extensions.ts
index 23be85aa1..1f09bef37 100644
--- a/apps/client/src/features/editor/extensions/extensions.ts
+++ b/apps/client/src/features/editor/extensions/extensions.ts
@@ -45,6 +45,9 @@ import {
SearchAndReplace,
Mention,
TableDndExtension,
+ TableHandleCommandsExtension,
+ TableHeaderPin,
+ TableReadonlySort,
Subpages,
Heading,
Highlight,
@@ -56,6 +59,7 @@ import {
Status,
TransclusionSource,
TransclusionReference,
+ TableView,
} from "@docmost/editor-ext";
import {
randomElement,
@@ -259,11 +263,16 @@ export const mainExtensions = [
resizable: true,
lastColumnResizable: true,
allowTableNodeSelection: true,
+ cellMinWidth: 49,
+ View: TableView,
}),
TableRow,
TableCell,
TableHeader,
TableDndExtension,
+ TableHandleCommandsExtension,
+ TableHeaderPin,
+ TableReadonlySort,
MathInline.configure({
view: MathInlineView,
}),
diff --git a/apps/client/src/features/editor/page-editor.tsx b/apps/client/src/features/editor/page-editor.tsx
index 57aab5bb0..4e2fcccf6 100644
--- a/apps/client/src/features/editor/page-editor.tsx
+++ b/apps/client/src/features/editor/page-editor.tsx
@@ -44,6 +44,7 @@ import { EditorBubbleMenu } from "@/features/editor/components/bubble-menu/bubbl
import { ReadonlyBubbleMenu } from "@/features/editor/components/bubble-menu/readonly-bubble-menu";
import TableCellMenu from "@/features/editor/components/table/table-cell-menu.tsx";
import TableMenu from "@/features/editor/components/table/table-menu.tsx";
+import { TableHandlesLayer } from "@/features/editor/components/table/handle/table-handles-layer";
import ImageMenu from "@/features/editor/components/image/image-menu.tsx";
import CalloutMenu from "@/features/editor/components/callout/callout-menu.tsx";
import VideoMenu from "@/features/editor/components/video/video-menu.tsx";
@@ -424,7 +425,7 @@ export default function PageEditor({
-
+
diff --git a/apps/client/src/features/editor/styles/core.css b/apps/client/src/features/editor/styles/core.css
index 34ddaca3c..077570fb5 100644
--- a/apps/client/src/features/editor/styles/core.css
+++ b/apps/client/src/features/editor/styles/core.css
@@ -203,7 +203,8 @@
}
}
- .resize-cursor {
+ &.resize-cursor,
+ &.resize-cursor * {
cursor: ew-resize;
cursor: col-resize;
}
diff --git a/apps/client/src/features/editor/styles/table.css b/apps/client/src/features/editor/styles/table.css
index 9926d0bc0..5d802e4ab 100644
--- a/apps/client/src/features/editor/styles/table.css
+++ b/apps/client/src/features/editor/styles/table.css
@@ -15,7 +15,8 @@
}
.table-dnd-drop-indicator {
- background-color: #adf;
+ background-color: var(--mantine-color-blue-5);
+ z-index: 3;
}
.ProseMirror {
@@ -57,13 +58,14 @@
}
.column-resize-handle {
- background-color: #adf;
+ background-color: var(--mantine-color-blue-5);
bottom: -1px;
position: absolute;
- right: -2px;
+ right: -1px;
pointer-events: none;
top: 0;
- width: 4px;
+ width: 2px;
+ z-index: 3;
}
.selectedCell:after {
@@ -129,6 +131,139 @@
}
}
+
+/* Header-row pinning. Two CSS paths, picked by `header-pin/controller.ts`:
+ - native sticky (preferred): wrapper drops its overflow constraint so
+ `position: sticky` on the row can resolve against the document scroll.
+ - transform fallback: wrapper keeps `overflow-x: auto` for horizontal
+ scrolling; the row is positioned imperatively per scroll frame.
+
+ `--editor-pin-offset` is published to :root by `pinOffsetWatcher` in
+ `header-pin/offset.ts`, measured against the lowest fixed surface above
+ the editor (app shell header, page header, fixed toolbar). */
+
+.tableWrapper.tableWrapperNoOverflow,
+.tableWrapper.tableWrapperNoOverflow table {
+ overflow: visible;
+}
+
+.tableWrapper.tableHeaderPinned table tr:first-child {
+ z-index: 2;
+}
+
+.tableWrapper.tableWrapperNoOverflow.tableHeaderPinned table tr:first-child {
+ position: sticky;
+ top: var(--editor-pin-offset, 90px);
+}
+
+.tableWrapper.tableHeaderPinned:not(.tableWrapperNoOverflow) table tr:first-child {
+ position: relative;
+ transform: translateY(var(--table-pin-offset, 0px));
+}
+
+@media print {
+ .tableWrapper.tableHeaderPinned table tr:first-child {
+ position: static;
+ transform: none;
+ }
+}
+
+.tableReadonlySortChevron {
+ /* Anchor to the cell's right edge, vertically centered with the cell
+ content. The cell content (a ) is block-level so an inline chevron
+ would wrap to a new line; absolute positioning takes it out of flow. */
+ position: absolute;
+ top: 50%;
+ right: 6px;
+ transform: translateY(-50%);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 18px;
+ height: 18px;
+ border-radius: 4px;
+ background: light-dark(
+ rgba(55, 53, 47, 0.08),
+ rgba(255, 255, 255, 0.08)
+ );
+ color: light-dark(
+ rgba(55, 53, 47, 0.55),
+ rgba(255, 255, 255, 0.55)
+ );
+ user-select: none;
+ cursor: pointer;
+ z-index: 1;
+ /* Hidden by default; revealed on header-cell hover or when this column is
+ the active sort (see selectors below). */
+ opacity: 0;
+ transition: opacity 120ms ease, background-color 120ms ease, color 120ms ease;
+}
+
+.ProseMirror table th:hover .tableReadonlySortChevron,
+.tableReadonlySortChevron[data-sort] {
+ opacity: 1;
+}
+
+.ProseMirror table th:has(.tableReadonlySortChevron) {
+ padding-right: 30px;
+}
+
+.tableReadonlySortChevron:hover {
+ background: light-dark(
+ rgba(55, 53, 47, 0.16),
+ rgba(255, 255, 255, 0.16)
+ );
+}
+
+/* Immediate tooltip on the chevron — same style language as the rest of the
+ app (small, dark, rounded), unlike the native `title` tooltip which only
+ appears after a long delay. */
+.tableReadonlySortChevron::after {
+ content: attr(data-tooltip);
+ position: absolute;
+ /* Below the chevron — placing it above the cell hits the table's
+ overflow clipping (the wrapper has `overflow-x: auto` which forces
+ `overflow-y: auto` per spec). */
+ top: calc(100% + 6px);
+ right: 0;
+ padding: 4px 8px;
+ border-radius: 4px;
+ background: var(--mantine-color-dark-7);
+ color: var(--mantine-color-white);
+ font-size: 12px;
+ font-weight: 400;
+ line-height: 1.4;
+ white-space: nowrap;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 120ms ease;
+ z-index: 10;
+}
+
+.tableReadonlySortChevron:hover::after {
+ opacity: 1;
+}
+
+.tableReadonlySortChevron svg {
+ display: block;
+}
+
+.tableReadonlySortChevron[data-sort="asc"],
+.tableReadonlySortChevron[data-sort="desc"] {
+ background: light-dark(
+ var(--mantine-color-blue-1),
+ var(--mantine-color-blue-9)
+ );
+ color: light-dark(
+ var(--mantine-color-blue-7),
+ var(--mantine-color-blue-2)
+ );
+}
+
+.tableReadonlySortChevron[data-sort="asc"] svg {
+ transform: rotate(180deg);
+}
+
.editor-container:has(.table-dnd-drop-indicator[data-dragging="true"]) {
.prosemirror-dropcursor-block {
display: none;
diff --git a/apps/client/src/features/page/components/header/page-header.tsx b/apps/client/src/features/page/components/header/page-header.tsx
index 12f131b8d..0614cf0bd 100644
--- a/apps/client/src/features/page/components/header/page-header.tsx
+++ b/apps/client/src/features/page/components/header/page-header.tsx
@@ -8,7 +8,7 @@ interface Props {
}
export default function PageHeader({ readOnly }: Props) {
return (
-
+
diff --git a/packages/editor-ext/src/lib/table/dnd/auto-scroll-controller.ts b/packages/editor-ext/src/lib/table/dnd/auto-scroll-controller.ts
deleted file mode 100644
index 9b8304d54..000000000
--- a/packages/editor-ext/src/lib/table/dnd/auto-scroll-controller.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { DraggingDOMs } from "./utils";
-
-const EDGE_THRESHOLD = 100;
-const SCROLL_SPEED = 10;
-
-export class AutoScrollController {
- private _autoScrollInterval?: number;
-
- checkYAutoScroll = (clientY: number) => {
- const scrollContainer = document.documentElement;
-
- if (clientY < 0 + EDGE_THRESHOLD) {
- this._startYAutoScroll(scrollContainer!, -1 * SCROLL_SPEED);
- } else if (clientY > window.innerHeight - EDGE_THRESHOLD) {
- this._startYAutoScroll(scrollContainer!, SCROLL_SPEED);
- } else {
- this._stopYAutoScroll();
- }
- }
-
- checkXAutoScroll = (clientX: number, draggingDOMs: DraggingDOMs) => {
- const table = draggingDOMs?.table;
- if (!table) return;
-
- const scrollContainer = table.closest('.tableWrapper');
- const editorRect = scrollContainer.getBoundingClientRect();
- if (!scrollContainer) return;
-
- if (clientX < editorRect.left + EDGE_THRESHOLD) {
- this._startXAutoScroll(scrollContainer!, -1 * SCROLL_SPEED);
- } else if (clientX > editorRect.right - EDGE_THRESHOLD) {
- this._startXAutoScroll(scrollContainer!, SCROLL_SPEED);
- } else {
- this._stopXAutoScroll();
- }
- }
-
- stop = () => {
- this._stopXAutoScroll();
- this._stopYAutoScroll();
- }
-
- private _startXAutoScroll = (scrollContainer: HTMLElement, speed: number) => {
- if (this._autoScrollInterval) {
- clearInterval(this._autoScrollInterval);
- }
-
- this._autoScrollInterval = window.setInterval(() => {
- scrollContainer.scrollLeft += speed;
- }, 16);
- }
-
- private _stopXAutoScroll = () => {
- if (this._autoScrollInterval) {
- clearInterval(this._autoScrollInterval);
- this._autoScrollInterval = undefined;
- }
- }
-
- private _startYAutoScroll = (scrollContainer: HTMLElement, speed: number) => {
- if (this._autoScrollInterval) {
- clearInterval(this._autoScrollInterval);
- }
-
- this._autoScrollInterval = window.setInterval(() => {
- scrollContainer.scrollTop += speed;
- }, 16);
- }
-
- private _stopYAutoScroll = () => {
- if (this._autoScrollInterval) {
- clearInterval(this._autoScrollInterval);
- this._autoScrollInterval = undefined;
- }
- }
-}
\ No newline at end of file
diff --git a/packages/editor-ext/src/lib/table/dnd/dnd-extension.ts b/packages/editor-ext/src/lib/table/dnd/dnd-extension.ts
index 1ad57ec1f..b4ca516ae 100644
--- a/packages/editor-ext/src/lib/table/dnd/dnd-extension.ts
+++ b/packages/editor-ext/src/lib/table/dnd/dnd-extension.ts
@@ -1,316 +1,393 @@
import { Editor, Extension } from "@tiptap/core";
-import { PluginKey, Plugin, PluginSpec } from "@tiptap/pm/state";
+import { PluginKey, Plugin, PluginSpec, TextSelection, Transaction } from "@tiptap/pm/state";
+import { Node as ProseMirrorNode } from "@tiptap/pm/model";
import { EditorProps, EditorView } from "@tiptap/pm/view";
+import { columnResizingPluginKey } from "@tiptap/pm/tables";
+import { cellAround } from "@tiptap/pm/tables";
import {
+ cellInfoFromResolvedCell,
DraggingDOMs,
getDndRelatedDOMs,
getHoveringCell,
HoveringCellInfo,
} from "./utils";
import { getDragOverColumn, getDragOverRow } from "./calc-drag-over";
+import { findTable } from "../utils/query";
import { moveColumn, moveRow } from "../utils";
import { PreviewController } from "./preview/preview-controller";
import { DropIndicatorController } from "./preview/drop-indicator-controller";
-import { DragHandleController } from "./handle/drag-handle-controller";
-import { EmptyImageController } from "./handle/empty-image-controller";
-import { AutoScrollController } from "./auto-scroll-controller";
-export const TableDndKey = new PluginKey("table-drag-and-drop");
+export interface TableHandleState {
+ hoveringCell: HoveringCellInfo | null;
+ tableNode: ProseMirrorNode | null;
+ tablePos: number | null;
+ dragging: { orientation: "col" | "row"; index: number } | null;
+ frozen: boolean;
+}
-class TableDragHandlePluginSpec implements PluginSpec {
+const INITIAL_STATE: TableHandleState = {
+ hoveringCell: null,
+ tableNode: null,
+ tablePos: null,
+ dragging: null,
+ frozen: false,
+};
+
+export const TableDndKey = new PluginKey("table-handles");
+
+class TableHandlePluginSpec implements PluginSpec {
key = TableDndKey;
- props: EditorProps>;
+ props: EditorProps>;
+
+ private _previewController: PreviewController;
+ private _dropIndicatorController: DropIndicatorController;
- private _colDragHandle: HTMLElement;
- private _rowDragHandle: HTMLElement;
private _hoveringCell?: HoveringCellInfo;
private _disposables: (() => void)[] = [];
- private _draggingCoords: { x: number; y: number } = { x: 0, y: 0 };
- private _dragging = false;
private _draggingDirection: "col" | "row" = "col";
private _draggingIndex = -1;
private _droppingIndex = -1;
- private _draggingDOMs?: DraggingDOMs | undefined;
- private _startCoords: { x: number; y: number } = { x: 0, y: 0 };
- private _previewController: PreviewController;
- private _dropIndicatorController: DropIndicatorController;
- private _dragHandleController: DragHandleController;
- private _emptyImageController: EmptyImageController;
- private _autoScrollController: AutoScrollController;
+ private _draggingDOMs?: DraggingDOMs;
+ private _startCoords = { x: 0, y: 0 };
+ private _dragging = false;
+
+ state = {
+ init: (): TableHandleState => INITIAL_STATE,
+ apply: (tr: Transaction, prev: TableHandleState): TableHandleState => {
+ const meta = tr.getMeta(TableDndKey) as Partial | null;
+ if (!meta) return prev;
+ let changed = false;
+ for (const key in meta) {
+ if (!Object.is(prev[key as keyof TableHandleState], meta[key as keyof TableHandleState])) {
+ changed = true;
+ break;
+ }
+ }
+ return changed ? { ...prev, ...meta } : prev;
+ },
+ };
constructor(public editor: Editor) {
this.props = {
handleDOMEvents: {
- pointerover: this._pointerOver,
+ pointermove: this._pointerMove,
+ // Force-unfreeze on any pointerdown that lands on the editor.
+ // Mantine's `Menu.onClose` doesn't always fire on outside click
+ // (the dropdown vanishes visually but the callback is skipped),
+ // which would otherwise leave `frozen=true` permanently.
+ pointerdown: this._pointerDown,
},
};
- this._dragHandleController = new DragHandleController();
- this._colDragHandle = this._dragHandleController.colDragHandle;
- this._rowDragHandle = this._dragHandleController.rowDragHandle;
-
this._previewController = new PreviewController();
this._dropIndicatorController = new DropIndicatorController();
- this._emptyImageController = new EmptyImageController();
-
- this._autoScrollController = new AutoScrollController();
-
- this._bindDragEvents();
}
view = () => {
const wrapper = this.editor.options.element;
- //@ts-ignore
- wrapper.appendChild(this._colDragHandle);
- //@ts-ignore
- wrapper.appendChild(this._rowDragHandle);
- //@ts-ignore
+ // @ts-ignore
wrapper.appendChild(this._previewController.previewRoot);
- //@ts-ignore
+ // @ts-ignore
wrapper.appendChild(this._dropIndicatorController.dropIndicatorRoot);
+ // Track the cursor cell so handles follow keyboard nav and clicks too.
+ this.editor.on("selectionUpdate", this._onSelectionUpdate);
+ this._disposables.push(() =>
+ this.editor.off("selectionUpdate", this._onSelectionUpdate),
+ );
+
return {
- update: this.update,
destroy: this.destroy,
};
};
- update = () => {};
-
destroy = () => {
- if (!this.editor.isDestroyed) return;
- this._dragHandleController.destroy();
- this._emptyImageController.destroy();
this._previewController.destroy();
this._dropIndicatorController.destroy();
- this._autoScrollController.stop();
-
- this._disposables.forEach((disposable) => disposable());
+ this._disposables.forEach((d) => d());
};
- private _pointerOver = (view: EditorView, event: PointerEvent) => {
- if (this._dragging) return;
+ private _pointerDown = (view: EditorView, _event: PointerEvent): boolean => {
+ const current = TableDndKey.getState(view.state);
+ if (current?.frozen) this.editor.commands.unfreezeHandles();
+ return false;
+ };
+
+ private _pointerMove = (view: EditorView, event: PointerEvent) => {
+ const current = TableDndKey.getState(view.state);
+ if (current?.frozen || current?.dragging) return;
+
+ const resizeState = columnResizingPluginKey.getState(view.state);
+ if (resizeState?.dragging) return;
- // Don't show drag handles in readonly mode
if (!this.editor.isEditable) {
- this._dragHandleController.hide();
+ if (current?.hoveringCell == null && current?.tableNode == null && current?.tablePos == null) return;
+ this._dispatchMeta({ hoveringCell: null, tableNode: null, tablePos: null });
return;
}
const hoveringCell = getHoveringCell(view, event);
- this._hoveringCell = hoveringCell;
- if (!hoveringCell) {
- this._dragHandleController.hide();
- } else {
- this._dragHandleController.show(this.editor, hoveringCell);
+ if (hoveringCell) {
+ if (current?.hoveringCell?.cellPos === hoveringCell.cellPos) return;
+ this._hoveringCell = hoveringCell;
+ const $cell = view.state.doc.resolve(hoveringCell.cellPos);
+ const tableInfo = findTable($cell);
+ this._dispatchMeta({
+ hoveringCell,
+ tableNode: tableInfo?.node ?? null,
+ tablePos: tableInfo?.pos ?? null,
+ });
+ return;
}
+
+ // Pointer isn't over a cell but may be transiting toward a handle that
+ // floats outside the cell — fall back to the selection's cell so the
+ // handles stay visible.
+ const $cellPos = cellAround(view.state.selection.$head);
+ if ($cellPos) {
+ const cellInfo = cellInfoFromResolvedCell($cellPos);
+ if (current?.hoveringCell?.cellPos === cellInfo.cellPos) return;
+ this._hoveringCell = cellInfo;
+ const tableInfo = findTable($cellPos);
+ this._dispatchMeta({
+ hoveringCell: cellInfo,
+ tableNode: tableInfo?.node ?? null,
+ tablePos: tableInfo?.pos ?? null,
+ });
+ return;
+ }
+
+ this._hoveringCell = undefined;
+ if (current?.hoveringCell == null && current?.tableNode == null && current?.tablePos == null) return;
+ this._dispatchMeta({ hoveringCell: null, tableNode: null, tablePos: null });
};
- private _onDragColStart = (event: DragEvent) => {
- this._onDragStart(event, "col");
+ private _onSelectionUpdate = () => {
+ if (!this.editor.isEditable) return;
+
+ const current = TableDndKey.getState(this.editor.state);
+ if (current?.frozen || current?.dragging) return;
+
+ const $cellPos = cellAround(this.editor.state.selection.$head);
+ if (!$cellPos) return;
+
+ const cellInfo = cellInfoFromResolvedCell($cellPos);
+ if (current?.hoveringCell?.cellPos === cellInfo.cellPos) return;
+
+ this._hoveringCell = cellInfo;
+ const tableInfo = findTable($cellPos);
+ this._dispatchMeta({
+ hoveringCell: cellInfo,
+ tableNode: tableInfo?.node ?? null,
+ tablePos: tableInfo?.pos ?? null,
+ });
};
- private _onDraggingCol = (event: DragEvent) => {
+ private _dispatchMeta = (patch: Partial) => {
+ const tr = this.editor.state.tr.setMeta(TableDndKey, patch);
+ tr.setMeta("addToHistory", false);
+ this.editor.view.dispatch(tr);
+ };
+
+ // ---- Public API for the React handle layer ----
+
+ // Returns true if the drag was set up successfully.
+ startDragFromHandle = (
+ orientation: "col" | "row",
+ clientX: number,
+ clientY: number,
+ ): boolean => {
+ if (!this._hoveringCell) return false;
+ this._dragging = true;
+ this._draggingDirection = orientation;
+ this._startCoords = { x: clientX, y: clientY };
+
+ const draggingIndex =
+ (orientation === "col"
+ ? this._hoveringCell.colIndex
+ : this._hoveringCell.rowIndex) ?? 0;
+ this._draggingIndex = draggingIndex;
+
+ const relatedDoms = getDndRelatedDOMs(
+ this.editor.view,
+ this._hoveringCell.cellPos,
+ draggingIndex,
+ orientation,
+ );
+ if (!relatedDoms) {
+ this._dragging = false;
+ return false;
+ }
+ this._draggingDOMs = relatedDoms;
+
+ this._previewController.onDragStart(relatedDoms, draggingIndex, orientation);
+ this._dropIndicatorController.onDragStart(relatedDoms, orientation);
+
+ // Park the selection inside the dragged cell unless it's already in the
+ // same table. PM auto-maps `selection.from` through concurrent remote
+ // transactions, so commitDrop can resolve the table even if the doc
+ // shifted mid-drag — same trick the pre-pragmatic-dnd implementation
+ // relied on.
+ const state = this.editor.state;
+ const currentTable = findTable(state.selection.$from);
+ const hoverTable = (() => {
+ try {
+ return findTable(state.doc.resolve(this._hoveringCell.cellPos));
+ } catch {
+ return undefined;
+ }
+ })();
+ const tr = state.tr;
+ if (
+ hoverTable &&
+ (!currentTable || currentTable.pos !== hoverTable.pos)
+ ) {
+ try {
+ const $inside = state.doc.resolve(this._hoveringCell.cellPos + 1);
+ tr.setSelection(TextSelection.near($inside, 1));
+ } catch {}
+ }
+ tr.setMeta(TableDndKey, {
+ dragging: { orientation, index: draggingIndex },
+ });
+ tr.setMeta("addToHistory", false);
+ this.editor.view.dispatch(tr);
+ return true;
+ };
+
+ updateDragPosition = (clientX: number, clientY: number) => {
const draggingDOMs = this._draggingDOMs;
- if (!draggingDOMs) return;
+ if (!draggingDOMs || !this._dragging) return;
- this._draggingCoords = { x: event.clientX, y: event.clientY };
- this._previewController.onDragging(
- draggingDOMs,
- this._draggingCoords.x,
- this._draggingCoords.y,
- "col",
- );
+ if (this._draggingDirection === "col") {
+ this._previewController.onDragging(
+ draggingDOMs,
+ clientX,
+ clientY,
+ "col",
+ );
+ const direction = this._startCoords.x > clientX ? "left" : "right";
+ const dragOverColumn = getDragOverColumn(draggingDOMs.table, clientX);
+ if (!dragOverColumn) return;
+ const [col, index] = dragOverColumn;
+ this._droppingIndex = index;
+ this._dropIndicatorController.onDragging(col, direction, "col");
+ return;
+ }
- this._autoScrollController.checkXAutoScroll(event.clientX, draggingDOMs);
-
- const direction =
- this._startCoords.x > this._draggingCoords.x ? "left" : "right";
- const dragOverColumn = getDragOverColumn(
- draggingDOMs.table,
- this._draggingCoords.x,
- );
- if (!dragOverColumn) return;
-
- const [col, index] = dragOverColumn;
- this._droppingIndex = index;
- this._dropIndicatorController.onDragging(col, direction, "col");
- };
-
- private _onDragRowStart = (event: DragEvent) => {
- this._onDragStart(event, "row");
- };
-
- private _onDraggingRow = (event: DragEvent) => {
- const draggingDOMs = this._draggingDOMs;
- if (!draggingDOMs) return;
-
- this._draggingCoords = { x: event.clientX, y: event.clientY };
- this._previewController.onDragging(
- draggingDOMs,
- this._draggingCoords.x,
- this._draggingCoords.y,
- "row",
- );
-
- this._autoScrollController.checkYAutoScroll(event.clientY);
-
- const direction =
- this._startCoords.y > this._draggingCoords.y ? "up" : "down";
- const dragOverRow = getDragOverRow(
- draggingDOMs.table,
- this._draggingCoords.y,
- );
+ this._previewController.onDragging(draggingDOMs, clientX, clientY, "row");
+ const direction = this._startCoords.y > clientY ? "up" : "down";
+ const dragOverRow = getDragOverRow(draggingDOMs.table, clientY);
if (!dragOverRow) return;
-
const [row, index] = dragOverRow;
this._droppingIndex = index;
this._dropIndicatorController.onDragging(row, direction, "row");
};
- private _onDragEnd = () => {
- this._dragging = false;
- this._draggingIndex = -1;
- this._droppingIndex = -1;
- this._startCoords = { x: 0, y: 0 };
- this._autoScrollController.stop();
- this._dropIndicatorController.onDragEnd();
- this._previewController.onDragEnd();
- };
-
- private _bindDragEvents = () => {
- this._colDragHandle.addEventListener("dragstart", this._onDragColStart);
- this._disposables.push(() => {
- this._colDragHandle.removeEventListener(
- "dragstart",
- this._onDragColStart,
- );
- });
-
- this._colDragHandle.addEventListener("dragend", this._onDragEnd);
- this._disposables.push(() => {
- this._colDragHandle.removeEventListener("dragend", this._onDragEnd);
- });
-
- this._rowDragHandle.addEventListener("dragstart", this._onDragRowStart);
- this._disposables.push(() => {
- this._rowDragHandle.removeEventListener(
- "dragstart",
- this._onDragRowStart,
- );
- });
-
- this._rowDragHandle.addEventListener("dragend", this._onDragEnd);
- this._disposables.push(() => {
- this._rowDragHandle.removeEventListener("dragend", this._onDragEnd);
- });
-
- const ownerDocument = this.editor.view.dom?.ownerDocument;
- if (ownerDocument) {
- // To make `drop` event work, we need to prevent the default behavior of the
- // `dragover` event for drop zone. Here we set the whole document as the
- // drop zone so that even the mouse moves outside the editor, the `drop`
- // event will still be triggered.
- ownerDocument.addEventListener("drop", this._onDrop);
- ownerDocument.addEventListener("dragover", this._onDrag);
- this._disposables.push(() => {
- ownerDocument.removeEventListener("drop", this._onDrop);
- ownerDocument.removeEventListener("dragover", this._onDrag);
- });
- }
- };
-
- private _onDragStart = (event: DragEvent, type: "col" | "row") => {
- const dataTransfer = event.dataTransfer;
- if (dataTransfer) {
- dataTransfer.effectAllowed = "move";
- this._emptyImageController.hideDragImage(dataTransfer);
- }
- this._dragging = true;
- this._draggingDirection = type;
- this._startCoords = { x: event.clientX, y: event.clientY };
- const draggingIndex =
- (type === "col"
- ? this._hoveringCell?.colIndex
- : this._hoveringCell?.rowIndex) ?? 0;
-
- this._draggingIndex = draggingIndex;
-
- const relatedDoms = getDndRelatedDOMs(
- this.editor.view,
- this._hoveringCell?.cellPos,
- draggingIndex,
- type,
- );
- this._draggingDOMs = relatedDoms;
-
- const index =
- type === "col"
- ? this._hoveringCell?.colIndex
- : this._hoveringCell?.rowIndex;
-
- this._previewController.onDragStart(relatedDoms, index, type);
- this._dropIndicatorController.onDragStart(relatedDoms, type);
- };
-
- private _onDrag = (event: DragEvent) => {
- event.preventDefault();
- if (!this._dragging) return;
- if (this._draggingDirection === "col") {
- this._onDraggingCol(event);
- } else {
- this._onDraggingRow(event);
- }
- };
-
- private _onDrop = () => {
+ commitDrop = () => {
if (!this._dragging) return;
const direction = this._draggingDirection;
const from = this._draggingIndex;
const to = this._droppingIndex;
+
+ if (from < 0 || to < 0 || from === to) return;
+
+ // Use the live (auto-mapped) selection as the table anchor — PM has
+ // already mapped it through any concurrent remote transactions, so
+ // it's safe to resolve even if the doc shifted mid-drag.
const tr = this.editor.state.tr;
const pos = this.editor.state.selection.from;
if (direction === "col") {
- const canMove = moveColumn({
- tr,
- originIndex: from,
- targetIndex: to,
- select: true,
- pos,
- });
- if (canMove) {
+ if (moveColumn({ tr, originIndex: from, targetIndex: to, select: true, pos })) {
this.editor.view.dispatch(tr);
}
-
return;
}
-
- if (direction === "row") {
- const canMove = moveRow({
- tr,
- originIndex: from,
- targetIndex: to,
- select: true,
- pos,
- });
- if (canMove) {
- this.editor.view.dispatch(tr);
- }
-
- return;
+ if (moveRow({ tr, originIndex: from, targetIndex: to, select: true, pos })) {
+ this.editor.view.dispatch(tr);
}
};
+
+ endDrag = () => {
+ this._dragging = false;
+ this._draggingIndex = -1;
+ this._droppingIndex = -1;
+ this._startCoords = { x: 0, y: 0 };
+ this._draggingDOMs = undefined;
+ this._dropIndicatorController.onDragEnd();
+ this._previewController.onDragEnd();
+ this._dispatchMeta({ dragging: null });
+ };
+}
+
+export type { TableHandlePluginSpec };
+
+// Resolve via plugin key, not a module singleton — survives StrictMode / HMR.
+export function getTableHandlePluginSpec(
+ editor: Editor,
+): TableHandlePluginSpec | null {
+ const plugin = TableDndKey.get(editor.state);
+ if (!plugin) return null;
+ return plugin.spec as unknown as TableHandlePluginSpec;
}
export const TableDndExtension = Extension.create({
name: "table-drag-and-drop",
addProseMirrorPlugins() {
const editor = this.editor;
-
- const dragHandlePluginSpec = new TableDragHandlePluginSpec(editor);
- const dragHandlePlugin = new Plugin(dragHandlePluginSpec);
-
- return [dragHandlePlugin];
+ const spec = new TableHandlePluginSpec(editor);
+ return [new Plugin(spec)];
},
});
+
+export const TableHandleCommandsExtension = Extension.create({
+ name: "table-handle-commands",
+ addCommands() {
+ return {
+ freezeHandles:
+ () =>
+ ({ tr, dispatch }) => {
+ if (dispatch) {
+ tr.setMeta(TableDndKey, { frozen: true });
+ tr.setMeta("addToHistory", false);
+ }
+ return true;
+ },
+ unfreezeHandles:
+ () =>
+ ({ tr, state, dispatch }) => {
+ if (dispatch) {
+ // Re-sync `hoveringCell` to the cursor's cell as we unfreeze:
+ // `selectionUpdate` was gated while frozen, so the stored
+ // hoveringCell may be stale.
+ const patch: Partial = { frozen: false };
+ const $cellPos = cellAround(state.selection.$head);
+ if ($cellPos) {
+ const cellInfo = cellInfoFromResolvedCell($cellPos);
+ const tableInfo = findTable($cellPos);
+ patch.hoveringCell = cellInfo;
+ patch.tableNode = tableInfo?.node ?? null;
+ patch.tablePos = tableInfo?.pos ?? null;
+ } else {
+ patch.hoveringCell = null;
+ patch.tableNode = null;
+ patch.tablePos = null;
+ }
+ tr.setMeta(TableDndKey, patch);
+ tr.setMeta("addToHistory", false);
+ }
+ return true;
+ },
+ };
+ },
+});
+
+declare module "@tiptap/core" {
+ interface Commands {
+ tableHandleCommands: {
+ freezeHandles: () => ReturnType;
+ unfreezeHandles: () => ReturnType;
+ };
+ }
+}
diff --git a/packages/editor-ext/src/lib/table/dnd/handle/drag-handle-controller.ts b/packages/editor-ext/src/lib/table/dnd/handle/drag-handle-controller.ts
deleted file mode 100644
index 33137e91f..000000000
--- a/packages/editor-ext/src/lib/table/dnd/handle/drag-handle-controller.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { Editor } from "@tiptap/core";
-import { HoveringCellInfo } from "../utils";
-import { computePosition, offset } from "@floating-ui/dom";
-
-export class DragHandleController {
- private _colDragHandle: HTMLElement;
- private _rowDragHandle: HTMLElement;
-
- constructor() {
- this._colDragHandle = this._createDragHandleDom('col');
- this._rowDragHandle = this._createDragHandleDom('row');
- }
-
- get colDragHandle() {
- return this._colDragHandle;
- }
-
- get rowDragHandle() {
- return this._rowDragHandle;
- }
-
- show = (editor: Editor, hoveringCell: HoveringCellInfo) => {
- this._showColDragHandle(editor, hoveringCell);
- this._showRowDragHandle(editor, hoveringCell);
- }
-
- hide = () => {
- Object.assign(this._colDragHandle.style, {
- display: 'none',
- left: '-999px',
- top: '-999px',
- });
- Object.assign(this._rowDragHandle.style, {
- display: 'none',
- left: '-999px',
- top: '-999px',
- });
- }
-
- destroy = () => {
- this._colDragHandle.remove()
- this._rowDragHandle.remove()
- }
-
- private _createDragHandleDom = (type: 'col' | 'row') => {
- const dragHandle = document.createElement('div')
- dragHandle.classList.add('drag-handle')
- dragHandle.setAttribute('draggable', 'true')
- dragHandle.setAttribute('data-direction', type === 'col' ? 'horizontal' : 'vertical')
- dragHandle.setAttribute('data-drag-handle', '')
- Object.assign(dragHandle.style, {
- position: 'absolute',
- top: '-999px',
- left: '-999px',
- display: 'none',
- })
- return dragHandle;
- }
-
- private _showColDragHandle(editor: Editor, hoveringCell: HoveringCellInfo) {
- const referenceCell = editor.view.nodeDOM(hoveringCell.colFirstCellPos);
- if (!referenceCell) return;
-
- const yOffset = -1 * parseInt(getComputedStyle(this._colDragHandle).height) / 2;
-
- computePosition(
- referenceCell as HTMLElement,
- this._colDragHandle,
- {
- placement: 'top',
- middleware: [offset(yOffset)]
- }
- )
- .then(({ x, y }) => {
- Object.assign(this._colDragHandle.style, {
- display: 'block',
- top: `${y}px`,
- left: `${x}px`,
- });
- })
- }
-
- private _showRowDragHandle(editor: Editor, hoveringCell: HoveringCellInfo) {
- const referenceCell = editor.view.nodeDOM(hoveringCell.rowFirstCellPos);
- if (!referenceCell) return;
-
- const xOffset = -1 * parseInt(getComputedStyle(this._rowDragHandle).width) / 2;
-
- computePosition(
- referenceCell as HTMLElement,
- this._rowDragHandle,
- {
- middleware: [offset(xOffset)],
- placement: 'left'
- }
- )
- .then(({ x, y}) => {
- Object.assign(this._rowDragHandle.style, {
- display: 'block',
- top: `${y}px`,
- left: `${x}px`,
- });
- })
- }
-}
\ No newline at end of file
diff --git a/packages/editor-ext/src/lib/table/dnd/handle/empty-image-controller.ts b/packages/editor-ext/src/lib/table/dnd/handle/empty-image-controller.ts
deleted file mode 100644
index 8848a6b04..000000000
--- a/packages/editor-ext/src/lib/table/dnd/handle/empty-image-controller.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-export class EmptyImageController {
- private _emptyImage: HTMLImageElement;
-
- constructor() {
- this._emptyImage = new Image(1, 1);
- this._emptyImage.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
- }
-
- get emptyImage() {
- return this._emptyImage;
- }
-
- hideDragImage = (dataTransfer: DataTransfer) => {
- dataTransfer.effectAllowed = 'move';
- dataTransfer.setDragImage(this._emptyImage, 0, 0);
- }
-
- destroy = () => {
- this._emptyImage.remove();
- }
-}
\ No newline at end of file
diff --git a/packages/editor-ext/src/lib/table/dnd/index.ts b/packages/editor-ext/src/lib/table/dnd/index.ts
index cb21bec14..eaeade987 100644
--- a/packages/editor-ext/src/lib/table/dnd/index.ts
+++ b/packages/editor-ext/src/lib/table/dnd/index.ts
@@ -1 +1,7 @@
-export * from './dnd-extension'
\ No newline at end of file
+export {
+ TableDndExtension,
+ TableHandleCommandsExtension,
+ TableDndKey,
+ getTableHandlePluginSpec,
+} from "./dnd-extension";
+export type { TableHandleState, TableHandlePluginSpec } from "./dnd-extension";
diff --git a/packages/editor-ext/src/lib/table/dnd/preview/drop-indicator-controller.ts b/packages/editor-ext/src/lib/table/dnd/preview/drop-indicator-controller.ts
index 0f0798282..a42c632f7 100644
--- a/packages/editor-ext/src/lib/table/dnd/preview/drop-indicator-controller.ts
+++ b/packages/editor-ext/src/lib/table/dnd/preview/drop-indicator-controller.ts
@@ -99,4 +99,4 @@ export class DropIndicatorController {
});
}
-}
\ No newline at end of file
+}
diff --git a/packages/editor-ext/src/lib/table/dnd/preview/preview-controller.ts b/packages/editor-ext/src/lib/table/dnd/preview/preview-controller.ts
index b7a0ea40d..9884f00f6 100644
--- a/packages/editor-ext/src/lib/table/dnd/preview/preview-controller.ts
+++ b/packages/editor-ext/src/lib/table/dnd/preview/preview-controller.ts
@@ -1,4 +1,4 @@
-import { computePosition, offset, ReferenceElement } from "@floating-ui/dom";
+import { computePosition, offset, shift, ReferenceElement } from "@floating-ui/dom";
import { DraggingDOMs } from "../utils";
import { clearPreviewDOM, createPreviewDOM } from "./render-preview";
@@ -23,7 +23,7 @@ export class PreviewController {
onDragStart = (relatedDoms: DraggingDOMs, index: number | undefined, type: 'col' | 'row') => {
this._initPreviewStyle(relatedDoms.table, relatedDoms.cell, type);
createPreviewDOM(relatedDoms.table, this._preview, index, type)
- this._initPreviewPosition(relatedDoms.cell, type);
+ this._initPreviewPosition(relatedDoms.table, relatedDoms.cell, type);
}
onDragEnd = () => {
@@ -32,7 +32,7 @@ export class PreviewController {
}
onDragging = (relatedDoms: DraggingDOMs, x: number, y: number, type: 'col' | 'row') => {
- this._updatePreviewPosition(x, y, relatedDoms.cell, type);
+ this._updatePreviewPosition(x, y, relatedDoms.table, relatedDoms.cell, type);
}
destroy = () => {
@@ -60,7 +60,7 @@ export class PreviewController {
}
}
- private _initPreviewPosition(cell: HTMLElement, type: 'col' | 'row') {
+ private _initPreviewPosition(table: HTMLElement, cell: HTMLElement, type: 'col' | 'row') {
void computePosition(cell, this._preview, {
placement: type === 'row' ? 'right' : 'bottom',
middleware: [
@@ -70,6 +70,7 @@ export class PreviewController {
}
return -rects.reference.width
}),
+ shift({ boundary: table, padding: 0 }),
],
}).then(({ x, y }) => {
Object.assign(this._preview.style, {
@@ -79,11 +80,20 @@ export class PreviewController {
});
}
- private _updatePreviewPosition(x: number, y: number, cell: HTMLElement, type: 'col' | 'row') {
+ // Clamp the preview to within the table's bounds via `shift({ boundary })`
+ // so it can't track the cursor past the table edge. Without the clamp,
+ // dragging near the viewport edge pushes the preview's `left` (or `top`)
+ // beyond the document's natural width/height, the browser extends the
+ // page to contain it, and the auto-scroll plugin then has a wider area
+ // to keep scrolling into — a feedback loop that grows the page forever.
+ private _updatePreviewPosition(x: number, y: number, table: HTMLElement, cell: HTMLElement, type: 'col' | 'row') {
computePosition(
getVirtualElement(cell, x, y),
this._preview,
- { placement: type === 'row' ? 'right' : 'bottom' },
+ {
+ placement: type === 'row' ? 'right' : 'bottom',
+ middleware: [shift({ boundary: table, padding: 0 })],
+ },
).then(({ x, y }) => {
if (type === 'row') {
Object.assign(this._preview.style, {
diff --git a/packages/editor-ext/src/lib/table/dnd/utils.ts b/packages/editor-ext/src/lib/table/dnd/utils.ts
index d184368f4..9b00769d3 100644
--- a/packages/editor-ext/src/lib/table/dnd/utils.ts
+++ b/packages/editor-ext/src/lib/table/dnd/utils.ts
@@ -1,4 +1,5 @@
import { cellAround, TableMap } from "@tiptap/pm/tables"
+import { ResolvedPos } from "@tiptap/pm/model"
import { EditorView } from "@tiptap/pm/view"
export function getHoveringCell(
@@ -8,19 +9,30 @@ export function getHoveringCell(
const domCell = domCellAround(event.target as HTMLElement | null)
if (!domCell) return
- const { left, top, width, height } = domCell.getBoundingClientRect()
- const eventPos = view.posAtCoords({
- // Use the center coordinates of the cell to ensure we're within the
- // selected cell. This prevents potential issues when the mouse is on the
- // border of two cells.
- left: left + width / 2,
- top: top + height / 2,
- })
- if (!eventPos) return
-
- const $cellPos = cellAround(view.state.doc.resolve(eventPos.pos))
+ // Resolve directly from the cell DOM rather than via coords. The previous
+ // center-coords approach broke on tall merged cells — their visual center
+ // can land in empty space whose closest PM position resolves to an
+ // adjacent cell. `posAtDOM(td, 0)` is always inside this cell, regardless
+ // of rowspan/colspan.
+ let pos: number
+ try {
+ pos = view.posAtDOM(domCell, 0)
+ } catch {
+ return
+ }
+ const $cellPos = cellAround(view.state.doc.resolve(pos))
if (!$cellPos) return
+ return cellInfoFromResolvedCell($cellPos)
+}
+
+/**
+ * Build HoveringCellInfo from a resolved position whose parent is a
+ * table cell (i.e. the result of `cellAround` on some inner position).
+ */
+export function cellInfoFromResolvedCell(
+ $cellPos: ResolvedPos,
+): HoveringCellInfo {
const map = TableMap.get($cellPos.node(-1))
const tableStart = $cellPos.start(-1)
const cellRect = map.findCell($cellPos.pos - tableStart)
diff --git a/packages/editor-ext/src/lib/table/header-pin/controller.ts b/packages/editor-ext/src/lib/table/header-pin/controller.ts
new file mode 100644
index 000000000..318d4145d
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/header-pin/controller.ts
@@ -0,0 +1,186 @@
+// Per-table header-pin controller: native sticky when table fits its wrapper, transform fallback when it doesn't.
+
+import { computePinTop, pinOffsetWatcher } from './offset';
+
+const WRAPPER_NO_OVERFLOW = 'tableWrapperNoOverflow';
+const HEADER_PINNED = 'tableHeaderPinned';
+const PIN_OFFSET_VAR = '--table-pin-offset';
+
+type PinMode = 'off' | 'native' | 'fallback';
+
+function firstRowIsAllHeaders(row: HTMLTableRowElement | null): boolean {
+ if (!row) return false;
+ const cells = Array.from(row.cells);
+ return cells.length > 0 && cells.every((c) => c.tagName === 'TH');
+}
+
+function isNestedTable(wrapper: HTMLElement): boolean {
+ return wrapper.closest('table .tableWrapper') !== null;
+}
+
+function isLayoutInert(rect: DOMRectReadOnly): boolean {
+ return rect.width === 0 && rect.height === 0;
+}
+
+const fallbackControllers = new Set();
+let fallbackScrollListener: (() => void) | null = null;
+let fallbackRafPending = false;
+
+function ensureFallbackListener() {
+ if (fallbackScrollListener) return;
+ fallbackScrollListener = () => {
+ if (fallbackRafPending) return;
+ fallbackRafPending = true;
+ requestAnimationFrame(() => {
+ fallbackRafPending = false;
+ for (const ctrl of fallbackControllers) ctrl.updateFallbackOffset();
+ });
+ };
+ document.addEventListener('scroll', fallbackScrollListener, {
+ passive: true,
+ capture: true,
+ });
+}
+
+function maybeTeardownFallbackListener() {
+ if (!fallbackScrollListener || fallbackControllers.size > 0) return;
+ document.removeEventListener('scroll', fallbackScrollListener, {
+ capture: true,
+ });
+ fallbackScrollListener = null;
+ fallbackRafPending = false;
+}
+
+export class TablePinController {
+ private wrapper: HTMLElement;
+ private table: HTMLTableElement;
+ private fitsObserver?: IntersectionObserver;
+ private mode: PinMode = 'off';
+ private cachedHeaderRow: HTMLTableRowElement | null = null;
+
+ constructor(wrapper: HTMLElement, table: HTMLTableElement) {
+ this.wrapper = wrapper;
+ this.table = table;
+ pinOffsetWatcher.acquire();
+ this.fitsObserver = new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries) this.evaluateFit(entry);
+ },
+ { root: this.wrapper, threshold: 1 },
+ );
+ this.fitsObserver.observe(this.table);
+ }
+
+ private getHeaderRow(): HTMLTableRowElement | null {
+ if (this.cachedHeaderRow && this.table.contains(this.cachedHeaderRow)) {
+ return this.cachedHeaderRow;
+ }
+ this.cachedHeaderRow = this.table.querySelector('tr');
+ return this.cachedHeaderRow;
+ }
+
+ private evaluateFit(entry: IntersectionObserverEntry) {
+ if (!this.isEligible()) {
+ this.apply('off');
+ return;
+ }
+ if (isLayoutInert(entry.boundingClientRect)) return;
+ this.apply(entry.isIntersecting ? 'native' : 'fallback');
+ }
+
+ private isEligible(): boolean {
+ return (
+ !isNestedTable(this.wrapper) && firstRowIsAllHeaders(this.getHeaderRow())
+ );
+ }
+
+ private apply(next: PinMode) {
+ if (next === this.mode) return;
+
+ if (this.mode === 'fallback' && next !== 'fallback') {
+ fallbackControllers.delete(this);
+ maybeTeardownFallbackListener();
+ }
+
+ this.mode = next;
+ const cls = this.wrapper.classList;
+
+ if (next === 'off') {
+ cls.remove(HEADER_PINNED);
+ cls.remove(WRAPPER_NO_OVERFLOW);
+ this.wrapper.style.removeProperty(PIN_OFFSET_VAR);
+ } else if (next === 'native') {
+ cls.add(HEADER_PINNED);
+ cls.add(WRAPPER_NO_OVERFLOW);
+ // Native mode reads --editor-pin-offset from :root; clear stale per-wrapper var from fallback.
+ this.wrapper.style.removeProperty(PIN_OFFSET_VAR);
+ } else if (next === 'fallback') {
+ cls.add(HEADER_PINNED);
+ cls.remove(WRAPPER_NO_OVERFLOW);
+ fallbackControllers.add(this);
+ ensureFallbackListener();
+ // Avoid one stale-frame paint under translateY.
+ this.updateFallbackOffset();
+ }
+ }
+
+ updateFallbackOffset() {
+ const pinTop = computePinTop();
+ const tableRect = this.table.getBoundingClientRect();
+ const headerRow = this.getHeaderRow();
+ if (!headerRow) return;
+ const rowHeight = headerRow.getBoundingClientRect().height;
+
+ const active = tableRect.top < pinTop && tableRect.bottom > pinTop + rowHeight;
+
+ if (active) {
+ const offset = Math.min(pinTop - tableRect.top, tableRect.height - rowHeight);
+ this.wrapper.style.setProperty(PIN_OFFSET_VAR, `${offset}px`);
+ } else {
+ this.wrapper.style.removeProperty(PIN_OFFSET_VAR);
+ }
+ }
+
+ refresh() {
+ // The header may have been replaced by a PM transaction; drop
+ // the cached reference before checking eligibility.
+ this.cachedHeaderRow = null;
+ if (!this.isEligible()) {
+ this.apply('off');
+ return;
+ }
+ if (this.mode === 'off') {
+ // Eligibility just flipped back on; re-trigger the observer so it
+ // emits the current intersection state.
+ this.fitsObserver?.unobserve(this.table);
+ this.fitsObserver?.observe(this.table);
+ }
+ }
+
+ destroy() {
+ this.fitsObserver?.disconnect();
+ this.fitsObserver = undefined;
+ this.apply('off');
+ pinOffsetWatcher.release();
+ }
+}
+
+const controllers = new WeakMap();
+
+export function attach(wrapper: HTMLElement) {
+ if (controllers.has(wrapper)) return;
+ const table = wrapper.querySelector(':scope > table') as HTMLTableElement | null;
+ if (!table) return;
+ controllers.set(wrapper, new TablePinController(wrapper, table));
+}
+
+export function detach(wrapper: HTMLElement) {
+ const ctrl = controllers.get(wrapper);
+ if (!ctrl) return;
+ ctrl.destroy();
+ controllers.delete(wrapper);
+}
+
+export function getController(wrapper: HTMLElement): TablePinController | undefined {
+ return controllers.get(wrapper);
+}
diff --git a/packages/editor-ext/src/lib/table/header-pin/extension.ts b/packages/editor-ext/src/lib/table/header-pin/extension.ts
new file mode 100644
index 000000000..8e5157ede
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/header-pin/extension.ts
@@ -0,0 +1,78 @@
+import { Extension } from '@tiptap/core';
+import { Plugin, PluginKey } from '@tiptap/pm/state';
+
+import { attach, detach, getController } from './controller';
+
+const tableHeaderPinKey = new PluginKey('tableHeaderPin');
+
+export const TableHeaderPin = Extension.create({
+ name: 'tableHeaderPin',
+
+ addProseMirrorPlugins() {
+ let editorRoot: HTMLElement | null = null;
+ let domObserver: MutationObserver | null = null;
+ const tracked = new Set();
+ let rafHandle: number | null = null;
+
+ const reconcile = () => {
+ rafHandle = null;
+ if (!editorRoot) return;
+ const current = new Set(
+ editorRoot.querySelectorAll('.tableWrapper'),
+ );
+ for (const w of tracked) {
+ if (!current.has(w)) {
+ detach(w);
+ tracked.delete(w);
+ }
+ }
+ for (const w of current) {
+ if (!tracked.has(w)) {
+ attach(w);
+ tracked.add(w);
+ }
+ }
+ };
+
+ const schedule = () => {
+ if (rafHandle !== null) return;
+ rafHandle = requestAnimationFrame(reconcile);
+ };
+
+ return [
+ new Plugin({
+ key: tableHeaderPinKey,
+
+ view(editorView) {
+ editorRoot = editorView.dom as HTMLElement;
+
+ schedule();
+
+ domObserver = new MutationObserver(schedule);
+ domObserver.observe(editorRoot, { subtree: true, childList: true });
+
+ return {
+ update(view, prevState) {
+ if (!editorRoot) return;
+ if (view.state.doc === prevState.doc) return;
+ editorRoot
+ .querySelectorAll('.tableWrapper')
+ .forEach((w) => getController(w)?.refresh());
+ },
+ destroy() {
+ if (rafHandle !== null) {
+ cancelAnimationFrame(rafHandle);
+ rafHandle = null;
+ }
+ domObserver?.disconnect();
+ domObserver = null;
+ for (const w of tracked) detach(w);
+ tracked.clear();
+ editorRoot = null;
+ },
+ };
+ },
+ }),
+ ];
+ },
+});
diff --git a/packages/editor-ext/src/lib/table/header-pin/index.ts b/packages/editor-ext/src/lib/table/header-pin/index.ts
new file mode 100644
index 000000000..b45e01aee
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/header-pin/index.ts
@@ -0,0 +1 @@
+export { TableHeaderPin } from './extension';
diff --git a/packages/editor-ext/src/lib/table/header-pin/offset.ts b/packages/editor-ext/src/lib/table/header-pin/offset.ts
new file mode 100644
index 000000000..89cc6bf9e
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/header-pin/offset.ts
@@ -0,0 +1,65 @@
+// Pin-offset measurement and watcher used by the table header-pin controller.
+
+// Fallback app-bar height (px) when no fixed surface is mounted; matches global-app-shell.tsx.
+const APP_BAR_FALLBACK_HEIGHT = 45;
+
+export const EDITOR_PIN_OFFSET_VAR = '--editor-pin-offset';
+
+// Selectors for fixed surfaces between viewport top and editor content. Use data attributes —
+// CSS module classes are build-time hashed and won't match.
+const PIN_ANCHOR_SELECTORS = [
+ '[data-page-header]',
+ '[data-fixed-toolbar]',
+] as const;
+
+export function computePinTop(): number {
+ let bottom = APP_BAR_FALLBACK_HEIGHT;
+ for (const sel of PIN_ANCHOR_SELECTORS) {
+ const el = document.querySelector(sel) as HTMLElement | null;
+ if (!el) continue;
+ const rect = el.getBoundingClientRect();
+ if (rect.height > 0 && rect.bottom > bottom) bottom = rect.bottom;
+ }
+ return bottom;
+}
+
+// Reference-counted watcher that publishes the editor's top offset to a CSS custom property.
+export const pinOffsetWatcher = {
+ refs: 0,
+ resizeObserver: null as ResizeObserver | null,
+ rafPending: false,
+ lastValue: -1,
+
+ acquire() {
+ if (this.refs++ > 0) return;
+ this.publish();
+ const schedule = () => {
+ if (this.rafPending) return;
+ this.rafPending = true;
+ requestAnimationFrame(() => {
+ this.rafPending = false;
+ this.publish();
+ });
+ };
+ this.resizeObserver = new ResizeObserver(schedule);
+ this.resizeObserver.observe(document.body);
+ },
+
+ release() {
+ if (--this.refs > 0) return;
+ this.resizeObserver?.disconnect();
+ this.resizeObserver = null;
+ document.documentElement.style.removeProperty(EDITOR_PIN_OFFSET_VAR);
+ this.lastValue = -1;
+ },
+
+ publish() {
+ const top = computePinTop();
+ if (top === this.lastValue) return;
+ this.lastValue = top;
+ document.documentElement.style.setProperty(
+ EDITOR_PIN_OFFSET_VAR,
+ `${top}px`,
+ );
+ },
+};
diff --git a/packages/editor-ext/src/lib/table/index.ts b/packages/editor-ext/src/lib/table/index.ts
index 9e5a92651..ed06582e3 100644
--- a/packages/editor-ext/src/lib/table/index.ts
+++ b/packages/editor-ext/src/lib/table/index.ts
@@ -2,4 +2,14 @@ export * from "./row";
export * from "./cell";
export * from "./header";
export * from "./table";
-export * from "./dnd";
\ No newline at end of file
+export * from "./dnd";
+export * from "./table-view";
+export * from "./header-pin";
+export * from "./table-readonly-sort";
+export { moveColumn } from "./utils/move-column";
+export type { MoveColumnParams } from "./utils/move-column";
+export { moveRow } from "./utils/move-row";
+export type { MoveRowParams } from "./utils/move-row";
+export { convertTableNodeToArrayOfRows } from "./utils/convert-table-node-to-array-of-rows";
+export { convertArrayOfRowsToTableNode } from "./utils/convert-array-of-rows-to-table-node";
+export { transpose } from "./utils/transpose";
diff --git a/packages/editor-ext/src/lib/table/table-readonly-sort.ts b/packages/editor-ext/src/lib/table/table-readonly-sort.ts
new file mode 100644
index 000000000..3e246a411
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/table-readonly-sort.ts
@@ -0,0 +1,233 @@
+import { Extension } from '@tiptap/core';
+import { Plugin, PluginKey } from '@tiptap/pm/state';
+
+type SortDirection = 'asc' | 'desc';
+
+type SortState = {
+ col: number;
+ direction: SortDirection;
+};
+
+const CHEVRON_CLASS = 'tableReadonlySortChevron';
+
+const tableReadonlySortKey = new PluginKey('tableReadonlySort');
+
+const sortStates = new WeakMap();
+const originalOrders = new WeakMap();
+
+const collator = new Intl.Collator(undefined, { sensitivity: 'base', numeric: true });
+
+function getColumnIndex(th: HTMLTableCellElement): number {
+ const row = th.parentElement as HTMLTableRowElement;
+ if (!row) return -1;
+ let col = 0;
+ for (let i = 0; i < row.cells.length; i++) {
+ if (row.cells[i] === th) return col;
+ col += row.cells[i].colSpan ?? 1;
+ }
+ return -1;
+}
+
+function getHeaderTh(target: EventTarget | null): HTMLTableCellElement | null {
+ if (!(target instanceof Element)) return null;
+ const th = target.closest('th') as HTMLTableCellElement | null;
+ if (!th) return null;
+ const row = th.parentElement;
+ if (!row) return null;
+ const tbody = row.parentElement;
+ if (!tbody) return null;
+ const table = tbody.closest('table');
+ if (!table) return null;
+
+ // th must be in the first row of the table (could be in thead or tbody)
+ const firstRow = table.querySelector('tr');
+ if (firstRow !== row) return null;
+
+ return th;
+}
+
+function getCellText(row: HTMLTableRowElement, colIndex: number): string {
+ let col = 0;
+ for (let i = 0; i < row.cells.length; i++) {
+ if (col === colIndex) return row.cells[i].textContent?.trim() ?? '';
+ col += row.cells[i].colSpan ?? 1;
+ }
+ return '';
+}
+
+function getOrSaveOriginalOrder(
+ table: HTMLTableElement,
+ dataRows: HTMLTableRowElement[],
+): HTMLTableRowElement[] {
+ if (!originalOrders.has(table)) {
+ originalOrders.set(table, [...dataRows]);
+ }
+ return originalOrders.get(table)!;
+}
+
+function sortDataRows(
+ dataRows: HTMLTableRowElement[],
+ colIndex: number,
+ direction: SortDirection,
+): HTMLTableRowElement[] {
+ return [...dataRows].sort((a, b) => {
+ const textA = getCellText(a, colIndex);
+ const textB = getCellText(b, colIndex);
+ const emptyA = textA === '';
+ const emptyB = textB === '';
+ if (emptyA && emptyB) return 0;
+ if (emptyA) return 1;
+ if (emptyB) return -1;
+ const cmp = collator.compare(textA, textB);
+ return direction === 'asc' ? cmp : -cmp;
+ });
+}
+
+function applySort(table: HTMLTableElement, colIndex: number): void {
+ const tbody = table.querySelector('tbody');
+ if (!tbody) return;
+
+ const allRows = Array.from(tbody.querySelectorAll(':scope > tr'));
+ if (allRows.length === 0) return;
+
+ const headerRow = allRows[0];
+ const dataRows = allRows.slice(1);
+ if (dataRows.length === 0) return;
+
+ const current = sortStates.get(table) ?? null;
+ const saved = getOrSaveOriginalOrder(table, dataRows);
+
+ let next: SortState | null;
+ if (!current || current.col !== colIndex) {
+ next = { col: colIndex, direction: 'asc' };
+ } else if (current.direction === 'asc') {
+ next = { col: colIndex, direction: 'desc' };
+ } else {
+ next = null;
+ }
+
+ if (next === null) {
+ sortStates.delete(table);
+ tbody.append(headerRow, ...saved);
+ } else {
+ sortStates.set(table, next);
+ const sorted = sortDataRows(saved, next.col, next.direction);
+ tbody.append(headerRow, ...sorted);
+ }
+
+ updateChevrons(table);
+}
+
+const CHEVRON_SVG =
+ '';
+
+function ensureChevron(th: HTMLTableCellElement): HTMLSpanElement {
+ let chevron = th.querySelector(`.${CHEVRON_CLASS}`);
+ if (!chevron) {
+ chevron = document.createElement('span');
+ chevron.className = CHEVRON_CLASS;
+ chevron.setAttribute('aria-hidden', 'true');
+ chevron.innerHTML = CHEVRON_SVG;
+ th.appendChild(chevron);
+ }
+ return chevron;
+}
+
+function updateChevrons(table: HTMLTableElement): void {
+ const firstRow = table.querySelector('tr');
+ if (!firstRow) return;
+
+ const state = sortStates.get(table) ?? null;
+ let col = 0;
+ for (let i = 0; i < firstRow.cells.length; i++) {
+ const cell = firstRow.cells[i];
+ if (cell.tagName !== 'TH') {
+ col += cell.colSpan ?? 1;
+ continue;
+ }
+ const chevron = ensureChevron(cell as HTMLTableCellElement);
+ let label: string;
+ if (state && state.col === col) {
+ chevron.setAttribute('data-sort', state.direction);
+ label = state.direction === 'asc' ? 'Sort descending' : 'Clear sort';
+ } else {
+ chevron.removeAttribute('data-sort');
+ label = 'Sort ascending';
+ }
+ chevron.setAttribute('data-tooltip', label);
+ chevron.setAttribute('aria-label', label);
+ chevron.title = label;
+ col += cell.colSpan ?? 1;
+ }
+}
+
+function addChevronsToAllTables(editorRoot: HTMLElement): void {
+ const tables = editorRoot.querySelectorAll('table');
+ tables.forEach((table) => updateChevrons(table));
+}
+
+function removeAllChevrons(editorRoot: HTMLElement): void {
+ editorRoot
+ .querySelectorAll(`.${CHEVRON_CLASS}`)
+ .forEach((el) => el.remove());
+}
+
+export const TableReadonlySort = Extension.create({
+ name: 'tableReadonlySort',
+
+ addProseMirrorPlugins() {
+ const editor = this.editor;
+ let editorRoot: HTMLElement | null = null;
+
+ const onClick = (event: MouseEvent) => {
+ if (editor.isEditable) return;
+ // Only react to clicks on the chevron, not anywhere else in the header
+ // cell. This lets the user click into a header to select text without
+ // accidentally triggering a sort.
+ if (!(event.target instanceof Element)) return;
+ const chevron = event.target.closest(`.${CHEVRON_CLASS}`);
+ if (!chevron) return;
+ const th = getHeaderTh(chevron);
+ if (!th) return;
+ const table = th.closest('table') as HTMLTableElement | null;
+ if (!table) return;
+ const colIndex = getColumnIndex(th);
+ if (colIndex < 0) return;
+ applySort(table, colIndex);
+ };
+
+ return [
+ new Plugin({
+ key: tableReadonlySortKey,
+
+ view(editorView) {
+ editorRoot = editorView.dom as HTMLElement;
+ editorRoot.addEventListener('click', onClick);
+
+ if (!editor.isEditable) {
+ addChevronsToAllTables(editorRoot);
+ }
+
+ return {
+ update(view) {
+ const root = view.dom as HTMLElement;
+ if (!editor.isEditable) {
+ addChevronsToAllTables(root);
+ } else {
+ removeAllChevrons(root);
+ }
+ },
+ destroy() {
+ if (editorRoot) {
+ editorRoot.removeEventListener('click', onClick);
+ removeAllChevrons(editorRoot);
+ }
+ },
+ };
+ },
+ }),
+ ];
+ },
+});
diff --git a/packages/editor-ext/src/lib/table/table-view.ts b/packages/editor-ext/src/lib/table/table-view.ts
new file mode 100644
index 000000000..7e410918e
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/table-view.ts
@@ -0,0 +1,158 @@
+import type { Node as ProseMirrorNode } from '@tiptap/pm/model';
+import type { NodeView, ViewMutationRecord } from '@tiptap/pm/view';
+import { getColStyleDeclaration } from './utils/col-style';
+
+export function updateColumns(
+ node: ProseMirrorNode,
+ colgroup: HTMLElement,
+ table: HTMLTableElement,
+ cellMinWidth: number,
+ overrideCol?: number,
+ overrideValue?: number,
+) {
+ let totalWidth = 0;
+ let fixedWidth = true;
+ let nextDOM = colgroup.firstChild;
+ const row = node.firstChild;
+
+ if (row !== null) {
+ for (let i = 0, col = 0; i < row.childCount; i += 1) {
+ const { colspan, colwidth } = row.child(i).attrs;
+
+ for (let j = 0; j < colspan; j += 1, col += 1) {
+ const hasWidth =
+ overrideCol === col
+ ? overrideValue
+ : ((colwidth && colwidth[j]) as number | undefined);
+ const cssWidth = hasWidth ? `${hasWidth}px` : '';
+
+ totalWidth += hasWidth || cellMinWidth;
+
+ if (!hasWidth) {
+ fixedWidth = false;
+ }
+
+ if (!nextDOM) {
+ const colElement = document.createElement('col');
+
+ const [propertyKey, propertyValue] = getColStyleDeclaration(
+ cellMinWidth,
+ hasWidth,
+ );
+
+ colElement.style.setProperty(propertyKey, propertyValue);
+
+ colgroup.appendChild(colElement);
+ } else {
+ if ((nextDOM as HTMLTableColElement).style.width !== cssWidth) {
+ const [propertyKey, propertyValue] = getColStyleDeclaration(
+ cellMinWidth,
+ hasWidth,
+ );
+
+ (nextDOM as HTMLTableColElement).style.setProperty(
+ propertyKey,
+ propertyValue,
+ );
+ }
+
+ nextDOM = nextDOM.nextSibling;
+ }
+ }
+ }
+ }
+
+ while (nextDOM) {
+ const after = nextDOM.nextSibling;
+
+ nextDOM.parentNode?.removeChild(nextDOM);
+ nextDOM = after;
+ }
+
+ const hasUserWidth =
+ node.attrs.style &&
+ typeof node.attrs.style === 'string' &&
+ /\bwidth\s*:/i.test(node.attrs.style);
+
+ if (fixedWidth && !hasUserWidth) {
+ table.style.width = `${totalWidth}px`;
+ table.style.minWidth = '';
+ } else {
+ table.style.width = '';
+ table.style.minWidth = `${totalWidth}px`;
+ }
+}
+
+export class TableView implements NodeView {
+ node: ProseMirrorNode;
+
+ cellMinWidth: number;
+
+ dom: HTMLDivElement;
+
+ table: HTMLTableElement;
+
+ colgroup: HTMLTableColElement;
+
+ contentDOM: HTMLTableSectionElement;
+
+ constructor(node: ProseMirrorNode, cellMinWidth: number) {
+ this.node = node;
+ this.cellMinWidth = cellMinWidth;
+ this.dom = document.createElement('div');
+ this.dom.className = 'tableWrapper';
+ this.table = this.dom.appendChild(document.createElement('table'));
+
+ if (node.attrs.style) {
+ this.table.style.cssText = node.attrs.style;
+ }
+
+ this.colgroup = this.table.appendChild(document.createElement('colgroup'));
+ updateColumns(node, this.colgroup, this.table, cellMinWidth);
+ this.contentDOM = this.table.appendChild(document.createElement('tbody'));
+ }
+
+ update(node: ProseMirrorNode) {
+ if (node.type !== this.node.type) return false;
+
+ this.node = node;
+ updateColumns(node, this.colgroup, this.table, this.cellMinWidth);
+
+ return true;
+ }
+
+ ignoreMutation(mutation: ViewMutationRecord) {
+ const target = mutation.target as Node;
+ const isInsideWrapper = this.dom.contains(target);
+ const isInsideContent = this.contentDOM.contains(target);
+
+ if (isInsideWrapper && !isInsideContent) {
+ if (
+ mutation.type === 'attributes' ||
+ mutation.type === 'childList' ||
+ mutation.type === 'characterData'
+ ) {
+ return true;
+ }
+ }
+
+ // Chevron span (.tableReadonlySortChevron) added/removed by sort plugin.
+ if (mutation.type === 'childList') {
+ const nodes = [
+ ...Array.from(mutation.addedNodes),
+ ...Array.from(mutation.removedNodes),
+ ];
+ if (
+ nodes.some(
+ (n) =>
+ n instanceof Element &&
+ n.classList.contains('tableReadonlySortChevron'),
+ )
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/packages/editor-ext/src/lib/table/table.ts b/packages/editor-ext/src/lib/table/table.ts
index f1436c28d..e87048a46 100644
--- a/packages/editor-ext/src/lib/table/table.ts
+++ b/packages/editor-ext/src/lib/table/table.ts
@@ -1,6 +1,8 @@
import { Table } from "@tiptap/extension-table";
import { Editor } from "@tiptap/core";
import { DOMOutputSpec } from "@tiptap/pm/model";
+import { TextSelection } from "@tiptap/pm/state";
+import { cellAround } from "@tiptap/pm/tables";
const LIST_TYPES = ["bulletList", "orderedList", "taskList"];
@@ -32,9 +34,36 @@ function handleListOutdent(editor: Editor): boolean {
}
export const CustomTable = Table.extend({
+
addKeyboardShortcuts() {
return {
...this.parent?.(),
+ "Mod-a": () => {
+ const { state, view } = this.editor;
+ const { selection, doc } = state;
+
+ const $cellPos = cellAround(selection.$anchor);
+ if (!$cellPos) return false;
+
+ const cellNode = doc.nodeAt($cellPos.pos);
+ // Empty cells have nothing useful to scope to — let the default
+ // Mod-a fall through and select the whole doc.
+ if (!cellNode || !cellNode.textContent) return false;
+
+ const from = $cellPos.pos + 1;
+ const to = $cellPos.pos + cellNode.nodeSize - 1;
+ if (from >= to) return true;
+
+ const nextSel = TextSelection.between(
+ doc.resolve(from),
+ doc.resolve(to),
+ 1,
+ );
+ if (!nextSel || selection.eq(nextSel)) return true;
+
+ view.dispatch(state.tr.setSelection(nextSel));
+ return true;
+ },
Tab: () => {
// If we're in a list within a table, handle list indentation
if (isInList(this.editor) && this.editor.isActive("table")) {
diff --git a/packages/editor-ext/src/lib/table/utils/col-style.ts b/packages/editor-ext/src/lib/table/utils/col-style.ts
new file mode 100644
index 000000000..8060962fd
--- /dev/null
+++ b/packages/editor-ext/src/lib/table/utils/col-style.ts
@@ -0,0 +1,7 @@
+export function getColStyleDeclaration(minWidth: number, width: number | undefined): [string, string] {
+ if (width) {
+ return ['width', `${Math.max(width, minWidth)}px`]
+ }
+
+ return ['min-width', `${minWidth}px`]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7a6dd37f6..f4a628064 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -248,22 +248,22 @@ importers:
apps/client:
dependencies:
'@atlaskit/pragmatic-drag-and-drop':
- specifier: ^1.8.1
+ specifier: 1.8.1
version: 1.8.1
'@atlaskit/pragmatic-drag-and-drop-auto-scroll':
- specifier: ^2.1.0
+ specifier: 2.1.5
version: 2.1.5
'@atlaskit/pragmatic-drag-and-drop-flourish':
- specifier: ^2.0.15
+ specifier: 2.0.15
version: 2.0.15(react@18.3.1)
'@atlaskit/pragmatic-drag-and-drop-hitbox':
- specifier: ^1.1.0
+ specifier: 1.1.0
version: 1.1.0
'@atlaskit/pragmatic-drag-and-drop-live-region':
- specifier: ^1.3.4
+ specifier: 1.3.4
version: 1.3.4
'@casl/react':
- specifier: ^5.0.1
+ specifier: 5.0.1
version: 5.0.1(@casl/ability@6.8.0)(react@18.3.1)
'@docmost/editor-ext':
specifier: workspace:*
@@ -272,37 +272,37 @@ importers:
specifier: 0.18.0-3a5ef40
version: 0.18.0-3a5ef40(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mantine/core':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mantine/dates':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.19)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mantine/form':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(react@18.3.1)
'@mantine/hooks':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(react@18.3.1)
'@mantine/modals':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mantine/notifications':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mantine/spotlight':
- specifier: ^8.3.18
+ specifier: 8.3.18
version: 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@slidoapp/emoji-mart':
- specifier: ^5.8.7
+ specifier: 5.8.7
version: 5.8.7
'@slidoapp/emoji-mart-data':
- specifier: ^1.2.4
+ specifier: 1.2.4
version: 1.2.4
'@slidoapp/emoji-mart-react':
- specifier: ^1.1.5
+ specifier: 1.1.5
version: 1.1.5(@slidoapp/emoji-mart@5.8.7)(react@18.3.1)
'@tabler/icons-react':
- specifier: ^3.40.0
+ specifier: 3.40.0
version: 3.40.0(react@18.3.1)
'@tanstack/react-query':
specifier: 5.90.17
@@ -311,22 +311,22 @@ importers:
specifier: 3.13.24
version: 3.13.24(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
alfaaz:
- specifier: ^1.1.0
+ specifier: 1.1.0
version: 1.1.0
axios:
specifier: 1.16.0
version: 1.16.0
blueimp-load-image:
- specifier: ^5.16.0
+ specifier: 5.16.0
version: 5.16.0
clsx:
- specifier: ^2.1.1
+ specifier: 2.1.1
version: 2.1.1
file-saver:
- specifier: ^2.0.5
+ specifier: 2.0.5
version: 2.0.5
highlightjs-sap-abap:
- specifier: ^0.3.0
+ specifier: 0.3.0
version: 0.3.0
i18next:
specifier: 25.10.1
@@ -335,37 +335,37 @@ importers:
specifier: 3.0.6
version: 3.0.6
jotai:
- specifier: ^2.18.1
+ specifier: 2.18.1
version: 2.18.1(@babel/core@7.28.5)(@babel/template@7.27.2)(@types/react@18.3.12)(react@18.3.1)
jotai-optics:
- specifier: ^0.4.0
+ specifier: 0.4.0
version: 0.4.0(jotai@2.18.1(@babel/core@7.28.5)(@babel/template@7.27.2)(@types/react@18.3.12)(react@18.3.1))(optics-ts@2.4.1)
js-cookie:
- specifier: ^3.0.5
+ specifier: 3.0.5
version: 3.0.5
jwt-decode:
- specifier: ^4.0.0
+ specifier: 4.0.0
version: 4.0.0
katex:
specifier: 0.16.40
version: 0.16.40
lowlight:
- specifier: ^3.3.0
+ specifier: 3.3.0
version: 3.3.0
mantine-form-zod-resolver:
- specifier: ^1.3.0
+ specifier: 1.3.0
version: 1.3.0(@mantine/form@8.3.18(react@18.3.1))(zod@4.3.6)
mermaid:
specifier: 11.13.0
version: 11.13.0
mitt:
- specifier: ^3.0.1
+ specifier: 3.0.1
version: 3.0.1
posthog-js:
specifier: 1.372.2
version: 1.372.2
react:
- specifier: ^18.3.1
+ specifier: 18.3.1
version: 18.3.1
react-clear-modal:
specifier: ^2.0.18
@@ -374,111 +374,111 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-drawio:
- specifier: ^1.0.7
+ specifier: 1.0.7
version: 1.0.7(react@18.3.1)
react-error-boundary:
- specifier: ^6.1.1
+ specifier: 6.1.1
version: 6.1.1(react@18.3.1)
react-helmet-async:
- specifier: ^3.0.0
+ specifier: 3.0.0
version: 3.0.0(react@18.3.1)
react-i18next:
specifier: 16.5.8
version: 16.5.8(i18next@25.10.1(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)
react-router-dom:
- specifier: ^7.13.1
+ specifier: 7.13.1
version: 7.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
semver:
- specifier: ^7.7.4
+ specifier: 7.7.4
version: 7.7.4
socket.io-client:
- specifier: ^4.8.3
+ specifier: 4.8.3
version: 4.8.3
zod:
- specifier: ^4.3.6
+ specifier: 4.3.6
version: 4.3.6
devDependencies:
'@eslint/js':
- specifier: ^9.28.0
- version: 9.39.4
+ specifier: 9.28.0
+ version: 9.28.0
'@tanstack/eslint-plugin-query':
- specifier: ^5.94.4
- version: 5.94.4(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)
+ specifier: 5.94.4
+ version: 5.94.4(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
'@testing-library/jest-dom':
- specifier: ^6.6.0
- version: 6.9.1
+ specifier: 6.6.0
+ version: 6.6.0
'@testing-library/react':
- specifier: ^16.1.0
- version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: 16.1.0
+ version: 16.1.0(@testing-library/dom@10.4.1)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/blueimp-load-image':
- specifier: ^5.16.6
+ specifier: 5.16.6
version: 5.16.6
'@types/file-saver':
- specifier: ^2.0.7
+ specifier: 2.0.7
version: 2.0.7
'@types/js-cookie':
- specifier: ^3.0.6
+ specifier: 3.0.6
version: 3.0.6
'@types/katex':
- specifier: ^0.16.8
+ specifier: 0.16.8
version: 0.16.8
'@types/node':
specifier: 22.19.1
version: 22.19.1
'@types/react':
- specifier: ^18.3.12
+ specifier: 18.3.12
version: 18.3.12
'@types/react-dom':
- specifier: ^18.3.1
+ specifier: 18.3.1
version: 18.3.1
'@vitejs/plugin-react':
- specifier: ^6.0.1
- version: 6.0.1(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))
+ specifier: 6.0.1
+ version: 6.0.1(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))
eslint:
- specifier: ^9.28.0
- version: 9.39.4(jiti@2.4.2)
+ specifier: 9.28.0
+ version: 9.28.0(jiti@2.4.2)
eslint-plugin-react:
- specifier: ^7.37.5
- version: 7.37.5(eslint@9.39.4(jiti@2.4.2))
+ specifier: 7.37.5
+ version: 7.37.5(eslint@9.28.0(jiti@2.4.2))
eslint-plugin-react-hooks:
- specifier: ^7.0.1
- version: 7.0.1(eslint@9.39.4(jiti@2.4.2))
+ specifier: 7.0.1
+ version: 7.0.1(eslint@9.28.0(jiti@2.4.2))
eslint-plugin-react-refresh:
- specifier: ^0.5.2
- version: 0.5.2(eslint@9.39.4(jiti@2.4.2))
+ specifier: 0.5.2
+ version: 0.5.2(eslint@9.28.0(jiti@2.4.2))
globals:
- specifier: ^15.13.0
+ specifier: 15.13.0
version: 15.13.0
jsdom:
- specifier: ^25.0.0
- version: 25.0.1
+ specifier: 25.0.0
+ version: 25.0.0
optics-ts:
- specifier: ^2.4.1
+ specifier: 2.4.1
version: 2.4.1
postcss:
- specifier: ^8.5.12
- version: 8.5.12
+ specifier: 8.5.14
+ version: 8.5.14
postcss-preset-mantine:
- specifier: ^1.18.0
- version: 1.18.0(postcss@8.5.12)
+ specifier: 1.18.0
+ version: 1.18.0(postcss@8.5.14)
postcss-simple-vars:
- specifier: ^7.0.1
- version: 7.0.1(postcss@8.5.12)
+ specifier: 7.0.1
+ version: 7.0.1(postcss@8.5.14)
prettier:
- specifier: ^3.8.1
+ specifier: 3.8.1
version: 3.8.1
typescript:
- specifier: ^5.9.3
+ specifier: 5.9.3
version: 5.9.3
typescript-eslint:
- specifier: ^8.57.1
- version: 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)
+ specifier: 8.57.1
+ version: 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
vite:
specifier: 8.0.5
- version: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
+ version: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
vitest:
- specifier: ^4.1.6
- version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@22.19.1)(happy-dom@20.8.9)(jsdom@25.0.1)(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))
+ specifier: 4.1.6
+ version: 4.1.6(@opentelemetry/api@1.9.0)(@types/node@22.19.1)(happy-dom@20.8.9)(jsdom@25.0.0)(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))
apps/server:
dependencies:
@@ -2237,14 +2237,30 @@ packages:
resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ '@eslint/config-array@0.20.1':
+ resolution: {integrity: sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@eslint/config-array@0.21.2':
resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@eslint/config-helpers@0.2.3':
+ resolution: {integrity: sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@eslint/config-helpers@0.4.2':
resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@eslint/core@0.14.0':
+ resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.15.2':
+ resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@eslint/core@0.17.0':
resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2253,6 +2269,10 @@ packages:
resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@eslint/js@9.28.0':
+ resolution: {integrity: sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@eslint/js@9.39.4':
resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2261,6 +2281,10 @@ packages:
resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@eslint/plugin-kit@0.3.5':
+ resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@eslint/plugin-kit@0.4.1':
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -4463,12 +4487,12 @@ packages:
resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
engines: {node: '>=18'}
- '@testing-library/jest-dom@6.9.1':
- resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==}
+ '@testing-library/jest-dom@6.6.0':
+ resolution: {integrity: sha512-Y76dmd7C85xekWqylJqRmO6lr83cdVprTs0muSvkXr6M73auYK5OvZMc3tKe1F7wMFdzfeBCwVbkoGrRKWb+fg==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
- '@testing-library/react@16.3.2':
- resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==}
+ '@testing-library/react@16.1.0':
+ resolution: {integrity: sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==}
engines: {node: '>=18'}
peerDependencies:
'@testing-library/dom': ^10.0.0
@@ -5540,10 +5564,6 @@ packages:
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
engines: {node: '>= 0.4'}
- array-buffer-byte-length@1.0.1:
- resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
- engines: {node: '>= 0.4'}
-
array-buffer-byte-length@1.0.2:
resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
engines: {node: '>= 0.4'}
@@ -5571,10 +5591,6 @@ packages:
resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
engines: {node: '>= 0.4'}
- arraybuffer.prototype.slice@1.0.3:
- resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
- engines: {node: '>= 0.4'}
-
arraybuffer.prototype.slice@1.0.4:
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
engines: {node: '>= 0.4'}
@@ -5787,10 +5803,6 @@ packages:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
- call-bind@1.0.7:
- resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
- engines: {node: '>= 0.4'}
-
call-bind@1.0.8:
resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
engines: {node: '>= 0.4'}
@@ -5825,6 +5837,10 @@ packages:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
+ chalk@3.0.0:
+ resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+ engines: {node: '>=8'}
+
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
@@ -6135,9 +6151,6 @@ packages:
resolution: {integrity: sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==}
engines: {node: '>=18'}
- csstype@3.1.3:
- resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
-
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -6301,26 +6314,14 @@ packages:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
- data-view-buffer@1.0.1:
- resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
- engines: {node: '>= 0.4'}
-
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
- data-view-byte-length@1.0.1:
- resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==}
- engines: {node: '>= 0.4'}
-
data-view-byte-length@1.0.2:
resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
engines: {node: '>= 0.4'}
- data-view-byte-offset@1.0.0:
- resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
- engines: {node: '>= 0.4'}
-
data-view-byte-offset@1.0.1:
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
engines: {node: '>= 0.4'}
@@ -6606,10 +6607,6 @@ packages:
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
- es-abstract@1.23.5:
- resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==}
- engines: {node: '>= 0.4'}
-
es-abstract@1.24.1:
resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==}
engines: {node: '>= 0.4'}
@@ -6626,9 +6623,6 @@ packages:
resolution: {integrity: sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==}
engines: {node: '>= 0.4'}
- es-module-lexer@2.0.0:
- resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
-
es-module-lexer@2.1.0:
resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==}
@@ -6727,6 +6721,16 @@ packages:
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+ eslint@9.28.0:
+ resolution: {integrity: sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
eslint@9.39.4:
resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -6954,9 +6958,6 @@ packages:
debug:
optional: true
- for-each@0.3.3:
- resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
-
for-each@0.3.5:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
@@ -7016,10 +7017,6 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- function.prototype.name@1.1.6:
- resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
- engines: {node: '>= 0.4'}
-
function.prototype.name@1.1.8:
resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
engines: {node: '>= 0.4'}
@@ -7059,10 +7056,6 @@ packages:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
- get-symbol-description@1.0.2:
- resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
- engines: {node: '>= 0.4'}
-
get-symbol-description@1.1.0:
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
engines: {node: '>= 0.4'}
@@ -7137,10 +7130,6 @@ packages:
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
- has-proto@1.0.3:
- resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
- engines: {node: '>= 0.4'}
-
has-proto@1.2.0:
resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
engines: {node: '>= 0.4'}
@@ -7292,10 +7281,6 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- internal-slot@1.0.7:
- resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
- engines: {node: '>= 0.4'}
-
internal-slot@1.1.0:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
@@ -7326,10 +7311,6 @@ packages:
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
engines: {node: '>= 10'}
- is-array-buffer@3.0.4:
- resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
- engines: {node: '>= 0.4'}
-
is-array-buffer@3.0.5:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
@@ -7349,10 +7330,6 @@ packages:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
- is-boolean-object@1.2.0:
- resolution: {integrity: sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw==}
- engines: {node: '>= 0.4'}
-
is-boolean-object@1.2.2:
resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
engines: {node: '>= 0.4'}
@@ -7364,18 +7341,10 @@ packages:
is-core-module@2.13.1:
resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
- is-data-view@1.0.1:
- resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
- engines: {node: '>= 0.4'}
-
is-data-view@1.0.2:
resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
engines: {node: '>= 0.4'}
- is-date-object@1.0.5:
- resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
- engines: {node: '>= 0.4'}
-
is-date-object@1.1.0:
resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
engines: {node: '>= 0.4'}
@@ -7421,10 +7390,6 @@ packages:
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
engines: {node: '>= 0.4'}
- is-number-object@1.1.0:
- resolution: {integrity: sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==}
- engines: {node: '>= 0.4'}
-
is-number-object@1.1.1:
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
engines: {node: '>= 0.4'}
@@ -7439,10 +7404,6 @@ packages:
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
- is-regex@1.2.0:
- resolution: {integrity: sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==}
- engines: {node: '>= 0.4'}
-
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -7451,10 +7412,6 @@ packages:
resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
engines: {node: '>= 0.4'}
- is-shared-array-buffer@1.0.3:
- resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
- engines: {node: '>= 0.4'}
-
is-shared-array-buffer@1.0.4:
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
engines: {node: '>= 0.4'}
@@ -7463,26 +7420,14 @@ packages:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
- is-string@1.1.0:
- resolution: {integrity: sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==}
- engines: {node: '>= 0.4'}
-
is-string@1.1.1:
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
engines: {node: '>= 0.4'}
- is-symbol@1.1.0:
- resolution: {integrity: sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==}
- engines: {node: '>= 0.4'}
-
is-symbol@1.1.1:
resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
engines: {node: '>= 0.4'}
- is-typed-array@1.1.13:
- resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
- engines: {node: '>= 0.4'}
-
is-typed-array@1.1.15:
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
engines: {node: '>= 0.4'}
@@ -7499,9 +7444,6 @@ packages:
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
engines: {node: '>= 0.4'}
- is-weakref@1.0.2:
- resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
-
is-weakref@1.1.1:
resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
engines: {node: '>= 0.4'}
@@ -7785,8 +7727,8 @@ packages:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
- jsdom@25.0.1:
- resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==}
+ jsdom@25.0.0:
+ resolution: {integrity: sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@@ -8555,10 +8497,6 @@ packages:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
- object.assign@4.1.5:
- resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
- engines: {node: '>= 0.4'}
-
object.assign@4.1.7:
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
engines: {node: '>= 0.4'}
@@ -8948,8 +8886,8 @@ packages:
peerDependencies:
postcss: ^8.2.1
- postcss@8.5.12:
- resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==}
+ postcss@8.5.14:
+ resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==}
engines: {node: ^10 || ^12 || >=14}
postgres-array@2.0.0:
@@ -9095,6 +9033,9 @@ packages:
prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
+ psl@1.15.0:
+ resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
+
pump@3.0.3:
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
@@ -9124,6 +9065,9 @@ packages:
query-selector-shadow-dom@1.0.1:
resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==}
+ querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+
quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
@@ -9324,10 +9268,6 @@ packages:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'}
- reflect.getprototypeof@1.0.7:
- resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==}
- engines: {node: '>= 0.4'}
-
regenerate-unicode-properties@10.1.1:
resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==}
engines: {node: '>=4'}
@@ -9338,10 +9278,6 @@ packages:
regenerator-transform@0.15.2:
resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==}
- regexp.prototype.flags@1.5.3:
- resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==}
- engines: {node: '>= 0.4'}
-
regexp.prototype.flags@1.5.4:
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
engines: {node: '>= 0.4'}
@@ -9365,6 +9301,9 @@ packages:
require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
resolve-cwd@3.0.0:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
@@ -9446,10 +9385,6 @@ packages:
rxjs@7.8.2:
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
- safe-array-concat@1.1.2:
- resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
- engines: {node: '>=0.4'}
-
safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
@@ -9464,10 +9399,6 @@ packages:
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
engines: {node: '>= 0.4'}
- safe-regex-test@1.0.3:
- resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
- engines: {node: '>= 0.4'}
-
safe-regex-test@1.1.0:
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
engines: {node: '>= 0.4'}
@@ -9710,13 +9641,6 @@ packages:
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
engines: {node: '>= 0.4'}
- string.prototype.trim@1.2.9:
- resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
- engines: {node: '>= 0.4'}
-
- string.prototype.trimend@1.0.8:
- resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
-
string.prototype.trimend@1.0.9:
resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
engines: {node: '>= 0.4'}
@@ -9920,6 +9844,10 @@ packages:
resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==}
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'}
@@ -10046,26 +9974,14 @@ packages:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'}
- typed-array-buffer@1.0.2:
- resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
- engines: {node: '>= 0.4'}
-
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
- typed-array-byte-length@1.0.1:
- resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
- engines: {node: '>= 0.4'}
-
typed-array-byte-length@1.0.3:
resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
engines: {node: '>= 0.4'}
- typed-array-byte-offset@1.0.3:
- resolution: {integrity: sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==}
- engines: {node: '>= 0.4'}
-
typed-array-byte-offset@1.0.4:
resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
engines: {node: '>= 0.4'}
@@ -10118,9 +10034,6 @@ packages:
resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==}
engines: {node: '>=18'}
- unbox-primitive@1.0.2:
- resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
-
unbox-primitive@1.1.0:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
@@ -10154,6 +10067,10 @@ packages:
resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
engines: {node: '>=4'}
+ 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'}
@@ -10174,6 +10091,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+
use-callback-ref@1.3.3:
resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
engines: {node: '>=10'}
@@ -10445,18 +10365,10 @@ packages:
when-exit@2.1.5:
resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==}
- which-boxed-primitive@1.1.0:
- resolution: {integrity: sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==}
- engines: {node: '>= 0.4'}
-
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
- which-builtin-type@1.2.0:
- resolution: {integrity: sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==}
- engines: {node: '>= 0.4'}
-
which-builtin-type@1.2.1:
resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
engines: {node: '>= 0.4'}
@@ -10468,10 +10380,6 @@ packages:
which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
- which-typed-array@1.1.16:
- resolution: {integrity: sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==}
- engines: {node: '>= 0.4'}
-
which-typed-array@1.1.20:
resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==}
engines: {node: '>= 0.4'}
@@ -12430,6 +12338,11 @@ snapshots:
'@esbuild/win32-x64@0.28.0':
optional: true
+ '@eslint-community/eslint-utils@4.9.1(eslint@9.28.0(jiti@2.4.2))':
+ dependencies:
+ eslint: 9.28.0(jiti@2.4.2)
+ eslint-visitor-keys: 3.4.3
+
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.4.2))':
dependencies:
eslint: 9.39.4(jiti@2.4.2)
@@ -12437,6 +12350,14 @@ snapshots:
'@eslint-community/regexpp@4.12.2': {}
+ '@eslint/config-array@0.20.1':
+ dependencies:
+ '@eslint/object-schema': 2.1.7
+ debug: 4.4.3
+ minimatch: 3.1.5
+ transitivePeerDependencies:
+ - supports-color
+
'@eslint/config-array@0.21.2':
dependencies:
'@eslint/object-schema': 2.1.7
@@ -12445,10 +12366,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@eslint/config-helpers@0.2.3': {}
+
'@eslint/config-helpers@0.4.2':
dependencies:
'@eslint/core': 0.17.0
+ '@eslint/core@0.14.0':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/core@0.15.2':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
'@eslint/core@0.17.0':
dependencies:
'@types/json-schema': 7.0.15
@@ -12467,10 +12398,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@eslint/js@9.28.0': {}
+
'@eslint/js@9.39.4': {}
'@eslint/object-schema@2.1.7': {}
+ '@eslint/plugin-kit@0.3.5':
+ dependencies:
+ '@eslint/core': 0.15.2
+ levn: 0.4.1
+
'@eslint/plugin-kit@0.4.1':
dependencies:
'@eslint/core': 0.17.0
@@ -13065,7 +13003,7 @@ snapshots:
'@jridgewell/gen-mapping@0.3.13':
dependencies:
- '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/remapping@2.3.5':
@@ -14985,10 +14923,10 @@ snapshots:
'@tabler/icons@3.40.0': {}
- '@tanstack/eslint-plugin-query@5.94.4(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)':
+ '@tanstack/eslint-plugin-query@5.94.4(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/utils': 8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)
- eslint: 9.39.4(jiti@2.4.2)
+ '@typescript-eslint/utils': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ eslint: 9.28.0(jiti@2.4.2)
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
@@ -15020,16 +14958,17 @@ snapshots:
picocolors: 1.1.1
pretty-format: 27.5.1
- '@testing-library/jest-dom@6.9.1':
+ '@testing-library/jest-dom@6.6.0':
dependencies:
'@adobe/css-tools': 4.4.3
aria-query: 5.3.2
+ chalk: 3.0.0
css.escape: 1.5.1
dom-accessibility-api: 0.6.3
- picocolors: 1.1.1
+ lodash: 4.18.1
redent: 3.0.0
- '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@testing-library/react@16.1.0(@testing-library/dom@10.4.1)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@babel/runtime': 7.29.2
'@testing-library/dom': 10.4.1
@@ -15517,11 +15456,11 @@ snapshots:
'@types/eslint-scope@3.7.7':
dependencies:
'@types/eslint': 8.56.10
- '@types/estree': 1.0.8
+ '@types/estree': 1.0.9
'@types/eslint@8.56.10':
dependencies:
- '@types/estree': 1.0.8
+ '@types/estree': 1.0.9
'@types/json-schema': 7.0.15
'@types/estree@1.0.8': {}
@@ -15686,7 +15625,7 @@ snapshots:
'@types/react@18.3.12':
dependencies:
'@types/prop-types': 15.7.11
- csstype: 3.1.3
+ csstype: 3.2.3
'@types/send@0.17.4':
dependencies:
@@ -15747,6 +15686,22 @@ snapshots:
dependencies:
'@types/node': 25.5.0
+ '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.2
+ '@typescript-eslint/parser': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ '@typescript-eslint/scope-manager': 8.57.1
+ '@typescript-eslint/type-utils': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.57.1
+ eslint: 9.28.0(jiti@2.4.2)
+ ignore: 7.0.5
+ natural-compare: 1.4.0
+ ts-api-utils: 2.5.0(typescript@5.9.3)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3))(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
@@ -15763,6 +15718,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/parser@8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.57.1
+ '@typescript-eslint/types': 8.57.1
+ '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.57.1
+ debug: 4.4.3
+ eslint: 9.28.0(jiti@2.4.2)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.57.1
@@ -15793,6 +15760,18 @@ snapshots:
dependencies:
typescript: 5.9.3
+ '@typescript-eslint/type-utils@8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)':
+ dependencies:
+ '@typescript-eslint/types': 8.57.1
+ '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ debug: 4.4.3
+ eslint: 9.28.0(jiti@2.4.2)
+ ts-api-utils: 2.5.0(typescript@5.9.3)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/type-utils@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.57.1
@@ -15822,6 +15801,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/utils@8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.28.0(jiti@2.4.2))
+ '@typescript-eslint/scope-manager': 8.57.1
+ '@typescript-eslint/types': 8.57.1
+ '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3)
+ eslint: 9.28.0(jiti@2.4.2)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/utils@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2))
@@ -15922,10 +15912,10 @@ snapshots:
'@vercel/oidc@3.1.0': {}
- '@vitejs/plugin-react@6.0.1(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))':
+ '@vitejs/plugin-react@6.0.1(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-rc.7
- vite: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
+ vite: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
'@vitest/expect@4.1.6':
dependencies:
@@ -15936,13 +15926,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
- '@vitest/mocker@4.1.6(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))':
+ '@vitest/mocker@4.1.6(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))':
dependencies:
'@vitest/spy': 4.1.6
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
- vite: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
+ vite: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
'@vitest/pretty-format@4.1.6':
dependencies:
@@ -16187,11 +16177,6 @@ snapshots:
aria-query@5.3.2: {}
- array-buffer-byte-length@1.0.1:
- dependencies:
- call-bind: 1.0.7
- is-array-buffer: 3.0.4
-
array-buffer-byte-length@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -16199,57 +16184,46 @@ snapshots:
array-includes@3.1.8:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
es-object-atoms: 1.1.1
get-intrinsic: 1.3.0
- is-string: 1.1.0
+ is-string: 1.1.1
array-timsort@1.0.3: {}
array.prototype.findlast@1.2.5:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
es-shim-unscopables: 1.0.2
array.prototype.flat@1.3.2:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
es-shim-unscopables: 1.0.2
array.prototype.flatmap@1.3.3:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
es-shim-unscopables: 1.0.2
array.prototype.tosorted@1.1.4:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
es-errors: 1.3.0
es-shim-unscopables: 1.0.2
- arraybuffer.prototype.slice@1.0.3:
- dependencies:
- array-buffer-byte-length: 1.0.1
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.5
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
- is-array-buffer: 3.0.4
- is-shared-array-buffer: 1.0.3
-
arraybuffer.prototype.slice@1.0.4:
dependencies:
array-buffer-byte-length: 1.0.2
@@ -16531,14 +16505,6 @@ snapshots:
es-errors: 1.3.0
function-bind: 1.1.2
- call-bind@1.0.7:
- dependencies:
- es-define-property: 1.0.1
- es-errors: 1.3.0
- function-bind: 1.1.2
- get-intrinsic: 1.3.0
- set-function-length: 1.2.2
-
call-bind@1.0.8:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -16565,6 +16531,11 @@ snapshots:
chai@6.2.2: {}
+ chalk@3.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
@@ -16890,8 +16861,6 @@ snapshots:
'@asamuzakjp/css-color': 2.8.3
rrweb-cssom: 0.8.0
- csstype@3.1.3: {}
-
csstype@3.2.3: {}
cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1):
@@ -17083,36 +17052,18 @@ snapshots:
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
- data-view-buffer@1.0.1:
- dependencies:
- call-bind: 1.0.7
- es-errors: 1.3.0
- is-data-view: 1.0.1
-
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
is-data-view: 1.0.2
- data-view-byte-length@1.0.1:
- dependencies:
- call-bind: 1.0.7
- es-errors: 1.3.0
- is-data-view: 1.0.1
-
data-view-byte-length@1.0.2:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
is-data-view: 1.0.2
- data-view-byte-offset@1.0.0:
- dependencies:
- call-bind: 1.0.7
- es-errors: 1.3.0
- is-data-view: 1.0.1
-
data-view-byte-offset@1.0.1:
dependencies:
call-bound: 1.0.4
@@ -17230,7 +17181,7 @@ snapshots:
dom-helpers@5.2.1:
dependencies:
'@babel/runtime': 7.29.2
- csstype: 3.1.3
+ csstype: 3.2.3
dom-serializer@2.0.0:
dependencies:
@@ -17368,55 +17319,6 @@ snapshots:
dependencies:
is-arrayish: 0.2.1
- es-abstract@1.23.5:
- dependencies:
- array-buffer-byte-length: 1.0.1
- arraybuffer.prototype.slice: 1.0.3
- available-typed-arrays: 1.0.7
- call-bind: 1.0.7
- data-view-buffer: 1.0.1
- data-view-byte-length: 1.0.1
- data-view-byte-offset: 1.0.0
- es-define-property: 1.0.1
- es-errors: 1.3.0
- es-object-atoms: 1.1.1
- es-set-tostringtag: 2.1.0
- es-to-primitive: 1.3.0
- function.prototype.name: 1.1.6
- get-intrinsic: 1.3.0
- get-symbol-description: 1.0.2
- globalthis: 1.0.4
- gopd: 1.2.0
- has-property-descriptors: 1.0.2
- has-proto: 1.0.3
- has-symbols: 1.1.0
- hasown: 2.0.2
- internal-slot: 1.0.7
- is-array-buffer: 3.0.4
- is-callable: 1.2.7
- is-data-view: 1.0.1
- is-negative-zero: 2.0.3
- is-regex: 1.2.0
- is-shared-array-buffer: 1.0.3
- is-string: 1.1.0
- is-typed-array: 1.1.13
- is-weakref: 1.0.2
- object-inspect: 1.13.3
- object-keys: 1.1.1
- object.assign: 4.1.5
- regexp.prototype.flags: 1.5.3
- safe-array-concat: 1.1.2
- safe-regex-test: 1.0.3
- string.prototype.trim: 1.2.9
- string.prototype.trimend: 1.0.8
- string.prototype.trimstart: 1.0.8
- typed-array-buffer: 1.0.2
- typed-array-byte-length: 1.0.1
- typed-array-byte-offset: 1.0.3
- typed-array-length: 1.0.7
- unbox-primitive: 1.0.2
- which-typed-array: 1.1.16
-
es-abstract@1.24.1:
dependencies:
array-buffer-byte-length: 1.0.2
@@ -17498,8 +17400,6 @@ snapshots:
math-intrinsics: 1.1.0
safe-array-concat: 1.1.3
- es-module-lexer@2.0.0: {}
-
es-module-lexer@2.1.0: {}
es-object-atoms@1.1.1:
@@ -17520,8 +17420,8 @@ snapshots:
es-to-primitive@1.3.0:
dependencies:
is-callable: 1.2.7
- is-date-object: 1.0.5
- is-symbol: 1.1.0
+ is-date-object: 1.1.0
+ is-symbol: 1.1.1
es6-promise-pool@2.5.0: {}
@@ -17599,22 +17499,22 @@ snapshots:
dependencies:
eslint: 9.39.4(jiti@2.4.2)
- eslint-plugin-react-hooks@7.0.1(eslint@9.39.4(jiti@2.4.2)):
+ eslint-plugin-react-hooks@7.0.1(eslint@9.28.0(jiti@2.4.2)):
dependencies:
'@babel/core': 7.28.5
'@babel/parser': 7.28.5
- eslint: 9.39.4(jiti@2.4.2)
+ eslint: 9.28.0(jiti@2.4.2)
hermes-parser: 0.25.1
zod: 4.3.6
zod-validation-error: 4.0.2(zod@4.3.6)
transitivePeerDependencies:
- supports-color
- eslint-plugin-react-refresh@0.5.2(eslint@9.39.4(jiti@2.4.2)):
+ eslint-plugin-react-refresh@0.5.2(eslint@9.28.0(jiti@2.4.2)):
dependencies:
- eslint: 9.39.4(jiti@2.4.2)
+ eslint: 9.28.0(jiti@2.4.2)
- eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.4.2)):
+ eslint-plugin-react@7.37.5(eslint@9.28.0(jiti@2.4.2)):
dependencies:
array-includes: 3.1.8
array.prototype.findlast: 1.2.5
@@ -17622,7 +17522,7 @@ snapshots:
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.3.1
- eslint: 9.39.4(jiti@2.4.2)
+ eslint: 9.28.0(jiti@2.4.2)
estraverse: 5.3.0
hasown: 2.0.2
jsx-ast-utils: 3.3.5
@@ -17652,6 +17552,48 @@ snapshots:
eslint-visitor-keys@5.0.1: {}
+ eslint@9.28.0(jiti@2.4.2):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.28.0(jiti@2.4.2))
+ '@eslint-community/regexpp': 4.12.2
+ '@eslint/config-array': 0.20.1
+ '@eslint/config-helpers': 0.2.3
+ '@eslint/core': 0.14.0
+ '@eslint/eslintrc': 3.3.5
+ '@eslint/js': 9.28.0
+ '@eslint/plugin-kit': 0.3.5
+ '@humanfs/node': 0.16.6
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.4.3
+ '@types/estree': 1.0.9
+ '@types/json-schema': 7.0.15
+ ajv: 6.14.0
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.3
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
+ esquery: 1.7.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.1
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.5
+ natural-compare: 1.4.0
+ optionator: 0.9.3
+ optionalDependencies:
+ jiti: 2.4.2
+ transitivePeerDependencies:
+ - supports-color
+
eslint@9.39.4(jiti@2.4.2):
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.4.2))
@@ -17955,10 +17897,6 @@ snapshots:
follow-redirects@1.16.0: {}
- for-each@0.3.3:
- dependencies:
- is-callable: 1.2.7
-
for-each@0.3.5:
dependencies:
is-callable: 1.2.7
@@ -18027,13 +17965,6 @@ snapshots:
function-bind@1.1.2: {}
- function.prototype.name@1.1.6:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.5
- functions-have-names: 1.2.3
-
function.prototype.name@1.1.8:
dependencies:
call-bind: 1.0.8
@@ -18075,12 +18006,6 @@ snapshots:
get-stream@6.0.1: {}
- get-symbol-description@1.0.2:
- dependencies:
- call-bind: 1.0.7
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
-
get-symbol-description@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -18157,8 +18082,6 @@ snapshots:
dependencies:
es-define-property: 1.0.1
- has-proto@1.0.3: {}
-
has-proto@1.2.0:
dependencies:
dunder-proto: 1.0.1
@@ -18306,12 +18229,6 @@ snapshots:
inherits@2.0.4: {}
- internal-slot@1.0.7:
- dependencies:
- es-errors: 1.3.0
- hasown: 2.0.2
- side-channel: 1.1.0
-
internal-slot@1.1.0:
dependencies:
es-errors: 1.3.0
@@ -18346,11 +18263,6 @@ snapshots:
ipaddr.js@2.2.0: {}
- is-array-buffer@3.0.4:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
-
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
@@ -18371,11 +18283,6 @@ snapshots:
dependencies:
binary-extensions: 2.3.0
- is-boolean-object@1.2.0:
- dependencies:
- call-bind: 1.0.7
- has-tostringtag: 1.0.2
-
is-boolean-object@1.2.2:
dependencies:
call-bound: 1.0.4
@@ -18387,20 +18294,12 @@ snapshots:
dependencies:
hasown: 2.0.2
- is-data-view@1.0.1:
- dependencies:
- is-typed-array: 1.1.13
-
is-data-view@1.0.2:
dependencies:
call-bound: 1.0.4
get-intrinsic: 1.3.0
is-typed-array: 1.1.15
- is-date-object@1.0.5:
- dependencies:
- has-tostringtag: 1.0.2
-
is-date-object@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -18432,11 +18331,6 @@ snapshots:
is-negative-zero@2.0.3: {}
- is-number-object@1.1.0:
- dependencies:
- call-bind: 1.0.7
- has-tostringtag: 1.0.2
-
is-number-object@1.1.1:
dependencies:
call-bound: 1.0.4
@@ -18448,13 +18342,6 @@ snapshots:
is-promise@4.0.0: {}
- is-regex@1.2.0:
- dependencies:
- call-bind: 1.0.7
- gopd: 1.2.0
- has-tostringtag: 1.0.2
- hasown: 2.0.2
-
is-regex@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -18464,42 +18351,23 @@ snapshots:
is-set@2.0.3: {}
- is-shared-array-buffer@1.0.3:
- dependencies:
- call-bind: 1.0.7
-
is-shared-array-buffer@1.0.4:
dependencies:
call-bound: 1.0.4
is-stream@2.0.1: {}
- is-string@1.1.0:
- dependencies:
- call-bind: 1.0.7
- has-tostringtag: 1.0.2
-
is-string@1.1.1:
dependencies:
call-bound: 1.0.4
has-tostringtag: 1.0.2
- is-symbol@1.1.0:
- dependencies:
- call-bind: 1.0.7
- has-symbols: 1.1.0
- safe-regex-test: 1.0.3
-
is-symbol@1.1.1:
dependencies:
call-bound: 1.0.4
has-symbols: 1.1.0
safe-regex-test: 1.1.0
- is-typed-array@1.1.13:
- dependencies:
- which-typed-array: 1.1.16
-
is-typed-array@1.1.15:
dependencies:
which-typed-array: 1.1.20
@@ -18510,10 +18378,6 @@ snapshots:
is-weakmap@2.0.2: {}
- is-weakref@1.0.2:
- dependencies:
- call-bind: 1.0.7
-
is-weakref@1.1.1:
dependencies:
call-bound: 1.0.4
@@ -18990,7 +18854,7 @@ snapshots:
dependencies:
argparse: 2.0.1
- jsdom@25.0.1:
+ jsdom@25.0.0:
dependencies:
cssstyle: 4.2.1
data-urls: 5.0.0
@@ -19005,7 +18869,7 @@ snapshots:
rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
- tough-cookie: 5.1.2
+ tough-cookie: 4.1.4
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
@@ -19098,7 +18962,7 @@ snapshots:
dependencies:
array-includes: 3.1.8
array.prototype.flat: 1.3.2
- object.assign: 4.1.5
+ object.assign: 4.1.7
object.values: 1.2.1
jszip@3.10.1:
@@ -19729,13 +19593,6 @@ snapshots:
object-keys@1.1.1: {}
- object.assign@4.1.5:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- has-symbols: 1.1.0
- object-keys: 1.1.1
-
object.assign@4.1.7:
dependencies:
call-bind: 1.0.8
@@ -19754,9 +19611,9 @@ snapshots:
object.fromentries@2.0.8:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
es-object-atoms: 1.1.1
object.values@1.2.1:
@@ -20134,40 +19991,40 @@ snapshots:
possible-typed-array-names@1.0.0: {}
- postcss-js@4.0.1(postcss@8.5.12):
+ postcss-js@4.0.1(postcss@8.5.14):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.5.12
+ postcss: 8.5.14
- postcss-mixins@12.1.2(postcss@8.5.12):
+ postcss-mixins@12.1.2(postcss@8.5.14):
dependencies:
- postcss: 8.5.12
- postcss-js: 4.0.1(postcss@8.5.12)
- postcss-simple-vars: 7.0.1(postcss@8.5.12)
- sugarss: 5.0.1(postcss@8.5.12)
+ postcss: 8.5.14
+ postcss-js: 4.0.1(postcss@8.5.14)
+ postcss-simple-vars: 7.0.1(postcss@8.5.14)
+ sugarss: 5.0.1(postcss@8.5.14)
tinyglobby: 0.2.15
- postcss-nested@7.0.2(postcss@8.5.12):
+ postcss-nested@7.0.2(postcss@8.5.14):
dependencies:
- postcss: 8.5.12
+ postcss: 8.5.14
postcss-selector-parser: 7.1.1
- postcss-preset-mantine@1.18.0(postcss@8.5.12):
+ postcss-preset-mantine@1.18.0(postcss@8.5.14):
dependencies:
- postcss: 8.5.12
- postcss-mixins: 12.1.2(postcss@8.5.12)
- postcss-nested: 7.0.2(postcss@8.5.12)
+ postcss: 8.5.14
+ postcss-mixins: 12.1.2(postcss@8.5.14)
+ postcss-nested: 7.0.2(postcss@8.5.14)
postcss-selector-parser@7.1.1:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
- postcss-simple-vars@7.0.1(postcss@8.5.12):
+ postcss-simple-vars@7.0.1(postcss@8.5.14):
dependencies:
- postcss: 8.5.12
+ postcss: 8.5.14
- postcss@8.5.12:
+ postcss@8.5.14:
dependencies:
nanoid: 3.3.8
picocolors: 1.1.1
@@ -20382,6 +20239,10 @@ snapshots:
prr@1.0.1:
optional: true
+ psl@1.15.0:
+ dependencies:
+ punycode: 2.3.1
+
pump@3.0.3:
dependencies:
end-of-stream: 1.4.4
@@ -20407,6 +20268,8 @@ snapshots:
query-selector-shadow-dom@1.0.1: {}
+ querystringify@2.2.0: {}
+
quick-format-unescaped@4.0.4: {}
radix-ui@1.4.3(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
@@ -20677,16 +20540,6 @@ snapshots:
get-proto: 1.0.1
which-builtin-type: 1.2.1
- reflect.getprototypeof@1.0.7:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.5
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
- gopd: 1.2.0
- which-builtin-type: 1.2.0
-
regenerate-unicode-properties@10.1.1:
dependencies:
regenerate: 1.4.2
@@ -20697,13 +20550,6 @@ snapshots:
dependencies:
'@babel/runtime': 7.29.2
- regexp.prototype.flags@1.5.3:
- dependencies:
- call-bind: 1.0.8
- define-properties: 1.2.1
- es-errors: 1.3.0
- set-function-name: 2.0.2
-
regexp.prototype.flags@1.5.4:
dependencies:
call-bind: 1.0.8
@@ -20732,6 +20578,8 @@ snapshots:
require-main-filename@2.0.0: {}
+ requires-port@1.0.0: {}
+
resolve-cwd@3.0.0:
dependencies:
resolve-from: 5.0.0
@@ -20832,13 +20680,6 @@ snapshots:
dependencies:
tslib: 2.8.1
- safe-array-concat@1.1.2:
- dependencies:
- call-bind: 1.0.7
- get-intrinsic: 1.3.0
- has-symbols: 1.1.0
- isarray: 2.0.5
-
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.8
@@ -20856,12 +20697,6 @@ snapshots:
es-errors: 1.3.0
isarray: 2.0.5
- safe-regex-test@1.0.3:
- dependencies:
- call-bind: 1.0.7
- es-errors: 1.3.0
- is-regex: 1.2.0
-
safe-regex-test@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -21149,14 +20984,14 @@ snapshots:
gopd: 1.2.0
has-symbols: 1.1.0
internal-slot: 1.1.0
- regexp.prototype.flags: 1.5.3
+ regexp.prototype.flags: 1.5.4
set-function-name: 2.0.2
side-channel: 1.1.0
string.prototype.repeat@1.0.0:
dependencies:
define-properties: 1.2.1
- es-abstract: 1.23.5
+ es-abstract: 1.24.1
string.prototype.trim@1.2.10:
dependencies:
@@ -21168,19 +21003,6 @@ snapshots:
es-object-atoms: 1.1.1
has-property-descriptors: 1.0.2
- string.prototype.trim@1.2.9:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.5
- es-object-atoms: 1.1.1
-
- string.prototype.trimend@1.0.8:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-object-atoms: 1.1.1
-
string.prototype.trimend@1.0.9:
dependencies:
call-bind: 1.0.8
@@ -21190,7 +21012,7 @@ snapshots:
string.prototype.trimstart@1.0.8:
dependencies:
- call-bind: 1.0.7
+ call-bind: 1.0.8
define-properties: 1.2.1
es-object-atoms: 1.1.1
@@ -21239,9 +21061,9 @@ snapshots:
stylis@4.3.6: {}
- sugarss@5.0.1(postcss@8.5.12):
+ sugarss@5.0.1(postcss@8.5.14):
dependencies:
- postcss: 8.5.12
+ postcss: 8.5.14
superagent@10.3.0:
dependencies:
@@ -21371,6 +21193,13 @@ snapshots:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
+ tough-cookie@4.1.4:
+ dependencies:
+ psl: 1.15.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+
tough-cookie@5.1.2:
dependencies:
tldts: 6.1.72
@@ -21497,49 +21326,25 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
- typed-array-buffer@1.0.2:
- dependencies:
- call-bind: 1.0.7
- es-errors: 1.3.0
- is-typed-array: 1.1.13
-
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
is-typed-array: 1.1.15
- typed-array-byte-length@1.0.1:
- dependencies:
- call-bind: 1.0.7
- for-each: 0.3.3
- gopd: 1.2.0
- has-proto: 1.0.3
- is-typed-array: 1.1.13
-
typed-array-byte-length@1.0.3:
dependencies:
call-bind: 1.0.8
- for-each: 0.3.3
+ for-each: 0.3.5
gopd: 1.2.0
has-proto: 1.2.0
is-typed-array: 1.1.15
- typed-array-byte-offset@1.0.3:
- dependencies:
- available-typed-arrays: 1.0.7
- call-bind: 1.0.7
- for-each: 0.3.3
- gopd: 1.2.0
- has-proto: 1.0.3
- is-typed-array: 1.1.13
- reflect.getprototypeof: 1.0.7
-
typed-array-byte-offset@1.0.4:
dependencies:
available-typed-arrays: 1.0.7
call-bind: 1.0.8
- for-each: 0.3.3
+ for-each: 0.3.5
gopd: 1.2.0
has-proto: 1.2.0
is-typed-array: 1.1.15
@@ -21547,12 +21352,23 @@ snapshots:
typed-array-length@1.0.7:
dependencies:
- call-bind: 1.0.7
- for-each: 0.3.3
+ call-bind: 1.0.8
+ for-each: 0.3.5
gopd: 1.2.0
- is-typed-array: 1.1.13
+ is-typed-array: 1.1.15
possible-typed-array-names: 1.0.0
- reflect.getprototypeof: 1.0.7
+ reflect.getprototypeof: 1.0.10
+
+ typescript-eslint@8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.57.1(eslint@9.28.0(jiti@2.4.2))(typescript@5.9.3)
+ eslint: 9.28.0(jiti@2.4.2)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
typescript-eslint@8.57.1(eslint@9.39.4(jiti@2.4.2))(typescript@5.9.3):
dependencies:
@@ -21593,13 +21409,6 @@ snapshots:
uint8array-extras@1.5.0: {}
- unbox-primitive@1.0.2:
- dependencies:
- call-bind: 1.0.7
- has-bigints: 1.0.2
- has-symbols: 1.1.0
- which-boxed-primitive: 1.1.0
-
unbox-primitive@1.1.0:
dependencies:
call-bound: 1.0.4
@@ -21626,6 +21435,8 @@ snapshots:
unicode-property-aliases-ecmascript@2.1.0: {}
+ universalify@0.2.0: {}
+
universalify@2.0.1: {}
unpipe@1.0.0: {}
@@ -21664,6 +21475,11 @@ snapshots:
dependencies:
punycode: 2.3.1
+ url-parse@1.5.10:
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+
use-callback-ref@1.3.3(@types/react@18.3.12)(react@18.3.1):
dependencies:
react: 18.3.1
@@ -21724,11 +21540,11 @@ snapshots:
vary@1.1.2: {}
- vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3):
+ vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
- postcss: 8.5.12
+ postcss: 8.5.14
rolldown: 1.0.0-rc.12
tinyglobby: 0.2.15
optionalDependencies:
@@ -21737,15 +21553,15 @@ snapshots:
fsevents: 2.3.3
jiti: 2.4.2
less: 4.2.0
- sugarss: 5.0.1(postcss@8.5.12)
+ sugarss: 5.0.1(postcss@8.5.14)
terser: 5.39.0
tsx: 4.21.0
yaml: 2.8.3
- vitest@4.1.6(@opentelemetry/api@1.9.0)(@types/node@22.19.1)(happy-dom@20.8.9)(jsdom@25.0.1)(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)):
+ vitest@4.1.6(@opentelemetry/api@1.9.0)(@types/node@22.19.1)(happy-dom@20.8.9)(jsdom@25.0.0)(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)):
dependencies:
'@vitest/expect': 4.1.6
- '@vitest/mocker': 4.1.6(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))
+ '@vitest/mocker': 4.1.6(vite@8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3))
'@vitest/pretty-format': 4.1.6
'@vitest/runner': 4.1.6
'@vitest/snapshot': 4.1.6
@@ -21762,13 +21578,13 @@ snapshots:
tinyexec: 1.1.2
tinyglobby: 0.2.15
tinyrainbow: 3.1.0
- vite: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.12))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
+ vite: 8.0.5(@types/node@22.19.1)(esbuild@0.28.0)(jiti@2.4.2)(less@4.2.0)(sugarss@5.0.1(postcss@8.5.14))(terser@5.39.0)(tsx@4.21.0)(yaml@2.8.3)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@types/node': 22.19.1
happy-dom: 20.8.9
- jsdom: 25.0.1
+ jsdom: 25.0.0
transitivePeerDependencies:
- msw
@@ -21825,7 +21641,7 @@ snapshots:
webpack@5.106.0(@swc/core@1.5.25(@swc/helpers@0.5.5)):
dependencies:
'@types/eslint-scope': 3.7.7
- '@types/estree': 1.0.8
+ '@types/estree': 1.0.9
'@types/json-schema': 7.0.15
'@webassemblyjs/ast': 1.14.1
'@webassemblyjs/wasm-edit': 1.14.1
@@ -21835,7 +21651,7 @@ snapshots:
browserslist: 4.28.1
chrome-trace-event: 1.0.3
enhanced-resolve: 5.20.1
- es-module-lexer: 2.0.0
+ es-module-lexer: 2.1.0
eslint-scope: 5.1.1
events: 3.3.0
glob-to-regexp: 0.4.1
@@ -21878,14 +21694,6 @@ snapshots:
when-exit@2.1.5: {}
- which-boxed-primitive@1.1.0:
- dependencies:
- is-bigint: 1.1.0
- is-boolean-object: 1.2.0
- is-number-object: 1.1.0
- is-string: 1.1.0
- is-symbol: 1.1.0
-
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
@@ -21894,22 +21702,6 @@ snapshots:
is-string: 1.1.1
is-symbol: 1.1.1
- which-builtin-type@1.2.0:
- dependencies:
- call-bind: 1.0.7
- function.prototype.name: 1.1.6
- has-tostringtag: 1.0.2
- is-async-function: 2.0.0
- is-date-object: 1.0.5
- is-finalizationregistry: 1.1.0
- is-generator-function: 1.0.10
- is-regex: 1.2.0
- is-weakref: 1.0.2
- isarray: 2.0.5
- which-boxed-primitive: 1.1.0
- which-collection: 1.0.2
- which-typed-array: 1.1.16
-
which-builtin-type@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -21922,7 +21714,7 @@ snapshots:
is-regex: 1.2.1
is-weakref: 1.1.1
isarray: 2.0.5
- which-boxed-primitive: 1.1.0
+ which-boxed-primitive: 1.1.1
which-collection: 1.0.2
which-typed-array: 1.1.20
@@ -21935,14 +21727,6 @@ snapshots:
which-module@2.0.1: {}
- which-typed-array@1.1.16:
- dependencies:
- available-typed-arrays: 1.0.7
- call-bind: 1.0.7
- for-each: 0.3.3
- gopd: 1.2.0
- has-tostringtag: 1.0.2
-
which-typed-array@1.1.20:
dependencies:
available-typed-arrays: 1.0.7
From 299a9ca3c886f74ddddbed38578747e3ba463f81 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 14 May 2026 02:54:00 +0100
Subject: [PATCH 03/12] fix: bug fixes (#2201)
* fix(editor): hide transclusion borders and reset spacing in read-only mode
* feat(share): add full width toggle for shared pages
* feat(share): support resizing sidebar on shared pages
* fix: auto redirect if there is only one SSO provider.
- fix tighten sso redirect
- fix share tree margin
* sync
* package overrides
---
apps/client/src/ee/components/sso-login.tsx | 69 +-
apps/client/src/ee/security/sso.utils.ts | 13 +-
.../src/features/auth/hooks/use-auth.ts | 2 +-
.../transclusion-reference-view.tsx | 1 +
.../transclusion/transclusion-view.tsx | 1 +
.../transclusion/transclusion.module.css | 31 +-
.../features/share/atoms/shared-page-atom.ts | 7 +-
.../features/share/components/share-shell.tsx | 73 +-
.../share/components/share.module.css | 24 +
apps/client/src/lib/app-route.ts | 42 +-
apps/client/src/pages/share/shared-page.tsx | 8 +-
apps/server/package.json | 4 +-
apps/server/src/ee | 2 +-
package.json | 9 +-
pnpm-lock.yaml | 1232 ++++++-----------
15 files changed, 696 insertions(+), 822 deletions(-)
diff --git a/apps/client/src/ee/components/sso-login.tsx b/apps/client/src/ee/components/sso-login.tsx
index ff739dd35..3e84f8efc 100644
--- a/apps/client/src/ee/components/sso-login.tsx
+++ b/apps/client/src/ee/components/sso-login.tsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { useWorkspacePublicDataQuery } from "@/features/workspace/queries/workspace-query.ts";
import { Button, Divider, Stack } from "@mantine/core";
import { IconLock, IconServer } from "@tabler/icons-react";
@@ -7,15 +7,37 @@ import { buildSsoLoginUrl } from "@/ee/security/sso.utils.ts";
import { SSO_PROVIDER } from "@/ee/security/contants.ts";
import { GoogleIcon } from "@/components/icons/google-icon.tsx";
import { LdapLoginModal } from "@/ee/components/ldap-login-modal.tsx";
+import { getRedirectParam } from "@/lib/app-route.ts";
+import useCurrentUser from "@/features/user/hooks/use-current-user.ts";
+
+const SSO_AUTO_ATTEMPT_KEY = "docmost:ssoAutoAttempt";
+const SSO_AUTO_ATTEMPT_TTL_MS = 5 * 60_000;
+
+function recentAutoAttempt(): boolean {
+ try {
+ const raw = window.sessionStorage.getItem(SSO_AUTO_ATTEMPT_KEY);
+ if (!raw) return false;
+ const ts = Number(raw);
+ return Number.isFinite(ts) && Date.now() - ts < SSO_AUTO_ATTEMPT_TTL_MS;
+ } catch {
+ return false;
+ }
+}
+
+function markAutoAttempt(): void {
+ try {
+ window.sessionStorage.setItem(SSO_AUTO_ATTEMPT_KEY, String(Date.now()));
+ } catch {
+ /* sessionStorage unavailable (private mode, etc.) — best effort */
+ }
+}
export default function SsoLogin() {
const { data, isLoading } = useWorkspacePublicDataQuery();
+ const { data: currentUser } = useCurrentUser();
const [ldapModalOpened, setLdapModalOpened] = useState(false);
const [selectedLdapProvider, setSelectedLdapProvider] = useState(null);
-
- if (!data?.authProviders || data?.authProviders?.length === 0) {
- return null;
- }
+ const autoRedirectedRef = useRef(false);
const handleSsoLogin = (provider: IAuthProvider) => {
if (provider.type === SSO_PROVIDER.LDAP) {
@@ -28,10 +50,47 @@ export default function SsoLogin() {
providerId: provider.id,
type: provider.type,
workspaceId: data.id,
+ redirect: getRedirectParam() ?? undefined,
});
}
};
+ // Auto-redirect when SSO is enforced and there is exactly one non-LDAP
+ // provider. The user has no other option, so skip the extra click.
+ useEffect(() => {
+ if (autoRedirectedRef.current) return;
+ if (!data?.enforceSso) return;
+ if (!data.authProviders || data.authProviders.length !== 1) return;
+ const onlyProvider = data.authProviders[0];
+ if (onlyProvider.type === SSO_PROVIDER.LDAP) return;
+
+ // Already signed in: let useRedirectIfAuthenticated handle navigation
+ // instead of racing it through the IdP.
+ if (currentUser?.user) return;
+
+ // Explicit logout: don't immediately bounce them back to the IdP.
+ const params = new URLSearchParams(window.location.search);
+ if (params.has("logout")) return;
+
+ // Circuit-breaker: if we already auto-redirected within the TTL, the
+ // user came back (likely from an IdP failure). Show the page so they
+ // can read errors or pick a different account.
+ if (recentAutoAttempt()) return;
+
+ autoRedirectedRef.current = true;
+ markAutoAttempt();
+ window.location.href = buildSsoLoginUrl({
+ providerId: onlyProvider.id,
+ type: onlyProvider.type,
+ workspaceId: data.id,
+ redirect: getRedirectParam() ?? undefined,
+ });
+ }, [data, currentUser]);
+
+ if (!data?.authProviders || data?.authProviders?.length === 0) {
+ return null;
+ }
+
const getProviderIcon = (provider: IAuthProvider) => {
if (provider.type === SSO_PROVIDER.GOOGLE) {
return ;
diff --git a/apps/client/src/ee/security/sso.utils.ts b/apps/client/src/ee/security/sso.utils.ts
index 4a4665c16..bfeb7c062 100644
--- a/apps/client/src/ee/security/sso.utils.ts
+++ b/apps/client/src/ee/security/sso.utils.ts
@@ -18,14 +18,21 @@ export function buildSsoLoginUrl(opts: {
providerId: string;
type: SSO_PROVIDER;
workspaceId?: string;
+ redirect?: string;
}): string {
- const { providerId, type, workspaceId } = opts;
+ const { providerId, type, workspaceId, redirect } = opts;
const domain = getAppUrl();
+ const params = new URLSearchParams();
+ if (redirect) params.set("redirect", redirect);
+
if (type === SSO_PROVIDER.GOOGLE) {
- return `${getServerAppUrl()}/api/sso/${type}/login?workspaceId=${workspaceId}`;
+ if (workspaceId) params.set("workspaceId", workspaceId);
+ return `${getServerAppUrl()}/api/sso/${type}/login?${params.toString()}`;
}
- return `${domain}/api/sso/${type}/${providerId}/login`;
+ const query = params.toString();
+ const base = `${domain}/api/sso/${type}/${providerId}/login`;
+ return query ? `${base}?${query}` : base;
}
export function getGoogleSignupUrl(): string {
diff --git a/apps/client/src/features/auth/hooks/use-auth.ts b/apps/client/src/features/auth/hooks/use-auth.ts
index 411e04b41..970a85897 100644
--- a/apps/client/src/features/auth/hooks/use-auth.ts
+++ b/apps/client/src/features/auth/hooks/use-auth.ts
@@ -166,7 +166,7 @@ export default function useAuth() {
const handleLogout = async () => {
setCurrentUser(RESET);
await logout();
- window.location.replace(APP_ROUTE.AUTH.LOGIN);
+ window.location.replace(`${APP_ROUTE.AUTH.LOGIN}?logout=1`);
};
const handleForgotPassword = async (data: IForgotPassword) => {
diff --git a/apps/client/src/features/editor/components/transclusion/transclusion-reference-view.tsx b/apps/client/src/features/editor/components/transclusion/transclusion-reference-view.tsx
index 490e179b2..e50793149 100644
--- a/apps/client/src/features/editor/components/transclusion/transclusion-reference-view.tsx
+++ b/apps/client/src/features/editor/components/transclusion/transclusion-reference-view.tsx
@@ -35,6 +35,7 @@ export default function TransclusionReferenceView(props: NodeViewProps) {
return (
0 ? "true" : "false"}
contentEditable={false}
diff --git a/apps/client/src/features/editor/components/transclusion/transclusion-view.tsx b/apps/client/src/features/editor/components/transclusion/transclusion-view.tsx
index c27024472..82997f5d5 100644
--- a/apps/client/src/features/editor/components/transclusion/transclusion-view.tsx
+++ b/apps/client/src/features/editor/components/transclusion/transclusion-view.tsx
@@ -62,6 +62,7 @@ export default function TransclusionView(props: NodeViewProps) {
return (
0 ? "true" : "false"}
data-id={transclusionId ?? undefined}
>
diff --git a/apps/client/src/features/editor/components/transclusion/transclusion.module.css b/apps/client/src/features/editor/components/transclusion/transclusion.module.css
index 2fb5f7547..4d8d321a1 100644
--- a/apps/client/src/features/editor/components/transclusion/transclusion.module.css
+++ b/apps/client/src/features/editor/components/transclusion/transclusion.module.css
@@ -44,8 +44,29 @@
transition: border 0.3s;
}
-.transclusionWrap:hover,
-.transclusionWrap:focus-within {
+.transclusionWrap[data-editable="false"],
+.includeWrap[data-editable="false"] {
+ margin-left: 0;
+ margin-right: 0;
+ width: 100%;
+ padding: 0;
+}
+
+/* Cancel the wrapping .react-renderer's vertical spacing in read-only mode
+ so the synced block sits flush with surrounding paragraphs (whose own
+ margins already provide the right rhythm). */
+:global(.react-renderer.node-transclusionSource):has(
+ .transclusionWrap[data-editable="false"]
+ ),
+:global(.react-renderer.node-transclusionReference):has(
+ .includeWrap[data-editable="false"]
+ ) {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.transclusionWrap[data-editable="true"]:hover,
+.transclusionWrap[data-editable="true"]:focus-within {
border: 2px solid
light-dark(
var(--mantine-color-orange-2),
@@ -114,9 +135,9 @@
transition: border 0.3s;
}
-.includeWrap:hover,
-.includeWrap[data-focused="true"],
-.includeWrap[data-menu-open="true"] {
+.includeWrap[data-editable="true"]:hover,
+.includeWrap[data-editable="true"][data-focused="true"],
+.includeWrap[data-editable="true"][data-menu-open="true"] {
border: 2px solid
light-dark(
var(--mantine-color-orange-2),
diff --git a/apps/client/src/features/share/atoms/shared-page-atom.ts b/apps/client/src/features/share/atoms/shared-page-atom.ts
index 813f5e61b..bf8929942 100644
--- a/apps/client/src/features/share/atoms/shared-page-atom.ts
+++ b/apps/client/src/features/share/atoms/shared-page-atom.ts
@@ -1,6 +1,11 @@
import { atom } from "jotai";
+import { atomWithStorage } from "jotai/utils";
import { ISharedPageTree } from "@/features/share/types/share.types";
import { SharedPageTreeNode } from "@/features/share/utils";
export const sharedPageTreeAtom = atom(null);
-export const sharedTreeDataAtom = atom(null);
\ No newline at end of file
+export const sharedTreeDataAtom = atom(null);
+export const sharedPageFullWidthAtom = atomWithStorage(
+ "sharedPageFullWidth",
+ false,
+);
\ No newline at end of file
diff --git a/apps/client/src/features/share/components/share-shell.tsx b/apps/client/src/features/share/components/share-shell.tsx
index bba226fe7..1bd559258 100644
--- a/apps/client/src/features/share/components/share-shell.tsx
+++ b/apps/client/src/features/share/components/share-shell.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo } from "react";
+import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
ActionIcon,
AppShell,
@@ -14,11 +14,16 @@ import { readOnlyEditorAtom } from "@/features/editor/atoms/editor-atoms.ts";
import { ThemeToggle } from "@/components/theme-toggle.tsx";
import { useAtomValue, useSetAtom } from "jotai";
import { useAtom } from "jotai";
-import { sharedPageTreeAtom, sharedTreeDataAtom } from "@/features/share/atoms/shared-page-atom";
+import {
+ sharedPageFullWidthAtom,
+ sharedPageTreeAtom,
+ sharedTreeDataAtom,
+} from "@/features/share/atoms/shared-page-atom";
import { buildSharedPageTree } from "@/features/share/utils";
import {
desktopSidebarAtom,
mobileSidebarAtom,
+ sidebarWidthAtom,
} from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import SidebarToggle from "@/components/ui/sidebar-toggle-button.tsx";
import { useTranslation } from "react-i18next";
@@ -27,7 +32,7 @@ import {
mobileTableOfContentAsideAtom,
tableOfContentAsideAtom,
} from "@/features/share/atoms/sidebar-atom.ts";
-import { IconList } from "@tabler/icons-react";
+import { IconArrowsHorizontal, IconList } from "@tabler/icons-react";
import { useToggleToc } from "@/features/share/hooks/use-toggle-toc.ts";
import classes from "./share.module.css";
import {
@@ -55,6 +60,46 @@ export default function ShareShell({
const [mobileTocOpened] = useAtom(mobileTableOfContentAsideAtom);
const toggleTocMobile = useToggleToc(mobileTableOfContentAsideAtom);
const toggleToc = useToggleToc(tableOfContentAsideAtom);
+ const [fullWidth, setFullWidth] = useAtom(sharedPageFullWidthAtom);
+ const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
+ const [isResizing, setIsResizing] = useState(false);
+ const sidebarRef = useRef(null);
+
+ const startResizing = useCallback((e: React.MouseEvent) => {
+ e.preventDefault();
+ setIsResizing(true);
+ }, []);
+
+ const stopResizing = useCallback(() => {
+ setIsResizing(false);
+ }, []);
+
+ const resize = useCallback(
+ (e: MouseEvent) => {
+ if (!isResizing || !sidebarRef.current) return;
+ const newWidth =
+ e.clientX - sidebarRef.current.getBoundingClientRect().left;
+ if (newWidth < 220) {
+ setSidebarWidth(220);
+ return;
+ }
+ if (newWidth > 600) {
+ setSidebarWidth(600);
+ return;
+ }
+ setSidebarWidth(newWidth);
+ },
+ [isResizing, setSidebarWidth],
+ );
+
+ useEffect(() => {
+ window.addEventListener("mousemove", resize);
+ window.addEventListener("mouseup", stopResizing);
+ return () => {
+ window.removeEventListener("mousemove", resize);
+ window.removeEventListener("mouseup", stopResizing);
+ };
+ }, [resize, stopResizing]);
const { shareId } = useParams();
const { data } = useGetSharedPageTreeQuery(shareId);
@@ -81,7 +126,7 @@ export default function ShareShell({
header={{ height: 50 }}
{...(data?.pageTree?.length > 1 && {
navbar: {
- width: 300,
+ width: sidebarWidth,
breakpoint: "sm",
collapsed: {
mobile: !mobileOpened,
@@ -166,6 +211,20 @@ export default function ShareShell({
+
+
+ setFullWidth((v) => !v)}
+ visibleFrom="sm"
+ size="sm"
+ >
+
+
+
>
@@ -174,7 +233,11 @@ export default function ShareShell({
{data?.pageTree?.length > 1 && (
-
+
+
)}
diff --git a/apps/client/src/features/share/components/share.module.css b/apps/client/src/features/share/components/share.module.css
index 617768ff1..ebf1e74cb 100644
--- a/apps/client/src/features/share/components/share.module.css
+++ b/apps/client/src/features/share/components/share.module.css
@@ -10,6 +10,7 @@
.treeNode {
text-decoration: none;
user-select: none;
+ padding-bottom: 0;
}
.navbar,
@@ -18,3 +19,26 @@
width: 350px;
}
}
+
+.resizeHandle {
+ width: 3px;
+ cursor: col-resize;
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+
+ &:hover,
+ &:active {
+ width: 5px;
+ background: light-dark(
+ var(--mantine-color-gray-4),
+ var(--mantine-color-dark-5)
+ );
+ }
+
+ @media (max-width: $mantine-breakpoint-sm) {
+ display: none;
+ }
+}
diff --git a/apps/client/src/lib/app-route.ts b/apps/client/src/lib/app-route.ts
index e817c0722..48c1b87d1 100644
--- a/apps/client/src/lib/app-route.ts
+++ b/apps/client/src/lib/app-route.ts
@@ -31,20 +31,38 @@ const APP_ROUTE = {
},
};
+export function safeRedirectPath(input: unknown): string | null {
+ if (typeof input !== "string") return null;
+ if (input.length === 0 || input.length > 2048) return null;
+ // Reject whitespace, backslash, and any Unicode "Other" category char
+ // (ASCII controls, zero-width space, BOM, bidi marks, etc).
+ if (/[\s\\]|\p{C}/u.test(input)) return null;
+ if (!input.startsWith("/") || input.startsWith("//")) return null;
+ if (input.toLowerCase().includes("://")) return null;
+ if (/^\/[a-z][a-z0-9+\-.]*:/i.test(input)) return null;
+ try {
+ const resolved = new URL(input, window.location.origin);
+ if (resolved.origin !== window.location.origin) return null;
+ return resolved.pathname + resolved.search + resolved.hash;
+ } catch {
+ return null;
+ }
+}
+
export function getPostLoginRedirect(): string {
const params = new URLSearchParams(window.location.search);
- const redirect = params.get("redirect");
- if (redirect) {
- try {
- const resolved = new URL(redirect, window.location.origin);
- if (resolved.origin === window.location.origin) {
- return resolved.pathname + resolved.search + resolved.hash;
- }
- } catch {
- // malformed URL, fall through to default
- }
- }
- return APP_ROUTE.HOME;
+ return safeRedirectPath(params.get("redirect")) ?? APP_ROUTE.HOME;
+}
+
+/**
+ * Returns the `?redirect=` value from the current URL only when it is a safe
+ * same-origin path. Unlike {@link getPostLoginRedirect} this returns `null`
+ * (not `/home`) when no redirect is present, so callers can distinguish
+ * "user came here directly" from "user was bounced from a deep link".
+ */
+export function getRedirectParam(): string | null {
+ const params = new URLSearchParams(window.location.search);
+ return safeRedirectPath(params.get("redirect"));
}
export default APP_ROUTE;
diff --git a/apps/client/src/pages/share/shared-page.tsx b/apps/client/src/pages/share/shared-page.tsx
index 0db817f60..f156208e5 100644
--- a/apps/client/src/pages/share/shared-page.tsx
+++ b/apps/client/src/pages/share/shared-page.tsx
@@ -9,7 +9,10 @@ import { extractPageSlugId } from "@/lib";
import { Error404 } from "@/components/ui/error-404.tsx";
import ShareBranding from "@/features/share/components/share-branding.tsx";
import { useAtomValue } from "jotai";
-import { sharedTreeDataAtom } from "@/features/share/atoms/shared-page-atom.ts";
+import {
+ sharedPageFullWidthAtom,
+ sharedTreeDataAtom,
+} from "@/features/share/atoms/shared-page-atom.ts";
import { isPageInTree } from "@/features/share/utils.ts";
export default function SharedPage() {
@@ -23,6 +26,7 @@ export default function SharedPage() {
});
const sharedTreeData = useAtomValue(sharedTreeDataAtom);
+ const fullWidth = useAtomValue(sharedPageFullWidthAtom);
useEffect(() => {
if (shareId && data) {
@@ -59,7 +63,7 @@ export default function SharedPage() {
)}
-
+
=20.0.0'}
- '@aws-sdk/core@3.974.7':
- resolution: {integrity: sha512-YhRC90ofz5oolTJZlA8voU/oUrCB2azi8Usx51k8hhB5LpWbYQMMXKUqSqkoL0Cru+RQJgWTHpAfEDDIwfUhJw==}
+ '@aws-sdk/core@3.974.9':
+ resolution: {integrity: sha512-bXxosFunr+v/kqNb99r1NRkrVBha7CG036fRSpWGbC1A/e363XFQN6wcZMx7MYTdRr1tYwNnkrWX2xc1rT3BCQ==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/crc64-nvme@3.972.7':
- resolution: {integrity: sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==}
+ '@aws-sdk/crc64-nvme@3.972.8':
+ resolution: {integrity: sha512-fVfUCL/Xh2zINYMPZvj+iBn6XWouQf0DAnjaWCI9MkmqXzL2Iy5FoQB8O7syFe6gN6AH1ecDDU58T51Ou0kFkA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-env@3.972.33':
- resolution: {integrity: sha512-bJV7eViSJV6GSuuN+VIdNVPdwPsNSf75BiC2v5alPrjR/OCcqgKwSZInKbDFz9mNeizldsyf67jt6YSIiv53Cw==}
+ '@aws-sdk/credential-provider-env@3.972.35':
+ resolution: {integrity: sha512-WkFQ8BedszVomhh/Zzs8WwnE/XBmTqZjoQVB8u/4zH6kZCjouXZpPpb93gD8m0EZmzAl7dxHE/y+yDpuKzNCMw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-http@3.972.35':
- resolution: {integrity: sha512-x/BQGEIdq0oI+4WxLjKmnQvT7CnF9r8ezdGt7wXwxb7ckHXQz0Zmgxt8v3Ne0JaT3R5YefmuybHX6E8EnsDXyA==}
+ '@aws-sdk/credential-provider-http@3.972.37':
+ resolution: {integrity: sha512-ylx0ZJTU+2eNcvXQ69VNR3TVSYa/ibpvdK717/NxqR9aXRMn2QRWZaiI8aa5yY/fOWZ5mknSmxGaVxxtdwv3EA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-ini@3.972.37':
- resolution: {integrity: sha512-eUTpmWfd/BKsq9medhCRcu+GRAhFP2Zrn7/2jKDHHOOjCkhrMoTp/t4cEthqFoG7gE0VGp5wUxrXTdvBCmSmJg==}
+ '@aws-sdk/credential-provider-ini@3.972.39':
+ resolution: {integrity: sha512-QhRSrdkk+Gq0AFIylpiI0N6lcJqFYV9Jtr4Luz5FpYOYbjJSfyTG6iLhnK/UPIgN1Jnon8WAmSC//16XYGvwkA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-login@3.972.37':
- resolution: {integrity: sha512-Ty68y8ISSC+g5Q3D0K8uAaoINwvfaOslnNpsF/LgVUxyosYXHawcK2yV4HLXDVugiTTYLQfJfcw0ce5meAGkKw==}
+ '@aws-sdk/credential-provider-login@3.972.39':
+ resolution: {integrity: sha512-1hU0NtC04QbFIuoBuF4aQ2A97GsSE5/A0ZJpDijwexsBREIQ4KPRYl3v/FfKCPBYsaTeGjkOFx5nLhWHY24LOw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-node@3.972.38':
- resolution: {integrity: sha512-BQ9XYnBDVxR2HuV5huXYQYF/PZMTsY+EnwfGnCU2cA8Zw63XpkOtPY8WqiMIZMQCrKPQQEiFURS/o9CIolRLqg==}
+ '@aws-sdk/credential-provider-node@3.972.40':
+ resolution: {integrity: sha512-ZgrQaGkpyTlVSCCsffzijVg+KgftTAWYvI5Otc36J/4jNiHb+7MmBiJIR0a5AHLvifC92PiYHt5pijP0dswd1w==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-process@3.972.33':
- resolution: {integrity: sha512-yfjGksI9WQbdMObb0VeLXqzTLI+a0qXLJT9gCDiv0+X/xjPpI3mTz6a5FibrhpuEKIe0gSgvs3MaoFZy5cx4WA==}
+ '@aws-sdk/credential-provider-process@3.972.35':
+ resolution: {integrity: sha512-hNj1rAwZWT1vfz54BwH8FUWxZuqStrM25Q5LEIwn2erHPMRVAjLlpZqEbCEEqS99eEEOhdeetnS0WeNa3iYeEQ==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-sso@3.972.37':
- resolution: {integrity: sha512-fpwE+20ntpp3i9Xb9vUuQfXLDKYHH+5I2V+ZG96SX1nBzrruhy10RXDgmN7t1etOz3c55stlA3TeQASUA451NQ==}
+ '@aws-sdk/credential-provider-sso@3.972.39':
+ resolution: {integrity: sha512-mwIPNPldyCZkvHozb6E0X/vuQLN1UCjcA6MwUf1gaO7EwghCmuNZXatq0L3zptKFvPC4Nds7+WFUkifI1XmbSw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/credential-provider-web-identity@3.972.37':
- resolution: {integrity: sha512-aryawqyebf+3WhAFNHfF62rekFpYtVcVN7dQ89qnAWsa4n5hJst8qBG6gXC24WHtW7Nnhkf9ScYnjwo0Brn3bw==}
+ '@aws-sdk/credential-provider-web-identity@3.972.39':
+ resolution: {integrity: sha512-b9HT8CnpyPVn1hU14Q7ihjwSPlRzToYmRYJxRd5jNHEZ43lrIhoLaTT8JmfQQt5j5M8rTX1iN1X8mvu0SM1dXA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/lib-storage@3.1040.0':
@@ -1057,20 +1058,20 @@ packages:
peerDependencies:
'@aws-sdk/client-s3': ^3.1040.0
- '@aws-sdk/middleware-bucket-endpoint@3.972.10':
- resolution: {integrity: sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA==}
+ '@aws-sdk/middleware-bucket-endpoint@3.972.11':
+ resolution: {integrity: sha512-AhVDn+qObNacklqmBABnFa3YfVk08CzksuuecL/x+lo95dZxXuAkqJZLUsAEKQ3EiDd5E9wTUBjh0cSogmKMYA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/middleware-expect-continue@3.972.10':
- resolution: {integrity: sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ==}
+ '@aws-sdk/middleware-expect-continue@3.972.11':
+ resolution: {integrity: sha512-xpobcctR1AHSrvkiArgTyLffn78Lt9unPMpa/yic9RKn+bOf/5M55UIM6RaPL5xKzI06/GSsTDywTWvzEAbyyw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/middleware-flexible-checksums@3.974.15':
- resolution: {integrity: sha512-j4Zp7rA1HfhDTteICnx/tPax4N/v5wmytgguXExUGyEwQ8Ug4EBA4kjp9puFAN1UZoBVpxoiXMiuTFvjaHjeEw==}
+ '@aws-sdk/middleware-flexible-checksums@3.974.17':
+ resolution: {integrity: sha512-Js24a6sdH9SU5DI5++nlQJayCuOweiiTjnCcAsY75/JtaXF+xysDQ6nRBYx6pUPNY22viRYmdDTFZDaA9AF46g==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/middleware-host-header@3.972.10':
- resolution: {integrity: sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==}
+ '@aws-sdk/middleware-host-header@3.972.11':
+ resolution: {integrity: sha512-CBC6+tVYaOJo7QXgN1zJ4Ba2f3/Cpy4eRViYFimXW/O5Mn8hBmgXXzHu4vy4ubT80YWnp8aCFygr7dTOa14yQg==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-location-constraint@3.972.10':
@@ -1081,67 +1082,63 @@ packages:
resolution: {integrity: sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/middleware-recursion-detection@3.972.11':
- resolution: {integrity: sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==}
+ '@aws-sdk/middleware-recursion-detection@3.972.12':
+ resolution: {integrity: sha512-5eltYxKB4MfdQv7/VhWxRbAVQKow5dz9votRFigTYrWJHMQXwLMltlbk7KFWSZh5NDBySfmjT7Jv/DWfYCmDng==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/middleware-sdk-s3@3.972.36':
- resolution: {integrity: sha512-YhPix+0x/MdQrb1Ug1GDKeS5fqylIy+naz800asX8II4jqfTk2KY2KhmmYCwZcky8YWtRQQwWCGdoqeAnip8Uw==}
+ '@aws-sdk/middleware-sdk-s3@3.972.38':
+ resolution: {integrity: sha512-Yuv3urkJtd1/b3kIURzHwihc1SV6n1t+uiXffOD2OpylZ7+4/QnO2W73yhLZzK1Z762BaqwQ3IVRqAHWzNbQ4A==}
engines: {node: '>=20.0.0'}
'@aws-sdk/middleware-ssec@3.972.10':
resolution: {integrity: sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/middleware-user-agent@3.972.37':
- resolution: {integrity: sha512-N1oNpdiLoVAWYD3WFBnUi3LlfoDA06ZHo4ozyjbsJNLvILzvt//0CnR8N+CZ0NWeYgVB/5V59ivixHCWCx2ALw==}
+ '@aws-sdk/middleware-user-agent@3.972.39':
+ resolution: {integrity: sha512-MlNSvNsSVlMKKWaCzA0GP1nS4Cuq3WCXUN1vmMvd+Ctztib5kmRcpmTtKx9kikN8szAc+gcdp7uqJJervV2nQg==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/nested-clients@3.997.5':
- resolution: {integrity: sha512-jGFr6DxtcMTmzOkG/a0jCZYv4BBDmeNYVeO+/memSoDkYCJu4Y58xviYmzwJfYyIVSts+X/BVjJm1uGBnwHEMg==}
+ '@aws-sdk/nested-clients@3.997.7':
+ resolution: {integrity: sha512-jT2AXOODobQfTYGC2SChMSnZ/voIcRV/LHlY1suyhY1bdgP/voKkhEg8Ci1jiGQ4lBiaso5BEAV3ZWWpPTfmYA==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/region-config-resolver@3.972.13':
- resolution: {integrity: sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==}
+ '@aws-sdk/region-config-resolver@3.972.14':
+ resolution: {integrity: sha512-VuLXVmm7+lKVxqFcOItPkXhjbJ02iUfxkxheRu41SfWf6/xrZup2A2SwHZos/LeQGu3SBHeqTQht80Uo3ienPA==}
engines: {node: '>=20.0.0'}
'@aws-sdk/s3-request-presigner@3.1040.0':
resolution: {integrity: sha512-AmesZGG/B5sDIiWahyY11fOkXSsuHc7LciE88YFURehMVSdEORo2Vzz1d2kBgmJG9oar5Vmmwf9X/w7mqb7ytg==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/signature-v4-multi-region@3.996.24':
- resolution: {integrity: sha512-amP7tLikppN940wbBFISYqiuzVmpzMS9U3mcgtmVLjX4fdWI/SNCvrXv6ZxfVzTT4cT0rPKOLhFah2xLwzREWw==}
+ '@aws-sdk/signature-v4-multi-region@3.996.26':
+ resolution: {integrity: sha512-2N62veqdMZBCwQUHsbhtnaovOFjOa5Dn3dAD1nRqFTUXR4QmirT3HZnfus/L1DS08Vm5CkoKmL0iMVt6YbqEag==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/token-providers@3.1039.0':
- resolution: {integrity: sha512-NMSFL2HwkAOoCeLCQiqoOq5pT3vVbSjww2QZTuYgYknVwhhv125PSDzZIcL5EYnlxuPWjEOdauZK+FspkZDVdw==}
+ '@aws-sdk/token-providers@3.1046.0':
+ resolution: {integrity: sha512-9je8nZt+ntB8IjhpGNayU/AkBgvq/f4aFO2bH1LSNC5JX6K8zY4LUnr/ymqunePrwq+B5OVBpL7ILjYzMFSZAw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/types@3.973.8':
resolution: {integrity: sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/util-arn-parser@3.972.3':
- resolution: {integrity: sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==}
+ '@aws-sdk/util-endpoints@3.996.9':
+ resolution: {integrity: sha512-ibx8Vd73rCTHekNGeXX8cpGWoBKbNAlwKHL3yjSxxttu5QnNDaSAM7/0MFYDjU31/F4lyrPoQcGirT0ew61xcg==}
engines: {node: '>=20.0.0'}
- '@aws-sdk/util-endpoints@3.996.8':
- resolution: {integrity: sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==}
- engines: {node: '>=20.0.0'}
-
- '@aws-sdk/util-format-url@3.972.10':
- resolution: {integrity: sha512-DEKiHNJVtNxdyTeQspzY+15Po/kHm6sF0Cs4HV9Q2+lplB63+DrvdeiSoOSdWEWAoO2RcY1veoXVDz2tWxWCgQ==}
+ '@aws-sdk/util-format-url@3.972.11':
+ resolution: {integrity: sha512-LSzASo5djqKTUWWHhmuj9oZ6KHLaH8eUKhZLPi75imT3CcNqzkPflU9+mwl7jHP9ROsC0dSarcnpDYwyp9J/uw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/util-locate-window@3.535.0':
resolution: {integrity: sha512-PHJ3SL6d2jpcgbqdgiPxkXpu7Drc2PYViwxSIqvvMKhDwzSB1W3mMvtpzwKM4IE7zLFodZo0GKjJ9AsoXndXhA==}
engines: {node: '>=14.0.0'}
- '@aws-sdk/util-user-agent-browser@3.972.10':
- resolution: {integrity: sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==}
+ '@aws-sdk/util-user-agent-browser@3.972.11':
+ resolution: {integrity: sha512-kq3RS6XQtHMrLFShbkem6h+8fxazB3jEIsbMC6aaSInOciRGE+eGAqTgJ+obO7Euo/pjM8thVqLiLISEH9X9DA==}
- '@aws-sdk/util-user-agent-node@3.973.23':
- resolution: {integrity: sha512-gGwq8L2Euw0aNG6Ey4EktiAo3fSCVoDy1CaBIthd+oeaKHPXUrNaApMewQ6La5Hv0lcznOtECZaNvYyc5LXXfA==}
+ '@aws-sdk/util-user-agent-node@3.973.25':
+ resolution: {integrity: sha512-066hKH/0nvV7x4ofV/iK9kz8r/qNfcR6rzuEOFqI2vQL/fcTTsDAbTw0jmXkyMzANK8ltQdALj19ns3zuOJiUw==}
engines: {node: '>=20.0.0'}
peerDependencies:
aws-crt: '>=1.0.0'
@@ -1149,8 +1146,8 @@ packages:
aws-crt:
optional: true
- '@aws-sdk/xml-builder@3.972.22':
- resolution: {integrity: sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA==}
+ '@aws-sdk/xml-builder@3.972.23':
+ resolution: {integrity: sha512-A0YmgYFv+hTI9c17Ntvd2hSehm9bmJfkb+ggADBwVKA8H/3+Jx94SzR2qOB9bAA9WFeDqnfz9PKKQ+D+YAKomA==}
engines: {node: '>=20.0.0'}
'@aws/lambda-invoke-store@0.2.3':
@@ -1817,21 +1814,12 @@ packages:
'@chevrotain/cst-dts-gen@11.0.3':
resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==}
- '@chevrotain/cst-dts-gen@11.1.2':
- resolution: {integrity: sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==}
-
'@chevrotain/gast@11.0.3':
resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==}
- '@chevrotain/gast@11.1.2':
- resolution: {integrity: sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==}
-
'@chevrotain/regexp-to-ast@11.0.3':
resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==}
- '@chevrotain/regexp-to-ast@11.1.2':
- resolution: {integrity: sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==}
-
'@chevrotain/types@11.0.3':
resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==}
@@ -1841,9 +1829,6 @@ packages:
'@chevrotain/utils@11.0.3':
resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
- '@chevrotain/utils@11.1.2':
- resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==}
-
'@clickhouse/client-common@1.18.2':
resolution: {integrity: sha512-J0SG6q9V31ydxonglpj9xhNRsUxCsF71iEZ784yldqMYwsHixj/9xHFDgBDX3DuMiDx/kPDfXnf+pimp08wIBA==}
@@ -2413,7 +2398,7 @@ packages:
resolution: {integrity: sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==}
engines: {node: '>=18.14.1'}
peerDependencies:
- hono: 4.12.14
+ hono: 4.12.18
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
@@ -2729,8 +2714,8 @@ packages:
'@keyv/serialize@1.1.1':
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
- '@langchain/core@1.1.39':
- resolution: {integrity: sha512-DP9c7TREy6iA7HnywstmUAsNyJNYTFpRg2yBfQ+6H0l1HnvQzei9GsQ36GeOLxgRaD3vm9K8urCcawSC7yQpCw==}
+ '@langchain/core@1.1.46':
+ resolution: {integrity: sha512-i8rDC83BpItxChCw4Lf+6tAr+k+OUcbirc5ZkrhI9ywYWmvxegUljLGOGYvtJNTbEAIFkhYIODPE5QRqyjF6sA==}
engines: {node: '>=20'}
'@langchain/textsplitters@1.0.1':
@@ -2811,8 +2796,8 @@ packages:
'@mermaid-js/parser@0.6.3':
resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==}
- '@mermaid-js/parser@1.0.1':
- resolution: {integrity: sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ==}
+ '@mermaid-js/parser@1.1.1':
+ resolution: {integrity: sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==}
'@modelcontextprotocol/sdk@1.29.0':
resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==}
@@ -3280,8 +3265,8 @@ packages:
'@protobufjs/base64@1.1.2':
resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
- '@protobufjs/codegen@2.0.4':
- resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==}
+ '@protobufjs/codegen@2.0.5':
+ resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==}
'@protobufjs/eventemitter@1.1.0':
resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
@@ -3292,8 +3277,8 @@ packages:
'@protobufjs/float@1.0.2':
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
- '@protobufjs/inquire@1.1.0':
- resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==}
+ '@protobufjs/inquire@1.1.1':
+ resolution: {integrity: sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==}
'@protobufjs/path@1.1.2':
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
@@ -3301,8 +3286,8 @@ packages:
'@protobufjs/pool@1.1.0':
resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
- '@protobufjs/utf8@1.1.0':
- resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
+ '@protobufjs/utf8@1.1.1':
+ resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==}
'@radix-ui/number@1.1.1':
resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==}
@@ -4140,217 +4125,156 @@ packages:
'@slidoapp/emoji-mart@5.8.7':
resolution: {integrity: sha512-zn8CBoZRFY0M0Tps0rFgcbu1nhQDmnSoD8CqkTVobI9k3MK2WHIYRp50DXhMxRoQnoct4nomrVaY9kU01ARDTQ==}
- '@smithy/chunked-blob-reader-native@4.2.3':
- resolution: {integrity: sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw==}
+ '@smithy/config-resolver@4.5.1':
+ resolution: {integrity: sha512-abXk3LhODsvRHsk0ZS9ztrg/fZatTa9Z/z4pgx65YSLR+rY6kvUG/1IgcDKEUciR8MfdnkT5oPeHJTy/HhzDIQ==}
engines: {node: '>=18.0.0'}
- '@smithy/chunked-blob-reader@5.2.2':
- resolution: {integrity: sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw==}
+ '@smithy/core@3.24.1':
+ resolution: {integrity: sha512-3mT7o4qQyUWttYnVK3A0Z/u3Xha3E81tXn32Tz6vjZiUXhBrkEivpw1hBYfh84iFF9CSzkBU9Y1DJ3Q6RQ231g==}
engines: {node: '>=18.0.0'}
- '@smithy/config-resolver@4.4.17':
- resolution: {integrity: sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ==}
+ '@smithy/credential-provider-imds@4.3.1':
+ resolution: {integrity: sha512-0S/acwHnqX4WrjXzhdiDRxsG2s9SC0cpPIK9nZ1R6UOHd+j7uL28+4bHu22urbLk2TVw3fkp6na/+fkUt/pLNQ==}
engines: {node: '>=18.0.0'}
- '@smithy/core@3.23.17':
- resolution: {integrity: sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ==}
+ '@smithy/eventstream-serde-browser@4.3.1':
+ resolution: {integrity: sha512-X7MyI1fu8M84IPKk49kO4kb27Mqp6un9/0o/MsA1ngZ5OxxWKGUxPS3S/AJ9q1cPVTSGmRcbaGNfGUSsflTJkg==}
engines: {node: '>=18.0.0'}
- '@smithy/credential-provider-imds@4.2.14':
- resolution: {integrity: sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==}
+ '@smithy/eventstream-serde-config-resolver@4.4.1':
+ resolution: {integrity: sha512-JZGbSXaBk7JY8VPzsh66ksJ0nTWXbApduFDkA/pEl3aTm2EoAiUZE1Iltp6c+X1bB8kxPQW0mHDfVdYCpWTOzg==}
engines: {node: '>=18.0.0'}
- '@smithy/eventstream-codec@4.2.14':
- resolution: {integrity: sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==}
+ '@smithy/eventstream-serde-node@4.3.1':
+ resolution: {integrity: sha512-6Cn4xTNVxn9PWTHSbvf8zmcDhQW8lrLE1Xq5CJgmX6wEvdjS2S0KuE79Aiznv/jx51jpFJ98OuWyE+Bt+oG1MQ==}
engines: {node: '>=18.0.0'}
- '@smithy/eventstream-serde-browser@4.2.14':
- resolution: {integrity: sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==}
+ '@smithy/fetch-http-handler@5.4.1':
+ resolution: {integrity: sha512-r7bN6spQ+caZC8AnyvSxkRUb57zt2jhhRw3Z+2Ez8hjq6coIikDBFUUI/+CQ1xx9K6eX1Gx6wUKo4ylU66TIqw==}
engines: {node: '>=18.0.0'}
- '@smithy/eventstream-serde-config-resolver@4.3.14':
- resolution: {integrity: sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==}
+ '@smithy/hash-blob-browser@4.3.1':
+ resolution: {integrity: sha512-2fbltQVQYmGd0OzPv2oDMRF0pxkzeIx8cbpx2x6W3UJWGaEyUzVPxF4d0sDXZ/r2obg+RbTyhTidXWlPDsKRKw==}
engines: {node: '>=18.0.0'}
- '@smithy/eventstream-serde-node@4.2.14':
- resolution: {integrity: sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==}
+ '@smithy/hash-node@4.3.1':
+ resolution: {integrity: sha512-u0/zo11mg7yNneoYgTkH4sXwSmcBpbl49o4UNCtQ7hYsXxynsN25KYHmXzqi7TPk5HQL5klGnpU5koOY0O+9hw==}
engines: {node: '>=18.0.0'}
- '@smithy/eventstream-serde-universal@4.2.14':
- resolution: {integrity: sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==}
+ '@smithy/hash-stream-node@4.3.1':
+ resolution: {integrity: sha512-4NOnngIoXngbJw9By3u8KXRgqt4vYATpAobNBnNWxOREP7JY3kB0bUmbBNhZ7dtZV/b4auO1eFMD4cLj9OauVg==}
engines: {node: '>=18.0.0'}
- '@smithy/fetch-http-handler@5.3.17':
- resolution: {integrity: sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/hash-blob-browser@4.2.15':
- resolution: {integrity: sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/hash-node@4.2.14':
- resolution: {integrity: sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/hash-stream-node@4.2.14':
- resolution: {integrity: sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/invalid-dependency@4.2.14':
- resolution: {integrity: sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==}
+ '@smithy/invalid-dependency@4.3.1':
+ resolution: {integrity: sha512-cLmwtDoulyZvRepAfyV+3rx5oMvuh51dbE+6En3vGC09j3uVSRt1U4oguNu32ub3soGX0oYtBs8E7S2Q4SxTqg==}
engines: {node: '>=18.0.0'}
'@smithy/is-array-buffer@2.2.0':
resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==}
engines: {node: '>=14.0.0'}
- '@smithy/is-array-buffer@4.2.2':
- resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==}
+ '@smithy/md5-js@4.3.1':
+ resolution: {integrity: sha512-98NalujRdzv6ggVQNYPWpL2K57UKeUB8roIr61u6+JiHd7KUlMQ+sn/vk6IG4XxEjw2vlC7eu/xjYXshUE4XXg==}
engines: {node: '>=18.0.0'}
- '@smithy/md5-js@4.2.14':
- resolution: {integrity: sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA==}
+ '@smithy/middleware-content-length@4.3.1':
+ resolution: {integrity: sha512-l4BUIP+wljW/Ar+0/QcGdmElI9lalrywfzNijXMBG34Z510FRzPyrDLx/blNTZOAm0C4Mvx5t/bf760CZo1ajg==}
engines: {node: '>=18.0.0'}
- '@smithy/middleware-content-length@4.2.14':
- resolution: {integrity: sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==}
+ '@smithy/middleware-endpoint@4.5.1':
+ resolution: {integrity: sha512-qtqu5TS+8Y18ZDkJoiXN5AMW1G4JAg1+xytzpsUvIR5a4EUsgd5HQg12lekEHWpm2TDUmOgg+hBaHK7dvyWdkA==}
engines: {node: '>=18.0.0'}
- '@smithy/middleware-endpoint@4.4.32':
- resolution: {integrity: sha512-ZZkgyjnJppiZbIm6Qbx92pbXYi1uzenIvGhBSCDlc7NwuAkiqSgS75j1czAD25ZLs2FjMjYy1q7gyRVWG6JA0Q==}
+ '@smithy/middleware-retry@4.6.1':
+ resolution: {integrity: sha512-eTaQhxs0rfUuAkL2MSKrH8DTO7YCeAgrdN0B2/RAeuHmXQ+x52dk5qUBsi/jtcqe5LxItgq5AG5tI6Cp8c0sow==}
engines: {node: '>=18.0.0'}
- '@smithy/middleware-retry@4.5.7':
- resolution: {integrity: sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg==}
+ '@smithy/middleware-serde@4.3.1':
+ resolution: {integrity: sha512-t7YtUe076zWVypVmy1rX91oKi2TFJCkpfFpfMhJFpEIRPP0iL9JxjeSyFQ+1bF45JUfDzOzslUJa150WcSrBug==}
engines: {node: '>=18.0.0'}
- '@smithy/middleware-serde@4.2.20':
- resolution: {integrity: sha512-Lx9JMO9vArPtiChE3wbEZ5akMIDQpWQtlu90lhACQmNOXcGXRbaDywMHDzuDZ2OkZzP+9wQfZi3YJT9F67zTQQ==}
+ '@smithy/middleware-stack@4.3.1':
+ resolution: {integrity: sha512-1jKwiKZxCMQNqmp4uVPYA6r+MLGjEtH07gnOUdPgbnjuOIrl/0JY/ICdpQtFgeBsQ/Up01gnSv8GYEL0fb8yvg==}
engines: {node: '>=18.0.0'}
- '@smithy/middleware-stack@4.2.14':
- resolution: {integrity: sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA==}
+ '@smithy/node-config-provider@4.4.1':
+ resolution: {integrity: sha512-q7tDJEJXcaSG/8TVpu2f2l9bzxTzDM9geWmltbzsY6Hfh3yiuXXTpLIO8+zwYASPPVFaTJpdKwjSSjdoDoccgw==}
engines: {node: '>=18.0.0'}
- '@smithy/node-config-provider@4.3.14':
- resolution: {integrity: sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg==}
+ '@smithy/node-http-handler@4.7.1':
+ resolution: {integrity: sha512-BdEYko85f/ldp68uH8XEyIvo810xFk6eyPH81SRggTOApYHWA+Xu7B2EzLuHbe37WVLaUA7F1fWR3/zBeme2WA==}
engines: {node: '>=18.0.0'}
- '@smithy/node-http-handler@4.6.1':
- resolution: {integrity: sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg==}
+ '@smithy/protocol-http@5.4.1':
+ resolution: {integrity: sha512-8irPNCQgYxcSFp1aGcnDNFkTwSA+xPUaFq9V/v1+JXWu8sKr5b3cFmg2kBTkjkvypDmGeNffuNu0x5iqw1NoAw==}
engines: {node: '>=18.0.0'}
- '@smithy/property-provider@4.2.14':
- resolution: {integrity: sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==}
+ '@smithy/signature-v4@5.4.1':
+ resolution: {integrity: sha512-728lZZEWYWubBESrfntNslZQYDKRlJDY4dcDnYbL50+gu35pGPLblu4S0/RH/RDLF6me1M87ECHsHELGL7dA/Q==}
engines: {node: '>=18.0.0'}
- '@smithy/protocol-http@5.3.14':
- resolution: {integrity: sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/querystring-builder@4.2.14':
- resolution: {integrity: sha512-XYA5Z0IqTeF+5XDdh4BBmSA0HvbgVZIyv4cmOoUheDNR57K1HgBp9ukUMx3Cr3XpDHHpLBnexPE3LAtDsZkj2A==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/querystring-parser@4.2.14':
- resolution: {integrity: sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/service-error-classification@4.3.1':
- resolution: {integrity: sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/shared-ini-file-loader@4.4.9':
- resolution: {integrity: sha512-495/V2I15SHgedSJoDPD23JuSfKAp726ZI1V0wtjB07Wh7q/0tri/0e0DLefZCHgxZonrGKt/OCTpAtP1wE1kQ==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/signature-v4@5.3.14':
- resolution: {integrity: sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/smithy-client@4.12.13':
- resolution: {integrity: sha512-y/Pcj1V9+qG98gyu1gvftHB7rDpdh+7kIBIggs55yGm3JdtBV8GT8IFF3a1qxZ79QnaJHX9GXzvBG6tAd+czJA==}
+ '@smithy/smithy-client@4.13.1':
+ resolution: {integrity: sha512-IcznNM8Qd9u1X3oflp12tkzyOB4HbT+sfYWlWiyEysgNzSHoWcHUUsTT4y1jjDjtVuuVVQbYks+g1kVd7u1eGQ==}
engines: {node: '>=18.0.0'}
'@smithy/types@4.14.1':
resolution: {integrity: sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==}
engines: {node: '>=18.0.0'}
- '@smithy/url-parser@4.2.14':
- resolution: {integrity: sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==}
+ '@smithy/url-parser@4.3.1':
+ resolution: {integrity: sha512-tuelFlF2PZR/wogFC58NIrPOv+Zna4N1+3kA161/33D1Gbwvl6Nh4WsAsW05ZyPp0O6CMGsdbb0S2b/qVjRMCw==}
engines: {node: '>=18.0.0'}
- '@smithy/util-base64@4.3.2':
- resolution: {integrity: sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==}
+ '@smithy/util-base64@4.4.1':
+ resolution: {integrity: sha512-fTHiwW2xbiRiWzfSk4IGAr3gNZCH4fuRYqt8+IuarsP/YON35576iVdePraZ6yJlFxlCL0eMec3/F7xYqoKzlg==}
engines: {node: '>=18.0.0'}
- '@smithy/util-body-length-browser@4.2.2':
- resolution: {integrity: sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==}
+ '@smithy/util-body-length-browser@4.3.1':
+ resolution: {integrity: sha512-1scg5t4nV3hV7CZs996/XHb80aDZ5YotH4NcvkW/w/rHj+cSz0aCIzwz8aUNKB4nCDPSHRCbrKoj+TvycYefmw==}
engines: {node: '>=18.0.0'}
- '@smithy/util-body-length-node@4.2.3':
- resolution: {integrity: sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==}
+ '@smithy/util-body-length-node@4.3.1':
+ resolution: {integrity: sha512-VRC8MKVPKrgUYThTA7ughcKMfjW6/X92H0wXGJoda0Apw4O5xbXL0GMLz40DTWlsb5hh2iItk6+XL72uJdxYcw==}
engines: {node: '>=18.0.0'}
'@smithy/util-buffer-from@2.2.0':
resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==}
engines: {node: '>=14.0.0'}
- '@smithy/util-buffer-from@4.2.2':
- resolution: {integrity: sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==}
+ '@smithy/util-defaults-mode-browser@4.4.1':
+ resolution: {integrity: sha512-1rA7w+LjK1WJClsffC81Z/ZtjFt22QsKhBjUYEnZsGVS2nOTfOENKBzdg4SxhdwFvBCjcbpjscUfXOPwE3UHWQ==}
engines: {node: '>=18.0.0'}
- '@smithy/util-config-provider@4.2.2':
- resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==}
+ '@smithy/util-defaults-mode-node@4.3.1':
+ resolution: {integrity: sha512-1fk1wfQHBenQD5NitVKOFgW0wsISYAFPIXGyStJWAeCtMyRhgHYvtJxBk2rwGWA0L5QX6oM6yeHSLKPFMk59ww==}
engines: {node: '>=18.0.0'}
- '@smithy/util-defaults-mode-browser@4.3.49':
- resolution: {integrity: sha512-a5bNrdiONYB/qE2BuKegvUMd/+ZDwdg4vsNuuSzYE8qs2EYAdK9CynL+Rzn29PbPiUqoz/cbpRbcLzD5lEevHw==}
+ '@smithy/util-endpoints@3.5.1':
+ resolution: {integrity: sha512-yORYzJD5zoGbSDkAACr0dIjDiSEA3X8h8lggDENl1dkKpCG0TQIoItPBqtvuJHzFFjRXumcoH+/09xIuixGyCw==}
engines: {node: '>=18.0.0'}
- '@smithy/util-defaults-mode-node@4.2.54':
- resolution: {integrity: sha512-g1cvrJvOnzeJgEdf7AE4luI7gp6L8weE0y9a9wQUSGtjb8QRHDbCJYuE4Sy0SD9N8RrnNPFsPltAz/OSoBR9Zw==}
+ '@smithy/util-middleware@4.3.1':
+ resolution: {integrity: sha512-SRRMDcIgVXVhVbxviBaSZbuWuVW3jD08wv4ESV0V2oiw0Mki8TPVQ5IxwD3MvSTPg52QYsRP+JoMw5WdUdeWAg==}
engines: {node: '>=18.0.0'}
- '@smithy/util-endpoints@3.4.2':
- resolution: {integrity: sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg==}
+ '@smithy/util-retry@4.4.1':
+ resolution: {integrity: sha512-qkgWgwn1xw0GoY9Ea/B6FrYSPfHA0zyOtJkokwxZuvucRf2+2lfTut6adi4e4Y7LEAaxsFG7r6i05mtDCxbHKA==}
engines: {node: '>=18.0.0'}
- '@smithy/util-hex-encoding@4.2.2':
- resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/util-middleware@4.2.14':
- resolution: {integrity: sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/util-retry@4.3.6':
- resolution: {integrity: sha512-p6/FO1n2KxMeQyna067i0uJ6TSbb165ZhnRtCpWh4Foxqbfc6oW+XITaL8QkFJj3KFnDe2URt4gOhgU06EP9ew==}
- engines: {node: '>=18.0.0'}
- deprecated: '@smithy/util-retry v4.3.6 contains a bug in Adaptive Retry, see https://github.com/smithy-lang/smithy-typescript/issues/1993. Upgrade to 4.3.7+'
-
- '@smithy/util-stream@4.5.25':
- resolution: {integrity: sha512-/PFpG4k8Ze8Ei+mMKj3oiPICYekthuzePZMgZbCqMiXIHHf4n2aZ4Ps0aSRShycFTGuj/J6XldmC0x0DwednIA==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/util-uri-escape@4.2.2':
- resolution: {integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==}
+ '@smithy/util-stream@4.6.1':
+ resolution: {integrity: sha512-GjZfEft0M0V3n2YM/LGkr5LeLd8gxHUIzW0rUz6VtTtlAq245GxHlJghvoPEjJHKTj255iHFAiA4IsIdK40Ueg==}
engines: {node: '>=18.0.0'}
'@smithy/util-utf8@2.3.0':
resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==}
engines: {node: '>=14.0.0'}
- '@smithy/util-utf8@4.2.2':
- resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==}
+ '@smithy/util-utf8@4.3.1':
+ resolution: {integrity: sha512-FtRrSnriXtOs4+J8/y9SbQ1xmN71hrOsN/YJr5PQQj5nR1l7YNkGS/TEk4gr0WN7gyrUqw8/RFaYVjI18732ZA==}
engines: {node: '>=18.0.0'}
- '@smithy/util-waiter@4.3.0':
- resolution: {integrity: sha512-JyjYmLAfS+pdxF92o4yLgEoy0zhayKTw73FU1aofLWwLcJw7iSqIY2exGmMTrl/lmZugP5p/zxdFSippJDfKWA==}
- engines: {node: '>=18.0.0'}
-
- '@smithy/uuid@1.1.2':
- resolution: {integrity: sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==}
+ '@smithy/util-waiter@4.4.1':
+ resolution: {integrity: sha512-G/gWDykZNL0NVcd1qXkoKm45jxJECp6q53DSomM5QKMsyAMEsGksVq+HwgonqYxfFJEzzHi6ljtWKXVS1pl0/Q==}
engines: {node: '>=18.0.0'}
'@socket.io/component-emitter@3.1.0':
@@ -5871,9 +5795,6 @@ packages:
chevrotain@11.0.3:
resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==}
- chevrotain@11.1.2:
- resolution: {integrity: sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==}
-
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -6641,6 +6562,9 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
+ es-toolkit@1.46.1:
+ resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==}
+
es6-promise-pool@2.5.0:
resolution: {integrity: sha512-VHErXfzR/6r/+yyzPKeBvO0lgjfC5cbDCQWjWwMZWSb6YU39TGIl51OUmCfWCq4ylMdJSB8zkz2vIuIeIxXApA==}
engines: {node: '>=0.10.0'}
@@ -7166,8 +7090,8 @@ packages:
highlightjs-sap-abap@0.3.0:
resolution: {integrity: sha512-nSiUvEOCycjtFA3pHaTowrbAAk5+lciBHyoVkDsd6FTRBtW9sT2dt42o2jAKbXjZVUidtacdk+j0Y2xnd233Mw==}
- hono@4.12.14:
- resolution: {integrity: sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==}
+ hono@4.12.18:
+ resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==}
engines: {node: '>=16.9.0'}
hookified@1.15.1:
@@ -7299,8 +7223,8 @@ packages:
resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==}
engines: {node: '>=12.22.0'}
- ip-address@10.1.0:
- resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
+ ip-address@10.1.1:
+ resolution: {integrity: sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw==}
engines: {node: '>= 12'}
ipaddr.js@1.9.1:
@@ -7891,20 +7815,16 @@ packages:
postgres:
optional: true
- kysely@0.28.14:
- resolution: {integrity: sha512-SU3lgh0rPvq7upc6vvdVrCsSMUG1h3ChvHVOY7wJ2fw4C9QEB7X3d5eyYEyULUX7UQtxZJtZXGuT6U2US72UYA==}
- engines: {node: '>=20.0.0'}
+ kysely@0.29.0:
+ resolution: {integrity: sha512-LrQfPUeTW7MXbMvT62moEMnpMTuj9TO3lqjCeLKjM975PJ4Alrl/43f2tlDX7xOsNptKgH4LSNGwIbXwEkLg4g==}
+ engines: {node: '>=22.0.0'}
langium@3.3.1:
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
engines: {node: '>=16.0.0'}
- langium@4.2.1:
- resolution: {integrity: sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==}
- engines: {node: '>=20.10.0', npm: '>=10.2.3'}
-
- langsmith@0.5.19:
- resolution: {integrity: sha512-5tFoETuFMvGkbPGsINNlIE4Ab86CsPhdPOQZCGwNt/NX0h5NDKQLKOWS/G2XcRUBOQl4mCNbrayUvUTWaIRsCg==}
+ langsmith@0.7.0:
+ resolution: {integrity: sha512-iiPAGHJZ3uIHGnnLSkgcYZ4+thzhsGp5U48pWuW3ETgCRtbYzoDxYJigiQ3iWkK8ovF7Vr37tYvbI1ZE0tB+6A==}
peerDependencies:
'@opentelemetry/api': '*'
'@opentelemetry/exporter-trace-otlp-proto': '*'
@@ -8226,8 +8146,8 @@ packages:
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
- mermaid@11.13.0:
- resolution: {integrity: sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw==}
+ mermaid@11.15.0:
+ resolution: {integrity: sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==}
methods@1.1.2:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
@@ -9018,8 +8938,8 @@ packages:
prosemirror-view@1.40.0:
resolution: {integrity: sha512-2G3svX0Cr1sJjkD/DYWSe3cfV5VPVTBOxI9XQEGWJDFEpsZb/gh4MV29ctv+OJx2RFX4BLt09i+6zaGM/ldkCw==}
- protobufjs@7.5.5:
- resolution: {integrity: sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==}
+ protobufjs@7.5.6:
+ resolution: {integrity: sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==}
engines: {node: '>=12.0.0'}
proxy-addr@2.0.7:
@@ -10288,9 +10208,6 @@ packages:
vscode-uri@3.0.8:
resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
- vscode-uri@3.1.0:
- resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
-
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
@@ -10851,182 +10768,164 @@ snapshots:
'@aws-crypto/sha1-browser': 5.2.0
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/credential-provider-node': 3.972.38
- '@aws-sdk/middleware-bucket-endpoint': 3.972.10
- '@aws-sdk/middleware-expect-continue': 3.972.10
- '@aws-sdk/middleware-flexible-checksums': 3.974.15
- '@aws-sdk/middleware-host-header': 3.972.10
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/credential-provider-node': 3.972.40
+ '@aws-sdk/middleware-bucket-endpoint': 3.972.11
+ '@aws-sdk/middleware-expect-continue': 3.972.11
+ '@aws-sdk/middleware-flexible-checksums': 3.974.17
+ '@aws-sdk/middleware-host-header': 3.972.11
'@aws-sdk/middleware-location-constraint': 3.972.10
'@aws-sdk/middleware-logger': 3.972.10
- '@aws-sdk/middleware-recursion-detection': 3.972.11
- '@aws-sdk/middleware-sdk-s3': 3.972.36
+ '@aws-sdk/middleware-recursion-detection': 3.972.12
+ '@aws-sdk/middleware-sdk-s3': 3.972.38
'@aws-sdk/middleware-ssec': 3.972.10
- '@aws-sdk/middleware-user-agent': 3.972.37
- '@aws-sdk/region-config-resolver': 3.972.13
- '@aws-sdk/signature-v4-multi-region': 3.996.24
+ '@aws-sdk/middleware-user-agent': 3.972.39
+ '@aws-sdk/region-config-resolver': 3.972.14
+ '@aws-sdk/signature-v4-multi-region': 3.996.26
'@aws-sdk/types': 3.973.8
- '@aws-sdk/util-endpoints': 3.996.8
- '@aws-sdk/util-user-agent-browser': 3.972.10
- '@aws-sdk/util-user-agent-node': 3.973.23
- '@smithy/config-resolver': 4.4.17
- '@smithy/core': 3.23.17
- '@smithy/eventstream-serde-browser': 4.2.14
- '@smithy/eventstream-serde-config-resolver': 4.3.14
- '@smithy/eventstream-serde-node': 4.2.14
- '@smithy/fetch-http-handler': 5.3.17
- '@smithy/hash-blob-browser': 4.2.15
- '@smithy/hash-node': 4.2.14
- '@smithy/hash-stream-node': 4.2.14
- '@smithy/invalid-dependency': 4.2.14
- '@smithy/md5-js': 4.2.14
- '@smithy/middleware-content-length': 4.2.14
- '@smithy/middleware-endpoint': 4.4.32
- '@smithy/middleware-retry': 4.5.7
- '@smithy/middleware-serde': 4.2.20
- '@smithy/middleware-stack': 4.2.14
- '@smithy/node-config-provider': 4.3.14
- '@smithy/node-http-handler': 4.6.1
- '@smithy/protocol-http': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@aws-sdk/util-endpoints': 3.996.9
+ '@aws-sdk/util-user-agent-browser': 3.972.11
+ '@aws-sdk/util-user-agent-node': 3.973.25
+ '@smithy/config-resolver': 4.5.1
+ '@smithy/core': 3.24.1
+ '@smithy/eventstream-serde-browser': 4.3.1
+ '@smithy/eventstream-serde-config-resolver': 4.4.1
+ '@smithy/eventstream-serde-node': 4.3.1
+ '@smithy/fetch-http-handler': 5.4.1
+ '@smithy/hash-blob-browser': 4.3.1
+ '@smithy/hash-node': 4.3.1
+ '@smithy/hash-stream-node': 4.3.1
+ '@smithy/invalid-dependency': 4.3.1
+ '@smithy/md5-js': 4.3.1
+ '@smithy/middleware-content-length': 4.3.1
+ '@smithy/middleware-endpoint': 4.5.1
+ '@smithy/middleware-retry': 4.6.1
+ '@smithy/middleware-serde': 4.3.1
+ '@smithy/middleware-stack': 4.3.1
+ '@smithy/node-config-provider': 4.4.1
+ '@smithy/node-http-handler': 4.7.1
+ '@smithy/protocol-http': 5.4.1
+ '@smithy/smithy-client': 4.13.1
'@smithy/types': 4.14.1
- '@smithy/url-parser': 4.2.14
- '@smithy/util-base64': 4.3.2
- '@smithy/util-body-length-browser': 4.2.2
- '@smithy/util-body-length-node': 4.2.3
- '@smithy/util-defaults-mode-browser': 4.3.49
- '@smithy/util-defaults-mode-node': 4.2.54
- '@smithy/util-endpoints': 3.4.2
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-retry': 4.3.6
- '@smithy/util-stream': 4.5.25
- '@smithy/util-utf8': 4.2.2
- '@smithy/util-waiter': 4.3.0
+ '@smithy/url-parser': 4.3.1
+ '@smithy/util-base64': 4.4.1
+ '@smithy/util-body-length-browser': 4.3.1
+ '@smithy/util-body-length-node': 4.3.1
+ '@smithy/util-defaults-mode-browser': 4.4.1
+ '@smithy/util-defaults-mode-node': 4.3.1
+ '@smithy/util-endpoints': 3.5.1
+ '@smithy/util-middleware': 4.3.1
+ '@smithy/util-retry': 4.4.1
+ '@smithy/util-stream': 4.6.1
+ '@smithy/util-utf8': 4.3.1
+ '@smithy/util-waiter': 4.4.1
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/core@3.974.7':
+ '@aws-sdk/core@3.974.9':
dependencies:
'@aws-sdk/types': 3.973.8
- '@aws-sdk/xml-builder': 3.972.22
- '@smithy/core': 3.23.17
- '@smithy/node-config-provider': 4.3.14
- '@smithy/property-provider': 4.2.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/signature-v4': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@aws-sdk/xml-builder': 3.972.23
+ '@smithy/core': 3.24.1
+ '@smithy/signature-v4': 5.4.1
'@smithy/types': 4.14.1
- '@smithy/util-base64': 4.3.2
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-retry': 4.3.6
- '@smithy/util-utf8': 4.2.2
tslib: 2.8.1
- '@aws-sdk/crc64-nvme@3.972.7':
+ '@aws-sdk/crc64-nvme@3.972.8':
dependencies:
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/credential-provider-env@3.972.33':
+ '@aws-sdk/credential-provider-env@3.972.35':
dependencies:
- '@aws-sdk/core': 3.974.7
+ '@aws-sdk/core': 3.974.9
'@aws-sdk/types': 3.973.8
- '@smithy/property-provider': 4.2.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/credential-provider-http@3.972.35':
+ '@aws-sdk/credential-provider-http@3.972.37':
dependencies:
- '@aws-sdk/core': 3.974.7
+ '@aws-sdk/core': 3.974.9
'@aws-sdk/types': 3.973.8
- '@smithy/fetch-http-handler': 5.3.17
- '@smithy/node-http-handler': 4.6.1
- '@smithy/property-provider': 4.2.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@smithy/core': 3.24.1
+ '@smithy/fetch-http-handler': 5.4.1
+ '@smithy/node-http-handler': 4.7.1
'@smithy/types': 4.14.1
- '@smithy/util-stream': 4.5.25
tslib: 2.8.1
- '@aws-sdk/credential-provider-ini@3.972.37':
+ '@aws-sdk/credential-provider-ini@3.972.39':
dependencies:
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/credential-provider-env': 3.972.33
- '@aws-sdk/credential-provider-http': 3.972.35
- '@aws-sdk/credential-provider-login': 3.972.37
- '@aws-sdk/credential-provider-process': 3.972.33
- '@aws-sdk/credential-provider-sso': 3.972.37
- '@aws-sdk/credential-provider-web-identity': 3.972.37
- '@aws-sdk/nested-clients': 3.997.5
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/credential-provider-env': 3.972.35
+ '@aws-sdk/credential-provider-http': 3.972.37
+ '@aws-sdk/credential-provider-login': 3.972.39
+ '@aws-sdk/credential-provider-process': 3.972.35
+ '@aws-sdk/credential-provider-sso': 3.972.39
+ '@aws-sdk/credential-provider-web-identity': 3.972.39
+ '@aws-sdk/nested-clients': 3.997.7
'@aws-sdk/types': 3.973.8
- '@smithy/credential-provider-imds': 4.2.14
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
+ '@smithy/credential-provider-imds': 4.3.1
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/credential-provider-login@3.972.37':
+ '@aws-sdk/credential-provider-login@3.972.39':
dependencies:
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/nested-clients': 3.997.5
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/nested-clients': 3.997.7
'@aws-sdk/types': 3.973.8
- '@smithy/property-provider': 4.2.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/credential-provider-node@3.972.38':
+ '@aws-sdk/credential-provider-node@3.972.40':
dependencies:
- '@aws-sdk/credential-provider-env': 3.972.33
- '@aws-sdk/credential-provider-http': 3.972.35
- '@aws-sdk/credential-provider-ini': 3.972.37
- '@aws-sdk/credential-provider-process': 3.972.33
- '@aws-sdk/credential-provider-sso': 3.972.37
- '@aws-sdk/credential-provider-web-identity': 3.972.37
+ '@aws-sdk/credential-provider-env': 3.972.35
+ '@aws-sdk/credential-provider-http': 3.972.37
+ '@aws-sdk/credential-provider-ini': 3.972.39
+ '@aws-sdk/credential-provider-process': 3.972.35
+ '@aws-sdk/credential-provider-sso': 3.972.39
+ '@aws-sdk/credential-provider-web-identity': 3.972.39
'@aws-sdk/types': 3.973.8
- '@smithy/credential-provider-imds': 4.2.14
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
+ '@smithy/credential-provider-imds': 4.3.1
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/credential-provider-process@3.972.33':
+ '@aws-sdk/credential-provider-process@3.972.35':
dependencies:
- '@aws-sdk/core': 3.974.7
+ '@aws-sdk/core': 3.974.9
'@aws-sdk/types': 3.973.8
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/credential-provider-sso@3.972.37':
+ '@aws-sdk/credential-provider-sso@3.972.39':
dependencies:
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/nested-clients': 3.997.5
- '@aws-sdk/token-providers': 3.1039.0
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/nested-clients': 3.997.7
+ '@aws-sdk/token-providers': 3.1046.0
'@aws-sdk/types': 3.973.8
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/credential-provider-web-identity@3.972.37':
+ '@aws-sdk/credential-provider-web-identity@3.972.39':
dependencies:
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/nested-clients': 3.997.5
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/nested-clients': 3.997.7
'@aws-sdk/types': 3.973.8
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
@@ -11035,53 +10934,46 @@ snapshots:
'@aws-sdk/lib-storage@3.1040.0(@aws-sdk/client-s3@3.1040.0)':
dependencies:
'@aws-sdk/client-s3': 3.1040.0
- '@smithy/middleware-endpoint': 4.4.32
- '@smithy/protocol-http': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@smithy/middleware-endpoint': 4.5.1
+ '@smithy/protocol-http': 5.4.1
+ '@smithy/smithy-client': 4.13.1
'@smithy/types': 4.14.1
buffer: 5.6.0
events: 3.3.0
stream-browserify: 3.0.0
tslib: 2.8.1
- '@aws-sdk/middleware-bucket-endpoint@3.972.10':
+ '@aws-sdk/middleware-bucket-endpoint@3.972.11':
dependencies:
+ '@aws-sdk/core': 3.974.9
'@aws-sdk/types': 3.973.8
- '@aws-sdk/util-arn-parser': 3.972.3
- '@smithy/node-config-provider': 4.3.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/types': 4.14.1
- '@smithy/util-config-provider': 4.2.2
- tslib: 2.8.1
-
- '@aws-sdk/middleware-expect-continue@3.972.10':
- dependencies:
- '@aws-sdk/types': 3.973.8
- '@smithy/protocol-http': 5.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/middleware-flexible-checksums@3.974.15':
+ '@aws-sdk/middleware-expect-continue@3.972.11':
+ dependencies:
+ '@aws-sdk/types': 3.973.8
+ '@smithy/core': 3.24.1
+ '@smithy/types': 4.14.1
+ tslib: 2.8.1
+
+ '@aws-sdk/middleware-flexible-checksums@3.974.17':
dependencies:
'@aws-crypto/crc32': 5.2.0
'@aws-crypto/crc32c': 5.2.0
'@aws-crypto/util': 5.2.0
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/crc64-nvme': 3.972.7
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/crc64-nvme': 3.972.8
'@aws-sdk/types': 3.973.8
- '@smithy/is-array-buffer': 4.2.2
- '@smithy/node-config-provider': 4.3.14
- '@smithy/protocol-http': 5.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-stream': 4.5.25
- '@smithy/util-utf8': 4.2.2
tslib: 2.8.1
- '@aws-sdk/middleware-host-header@3.972.10':
+ '@aws-sdk/middleware-host-header@3.972.11':
dependencies:
'@aws-sdk/types': 3.973.8
- '@smithy/protocol-http': 5.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
@@ -11097,29 +10989,22 @@ snapshots:
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/middleware-recursion-detection@3.972.11':
+ '@aws-sdk/middleware-recursion-detection@3.972.12':
dependencies:
'@aws-sdk/types': 3.973.8
'@aws/lambda-invoke-store': 0.2.3
- '@smithy/protocol-http': 5.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/middleware-sdk-s3@3.972.36':
+ '@aws-sdk/middleware-sdk-s3@3.972.38':
dependencies:
- '@aws-sdk/core': 3.974.7
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/signature-v4-multi-region': 3.996.26
'@aws-sdk/types': 3.973.8
- '@aws-sdk/util-arn-parser': 3.972.3
- '@smithy/core': 3.23.17
- '@smithy/node-config-provider': 4.3.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/signature-v4': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@smithy/core': 3.24.1
+ '@smithy/signature-v4': 5.4.1
'@smithy/types': 4.14.1
- '@smithy/util-config-provider': 4.2.2
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-stream': 4.5.25
- '@smithy/util-utf8': 4.2.2
tslib: 2.8.1
'@aws-sdk/middleware-ssec@3.972.10':
@@ -11128,96 +11013,70 @@ snapshots:
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/middleware-user-agent@3.972.37':
+ '@aws-sdk/middleware-user-agent@3.972.39':
dependencies:
- '@aws-sdk/core': 3.974.7
+ '@aws-sdk/core': 3.974.9
'@aws-sdk/types': 3.973.8
- '@aws-sdk/util-endpoints': 3.996.8
- '@smithy/core': 3.23.17
- '@smithy/protocol-http': 5.3.14
+ '@aws-sdk/util-endpoints': 3.996.9
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
- '@smithy/util-retry': 4.3.6
tslib: 2.8.1
- '@aws-sdk/nested-clients@3.997.5':
+ '@aws-sdk/nested-clients@3.997.7':
dependencies:
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/middleware-host-header': 3.972.10
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/middleware-host-header': 3.972.11
'@aws-sdk/middleware-logger': 3.972.10
- '@aws-sdk/middleware-recursion-detection': 3.972.11
- '@aws-sdk/middleware-user-agent': 3.972.37
- '@aws-sdk/region-config-resolver': 3.972.13
- '@aws-sdk/signature-v4-multi-region': 3.996.24
+ '@aws-sdk/middleware-recursion-detection': 3.972.12
+ '@aws-sdk/middleware-user-agent': 3.972.39
+ '@aws-sdk/region-config-resolver': 3.972.14
+ '@aws-sdk/signature-v4-multi-region': 3.996.26
'@aws-sdk/types': 3.973.8
- '@aws-sdk/util-endpoints': 3.996.8
- '@aws-sdk/util-user-agent-browser': 3.972.10
- '@aws-sdk/util-user-agent-node': 3.973.23
- '@smithy/config-resolver': 4.4.17
- '@smithy/core': 3.23.17
- '@smithy/fetch-http-handler': 5.3.17
- '@smithy/hash-node': 4.2.14
- '@smithy/invalid-dependency': 4.2.14
- '@smithy/middleware-content-length': 4.2.14
- '@smithy/middleware-endpoint': 4.4.32
- '@smithy/middleware-retry': 4.5.7
- '@smithy/middleware-serde': 4.2.20
- '@smithy/middleware-stack': 4.2.14
- '@smithy/node-config-provider': 4.3.14
- '@smithy/node-http-handler': 4.6.1
- '@smithy/protocol-http': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@aws-sdk/util-endpoints': 3.996.9
+ '@aws-sdk/util-user-agent-browser': 3.972.11
+ '@aws-sdk/util-user-agent-node': 3.973.25
+ '@smithy/core': 3.24.1
+ '@smithy/fetch-http-handler': 5.4.1
+ '@smithy/node-http-handler': 4.7.1
'@smithy/types': 4.14.1
- '@smithy/url-parser': 4.2.14
- '@smithy/util-base64': 4.3.2
- '@smithy/util-body-length-browser': 4.2.2
- '@smithy/util-body-length-node': 4.2.3
- '@smithy/util-defaults-mode-browser': 4.3.49
- '@smithy/util-defaults-mode-node': 4.2.54
- '@smithy/util-endpoints': 3.4.2
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-retry': 4.3.6
- '@smithy/util-utf8': 4.2.2
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
- '@aws-sdk/region-config-resolver@3.972.13':
+ '@aws-sdk/region-config-resolver@3.972.14':
dependencies:
'@aws-sdk/types': 3.973.8
- '@smithy/config-resolver': 4.4.17
- '@smithy/node-config-provider': 4.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
'@aws-sdk/s3-request-presigner@3.1040.0':
dependencies:
- '@aws-sdk/signature-v4-multi-region': 3.996.24
+ '@aws-sdk/signature-v4-multi-region': 3.996.26
'@aws-sdk/types': 3.973.8
- '@aws-sdk/util-format-url': 3.972.10
- '@smithy/middleware-endpoint': 4.4.32
- '@smithy/protocol-http': 5.3.14
- '@smithy/smithy-client': 4.12.13
+ '@aws-sdk/util-format-url': 3.972.11
+ '@smithy/middleware-endpoint': 4.5.1
+ '@smithy/protocol-http': 5.4.1
+ '@smithy/smithy-client': 4.13.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/signature-v4-multi-region@3.996.24':
+ '@aws-sdk/signature-v4-multi-region@3.996.26':
dependencies:
- '@aws-sdk/middleware-sdk-s3': 3.972.36
'@aws-sdk/types': 3.973.8
- '@smithy/protocol-http': 5.3.14
- '@smithy/signature-v4': 5.3.14
+ '@smithy/core': 3.24.1
+ '@smithy/signature-v4': 5.4.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/token-providers@3.1039.0':
+ '@aws-sdk/token-providers@3.1046.0':
dependencies:
- '@aws-sdk/core': 3.974.7
- '@aws-sdk/nested-clients': 3.997.5
+ '@aws-sdk/core': 3.974.9
+ '@aws-sdk/nested-clients': 3.997.7
'@aws-sdk/types': 3.973.8
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
@@ -11228,46 +11087,38 @@ snapshots:
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@aws-sdk/util-arn-parser@3.972.3':
- dependencies:
- tslib: 2.8.1
-
- '@aws-sdk/util-endpoints@3.996.8':
+ '@aws-sdk/util-endpoints@3.996.9':
dependencies:
'@aws-sdk/types': 3.973.8
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
- '@smithy/url-parser': 4.2.14
- '@smithy/util-endpoints': 3.4.2
tslib: 2.8.1
- '@aws-sdk/util-format-url@3.972.10':
+ '@aws-sdk/util-format-url@3.972.11':
dependencies:
- '@aws-sdk/types': 3.973.8
- '@smithy/querystring-builder': 4.2.14
- '@smithy/types': 4.14.1
+ '@aws-sdk/core': 3.974.9
tslib: 2.8.1
'@aws-sdk/util-locate-window@3.535.0':
dependencies:
tslib: 2.8.1
- '@aws-sdk/util-user-agent-browser@3.972.10':
+ '@aws-sdk/util-user-agent-browser@3.972.11':
dependencies:
'@aws-sdk/types': 3.973.8
'@smithy/types': 4.14.1
bowser: 2.14.1
tslib: 2.8.1
- '@aws-sdk/util-user-agent-node@3.973.23':
+ '@aws-sdk/util-user-agent-node@3.973.25':
dependencies:
- '@aws-sdk/middleware-user-agent': 3.972.37
+ '@aws-sdk/middleware-user-agent': 3.972.39
'@aws-sdk/types': 3.973.8
- '@smithy/node-config-provider': 4.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
- '@smithy/util-config-provider': 4.2.2
tslib: 2.8.1
- '@aws-sdk/xml-builder@3.972.22':
+ '@aws-sdk/xml-builder@3.972.23':
dependencies:
'@nodable/entities': 2.1.0
'@smithy/types': 4.14.1
@@ -12090,34 +11941,19 @@ snapshots:
'@chevrotain/types': 11.0.3
lodash-es: 4.18.1
- '@chevrotain/cst-dts-gen@11.1.2':
- dependencies:
- '@chevrotain/gast': 11.1.2
- '@chevrotain/types': 11.1.2
- lodash-es: 4.18.1
-
'@chevrotain/gast@11.0.3':
dependencies:
'@chevrotain/types': 11.0.3
lodash-es: 4.18.1
- '@chevrotain/gast@11.1.2':
- dependencies:
- '@chevrotain/types': 11.1.2
- lodash-es: 4.18.1
-
'@chevrotain/regexp-to-ast@11.0.3': {}
- '@chevrotain/regexp-to-ast@11.1.2': {}
-
'@chevrotain/types@11.0.3': {}
'@chevrotain/types@11.1.2': {}
'@chevrotain/utils@11.0.3': {}
- '@chevrotain/utils@11.1.2': {}
-
'@clickhouse/client-common@1.18.2': {}
'@clickhouse/client@1.18.2':
@@ -12476,7 +12312,7 @@ snapshots:
dependencies:
'@excalidraw/markdown-to-text': 0.1.2
'@mermaid-js/parser': 0.6.3
- mermaid: 11.13.0
+ mermaid: 11.15.0
nanoid: 4.0.2
'@excalidraw/random-username@1.1.0': {}
@@ -12618,9 +12454,9 @@ snapshots:
y-prosemirror: 1.3.7(prosemirror-model@1.25.1)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.30))(yjs@13.6.30)
yjs: 13.6.30
- '@hono/node-server@1.19.13(hono@4.12.14)':
+ '@hono/node-server@1.19.13(hono@4.12.18)':
dependencies:
- hono: 4.12.14
+ hono: 4.12.18
'@humanfs/core@0.19.1': {}
@@ -13043,18 +12879,14 @@ snapshots:
'@keyv/serialize@1.1.1': {}
- '@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0)':
+ '@langchain/core@1.1.46(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0)':
dependencies:
'@cfworker/json-schema': 4.1.1
'@standard-schema/spec': 1.1.0
- ansi-styles: 5.2.0
- camelcase: 6.3.0
- decamelize: 1.2.0
js-tiktoken: 1.0.21
- langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0)
+ langsmith: 0.7.0(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0)
mustache: 4.2.0
p-queue: 6.6.2
- uuid: 11.1.0
zod: 4.3.6
transitivePeerDependencies:
- '@opentelemetry/api'
@@ -13063,9 +12895,9 @@ snapshots:
- openai
- ws
- '@langchain/textsplitters@1.0.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0))':
+ '@langchain/textsplitters@1.0.1(@langchain/core@1.1.46(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0))':
dependencies:
- '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0)
+ '@langchain/core': 1.1.46(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0)
js-tiktoken: 1.0.21
'@lifeomic/attempt@3.0.3': {}
@@ -13141,13 +12973,13 @@ snapshots:
dependencies:
langium: 3.3.1
- '@mermaid-js/parser@1.0.1':
+ '@mermaid-js/parser@1.1.1':
dependencies:
- langium: 4.2.1
+ '@chevrotain/types': 11.1.2
'@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(zod@4.3.6)':
dependencies:
- '@hono/node-server': 1.19.13(hono@4.12.14)
+ '@hono/node-server': 1.19.13(hono@4.12.18)
ajv: 8.18.0
ajv-formats: 3.0.1(ajv@8.18.0)
content-type: 1.0.5
@@ -13157,7 +12989,7 @@ snapshots:
eventsource-parser: 3.0.6
express: 5.2.1
express-rate-limit: 8.2.2(express@5.2.1)
- hono: 4.12.14
+ hono: 4.12.18
jose: 6.1.3
json-schema-typed: 8.0.2
pkce-challenge: 5.0.1
@@ -13585,7 +13417,7 @@ snapshots:
'@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-metrics': 2.2.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0)
- protobufjs: 7.5.5
+ protobufjs: 7.5.6
'@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0)':
dependencies:
@@ -13641,24 +13473,24 @@ snapshots:
'@protobufjs/base64@1.1.2': {}
- '@protobufjs/codegen@2.0.4': {}
+ '@protobufjs/codegen@2.0.5': {}
'@protobufjs/eventemitter@1.1.0': {}
'@protobufjs/fetch@1.1.0':
dependencies:
'@protobufjs/aspromise': 1.1.2
- '@protobufjs/inquire': 1.1.0
+ '@protobufjs/inquire': 1.1.1
'@protobufjs/float@1.0.2': {}
- '@protobufjs/inquire@1.1.0': {}
+ '@protobufjs/inquire@1.1.1': {}
'@protobufjs/path@1.1.2': {}
'@protobufjs/pool@1.1.0': {}
- '@protobufjs/utf8@1.1.0': {}
+ '@protobufjs/utf8@1.1.1': {}
'@radix-ui/number@1.1.1': {}
@@ -14502,251 +14334,148 @@ snapshots:
'@slidoapp/emoji-mart@5.8.7': {}
- '@smithy/chunked-blob-reader-native@4.2.3':
+ '@smithy/config-resolver@4.5.1':
dependencies:
- '@smithy/util-base64': 4.3.2
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/chunked-blob-reader@5.2.2':
- dependencies:
- tslib: 2.8.1
-
- '@smithy/config-resolver@4.4.17':
- dependencies:
- '@smithy/node-config-provider': 4.3.14
- '@smithy/types': 4.14.1
- '@smithy/util-config-provider': 4.2.2
- '@smithy/util-endpoints': 3.4.2
- '@smithy/util-middleware': 4.2.14
- tslib: 2.8.1
-
- '@smithy/core@3.23.17':
- dependencies:
- '@smithy/protocol-http': 5.3.14
- '@smithy/types': 4.14.1
- '@smithy/url-parser': 4.2.14
- '@smithy/util-base64': 4.3.2
- '@smithy/util-body-length-browser': 4.2.2
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-stream': 4.5.25
- '@smithy/util-utf8': 4.2.2
- '@smithy/uuid': 1.1.2
- tslib: 2.8.1
-
- '@smithy/credential-provider-imds@4.2.14':
- dependencies:
- '@smithy/node-config-provider': 4.3.14
- '@smithy/property-provider': 4.2.14
- '@smithy/types': 4.14.1
- '@smithy/url-parser': 4.2.14
- tslib: 2.8.1
-
- '@smithy/eventstream-codec@4.2.14':
+ '@smithy/core@3.24.1':
dependencies:
'@aws-crypto/crc32': 5.2.0
'@smithy/types': 4.14.1
- '@smithy/util-hex-encoding': 4.2.2
tslib: 2.8.1
- '@smithy/eventstream-serde-browser@4.2.14':
+ '@smithy/credential-provider-imds@4.3.1':
dependencies:
- '@smithy/eventstream-serde-universal': 4.2.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@smithy/eventstream-serde-config-resolver@4.3.14':
+ '@smithy/eventstream-serde-browser@4.3.1':
dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/eventstream-serde-config-resolver@4.4.1':
+ dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/eventstream-serde-node@4.3.1':
+ dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/fetch-http-handler@5.4.1':
+ dependencies:
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@smithy/eventstream-serde-node@4.2.14':
+ '@smithy/hash-blob-browser@4.3.1':
dependencies:
- '@smithy/eventstream-serde-universal': 4.2.14
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/eventstream-serde-universal@4.2.14':
+ '@smithy/hash-node@4.3.1':
dependencies:
- '@smithy/eventstream-codec': 4.2.14
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/fetch-http-handler@5.3.17':
+ '@smithy/hash-stream-node@4.3.1':
dependencies:
- '@smithy/protocol-http': 5.3.14
- '@smithy/querystring-builder': 4.2.14
- '@smithy/types': 4.14.1
- '@smithy/util-base64': 4.3.2
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/hash-blob-browser@4.2.15':
+ '@smithy/invalid-dependency@4.3.1':
dependencies:
- '@smithy/chunked-blob-reader': 5.2.2
- '@smithy/chunked-blob-reader-native': 4.2.3
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/hash-node@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
- '@smithy/util-buffer-from': 4.2.2
- '@smithy/util-utf8': 4.2.2
- tslib: 2.8.1
-
- '@smithy/hash-stream-node@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
- '@smithy/util-utf8': 4.2.2
- tslib: 2.8.1
-
- '@smithy/invalid-dependency@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
'@smithy/is-array-buffer@2.2.0':
dependencies:
tslib: 2.8.1
- '@smithy/is-array-buffer@4.2.2':
+ '@smithy/md5-js@4.3.1':
dependencies:
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/md5-js@4.2.14':
+ '@smithy/middleware-content-length@4.3.1':
dependencies:
- '@smithy/types': 4.14.1
- '@smithy/util-utf8': 4.2.2
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/middleware-content-length@4.2.14':
+ '@smithy/middleware-endpoint@4.5.1':
dependencies:
- '@smithy/protocol-http': 5.3.14
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/middleware-retry@4.6.1':
+ dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/middleware-serde@4.3.1':
+ dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/middleware-stack@4.3.1':
+ dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/node-config-provider@4.4.1':
+ dependencies:
+ '@smithy/core': 3.24.1
+ tslib: 2.8.1
+
+ '@smithy/node-http-handler@4.7.1':
+ dependencies:
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@smithy/middleware-endpoint@4.4.32':
+ '@smithy/protocol-http@5.4.1':
dependencies:
- '@smithy/core': 3.23.17
- '@smithy/middleware-serde': 4.2.20
- '@smithy/node-config-provider': 4.3.14
- '@smithy/shared-ini-file-loader': 4.4.9
- '@smithy/types': 4.14.1
- '@smithy/url-parser': 4.2.14
- '@smithy/util-middleware': 4.2.14
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/middleware-retry@4.5.7':
+ '@smithy/signature-v4@5.4.1':
dependencies:
- '@smithy/core': 3.23.17
- '@smithy/node-config-provider': 4.3.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/service-error-classification': 4.3.1
- '@smithy/smithy-client': 4.12.13
- '@smithy/types': 4.14.1
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-retry': 4.3.6
- '@smithy/uuid': 1.1.2
- tslib: 2.8.1
-
- '@smithy/middleware-serde@4.2.20':
- dependencies:
- '@smithy/core': 3.23.17
- '@smithy/protocol-http': 5.3.14
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@smithy/middleware-stack@4.2.14':
+ '@smithy/smithy-client@4.13.1':
dependencies:
+ '@smithy/core': 3.24.1
'@smithy/types': 4.14.1
tslib: 2.8.1
- '@smithy/node-config-provider@4.3.14':
- dependencies:
- '@smithy/property-provider': 4.2.14
- '@smithy/shared-ini-file-loader': 4.4.9
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/node-http-handler@4.6.1':
- dependencies:
- '@smithy/protocol-http': 5.3.14
- '@smithy/querystring-builder': 4.2.14
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/property-provider@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/protocol-http@5.3.14':
- dependencies:
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/querystring-builder@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
- '@smithy/util-uri-escape': 4.2.2
- tslib: 2.8.1
-
- '@smithy/querystring-parser@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/service-error-classification@4.3.1':
- dependencies:
- '@smithy/types': 4.14.1
-
- '@smithy/shared-ini-file-loader@4.4.9':
- dependencies:
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/signature-v4@5.3.14':
- dependencies:
- '@smithy/is-array-buffer': 4.2.2
- '@smithy/protocol-http': 5.3.14
- '@smithy/types': 4.14.1
- '@smithy/util-hex-encoding': 4.2.2
- '@smithy/util-middleware': 4.2.14
- '@smithy/util-uri-escape': 4.2.2
- '@smithy/util-utf8': 4.2.2
- tslib: 2.8.1
-
- '@smithy/smithy-client@4.12.13':
- dependencies:
- '@smithy/core': 3.23.17
- '@smithy/middleware-endpoint': 4.4.32
- '@smithy/middleware-stack': 4.2.14
- '@smithy/protocol-http': 5.3.14
- '@smithy/types': 4.14.1
- '@smithy/util-stream': 4.5.25
- tslib: 2.8.1
-
'@smithy/types@4.14.1':
dependencies:
tslib: 2.8.1
- '@smithy/url-parser@4.2.14':
+ '@smithy/url-parser@4.3.1':
dependencies:
- '@smithy/querystring-parser': 4.2.14
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-base64@4.3.2':
+ '@smithy/util-base64@4.4.1':
dependencies:
- '@smithy/util-buffer-from': 4.2.2
- '@smithy/util-utf8': 4.2.2
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-body-length-browser@4.2.2':
+ '@smithy/util-body-length-browser@4.3.1':
dependencies:
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-body-length-node@4.2.3':
+ '@smithy/util-body-length-node@4.3.1':
dependencies:
+ '@smithy/core': 3.24.1
tslib: 2.8.1
'@smithy/util-buffer-from@2.2.0':
@@ -14754,66 +14483,34 @@ snapshots:
'@smithy/is-array-buffer': 2.2.0
tslib: 2.8.1
- '@smithy/util-buffer-from@4.2.2':
+ '@smithy/util-defaults-mode-browser@4.4.1':
dependencies:
- '@smithy/is-array-buffer': 4.2.2
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-config-provider@4.2.2':
+ '@smithy/util-defaults-mode-node@4.3.1':
dependencies:
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-defaults-mode-browser@4.3.49':
+ '@smithy/util-endpoints@3.5.1':
dependencies:
- '@smithy/property-provider': 4.2.14
- '@smithy/smithy-client': 4.12.13
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-defaults-mode-node@4.2.54':
+ '@smithy/util-middleware@4.3.1':
dependencies:
- '@smithy/config-resolver': 4.4.17
- '@smithy/credential-provider-imds': 4.2.14
- '@smithy/node-config-provider': 4.3.14
- '@smithy/property-provider': 4.2.14
- '@smithy/smithy-client': 4.12.13
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-endpoints@3.4.2':
+ '@smithy/util-retry@4.4.1':
dependencies:
- '@smithy/node-config-provider': 4.3.14
- '@smithy/types': 4.14.1
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-hex-encoding@4.2.2':
- dependencies:
- tslib: 2.8.1
-
- '@smithy/util-middleware@4.2.14':
- dependencies:
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/util-retry@4.3.6':
- dependencies:
- '@smithy/service-error-classification': 4.3.1
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/util-stream@4.5.25':
- dependencies:
- '@smithy/fetch-http-handler': 5.3.17
- '@smithy/node-http-handler': 4.6.1
- '@smithy/types': 4.14.1
- '@smithy/util-base64': 4.3.2
- '@smithy/util-buffer-from': 4.2.2
- '@smithy/util-hex-encoding': 4.2.2
- '@smithy/util-utf8': 4.2.2
- tslib: 2.8.1
-
- '@smithy/util-uri-escape@4.2.2':
+ '@smithy/util-stream@4.6.1':
dependencies:
+ '@smithy/core': 3.24.1
tslib: 2.8.1
'@smithy/util-utf8@2.3.0':
@@ -14821,18 +14518,14 @@ snapshots:
'@smithy/util-buffer-from': 2.2.0
tslib: 2.8.1
- '@smithy/util-utf8@4.2.2':
+ '@smithy/util-utf8@4.3.1':
dependencies:
- '@smithy/util-buffer-from': 4.2.2
+ '@smithy/core': 3.24.1
tslib: 2.8.1
- '@smithy/util-waiter@4.3.0':
- dependencies:
- '@smithy/types': 4.14.1
- tslib: 2.8.1
-
- '@smithy/uuid@1.1.2':
+ '@smithy/util-waiter@4.4.1':
dependencies:
+ '@smithy/core': 3.24.1
tslib: 2.8.1
'@socket.io/component-emitter@3.1.0': {}
@@ -16575,11 +16268,6 @@ snapshots:
chevrotain: 11.0.3
lodash-es: 4.18.1
- chevrotain-allstar@0.3.1(chevrotain@11.1.2):
- dependencies:
- chevrotain: 11.1.2
- lodash-es: 4.18.1
-
chevrotain@11.0.3:
dependencies:
'@chevrotain/cst-dts-gen': 11.0.3
@@ -16589,15 +16277,6 @@ snapshots:
'@chevrotain/utils': 11.0.3
lodash-es: 4.18.1
- chevrotain@11.1.2:
- dependencies:
- '@chevrotain/cst-dts-gen': 11.1.2
- '@chevrotain/gast': 11.1.2
- '@chevrotain/regexp-to-ast': 11.1.2
- '@chevrotain/types': 11.1.2
- '@chevrotain/utils': 11.1.2
- lodash-es: 4.18.1
-
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -17423,6 +17102,8 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
+ es-toolkit@1.46.1: {}
+
es6-promise-pool@2.5.0: {}
esbuild@0.27.4:
@@ -17712,7 +17393,7 @@ snapshots:
express-rate-limit@8.2.2(express@5.2.1):
dependencies:
express: 5.2.1
- ip-address: 10.1.0
+ ip-address: 10.1.1
express@5.2.1:
dependencies:
@@ -18112,7 +17793,7 @@ snapshots:
highlightjs-sap-abap@0.3.0: {}
- hono@4.12.14: {}
+ hono@4.12.18: {}
hookified@1.15.1: {}
@@ -18257,7 +17938,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- ip-address@10.1.0: {}
+ ip-address@10.1.1: {}
ipaddr.js@1.9.1: {}
@@ -19005,14 +18686,14 @@ snapshots:
klona@2.0.6: {}
- kysely-codegen@0.20.0(kysely@0.28.14)(pg@8.16.3)(typescript@5.9.3):
+ kysely-codegen@0.20.0(kysely@0.29.0)(pg@8.16.3)(typescript@5.9.3):
dependencies:
chalk: 4.1.2
cosmiconfig: 9.0.0(typescript@5.9.3)
diff: 8.0.3
dotenv: 17.2.4
dotenv-expand: 12.0.3
- kysely: 0.28.14
+ kysely: 0.29.0
micromatch: 4.0.8
minimist: 1.2.8
pluralize: 8.0.0
@@ -19027,13 +18708,13 @@ snapshots:
'@commander-js/extra-typings': 11.1.0(commander@11.1.0)
commander: 11.1.0
- kysely-postgres-js@3.0.0(kysely@0.28.14)(postgres@3.4.8):
+ kysely-postgres-js@3.0.0(kysely@0.29.0)(postgres@3.4.8):
dependencies:
- kysely: 0.28.14
+ kysely: 0.29.0
optionalDependencies:
postgres: 3.4.8
- kysely@0.28.14: {}
+ kysely@0.29.0: {}
langium@3.3.1:
dependencies:
@@ -19043,18 +18724,9 @@ snapshots:
vscode-languageserver-textdocument: 1.0.12
vscode-uri: 3.0.8
- langium@4.2.1:
- dependencies:
- chevrotain: 11.1.2
- chevrotain-allstar: 0.3.1(chevrotain@11.1.2)
- vscode-languageserver: 9.0.1
- vscode-languageserver-textdocument: 1.0.12
- vscode-uri: 3.1.0
-
- langsmith@0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0):
+ langsmith@0.7.0(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@6.2.0(ws@8.20.0)(zod@4.3.6))(ws@8.20.0):
dependencies:
p-queue: 6.6.2
- uuid: 10.0.0
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0)
@@ -19325,11 +18997,11 @@ snapshots:
merge-stream@2.0.0: {}
- mermaid@11.13.0:
+ mermaid@11.15.0:
dependencies:
'@braintree/sanitize-url': 7.1.2
'@iconify/utils': 3.1.0
- '@mermaid-js/parser': 1.0.1
+ '@mermaid-js/parser': 1.1.1
'@types/d3': 7.4.3
'@upsetjs/venn.js': 2.0.0
cytoscape: 3.33.1
@@ -19340,14 +19012,14 @@ snapshots:
dagre-d3-es: 7.0.14
dayjs: 1.11.19
dompurify: 3.4.1
+ es-toolkit: 1.46.1
katex: 0.16.40
khroma: 2.1.0
- lodash-es: 4.18.1
marked: 16.4.2
roughjs: 4.6.6
stylis: 4.3.6
ts-dedent: 2.2.0
- uuid: 11.1.0
+ uuid: 14.0.0
methods@1.1.2: {}
@@ -19470,11 +19142,11 @@ snapshots:
reflect-metadata: 0.2.2
rxjs: 7.8.2
- nestjs-kysely@3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.28.14)(reflect-metadata@0.2.2):
+ nestjs-kysely@3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.29.0)(reflect-metadata@0.2.2):
dependencies:
'@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
- kysely: 0.28.14
+ kysely: 0.29.0
reflect-metadata: 0.2.2
nestjs-pino@4.6.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(pino-http@11.0.0)(pino@10.1.0)(rxjs@7.8.2):
@@ -20214,18 +19886,18 @@ snapshots:
prosemirror-state: 1.4.3
prosemirror-transform: 1.10.4
- protobufjs@7.5.5:
+ protobufjs@7.5.6:
dependencies:
'@protobufjs/aspromise': 1.1.2
'@protobufjs/base64': 1.1.2
- '@protobufjs/codegen': 2.0.4
+ '@protobufjs/codegen': 2.0.5
'@protobufjs/eventemitter': 1.1.0
'@protobufjs/fetch': 1.1.0
'@protobufjs/float': 1.0.2
- '@protobufjs/inquire': 1.1.0
+ '@protobufjs/inquire': 1.1.1
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
- '@protobufjs/utf8': 1.1.0
+ '@protobufjs/utf8': 1.1.1
'@types/node': 25.5.0
long: 5.3.2
@@ -21607,8 +21279,6 @@ snapshots:
vscode-uri@3.0.8: {}
- vscode-uri@3.1.0: {}
-
w3c-keyname@2.2.8: {}
w3c-xmlserializer@5.0.0:
From 3b983a27f62f0341c449773ee8372c6124bfb95d Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 14 May 2026 03:01:55 +0100
Subject: [PATCH 04/12] sync
---
apps/server/package.json | 2 +-
apps/server/src/ee | 2 +-
pnpm-lock.yaml | 30 +++++++++++++++---------------
3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/apps/server/package.json b/apps/server/package.json
index f3e14770d..17d763fb8 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -81,7 +81,7 @@
"ioredis": "^5.10.1",
"js-tiktoken": "^1.0.21",
"jsonwebtoken": "^9.0.3",
- "kysely": "^0.29.0",
+ "kysely": "^0.28.17",
"kysely-migration-cli": "^0.4.2",
"kysely-postgres-js": "^3.0.0",
"ldapts": "^8.1.7",
diff --git a/apps/server/src/ee b/apps/server/src/ee
index 71844c097..b30e92f6a 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit 71844c097213ee3d861bf5b0e91eb6766b09d215
+Subproject commit b30e92f6a024b2b1106a8243e5a313122c4b0712
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 58423036b..e7980205a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -637,14 +637,14 @@ importers:
specifier: ^9.0.3
version: 9.0.3
kysely:
- specifier: ^0.29.0
- version: 0.29.0
+ specifier: ^0.28.17
+ version: 0.28.17
kysely-migration-cli:
specifier: ^0.4.2
version: 0.4.2
kysely-postgres-js:
specifier: ^3.0.0
- version: 3.0.0(kysely@0.29.0)(postgres@3.4.8)
+ version: 3.0.0(kysely@0.28.17)(postgres@3.4.8)
ldapts:
specifier: ^8.1.7
version: 8.1.7
@@ -668,7 +668,7 @@ importers:
version: 6.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
nestjs-kysely:
specifier: ^3.1.2
- version: 3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.29.0)(reflect-metadata@0.2.2)
+ version: 3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.28.17)(reflect-metadata@0.2.2)
nestjs-pino:
specifier: ^4.6.1
version: 4.6.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(pino-http@11.0.0)(pino@10.1.0)(rxjs@7.8.2)
@@ -819,7 +819,7 @@ importers:
version: 30.3.0(@types/node@25.5.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@25.5.0)(typescript@5.9.3))
kysely-codegen:
specifier: ^0.20.0
- version: 0.20.0(kysely@0.29.0)(pg@8.16.3)(typescript@5.9.3)
+ version: 0.20.0(kysely@0.28.17)(pg@8.16.3)(typescript@5.9.3)
prettier:
specifier: ^3.8.1
version: 3.8.1
@@ -7815,9 +7815,9 @@ packages:
postgres:
optional: true
- kysely@0.29.0:
- resolution: {integrity: sha512-LrQfPUeTW7MXbMvT62moEMnpMTuj9TO3lqjCeLKjM975PJ4Alrl/43f2tlDX7xOsNptKgH4LSNGwIbXwEkLg4g==}
- engines: {node: '>=22.0.0'}
+ kysely@0.28.17:
+ resolution: {integrity: sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==}
+ engines: {node: '>=20.0.0'}
langium@3.3.1:
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
@@ -18686,14 +18686,14 @@ snapshots:
klona@2.0.6: {}
- kysely-codegen@0.20.0(kysely@0.29.0)(pg@8.16.3)(typescript@5.9.3):
+ kysely-codegen@0.20.0(kysely@0.28.17)(pg@8.16.3)(typescript@5.9.3):
dependencies:
chalk: 4.1.2
cosmiconfig: 9.0.0(typescript@5.9.3)
diff: 8.0.3
dotenv: 17.2.4
dotenv-expand: 12.0.3
- kysely: 0.29.0
+ kysely: 0.28.17
micromatch: 4.0.8
minimist: 1.2.8
pluralize: 8.0.0
@@ -18708,13 +18708,13 @@ snapshots:
'@commander-js/extra-typings': 11.1.0(commander@11.1.0)
commander: 11.1.0
- kysely-postgres-js@3.0.0(kysely@0.29.0)(postgres@3.4.8):
+ kysely-postgres-js@3.0.0(kysely@0.28.17)(postgres@3.4.8):
dependencies:
- kysely: 0.29.0
+ kysely: 0.28.17
optionalDependencies:
postgres: 3.4.8
- kysely@0.29.0: {}
+ kysely@0.28.17: {}
langium@3.3.1:
dependencies:
@@ -19142,11 +19142,11 @@ snapshots:
reflect-metadata: 0.2.2
rxjs: 7.8.2
- nestjs-kysely@3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.29.0)(reflect-metadata@0.2.2):
+ nestjs-kysely@3.1.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(kysely@0.28.17)(reflect-metadata@0.2.2):
dependencies:
'@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)
- kysely: 0.29.0
+ kysely: 0.28.17
reflect-metadata: 0.2.2
nestjs-pino@4.6.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(pino-http@11.0.0)(pino@10.1.0)(rxjs@7.8.2):
From f4af4c3fc0957f7cc7005182a09f41ccba0ec032 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 14 May 2026 03:48:13 +0100
Subject: [PATCH 05/12] feat(editor): add page break node (#2202)
---
.../public/locales/en-US/translation.json | 2 +
.../fixed-toolbar/groups/block-type-group.tsx | 7 +++
.../components/slash-menu/menu-items.ts | 9 +++
.../features/editor/extensions/extensions.ts | 2 +
.../src/features/editor/styles/index.css | 1 +
.../src/features/editor/styles/page-break.css | 50 ++++++++++++++++
.../src/collaboration/collaboration.util.ts | 2 +
packages/editor-ext/src/index.ts | 1 +
.../editor-ext/src/lib/page-break/index.ts | 1 +
.../src/lib/page-break/page-break.ts | 60 +++++++++++++++++++
10 files changed, 135 insertions(+)
create mode 100644 apps/client/src/features/editor/styles/page-break.css
create mode 100644 packages/editor-ext/src/lib/page-break/index.ts
create mode 100644 packages/editor-ext/src/lib/page-break/page-break.ts
diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index 268d696c8..e85f2af23 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -361,6 +361,8 @@
"Create block quote.": "Create block quote.",
"Insert code snippet.": "Insert code snippet.",
"Insert horizontal rule divider": "Insert horizontal rule divider",
+ "Page break": "Page break",
+ "Insert a page break for printing.": "Insert a page break for printing.",
"Upload any image from your device.": "Upload any image from your device.",
"Upload any video from your device.": "Upload any video from your device.",
"Upload any audio from your device.": "Upload any audio from your device.",
diff --git a/apps/client/src/features/editor/components/fixed-toolbar/groups/block-type-group.tsx b/apps/client/src/features/editor/components/fixed-toolbar/groups/block-type-group.tsx
index 3edb28eda..69911f7cb 100644
--- a/apps/client/src/features/editor/components/fixed-toolbar/groups/block-type-group.tsx
+++ b/apps/client/src/features/editor/components/fixed-toolbar/groups/block-type-group.tsx
@@ -10,6 +10,7 @@ import {
IconH2,
IconH3,
IconMenu4,
+ IconPageBreak,
IconTypography,
} from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
@@ -102,6 +103,12 @@ export const BlockTypeGroup: FC = ({ editor }) => {
>
{t("Divider")}
+ }
+ onClick={() => editor.chain().focus().setPageBreak().run()}
+ >
+ {t("Page break")}
+
);
diff --git a/apps/client/src/features/editor/components/slash-menu/menu-items.ts b/apps/client/src/features/editor/components/slash-menu/menu-items.ts
index 4a0532fe3..cddddc35f 100644
--- a/apps/client/src/features/editor/components/slash-menu/menu-items.ts
+++ b/apps/client/src/features/editor/components/slash-menu/menu-items.ts
@@ -19,6 +19,7 @@ import {
IconTable,
IconTypography,
IconMenu4,
+ IconPageBreak,
IconCalendar,
IconAppWindow,
IconSitemap,
@@ -164,6 +165,14 @@ const CommandGroups: SlashMenuGroupedItemsType = {
command: ({ editor, range }: CommandProps) =>
editor.chain().focus().deleteRange(range).setHorizontalRule().run(),
},
+ {
+ title: "Page break",
+ description: "Insert a page break for printing.",
+ searchTerms: ["page", "break", "pagebreak", "print"],
+ icon: IconPageBreak,
+ command: ({ editor, range }: CommandProps) =>
+ editor.chain().focus().deleteRange(range).setPageBreak().run(),
+ },
{
title: "Image",
description: "Upload any image from your device.",
diff --git a/apps/client/src/features/editor/extensions/extensions.ts b/apps/client/src/features/editor/extensions/extensions.ts
index 1f09bef37..91411daef 100644
--- a/apps/client/src/features/editor/extensions/extensions.ts
+++ b/apps/client/src/features/editor/extensions/extensions.ts
@@ -42,6 +42,7 @@ import {
Excalidraw,
Embed,
TiptapPdf,
+ PageBreak,
SearchAndReplace,
Mention,
TableDndExtension,
@@ -366,6 +367,7 @@ export const mainExtensions = [
TiptapPdf.configure({
view: PdfView,
}),
+ PageBreak,
Subpages.configure({
view: SubpagesView,
}),
diff --git a/apps/client/src/features/editor/styles/index.css b/apps/client/src/features/editor/styles/index.css
index 7abfe1086..52d9268e1 100644
--- a/apps/client/src/features/editor/styles/index.css
+++ b/apps/client/src/features/editor/styles/index.css
@@ -9,6 +9,7 @@
@import "./media.css";
@import "./code.css";
@import "./print.css";
+@import "./page-break.css";
@import "./find.css";
@import "./mention.css";
@import "./ordered-list.css";
diff --git a/apps/client/src/features/editor/styles/page-break.css b/apps/client/src/features/editor/styles/page-break.css
new file mode 100644
index 000000000..6dc97c738
--- /dev/null
+++ b/apps/client/src/features/editor/styles/page-break.css
@@ -0,0 +1,50 @@
+.ProseMirror .page-break {
+ position: relative;
+ margin: 1.5rem 0;
+ border-top: 1px dashed var(--mantine-color-default-border);
+ height: 0;
+ user-select: none;
+}
+
+.ProseMirror[contenteditable="false"] .page-break {
+ margin: 0;
+ border: none;
+ height: 0;
+}
+
+.ProseMirror[contenteditable="false"] .page-break::after {
+ content: none;
+}
+
+.ProseMirror .page-break::after {
+ content: "Page break";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ padding: 0 0.5rem;
+ background: var(--mantine-color-body);
+ color: var(--mantine-color-dimmed);
+ font-size: 0.75rem;
+ line-height: 1;
+ letter-spacing: 0.02em;
+ text-transform: uppercase;
+}
+
+.ProseMirror .page-break.ProseMirror-selectednode {
+ border-top-color: var(--mantine-primary-color-filled);
+}
+
+@media print {
+ .ProseMirror .page-break {
+ break-before: always;
+ page-break-before: always;
+ visibility: hidden;
+ border: none;
+ margin: 0;
+ }
+
+ .ProseMirror .page-break::after {
+ content: none;
+ }
+}
diff --git a/apps/server/src/collaboration/collaboration.util.ts b/apps/server/src/collaboration/collaboration.util.ts
index 5787e2e3a..554aa43bd 100644
--- a/apps/server/src/collaboration/collaboration.util.ts
+++ b/apps/server/src/collaboration/collaboration.util.ts
@@ -26,6 +26,7 @@ import {
TiptapVideo,
TiptapAudio,
TiptapPdf,
+ PageBreak,
TrailingNode,
Attachment,
Drawio,
@@ -94,6 +95,7 @@ export const tiptapExtensions = [
TiptapVideo,
TiptapAudio,
TiptapPdf,
+ PageBreak,
Callout,
Attachment,
CustomCodeBlock,
diff --git a/packages/editor-ext/src/index.ts b/packages/editor-ext/src/index.ts
index 354b1a617..003d22886 100644
--- a/packages/editor-ext/src/index.ts
+++ b/packages/editor-ext/src/index.ts
@@ -31,5 +31,6 @@ export * from "./lib/recreate-transform";
export * from "./lib/columns";
export * from "./lib/status";
export * from "./lib/pdf";
+export * from "./lib/page-break";
export * from "./lib/resizable-nodeview";
diff --git a/packages/editor-ext/src/lib/page-break/index.ts b/packages/editor-ext/src/lib/page-break/index.ts
new file mode 100644
index 000000000..701b20b78
--- /dev/null
+++ b/packages/editor-ext/src/lib/page-break/index.ts
@@ -0,0 +1 @@
+export * from "./page-break";
diff --git a/packages/editor-ext/src/lib/page-break/page-break.ts b/packages/editor-ext/src/lib/page-break/page-break.ts
new file mode 100644
index 000000000..f8991b266
--- /dev/null
+++ b/packages/editor-ext/src/lib/page-break/page-break.ts
@@ -0,0 +1,60 @@
+import { mergeAttributes, Node } from "@tiptap/core";
+
+export interface PageBreakOptions {
+ HTMLAttributes: Record;
+}
+
+declare module "@tiptap/core" {
+ interface Commands {
+ pageBreak: {
+ setPageBreak: () => ReturnType;
+ };
+ }
+}
+
+export const PageBreak = Node.create