diff --git a/.github/workflows/cue.yml b/.github/workflows/cue.yml index 1751e2c3..acb82efe 100644 --- a/.github/workflows/cue.yml +++ b/.github/workflows/cue.yml @@ -44,7 +44,7 @@ jobs: with: enable_go: true enable_cue: true - cue_version: 'v0.15.4' + cue_version: 'v0.16.1' - name: Login to Central Registry # to allow publishing the module run: cue login --token=${{ secrets.CUE_REG_TOKEN }} - name: Publish the module diff --git a/client/package.json b/client/package.json index 14c11447..3b9eec7c 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@perses-dev/client", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "description": "Functions as an API client or Data fetching Layer for interacting with a backend service", "license": "Apache-2.0", "homepage": "https://github.com/perses/perses/blob/main/README.md", diff --git a/components/.ladle/components.tsx b/components/.ladle/components.tsx new file mode 100644 index 00000000..a79bf60f --- /dev/null +++ b/components/.ladle/components.tsx @@ -0,0 +1,30 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { GlobalProvider } from '@ladle/react'; +import '@perses-dev/design-tokens/css'; + +import { ComponentsProvider } from '../src/next/contexts/ComponentsProvider'; +import { ThemeModeProvider } from '../src/next/contexts/ThemeModeProvider'; +import { defaultComponents, defaultIcons } from '../src/next/primitives/defaults'; + +import '../src/next/css/index.css'; +import './theme-mode.css'; + +export const Provider: GlobalProvider = ({ children, globalState }) => ( + + + {children} + + +); diff --git a/components/.ladle/config.mjs b/components/.ladle/config.mjs new file mode 100644 index 00000000..a15574f7 --- /dev/null +++ b/components/.ladle/config.mjs @@ -0,0 +1,17 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** @type {import('@ladle/react').UserConfig} */ +export default { + stories: 'src/next/**/*.stories.tsx', +}; diff --git a/components/.ladle/theme-mode.css b/components/.ladle/theme-mode.css new file mode 100644 index 00000000..0017670e --- /dev/null +++ b/components/.ladle/theme-mode.css @@ -0,0 +1,31 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +[data-perses-mode='dark'] { + min-height: 100vh; + background: var(--perses-bg-default); + color: var(--perses-text-primary); +} + +[data-perses-mode='dark'] h1, +[data-perses-mode='dark'] h2, +[data-perses-mode='dark'] h3, +[data-perses-mode='dark'] h4, +[data-perses-mode='dark'] h5, +[data-perses-mode='dark'] h6, +[data-perses-mode='dark'] p, +[data-perses-mode='dark'] label { + color: var(--perses-text-primary); +} diff --git a/components/package.json b/components/package.json index b8afeb75..98aec595 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "@perses-dev/components", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "description": "Common UI components used across Perses features", "license": "Apache-2.0", "homepage": "https://github.com/perses/perses/blob/main/README.md", @@ -15,11 +15,37 @@ "module": "dist/index.js", "main": "dist/index.js", "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/cjs/index.js" + }, + "./next": { + "types": "./dist/next/index.d.ts", + "import": "./dist/next/index.js", + "require": "./dist/cjs/next/index.js" + }, + "./next/primitives": { + "types": "./dist/next/primitives/index.d.ts", + "import": "./dist/next/primitives/index.js", + "require": "./dist/cjs/next/primitives/index.js" + }, + "./next/css": "./dist/next/css/index.css", + "./next/primitives/defaults": { + "types": "./dist/next/primitives/defaults.d.ts", + "import": "./dist/next/primitives/defaults.js", + "require": "./dist/cjs/next/primitives/defaults.js" + } + }, "scripts": { "clean": "rimraf dist/", "build": "concurrently \"npm:build:*\"", "build:esm": "swc ./src -d dist --strip-leading-paths --config-file ../.swcrc", "build:types": "tsc --project tsconfig.build.json", + "build:next-css": "copyfiles -u 1 \"src/next/**/*.css\" dist", + "ladle": "ladle serve", + "ladle:build": "ladle build", "type-check": "tsc --noEmit", "start": "concurrently -P \"npm:build:* -- {*}\" -- --watch", "test": "cross-env TZ=UTC vitest run", @@ -30,16 +56,18 @@ "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.4.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3", + "@base-ui/react": "^1.0.0", "@codemirror/lang-json": "^6.0.1", "@date-fns/tz": "^1.4.1", "@fontsource/inter": "^5.0.0", "@mui/x-date-pickers": "^7.23.1", "@perses-dev/spec": "0.3.0-beta.8", - "@perses-dev/client": "0.55.0-beta.8", + "@perses-dev/client": "0.55.0-beta.11", "numbro": "^2.3.6", "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-table": "^8.20.5", "@uiw/react-codemirror": "^4.19.1", + "clsx": "^2.1.1", "date-fns": "^4.1.0", "echarts": "5.5.0", "immer": "^10.1.1", @@ -47,21 +75,28 @@ "mathjs": "^10.6.4", "mdi-material-ui": "^7.9.2", "notistack": "^3.0.2", + "numbro": "^2.3.6", "react-colorful": "^5.6.1", "react-error-boundary": "^3.1.4", "react-virtuoso": "^4.12.2" }, "devDependencies": { - "@types/lodash": "^4.17.20" + "@ladle/react": "^4.0.0", + "@types/lodash": "^4.17.20", + "copyfiles": "^2.4.1" }, "peerDependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^6.1.10", + "@perses-dev/design-tokens": "^0.54.0", "lodash": "^4.17.21", - "react": "^18.3.0", - "react-dom": "^18.3.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" }, + "sideEffects": [ + "*.css" + ], "files": [ "dist" ] diff --git a/components/src/ExemplarMetadata/ExemplarMetadataTooltip.test.tsx b/components/src/ExemplarMetadata/ExemplarMetadataTooltip.test.tsx new file mode 100644 index 00000000..c99ff20c --- /dev/null +++ b/components/src/ExemplarMetadata/ExemplarMetadataTooltip.test.tsx @@ -0,0 +1,96 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Exemplar, Labels } from '@perses-dev/spec'; +import { fireEvent, render, screen } from '@testing-library/react'; + +import type { CursorCoordinates } from '../TimeSeriesTooltip/tooltip-model'; +import { ExemplarMetadataTooltip } from './ExemplarMetadataTooltip'; + +const seriesLabels: Labels = { + __name__: 'http_requests_total', + job: 'demo', +}; + +const exemplar: Exemplar = { + labels: { trace_id: 'abc-123', span_id: 'def-456' }, + value: 42, + timestamp: 1700000000000, +}; + +const pinnedPos: CursorCoordinates = { + page: { x: 10, y: 10 }, + client: { x: 10, y: 10 }, + plotCanvas: { x: 10, y: 10 }, + target: null, +}; + +describe('ExemplarMetadataTooltip', () => { + const onUnpinClick = vi.fn(); + + const renderComponent = (props?: Partial>): void => { + render( + , + ); + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders exemplar labels, series labels, value and date-time header when pinned', () => { + renderComponent(); + expect(screen.getByText('Nov 14, 2023 -')).toBeVisible(); + expect(screen.getByText('22:13:20')).toBeVisible(); + expect(screen.getByText('Exemplar labels')).toBeVisible(); + expect(screen.getByText('trace_id:')).toBeVisible(); + expect(screen.getByText('abc-123')).toBeVisible(); + expect(screen.getByText('Series labels')).toBeVisible(); + expect(screen.getByText('http_requests_total')).toBeVisible(); + expect(screen.getByText('42')).toBeVisible(); + }); + + it('renders while following the mouse when not pinned', () => { + renderComponent({ pinnedPos: null }); + expect(screen.queryByText('Exemplar labels')).not.toBeInTheDocument(); + fireEvent.mouseMove(window, { pageX: 10, pageY: 10, clientX: 10, clientY: 10 }); + expect(screen.getByText('Exemplar labels')).toBeVisible(); + }); + + it('shows the unpin affordance and calls onUnpinClick when the pin icon is clicked', () => { + renderComponent(); + expect(screen.getByText('Click chart to unpin')).toBeVisible(); + fireEvent.click(screen.getByTestId('PinIcon')); + expect(onUnpinClick).toHaveBeenCalledTimes(1); + }); + + it('does not render a series labels section when seriesLabels is undefined', () => { + renderComponent({ seriesLabels: undefined }); + expect(screen.queryByText('Series labels')).not.toBeInTheDocument(); + expect(screen.getByText('Exemplar labels')).toBeVisible(); + }); + + it('does not render a divider for empty label sets', () => { + render(); + expect(screen.queryByText('Series labels')).not.toBeInTheDocument(); + expect(screen.queryByText('Exemplar labels')).not.toBeInTheDocument(); + expect(screen.getByText('Value')).toBeVisible(); + // Only the header divider remains: no separator is left for the hidden label sections. + expect(document.body.querySelectorAll('hr')).toHaveLength(1); + }); +}); diff --git a/components/src/ExemplarMetadata/ExemplarMetadataTooltip.tsx b/components/src/ExemplarMetadata/ExemplarMetadataTooltip.tsx new file mode 100644 index 00000000..bff6aff3 --- /dev/null +++ b/components/src/ExemplarMetadata/ExemplarMetadataTooltip.tsx @@ -0,0 +1,199 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Box, Divider, IconButton, Portal, Stack, Typography } from '@mui/material'; +import type { Exemplar, Labels } from '@perses-dev/spec'; +import Pin from 'mdi-material-ui/Pin'; +import PinOutline from 'mdi-material-ui/PinOutline'; +import type { ReactElement } from 'react'; +import { Fragment } from 'react'; +import useResizeObserver from 'use-resize-observer'; + +import { useTimeZone } from '../context/TimeZoneProvider'; +import type { FormatOptions } from '../model/units'; +import { formatValue } from '../model/units'; +import { + assembleTransform, + getTooltipStyles, + PIN_TOOLTIP_HELP_TEXT, + TOOLTIP_BG_COLOR_FALLBACK, + TOOLTIP_MAX_WIDTH, + UNPIN_TOOLTIP_HELP_TEXT, + useMousePosition, +} from '../TimeSeriesTooltip'; +import type { CursorCoordinates } from '../TimeSeriesTooltip/tooltip-model'; + +export interface ExemplarMetadataTooltipProps { + exemplar: Exemplar; + seriesLabels?: Labels; + /** + * CSS selector of the element the tooltip should be portaled into (e.g. `#dashboard`). + * Passed as-is to `document.querySelector`, so it must be a selector and not a bare element id. + */ + containerId?: string; + format?: FormatOptions; + /** + * Position where the tooltip has been pinned, or null when it follows the mouse. + */ + pinnedPos: CursorCoordinates | null; + enablePinning?: boolean; + onUnpinClick?: () => void; +} + +/** + * Tooltip showing an exemplar's metadata (series labels, exemplar labels, value and timestamp). + * Follows the mouse while hovering an exemplar marker and can be pinned in place, the same way + * the annotation tooltip works. + */ +export function ExemplarMetadataTooltip({ + exemplar, + seriesLabels, + containerId, + format, + pinnedPos, + enablePinning = true, + onUnpinClick, +}: ExemplarMetadataTooltipProps): ReactElement | null { + const { formatWithUserTimeZone } = useTimeZone(); + const mousePos = useMousePosition(); + const { height, width, ref: tooltipRef } = useResizeObserver(); + + const isPinned = pinnedPos !== null; + if (!isPinned && mousePos === null) return null; + + const containerElement = containerId ? document.querySelector(containerId) : undefined; + const maxHeight = containerElement ? containerElement.getBoundingClientRect().height : undefined; + // Fall back to the pinned position: a pinned tooltip can render before any mousemove happened. + const transform = assembleTransform(mousePos ?? pinnedPos, pinnedPos, height ?? 0, width ?? 0, containerElement); + + const { labels, value, timestamp } = exemplar; + const formattedValue = formatValue(value, format); + const date = new Date(timestamp); + const formattedDate = formatWithUserTimeZone(date, 'MMM dd, yyyy - '); + const formattedTime = formatWithUserTimeZone(date, 'HH:mm:ss'); + + // Only sections with content take part in the layout, so no divider is left dangling + // when a label set is empty. + const sections: Array<{ key: string; content: ReactElement }> = []; + if (seriesLabels && Object.keys(seriesLabels).length > 0) { + sections.push({ key: 'series-labels', content: }); + } + if (Object.keys(labels).length > 0) { + sections.push({ key: 'exemplar-labels', content: }); + } + sections.push({ + key: 'value', + content: ( + + + Value + + {formattedValue} + + ), + }); + + return ( + + getTooltipStyles(theme, pinnedPos, maxHeight)} style={{ transform }}> + + ({ + width: '100%', + maxWidth: TOOLTIP_MAX_WIDTH, + padding: theme.spacing(1.5, 2, 0.5, 2), + backgroundColor: theme.palette.designSystem?.grey[800] ?? TOOLTIP_BG_COLOR_FALLBACK, + position: 'sticky', + top: 0, + left: 0, + })} + > + + + ({ + color: theme.palette.common.white, + })} + > + {formattedDate} + + + {formattedTime} + + + {enablePinning && ( + + + {isPinned ? UNPIN_TOOLTIP_HELP_TEXT : PIN_TOOLTIP_HELP_TEXT} + + {isPinned ? ( + { + if (onUnpinClick !== undefined) onUnpinClick(); + }} + sx={{ padding: 0, color: 'inherit' }} + > + + + ) : ( + + )} + + )} + + ({ width: '100%', borderColor: theme.palette.grey['500'] })} /> + + ({ padding: theme.spacing(0.5, 2, 1.5, 2) })}> + {sections.map((section, index) => ( + + {index > 0 && ({ borderColor: theme.palette.grey['500'] })} />} + {section.content} + + ))} + + + + + ); +} + +function LabelGrid({ title, labels }: { title: string; labels: Labels }): ReactElement { + const entries = Object.entries(labels); + return ( + + + {title} + + + {entries.map(([labelName, labelValue]) => ( + + {labelName}: + + {labelValue} + + + ))} + + + ); +} diff --git a/components/src/ExemplarMetadata/index.ts b/components/src/ExemplarMetadata/index.ts new file mode 100644 index 00000000..f9b58916 --- /dev/null +++ b/components/src/ExemplarMetadata/index.ts @@ -0,0 +1,13 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './ExemplarMetadataTooltip'; diff --git a/components/src/TransformsEditor/TransformEditor.tsx b/components/src/TransformsEditor/TransformEditor.tsx index 0fb14752..5c3523eb 100644 --- a/components/src/TransformsEditor/TransformEditor.tsx +++ b/components/src/TransformsEditor/TransformEditor.tsx @@ -29,6 +29,7 @@ import type { MergeColumnsTransform, MergeIndexedColumnsTransform, MergeSeriesTransform, + PivotByLabelTransform, Transform, } from '../model'; @@ -245,11 +246,69 @@ export function TransformEditor({ value, onChange, ...props }: TransformEditorPr Series will be merged by their labels + + + Pivot by label + Time × label matrix (rows = time, columns = label values) + + {value.kind === 'JoinByColumnValue' && } {value.kind === 'MergeColumns' && } {value.kind === 'MergeIndexedColumns' && } {value.kind === 'MergeSeries' && } + {value.kind === 'PivotByLabel' && } + + ); +} + +function PivotByLabelTransformEditor({ + value, + onChange, +}: TransformSpecEditorProps): ReactElement { + return ( + + onChange({ ...value, spec: { ...value.spec, columnLabel: e.target.value } })} + helperText="Label that becomes dynamic column headers (e.g. farm_short)" + /> + onChange({ ...value, spec: { ...value.spec, rowField: e.target.value } })} + helperText="Field used for row identity (default: timestamp)" + /> + onChange({ ...value, spec: { ...value.spec, valueField: e.target.value } })} + /> + + onChange({ + ...value, + spec: { ...value.spec, rowColumnName: e.target.value || undefined }, + }) + } + helperText="Optional display name for the row column (default: row field)" + /> + onChange({ ...value, spec: { ...value.spec, disabled: checked } })} + /> + } + label="Disabled" + /> ); } diff --git a/components/src/TransformsEditor/TransformsEditor.test.tsx b/components/src/TransformsEditor/TransformsEditor.test.tsx index 0b846675..95e17c7b 100644 --- a/components/src/TransformsEditor/TransformsEditor.test.tsx +++ b/components/src/TransformsEditor/TransformsEditor.test.tsx @@ -49,4 +49,37 @@ describe('TransformsEditor', () => { vi.advanceTimersByTime(500); expect(onChange).toHaveBeenCalledWith([{ kind: 'MergeIndexedColumns', spec: { column: 'MySuperName' } }]); }); + + it('edits PivotByLabel column label field', () => { + const onChange = vi.fn(); + const initial: Transform[] = [ + { + kind: 'PivotByLabel', + spec: { + columnLabel: 'farm_short', + rowField: 'timestamp', + valueField: 'value', + rowColumnName: 'Time', + }, + }, + ]; + renderTableColumnsEditor(initial, onChange); + + fireEvent.click(screen.getByTestId('transform-toggle#0')); + + const columnLabel = screen.getByLabelText(/Column label/i); + fireEvent.change(columnLabel, { target: { value: 'stack' } }); + vi.advanceTimersByTime(500); + expect(onChange).toHaveBeenCalledWith([ + { + kind: 'PivotByLabel', + spec: { + columnLabel: 'stack', + rowField: 'timestamp', + valueField: 'value', + rowColumnName: 'Time', + }, + }, + ]); + }); }); diff --git a/components/src/index.ts b/components/src/index.ts index 1c3199b3..6c9f7ac6 100644 --- a/components/src/index.ts +++ b/components/src/index.ts @@ -16,6 +16,7 @@ export * from './ColorPicker'; export * from './ContentWithLegend'; export * from './controls'; export * from './Dialog'; +export * from './ExemplarMetadata'; export * from './DensitySelector'; export * from './DragAndDrop'; export * from './Drawer'; diff --git a/components/src/model/transforms.ts b/components/src/model/transforms.ts index 85733448..25ec6687 100644 --- a/components/src/model/transforms.ts +++ b/components/src/model/transforms.ts @@ -51,12 +51,34 @@ export interface MergeSeriesTransform { spec: TransformCommonSpec; } +/** + * Pivot multi-series table rows into a time × label matrix + * (Grafana groupingToMatrix parity). + * + * Example: columnLabel=farm_short, rowField=timestamp + * → one row per timestamp, one column per farm_short value. + */ +export interface PivotByLabelTransform { + kind: 'PivotByLabel'; + spec: TransformCommonSpec & { + /** Label/column that becomes dynamic column headers (e.g. farm_short). */ + columnLabel: string; + /** Field for row identity (default: timestamp). */ + rowField?: string; + /** Value field name (default: value). */ + valueField?: string; + /** Name of the row column after pivot (default: rowField). */ + rowColumnName?: string; + }; +} + export type Transform = | JoinByColumnValueTransform | MergeColumnsTransform | MergeIndexedColumnsTransform | MergeSeriesTransform - | ExtractColumnFieldsTransform; + | ExtractColumnFieldsTransform + | PivotByLabelTransform; // Can be moved somewhere else export const TRANSFORM_TEXT = { @@ -65,4 +87,5 @@ export const TRANSFORM_TEXT = { MergeIndexedColumns: 'Merge indexed columns', MergeSeries: 'Merge series', ExtractColumnFields: 'Extract column fields', + PivotByLabel: 'Pivot by label', }; diff --git a/components/src/next/contexts/ComponentsContext.ts b/components/src/next/contexts/ComponentsContext.ts new file mode 100644 index 00000000..0a397d38 --- /dev/null +++ b/components/src/next/contexts/ComponentsContext.ts @@ -0,0 +1,83 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { createContext } from 'react'; +import type { ComponentType, ReactNode, SVGProps } from 'react'; + +import type { AlertProps } from '../primitives/Alert'; +import type { ButtonProps } from '../primitives/Button'; +import type { SpinnerProps } from '../primitives/Spinner'; + +export interface PersesComponents { + Button: ComponentType; + Alert: ComponentType; + Spinner: ComponentType; +} + +export interface PersesIcons { + Error: ComponentType>; + Info: ComponentType>; + Success: ComponentType>; + Warning: ComponentType>; +} + +export interface ComponentsContextValue { + components: PersesComponents; + icons: PersesIcons; +} + +export interface ComponentsProviderProps { + /** + * Map of components that will be loaded when using the `useComponents` hook. + * + * @example + * // Use the default components + * import { defaultComponents } from '@perses-dev/components/next/primitives/defaults'; + * + * const components: PersesComponents = defaultComponents; + * + * @example + * // Override one component, spreading over the defaults + * import { defaultComponents } from '@perses-dev/components/next/primitives/defaults'; + * + * const components: PersesComponents = { ...defaultComponents, Button: MyButton }; + * + * @example + * // Provide only custom components + * const components: PersesComponents = { Alert: MyAlert, Button: MyButton, Spinner: MySpinner }; + */ + components: PersesComponents; + /** + * Map of icons that will be loaded when using the `useComponents` hook. + * + * @example + * // Use the default icons + * import { defaultIcons } from '@perses-dev/components/next/primitives/defaults'; + * + * const icons: PersesIcons = defaultIcons; + * + * @example + * // Override one icon, spreading over the defaults + * import { defaultIcons } from '@perses-dev/components/next/primitives/defaults'; + * + * const icons: PersesIcons = { ...defaultIcons, Error: MyErrorIcon }; + * + * @example + * // Provide all custom icons + * const icons: PersesIcons = { Error: MyErrorIcon, Info: MyInfoIcon, Success: MySuccessIcon, Warning: MyWarningIcon }; + */ + icons: PersesIcons; + children?: ReactNode; +} + +export const ComponentsContext = createContext(undefined); diff --git a/components/src/next/contexts/ComponentsProvider.stories.tsx b/components/src/next/contexts/ComponentsProvider.stories.tsx new file mode 100644 index 00000000..6ce11f57 --- /dev/null +++ b/components/src/next/contexts/ComponentsProvider.stories.tsx @@ -0,0 +1,91 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Story } from '@ladle/react'; +import { forwardRef } from 'react'; +import type { ReactElement } from 'react'; + +import type { ButtonProps } from '../primitives'; +import { defaultComponents, defaultIcons } from '../primitives/defaults'; +import { PatternFlyV6Alert, Pf6AlertDemo } from '../stories/pf6/PatternFlyV6Alert'; +import { ComponentsProvider, useComponents } from './ComponentsProvider'; + +const SIZE_PADDING: Record = { sm: '4px 8px', lg: '12px 24px', md: '8px 16px' }; + +const CustomButton = forwardRef(function CustomButton( + { children, variant = 'solid', size = 'md', loading, disabled, ...rest }, + ref, +) { + return ( + + ); +}); + +function CustomButtonDemo(): ReactElement { + const { components } = useComponents(); + + return ( +
+

Custom Button (via ComponentsProvider)

+

+ A minimal custom Button injected through ComponentsProvider, replacing the default. +

+
+ + Solid + + + Outline + + + Ghost + + + Disabled + +
+
+ ); +} + +export const CustomButtonInjection: Story = () => ( + + + +); +CustomButtonInjection.storyName = 'Button customization'; + +export const PatternFlyAlertInjection: Story = () => ( + + + +); +PatternFlyAlertInjection.storyName = 'Alert customization'; diff --git a/components/src/next/contexts/ComponentsProvider.test.tsx b/components/src/next/contexts/ComponentsProvider.test.tsx new file mode 100644 index 00000000..3539c47f --- /dev/null +++ b/components/src/next/contexts/ComponentsProvider.test.tsx @@ -0,0 +1,239 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render, screen } from '@testing-library/react'; +import { forwardRef } from 'react'; +import type { FC, ReactElement, SVGProps } from 'react'; + +import type { ButtonProps } from '../primitives'; +import { defaultComponents, defaultIcons } from '../primitives/defaults'; +import { ComponentsProvider, useComponents } from './ComponentsProvider'; +import type { ComponentsContextValue, PersesComponents } from './ComponentsProvider'; + +const components = defaultComponents; +const icons = defaultIcons; + +describe('ComponentsProvider', () => { + it('renders components passed in via props', () => { + function TestConsumer(): ReactElement { + const { + components: { Button, Alert }, + } = useComponents(); + return ( +
+ + Default Alert +
+ ); + } + + render( + + + , + ); + + expect(screen.getByText('Default Button')).toBeInTheDocument(); + expect(screen.getByText('Default Alert')).toBeInTheDocument(); + }); + + it('supports overriding an individual component by spreading the defaults', () => { + const CustomButton = forwardRef(function CustomButton({ children }, ref) { + return ( + + ); + }); + + function TestConsumer(): ReactElement { + const { components } = useComponents(); + return ( +
+ My Button + My Alert +
+ ); + } + + render( + + + , + ); + + expect(screen.getByTestId('custom-button')).toBeInTheDocument(); + expect(screen.getByText('My Alert')).toBeInTheDocument(); + }); + + it('throws when useComponents is called outside provider', () => { + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + function BadConsumer(): null { + useComponents(); + return null; + } + + expect(() => render()).toThrow('No ComponentsContext found. Did you forget a ComponentsProvider?'); + + consoleSpy.mockRestore(); + }); + + it('supports icon overrides independently of component overrides', () => { + const CustomErrorIcon: FC> = (props) => ( + + + + ); + + function TestConsumer(): ReactElement { + const { icons, components } = useComponents(); + return ( +
+ + Still Default +
+ ); + } + + render( + + + , + ); + + expect(screen.getByTestId('rendered-error')).toBeInTheDocument(); + expect(screen.getByText('Still Default')).toBeInTheDocument(); + }); + + it('memoizes context value when props are stable', () => { + const values: ComponentsContextValue[] = []; + + function Collector(): null { + values.push(useComponents()); + return null; + } + + const { rerender } = render( + + + , + ); + + rerender( + + + , + ); + + expect(values).toHaveLength(2); + expect(values[0]).toBe(values[1]); + }); + + it('memoizes context value when override object reference is stable (hoisted)', () => { + const values: ComponentsContextValue[] = []; + + function Collector(): null { + values.push(useComponents()); + return null; + } + + const CustomButton = forwardRef(function CustomButton({ children }, ref) { + return ; + }); + + const overrides = { ...components, Button: CustomButton }; + + const { rerender } = render( + + + , + ); + + rerender( + + + , + ); + + expect(values).toHaveLength(2); + expect(values[0]).toBe(values[1]); + }); + + it('does not automatically merge partial components with defaults', () => { + const partialComponents = { Button: components.Button } as PersesComponents; + + function TestConsumer(): ReactElement { + const { components } = useComponents(); + return
{String(components.Alert)}
; + } + + render( + + + , + ); + + expect(screen.getByTestId('alert-check')).toHaveTextContent('undefined'); + }); + + it('renders a custom component injected via provider', () => { + const CustomButton = forwardRef(function CustomButton({ children, ...rest }, ref) { + return ( + + ); + }); + + function App(): ReactElement { + const { components } = useComponents(); + return Click Me; + } + + render( + + + , + ); + + const button = screen.getByText('Custom: Click Me'); + expect(button).toBeInTheDocument(); + expect(button).toHaveClass('custom-injected'); + }); + + it('renders icons passed in via props', () => { + function TestConsumer(): ReactElement { + const { icons } = useComponents(); + return ( +
+ + + + +
+ ); + } + + render( + + + , + ); + + expect(screen.getByTestId('error-icon')).toBeInTheDocument(); + expect(screen.getByTestId('info-icon')).toBeInTheDocument(); + expect(screen.getByTestId('success-icon')).toBeInTheDocument(); + expect(screen.getByTestId('warning-icon')).toBeInTheDocument(); + }); +}); diff --git a/components/src/next/contexts/ComponentsProvider.tsx b/components/src/next/contexts/ComponentsProvider.tsx new file mode 100644 index 00000000..4653365c --- /dev/null +++ b/components/src/next/contexts/ComponentsProvider.tsx @@ -0,0 +1,39 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { useContext, useMemo } from 'react'; +import type { ReactElement } from 'react'; + +import { ComponentsContext } from './ComponentsContext'; +import type { + PersesComponents, + PersesIcons, + ComponentsContextValue, + ComponentsProviderProps, +} from './ComponentsContext'; + +export type { PersesComponents, PersesIcons, ComponentsContextValue, ComponentsProviderProps }; + +export function ComponentsProvider({ children, components, icons }: ComponentsProviderProps): ReactElement { + const value = useMemo(() => ({ components, icons }), [components, icons]); + + return {children}; +} + +export function useComponents(): ComponentsContextValue { + const ctx = useContext(ComponentsContext); + if (ctx === undefined) { + throw new Error('No ComponentsContext found. Did you forget a ComponentsProvider?'); + } + return ctx; +} diff --git a/components/src/next/contexts/ThemeModeProvider.test.tsx b/components/src/next/contexts/ThemeModeProvider.test.tsx new file mode 100644 index 00000000..e3889c4f --- /dev/null +++ b/components/src/next/contexts/ThemeModeProvider.test.tsx @@ -0,0 +1,50 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render, screen } from '@testing-library/react'; + +import { ThemeModeProvider } from './ThemeModeProvider'; + +describe('ThemeModeProvider', () => { + it('sets data-perses-mode on its wrapper element', () => { + render( + + Content + , + ); + expect(screen.getByTestId('child').parentElement).toHaveAttribute('data-perses-mode', 'dark'); + }); + + it('renders children', () => { + render( + + Content + , + ); + expect(screen.getByTestId('child')).toBeInTheDocument(); + }); + + it('updates the wrapper when mode changes', () => { + render( + + Content + , + ); + expect(screen.getByTestId('child').parentElement).toHaveAttribute('data-perses-mode', 'light'); + }); + + it('does not set attributes on document.documentElement', () => { + render(Content); + expect(document.documentElement).not.toHaveAttribute('data-perses-mode'); + }); +}); diff --git a/components/src/next/contexts/ThemeModeProvider.tsx b/components/src/next/contexts/ThemeModeProvider.tsx new file mode 100644 index 00000000..28cd96a4 --- /dev/null +++ b/components/src/next/contexts/ThemeModeProvider.tsx @@ -0,0 +1,25 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { ReactElement, ReactNode } from 'react'; + +export type ThemeMode = 'dark' | 'light'; + +export interface ThemeModeProviderProps { + mode: ThemeMode; + children?: ReactNode; +} + +export function ThemeModeProvider({ mode, children }: ThemeModeProviderProps): ReactElement { + return
{children}
; +} diff --git a/components/src/next/contexts/TokenCustomization.stories.tsx b/components/src/next/contexts/TokenCustomization.stories.tsx new file mode 100644 index 00000000..f1090a38 --- /dev/null +++ b/components/src/next/contexts/TokenCustomization.stories.tsx @@ -0,0 +1,63 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Story } from '@ladle/react'; +import type { CSSProperties, ReactElement } from 'react'; + +import { defaultComponents, defaultIcons } from '../primitives/defaults'; +import { ComponentsProvider, useComponents } from './ComponentsProvider'; + +function TokenDemo(): ReactElement { + const { + components: { Button }, + } = useComponents(); + + return ( +
+

Token Customization

+

+ Same default Button, different look — achieved by overriding CSS custom properties on a wrapper element. +

+
+ + + +
+
+ ); +} + +export const TokenCustomization: Story = () => ( + +
+ +
+
+); +TokenCustomization.storyName = 'Token Customization'; diff --git a/components/src/next/css.d.ts b/components/src/next/css.d.ts new file mode 100644 index 00000000..466fd5e3 --- /dev/null +++ b/components/src/next/css.d.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +declare module '*.css'; diff --git a/components/src/next/css/index.css b/components/src/next/css/index.css new file mode 100644 index 00000000..bc9cfb05 --- /dev/null +++ b/components/src/next/css/index.css @@ -0,0 +1,16 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.reset, perses.tokens, perses.semantic, perses.components; diff --git a/components/src/next/exports.test.tsx b/components/src/next/exports.test.tsx new file mode 100644 index 00000000..bb04b791 --- /dev/null +++ b/components/src/next/exports.test.tsx @@ -0,0 +1,33 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ComponentsProvider, useComponents } from './index'; +import type { PersesComponents, PersesIcons, ComponentsProviderProps, ComponentsContextValue } from './index'; + +describe('next barrel exports', () => { + it('exports the configuration API', () => { + expect(ComponentsProvider).toBeDefined(); + expect(useComponents).toBeDefined(); + }); + + it('exports the provider configuration types', () => { + const assertTypesExist = ( + _components?: PersesComponents, + _icons?: PersesIcons, + _providerProps?: ComponentsProviderProps, + _contextValue?: ComponentsContextValue, + ): void => undefined; + + expect(assertTypesExist).toBeDefined(); + }); +}); diff --git a/components/src/next/index.ts b/components/src/next/index.ts new file mode 100644 index 00000000..3633fdad --- /dev/null +++ b/components/src/next/index.ts @@ -0,0 +1,23 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export { ComponentsProvider, useComponents } from './contexts/ComponentsProvider'; +export type { + PersesComponents, + PersesIcons, + ComponentsProviderProps, + ComponentsContextValue, +} from './contexts/ComponentsProvider'; + +export { ThemeModeProvider } from './contexts/ThemeModeProvider'; +export type { ThemeMode, ThemeModeProviderProps } from './contexts/ThemeModeProvider'; diff --git a/components/src/next/primitives/Alert/Alert.stories.tsx b/components/src/next/primitives/Alert/Alert.stories.tsx new file mode 100644 index 00000000..83772bbb --- /dev/null +++ b/components/src/next/primitives/Alert/Alert.stories.tsx @@ -0,0 +1,60 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Story } from '@ladle/react'; + +import { Alert } from './Alert'; +import type { AlertSeverity } from './Alert'; + +const severities: AlertSeverity[] = ['error', 'warning', 'success', 'info']; + +export const AllSeverities: Story = () => ( +
+ {severities.map((severity) => ( + + This is a {severity} alert. + + ))} +
+); +AllSeverities.storyName = 'All Severities'; + +export const NoIcon: Story = () => ( +
+ {severities.map((severity) => ( + + No icon by default for a {severity} alert. + + ))} +
+); +NoIcon.storyName = 'No Icon (default)'; + +const SmileyIcon = ( + + + +); + +export const CustomIcon: Story = () => This alert uses a custom icon.; +CustomIcon.storyName = 'Custom Icon'; + +export const FalsyIcon: Story = () => ( +
+ icon={'{0}'} renders no icon (not a literal "0"). + icon={'{false}'} renders no icon. + icon={'{null}'} renders no icon. + icon={'{undefined}'} (or omitted) renders no icon. +
+); +FalsyIcon.storyName = 'Falsy Icon (0 / false / null / undefined)'; diff --git a/components/src/next/primitives/Alert/Alert.test.tsx b/components/src/next/primitives/Alert/Alert.test.tsx new file mode 100644 index 00000000..cbfc4e44 --- /dev/null +++ b/components/src/next/primitives/Alert/Alert.test.tsx @@ -0,0 +1,142 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render, screen } from '@testing-library/react'; +import type { ReactElement, ReactNode, SVGProps } from 'react'; + +import { ComponentsProvider } from '../../contexts/ComponentsProvider'; +import { defaultComponents, defaultIcons } from '../defaults'; +import { Alert } from './Alert'; + +function Wrapper({ children }: { children: ReactNode }): ReactElement { + return ( + + {children} + + ); +} + +describe('Alert', () => { + it('renders children', () => { + render(Something happened, { wrapper: Wrapper }); + expect(screen.getByRole('alert')).toHaveTextContent('Something happened'); + }); + + it('applies the ps-Alert class', () => { + render(Test, { wrapper: Wrapper }); + expect(screen.getByRole('alert')).toHaveClass('ps-Alert'); + }); + + it('defaults to info severity', () => { + render(Test, { wrapper: Wrapper }); + expect(screen.getByRole('alert')).toHaveAttribute('data-severity', 'info'); + }); + + it('sets data-severity attribute', () => { + render(Error!, { wrapper: Wrapper }); + expect(screen.getByRole('alert')).toHaveAttribute('data-severity', 'error'); + }); + + it('merges additional className', () => { + render(Test, { wrapper: Wrapper }); + const alert = screen.getByRole('alert'); + expect(alert).toHaveClass('ps-Alert'); + expect(alert).toHaveClass('custom'); + }); + + it('renders all severity levels', () => { + const severities = ['error', 'warning', 'success', 'info'] as const; + + for (const severity of severities) { + const { unmount } = render({severity}, { wrapper: Wrapper }); + expect(screen.getByRole('alert')).toHaveAttribute('data-severity', severity); + unmount(); + } + }); + + it('renders no icon when icon prop is omitted', () => { + render(Test, { wrapper: Wrapper }); + const iconContainer = screen.getByRole('alert').querySelector('.ps-Alert__icon'); + expect(iconContainer).not.toBeInTheDocument(); + }); + + it('renders the built-in icon matching a severity key passed to icon', () => { + render(Test, { wrapper: Wrapper }); + const iconContainer = screen.getByRole('alert').querySelector('.ps-Alert__icon'); + expect(iconContainer).toBeInTheDocument(); + expect(iconContainer?.querySelector('svg')).toBeInTheDocument(); + }); + + it('composes the shared Icon primitive for its icon wrapper', () => { + render(Test, { wrapper: Wrapper }); + const iconContainer = screen.getByRole('alert').querySelector('.ps-Alert__icon'); + expect(iconContainer).toHaveClass('ps-Icon'); + }); + + it('resolves the icon key independently of the severity prop', () => { + render( + + Test + , + { wrapper: Wrapper }, + ); + const alert = screen.getByRole('alert'); + expect(alert).toHaveAttribute('data-severity', 'error'); + expect(alert.querySelector('.ps-Alert__icon svg')).toBeInTheDocument(); + }); + + it('renders a custom icon when icon prop is provided', () => { + const customIcon = ; + render(Test, { wrapper: Wrapper }); + expect(screen.getByTestId('custom-icon')).toBeInTheDocument(); + }); + + it('renders no icon when icon is set to null', () => { + render(Test, { wrapper: Wrapper }); + const iconContainer = screen.getByRole('alert').querySelector('.ps-Alert__icon'); + expect(iconContainer).not.toBeInTheDocument(); + }); + + it('renders no icon when icon is set to false or 0', () => { + const { rerender } = render(Test, { wrapper: Wrapper }); + expect(screen.getByRole('alert').querySelector('.ps-Alert__icon')).not.toBeInTheDocument(); + + rerender(Test); + expect(screen.getByRole('alert').querySelector('.ps-Alert__icon')).not.toBeInTheDocument(); + expect(screen.getByRole('alert')).not.toHaveTextContent('0'); + }); + + it('uses provider icons when inside a ComponentsProvider', () => { + const CustomErrorIcon = (props: SVGProps): ReactElement => ( + + ); + + render( + + + Error + + , + ); + + expect(screen.getByTestId('provider-error-icon')).toBeInTheDocument(); + }); + + it('throws when rendered outside a ComponentsProvider', () => { + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + expect(() => render(Error)).toThrow( + 'No ComponentsContext found. Did you forget a ComponentsProvider?', + ); + consoleSpy.mockRestore(); + }); +}); diff --git a/components/src/next/primitives/Alert/Alert.tsx b/components/src/next/primitives/Alert/Alert.tsx new file mode 100644 index 00000000..24311593 --- /dev/null +++ b/components/src/next/primitives/Alert/Alert.tsx @@ -0,0 +1,72 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import clsx from 'clsx'; +import { forwardRef } from 'react'; +import type { ComponentType, HTMLAttributes, ReactElement, ReactNode, SVGProps } from 'react'; + +import type { PersesIcons } from '../../contexts/ComponentsContext'; +import { useComponents } from '../../contexts/ComponentsProvider'; +import { Icon } from '../Icon/Icon'; +import { SuccessIcon, InfoIcon, WarningIcon, ErrorIcon } from '../Icon/icons'; + +import './alert.css'; + +export type AlertSeverity = 'error' | 'warning' | 'success' | 'info'; + +const SEVERITY_ICONS: Record> }> = + { + success: { key: 'Success', icon: SuccessIcon }, + info: { key: 'Info', icon: InfoIcon }, + warning: { key: 'Warning', icon: WarningIcon }, + error: { key: 'Error', icon: ErrorIcon }, + }; + +function isAlertSeverity(icon: unknown): icon is AlertSeverity { + return typeof icon === 'string' && icon in SEVERITY_ICONS; +} + +export interface AlertProps extends HTMLAttributes { + severity?: AlertSeverity; + icon?: AlertSeverity | ReactElement | number | boolean | null; +} + +/** + * DOM structure: `.ps-Alert > .ps-Alert__icon? + .ps-Alert__message` + * `.ps-Alert__icon` is only rendered when `icon` resolves to a non-empty value. + * Consumers should target `.ps-Alert__message` for content styling. + */ +export const Alert = forwardRef(function Alert( + { severity = 'info', role = 'alert', className, icon, children, ...rest }, + ref, +) { + const classes = clsx('ps-Alert', className); + const { icons } = useComponents(); + + let resolvedIcon: ReactNode; + + if (isAlertSeverity(icon)) { + const { key, icon: DefaultIcon } = SEVERITY_ICONS[icon]; + const IconComponent = icons[key] ?? DefaultIcon; + resolvedIcon = ; + } else { + resolvedIcon = icon; + } + + return ( +
+ {Boolean(resolvedIcon) && {resolvedIcon}} +
{children}
+
+ ); +}); diff --git a/components/src/next/primitives/Alert/alert.css b/components/src/next/primitives/Alert/alert.css new file mode 100644 index 00000000..e4680967 --- /dev/null +++ b/components/src/next/primitives/Alert/alert.css @@ -0,0 +1,71 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.components { + .ps-Alert { + display: flex; + align-items: center; + gap: var(--perses-spacing-sm); + padding: var(--perses-spacing-md) var(--perses-spacing-lg); + border: 1px solid transparent; + border-radius: var(--perses-radius-md); + font-family: var(--perses-font-family); + font-size: var(--perses-font-size-sm); + line-height: var(--perses-line-height-normal); + } + + .ps-Alert[data-severity='error'] { + background-color: var(--perses-status-bg-error); + border-color: var(--perses-status-border-error); + color: var(--perses-status-text-error); + } + + .ps-Alert[data-severity='warning'] { + background-color: var(--perses-status-bg-warning); + border-color: var(--perses-status-border-warning); + color: var(--perses-status-text-warning); + } + + .ps-Alert[data-severity='success'] { + background-color: var(--perses-status-bg-success); + border-color: var(--perses-status-border-success); + color: var(--perses-status-text-success); + } + + .ps-Alert[data-severity='info'] { + background-color: var(--perses-status-bg-info); + border-color: var(--perses-status-border-info); + color: var(--perses-status-text-info); + } + + /* ---- Icon ---- */ + .ps-Alert > .ps-Icon { + width: 1.6em; + height: 1.6em; + } + + .ps-Alert[data-severity='error'] > .ps-Icon { + color: var(--perses-status-icon-error); + } + .ps-Alert[data-severity='warning'] > .ps-Icon { + color: var(--perses-status-icon-warning); + } + .ps-Alert[data-severity='success'] > .ps-Icon { + color: var(--perses-status-icon-success); + } + .ps-Alert[data-severity='info'] > .ps-Icon { + color: var(--perses-status-icon-info); + } +} diff --git a/components/src/next/primitives/Alert/index.ts b/components/src/next/primitives/Alert/index.ts new file mode 100644 index 00000000..9c6e082f --- /dev/null +++ b/components/src/next/primitives/Alert/index.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './Alert'; diff --git a/components/src/next/primitives/Button/Button.stories.tsx b/components/src/next/primitives/Button/Button.stories.tsx new file mode 100644 index 00000000..a2dfeb27 --- /dev/null +++ b/components/src/next/primitives/Button/Button.stories.tsx @@ -0,0 +1,72 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Story } from '@ladle/react'; + +import { Button } from './Button'; +import type { ButtonVariant, ButtonColor, ButtonSize } from './Button'; + +const variants: ButtonVariant[] = ['solid', 'outline', 'ghost']; +const colors: ButtonColor[] = ['primary', 'secondary', 'error', 'warning', 'success', 'info']; +const sizes: ButtonSize[] = ['sm', 'md', 'lg']; + +export const AllVariantsAndColors: Story = () => ( +
+ {sizes.map((size) => ( +
+

Size: {size}

+
+ {variants.map((variant) => ( +
+ {variant} + {colors.map((color) => ( + + ))} +
+ ))} +
+
+ ))} +
+); +AllVariantsAndColors.storyName = 'All Variants & Colors'; + +export const Disabled: Story = () => ( +
+ + + +
+); + +export const Loading: Story = () => ( +
+ + + +
+); diff --git a/components/src/next/primitives/Button/Button.test.tsx b/components/src/next/primitives/Button/Button.test.tsx new file mode 100644 index 00000000..741dadc2 --- /dev/null +++ b/components/src/next/primitives/Button/Button.test.tsx @@ -0,0 +1,109 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import type { ReactElement, ReactNode } from 'react'; + +import { ComponentsProvider } from '../../contexts/ComponentsProvider'; +import { defaultComponents, defaultIcons } from '../defaults'; +import { Button } from './Button'; + +function Wrapper({ children }: { children: ReactNode }): ReactElement { + return ( + + {children} + + ); +} + +describe('Button', () => { + it('renders children', () => { + render(, { wrapper: Wrapper }); + expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument(); + }); + + it('applies the ps-Button class', () => { + render(, { wrapper: Wrapper }); + expect(screen.getByRole('button')).toHaveClass('ps-Button'); + }); + + it('sets data-variant, data-color, and data-size attributes', () => { + render( + , + { wrapper: Wrapper }, + ); + const button = screen.getByRole('button'); + expect(button).toHaveAttribute('data-variant', 'outline'); + expect(button).toHaveAttribute('data-color', 'error'); + expect(button).toHaveAttribute('data-size', 'lg'); + }); + + it('uses default props when none are provided', () => { + render(, { wrapper: Wrapper }); + const button = screen.getByRole('button'); + expect(button).toHaveAttribute('data-variant', 'solid'); + expect(button).toHaveAttribute('data-color', 'primary'); + expect(button).toHaveAttribute('data-size', 'md'); + }); + + it('merges additional className', () => { + render(, { wrapper: Wrapper }); + const button = screen.getByRole('button'); + expect(button).toHaveClass('ps-Button'); + expect(button).toHaveClass('custom-class'); + }); + + it('handles click events', async () => { + const handleClick = vi.fn(); + render(, { wrapper: Wrapper }); + await userEvent.click(screen.getByRole('button')); + expect(handleClick).toHaveBeenCalledTimes(1); + }); + + it('supports disabled state', () => { + render(, { wrapper: Wrapper }); + expect(screen.getByRole('button')).toBeDisabled(); + }); + + it('renders spinner when loading is true', () => { + const { container } = render(, { wrapper: Wrapper }); + expect(container.querySelector('.ps-Button__spinner')).toBeInTheDocument(); + expect(container.querySelector('.ps-Spinner')).toBeInTheDocument(); + }); + + it('composes the shared Icon primitive for its spinner wrapper', () => { + const { container } = render(, { wrapper: Wrapper }); + const spinnerContainer = container.querySelector('.ps-Button__spinner'); + expect(spinnerContainer).toHaveClass('ps-Icon'); + }); + + it('disables button when loading is true', () => { + render(, { wrapper: Wrapper }); + expect(screen.getByRole('button')).toBeDisabled(); + }); + + it('sets aria-busy and data-loading when loading', () => { + render(, { wrapper: Wrapper }); + const button = screen.getByRole('button'); + expect(button).toHaveAttribute('aria-busy', 'true'); + expect(button).toHaveAttribute('data-loading'); + }); + + it('does not render spinner when loading is false', () => { + const { container } = render(, { wrapper: Wrapper }); + expect(container.querySelector('.ps-Button__spinner')).not.toBeInTheDocument(); + }); +}); diff --git a/components/src/next/primitives/Button/Button.tsx b/components/src/next/primitives/Button/Button.tsx new file mode 100644 index 00000000..7a314893 --- /dev/null +++ b/components/src/next/primitives/Button/Button.tsx @@ -0,0 +1,65 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Button as BaseButton } from '@base-ui/react/button'; +import clsx from 'clsx'; +import { forwardRef } from 'react'; +import type { ButtonHTMLAttributes } from 'react'; + +import { useComponents } from '../../contexts/ComponentsProvider'; +import { Icon } from '../Icon/Icon'; + +import './button.css'; + +export type ButtonVariant = 'solid' | 'outline' | 'ghost'; +export type ButtonColor = 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'info'; +export type ButtonSize = 'sm' | 'md' | 'lg'; + +export interface ButtonProps extends Omit, 'color'> { + variant?: ButtonVariant; + color?: ButtonColor; + size?: ButtonSize; + loading?: boolean; +} + +export const Button = forwardRef(function Button( + { variant = 'solid', color = 'primary', size = 'md', loading = false, disabled, className, children, ...rest }, + ref, +) { + const { + components: { Spinner }, + } = useComponents(); + const classes = clsx('ps-Button', className); + const isDisabled = disabled || loading; + + return ( + + {loading && ( + + + + )} + {children} + + ); +}); diff --git a/components/src/next/primitives/Button/button.css b/components/src/next/primitives/Button/button.css new file mode 100644 index 00000000..5ede5e34 --- /dev/null +++ b/components/src/next/primitives/Button/button.css @@ -0,0 +1,144 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.components { + /* ---- Base ---- */ + .ps-Button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--perses-spacing-xs); + border: 1px solid transparent; + border-radius: var(--perses-radius-md); + cursor: pointer; + font-family: var(--perses-font-family); + font-weight: var(--perses-font-weight-medium); + line-height: var(--perses-line-height-relaxed); + transition: + background-color 0.15s ease, + border-color 0.15s ease, + color 0.15s ease; + } + + .ps-Button:focus-visible { + outline: 2px solid var(--perses-status-border-primary); + outline-offset: 2px; + } + + .ps-Button:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + /* ---- Sizes ---- */ + .ps-Button[data-size='sm'] { + padding: var(--perses-spacing-xs) var(--perses-spacing-sm); + font-size: var(--perses-font-size-xs); + } + + .ps-Button[data-size='md'] { + padding: var(--perses-spacing-sm) var(--perses-spacing-lg); + font-size: var(--perses-font-size-sm); + } + + .ps-Button[data-size='lg'] { + padding: var(--perses-spacing-md) var(--perses-spacing-xl); + font-size: var(--perses-font-size-md); + } + + /* ---- Color tokens (scoped per data-color) ---- */ + .ps-Button[data-color='primary'] { + --btn-bg: var(--perses-status-solid-primary); + --btn-bg-hover: var(--perses-status-bg-primary-hover); + --btn-text: var(--perses-status-solid-primary); + --btn-border: var(--perses-status-border-primary); + --btn-bg-subtle: var(--perses-status-bg-primary); + } + + .ps-Button[data-color='secondary'] { + --btn-bg: var(--perses-status-solid-secondary); + --btn-bg-hover: var(--perses-status-bg-secondary-hover); + --btn-text: var(--perses-status-solid-secondary); + --btn-border: var(--perses-status-border-secondary); + --btn-bg-subtle: var(--perses-status-bg-secondary); + } + + .ps-Button[data-color='error'] { + --btn-bg: var(--perses-status-solid-error); + --btn-bg-hover: var(--perses-status-bg-error-hover); + --btn-text: var(--perses-status-solid-error); + --btn-border: var(--perses-status-border-error); + --btn-bg-subtle: var(--perses-status-bg-error); + } + + .ps-Button[data-color='warning'] { + --btn-bg: var(--perses-status-solid-warning); + --btn-bg-hover: var(--perses-status-bg-warning-hover); + --btn-text: var(--perses-status-solid-warning); + --btn-border: var(--perses-status-border-warning); + --btn-bg-subtle: var(--perses-status-bg-warning); + } + + .ps-Button[data-color='success'] { + --btn-bg: var(--perses-status-solid-success); + --btn-bg-hover: var(--perses-status-bg-success-hover); + --btn-text: var(--perses-status-solid-success); + --btn-border: var(--perses-status-border-success); + --btn-bg-subtle: var(--perses-status-bg-success); + } + + .ps-Button[data-color='info'] { + --btn-bg: var(--perses-status-solid-info); + --btn-bg-hover: var(--perses-status-bg-info-hover); + --btn-text: var(--perses-status-solid-info); + --btn-border: var(--perses-status-border-info); + --btn-bg-subtle: var(--perses-status-bg-info); + } + + /* ---- Loading state ---- */ + .ps-Button[data-loading]:disabled { + opacity: 1; + cursor: wait; + } + + /* ---- Variant: solid ---- */ + .ps-Button[data-variant='solid'] { + color: var(--perses-text-on-solid); + background-color: var(--btn-bg); + } + .ps-Button[data-variant='solid']:hover:not(:disabled) { + background-color: var(--btn-bg-hover); + } + + /* ---- Variant: outline ---- */ + .ps-Button[data-variant='outline'] { + color: var(--btn-text); + background-color: transparent; + border-color: var(--btn-border); + } + .ps-Button[data-variant='outline']:hover:not(:disabled) { + background-color: var(--btn-bg-subtle); + } + + /* ---- Variant: ghost ---- */ + .ps-Button[data-variant='ghost'] { + color: var(--btn-text); + background-color: transparent; + border-color: transparent; + } + .ps-Button[data-variant='ghost']:hover:not(:disabled) { + background-color: var(--btn-bg-subtle); + } +} diff --git a/components/src/next/primitives/Button/index.ts b/components/src/next/primitives/Button/index.ts new file mode 100644 index 00000000..47647dce --- /dev/null +++ b/components/src/next/primitives/Button/index.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './Button'; diff --git a/components/src/next/primitives/Icon/Icon.test.tsx b/components/src/next/primitives/Icon/Icon.test.tsx new file mode 100644 index 00000000..019bf18f --- /dev/null +++ b/components/src/next/primitives/Icon/Icon.test.tsx @@ -0,0 +1,50 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render } from '@testing-library/react'; +import { createRef } from 'react'; + +import { Icon } from './Icon'; + +describe('Icon', () => { + it('renders its children', () => { + const { getByTestId } = render( + + + , + ); + expect(getByTestId('child-svg')).toBeInTheDocument(); + }); + + it('applies the ps-Icon class', () => { + const { container } = render({null}); + expect(container.firstChild).toHaveClass('ps-Icon'); + }); + + it('is hidden from the accessibility tree', () => { + const { container } = render({null}); + expect(container.firstChild).toHaveAttribute('aria-hidden', 'true'); + }); + + it('merges an additional className with ps-Icon', () => { + const { container } = render({null}); + expect(container.firstChild).toHaveClass('ps-Icon'); + expect(container.firstChild).toHaveClass('ps-Alert__icon'); + }); + + it('forwards a ref to the underlying span', () => { + const ref = createRef(); + render({null}); + expect(ref.current).toBeInstanceOf(HTMLSpanElement); + }); +}); diff --git a/components/src/next/primitives/Icon/Icon.tsx b/components/src/next/primitives/Icon/Icon.tsx new file mode 100644 index 00000000..1fac0add --- /dev/null +++ b/components/src/next/primitives/Icon/Icon.tsx @@ -0,0 +1,30 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import clsx from 'clsx'; +import { forwardRef } from 'react'; +import type { HTMLAttributes, ReactNode } from 'react'; + +import './icon.css'; + +export interface IconProps extends HTMLAttributes { + children?: ReactNode; +} + +export const Icon = forwardRef(function Icon({ className, children, ...rest }, ref) { + return ( + + ); +}); diff --git a/components/src/next/primitives/Icon/icon.css b/components/src/next/primitives/Icon/icon.css new file mode 100644 index 00000000..924cca1b --- /dev/null +++ b/components/src/next/primitives/Icon/icon.css @@ -0,0 +1,27 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.components { + .ps-Icon { + display: inline-flex; + align-items: center; + flex-shrink: 0; + } + + .ps-Icon svg { + width: 1em; + height: 1em; + } +} diff --git a/components/src/next/primitives/Icon/icons/ErrorIcon.tsx b/components/src/next/primitives/Icon/icons/ErrorIcon.tsx new file mode 100644 index 00000000..dd710d1d --- /dev/null +++ b/components/src/next/primitives/Icon/icons/ErrorIcon.tsx @@ -0,0 +1,22 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; + +export function ErrorIcon(props: React.SVGProps): React.ReactElement { + return ( + + + + ); +} diff --git a/components/src/next/primitives/Icon/icons/InfoIcon.tsx b/components/src/next/primitives/Icon/icons/InfoIcon.tsx new file mode 100644 index 00000000..94805b85 --- /dev/null +++ b/components/src/next/primitives/Icon/icons/InfoIcon.tsx @@ -0,0 +1,22 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; + +export function InfoIcon(props: React.SVGProps): React.ReactElement { + return ( + + + + ); +} diff --git a/components/src/next/primitives/Icon/icons/SuccessIcon.tsx b/components/src/next/primitives/Icon/icons/SuccessIcon.tsx new file mode 100644 index 00000000..8253b7b1 --- /dev/null +++ b/components/src/next/primitives/Icon/icons/SuccessIcon.tsx @@ -0,0 +1,22 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; + +export function SuccessIcon(props: React.SVGProps): React.ReactElement { + return ( + + + + ); +} diff --git a/components/src/next/primitives/Icon/icons/WarningIcon.tsx b/components/src/next/primitives/Icon/icons/WarningIcon.tsx new file mode 100644 index 00000000..fb9c6c64 --- /dev/null +++ b/components/src/next/primitives/Icon/icons/WarningIcon.tsx @@ -0,0 +1,22 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; + +export function WarningIcon(props: React.SVGProps): React.ReactElement { + return ( + + + + ); +} diff --git a/components/src/next/primitives/Icon/icons/index.ts b/components/src/next/primitives/Icon/icons/index.ts new file mode 100644 index 00000000..1d7bfa1c --- /dev/null +++ b/components/src/next/primitives/Icon/icons/index.ts @@ -0,0 +1,17 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export { ErrorIcon } from './ErrorIcon'; +export { InfoIcon } from './InfoIcon'; +export { SuccessIcon } from './SuccessIcon'; +export { WarningIcon } from './WarningIcon'; diff --git a/components/src/next/primitives/Icon/index.ts b/components/src/next/primitives/Icon/index.ts new file mode 100644 index 00000000..b6b6aa79 --- /dev/null +++ b/components/src/next/primitives/Icon/index.ts @@ -0,0 +1,15 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './Icon'; +export * from './icons'; diff --git a/components/src/next/primitives/Spinner/Spinner.test.tsx b/components/src/next/primitives/Spinner/Spinner.test.tsx new file mode 100644 index 00000000..43275898 --- /dev/null +++ b/components/src/next/primitives/Spinner/Spinner.test.tsx @@ -0,0 +1,35 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { render } from '@testing-library/react'; + +import { Spinner } from './Spinner'; + +describe('Spinner', () => { + it('renders an svg', () => { + const { container } = render(); + expect(container.querySelector('svg')).toBeInTheDocument(); + }); + + it('applies the ps-Spinner class', () => { + const { container } = render(); + expect(container.querySelector('svg')).toHaveClass('ps-Spinner'); + }); + + it('merges an additional className with ps-Spinner', () => { + const { container } = render(); + const svg = container.querySelector('svg'); + expect(svg).toHaveClass('ps-Spinner'); + expect(svg).toHaveClass('custom'); + }); +}); diff --git a/components/src/next/primitives/Spinner/Spinner.tsx b/components/src/next/primitives/Spinner/Spinner.tsx new file mode 100644 index 00000000..9b1c2865 --- /dev/null +++ b/components/src/next/primitives/Spinner/Spinner.tsx @@ -0,0 +1,34 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import clsx from 'clsx'; +import type { ReactElement, SVGProps } from 'react'; + +import './spinner.css'; + +export type SpinnerProps = SVGProps; + +export function Spinner({ className, ...rest }: SpinnerProps): ReactElement { + return ( + + + + + ); +} diff --git a/components/src/next/primitives/Spinner/index.ts b/components/src/next/primitives/Spinner/index.ts new file mode 100644 index 00000000..75f23d62 --- /dev/null +++ b/components/src/next/primitives/Spinner/index.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './Spinner'; diff --git a/components/src/next/primitives/Spinner/spinner.css b/components/src/next/primitives/Spinner/spinner.css new file mode 100644 index 00000000..0938892b --- /dev/null +++ b/components/src/next/primitives/Spinner/spinner.css @@ -0,0 +1,28 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.components { + @keyframes ps-spin { + to { + transform: rotate(360deg); + } + } + + .ps-Spinner { + width: 1em; + height: 1em; + animation: ps-spin 0.75s linear infinite; + } +} diff --git a/components/src/next/primitives/defaults.ts b/components/src/next/primitives/defaults.ts new file mode 100644 index 00000000..ecfbc081 --- /dev/null +++ b/components/src/next/primitives/defaults.ts @@ -0,0 +1,27 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { PersesComponents, PersesIcons } from '../contexts/ComponentsContext'; +import { Alert } from './Alert'; +import { Button } from './Button'; +import { ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from './Icon'; +import { Spinner } from './Spinner'; + +export const defaultComponents: PersesComponents = { Button, Alert, Spinner }; + +export const defaultIcons: PersesIcons = { + Error: ErrorIcon, + Info: InfoIcon, + Success: SuccessIcon, + Warning: WarningIcon, +}; diff --git a/components/src/next/primitives/exports.test.tsx b/components/src/next/primitives/exports.test.tsx new file mode 100644 index 00000000..cbb686d8 --- /dev/null +++ b/components/src/next/primitives/exports.test.tsx @@ -0,0 +1,53 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Alert, Button, Icon, Spinner } from './index'; +import type { + AlertProps, + AlertSeverity, + ButtonColor, + ButtonProps, + ButtonSize, + ButtonVariant, + IconProps, + SpinnerProps, +} from './index'; + +describe('primitives barrel exports', () => { + it('exports the concrete component implementations', () => { + expect(Alert).toBeDefined(); + expect(Button).toBeDefined(); + expect(Icon).toBeDefined(); + expect(Spinner).toBeDefined(); + }); + + it('exports their prop types', () => { + const alertProps: AlertProps = {}; + const severity: AlertSeverity = 'info'; + const buttonProps: ButtonProps = {}; + const variant: ButtonVariant = 'solid'; + const color: ButtonColor = 'primary'; + const size: ButtonSize = 'md'; + const iconProps: IconProps = {}; + const spinnerProps: SpinnerProps = {}; + + expect(alertProps).toBeDefined(); + expect(severity).toBe('info'); + expect(buttonProps).toBeDefined(); + expect(variant).toBe('solid'); + expect(color).toBe('primary'); + expect(size).toBe('md'); + expect(iconProps).toBeDefined(); + expect(spinnerProps).toBeDefined(); + }); +}); diff --git a/components/src/next/primitives/index.ts b/components/src/next/primitives/index.ts new file mode 100644 index 00000000..27680cde --- /dev/null +++ b/components/src/next/primitives/index.ts @@ -0,0 +1,17 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './Alert'; +export * from './Button'; +export * from './Icon'; +export * from './Spinner'; diff --git a/components/src/next/stories/pf6/PatternFlyV6Alert.tsx b/components/src/next/stories/pf6/PatternFlyV6Alert.tsx new file mode 100644 index 00000000..27f74267 --- /dev/null +++ b/components/src/next/stories/pf6/PatternFlyV6Alert.tsx @@ -0,0 +1,191 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { forwardRef, useRef } from 'react'; +import type { CSSProperties, FC, ReactElement, ReactNode, SVGProps } from 'react'; + +import { useComponents } from '../../contexts/ComponentsProvider'; +import type { AlertProps } from '../../primitives/Alert'; +import { PF_FONT, mergeRefs, useDarkMode } from './utils'; + +function Pf6CustomIcon(props: SVGProps): ReactElement { + return ( + + ); +} + +function Pf6InfoIcon(props: SVGProps): ReactElement { + return ( + + ); +} + +function Pf6SuccessIcon(props: SVGProps): ReactElement { + return ( + + ); +} + +function Pf6WarningIcon(props: SVGProps): ReactElement { + return ( + + ); +} + +function Pf6DangerIcon(props: SVGProps): ReactElement { + return ( + + ); +} + +const PF6_ALERT_COLORS: Record = { + custom: { light: '#147878', dark: '#63bdbd' }, + info: { light: '#5e40be', dark: '#b6a6e9' }, + success: { light: '#3d7317', dark: '#87bb62' }, + warning: { light: '#dca614', dark: '#ffcc17' }, + error: { light: '#b1380b', dark: '#f0561d' }, +}; + +const PF6_ALERT_ICONS: Record>> = { + custom: Pf6CustomIcon, + info: Pf6InfoIcon, + success: Pf6SuccessIcon, + warning: Pf6WarningIcon, + error: Pf6DangerIcon, +}; + +function pf6AlertStyle(statusColor: string, isDark: boolean): CSSProperties { + return { + fontFamily: PF_FONT, + display: 'flex', + alignItems: 'center', + gap: '0.75rem', + padding: '1rem 1.25rem', + border: `2px solid ${statusColor}`, + borderRadius: '16px', + background: isDark ? '#292929' : '#fff', + color: isDark ? '#fff' : '#151515', + fontSize: '0.875rem', + lineHeight: 1.5, + }; +} + +function Pf6AlertContent({ + variant, + isDark, + icon, + children, +}: { + variant: string; + isDark: boolean; + icon?: ReactNode; + children: ReactNode; +}): ReactElement { + const colors = PF6_ALERT_COLORS[variant] ?? PF6_ALERT_COLORS['custom']; + const statusColor = isDark ? colors!.dark : colors!.light; + const IconComponent = PF6_ALERT_ICONS[variant] ?? Pf6CustomIcon; + + const resolvedIcon = + icon !== undefined ? ( + icon + ) : ( + + + + ); + + return ( + <> + {resolvedIcon} +

{children}

+ + ); +} + +function Pf6AlertBox({ + variant, + isDark, + children, +}: { + variant: string; + isDark: boolean; + children: ReactNode; +}): ReactElement { + const colors = PF6_ALERT_COLORS[variant] ?? PF6_ALERT_COLORS['custom']; + const statusColor = isDark ? colors!.dark : colors!.light; + + return ( +
+ + {children} + +
+ ); +} + +export const PatternFlyV6Alert = forwardRef(function PatternFlyV6Alert( + { severity = 'info', icon, children, className, style, ...rest }, + ref, +) { + const innerRef = useRef(null); + const isDark = useDarkMode(innerRef); + const colors = PF6_ALERT_COLORS[severity] ?? PF6_ALERT_COLORS['info']; + const statusColor = isDark ? colors!.dark : colors!.light; + + return ( +
+ + {children} + +
+ ); +}); + +export function Pf6AlertDemo(): ReactElement { + const { components } = useComponents(); + const Alert = components.Alert; + + const innerRef = useRef(null); + const isDark = useDarkMode(innerRef); + + return ( +
+

Alert Customization (via ComponentsProvider)

+
+ + Custom alert title + + Info alert title + Success alert title + Warning alert title + Danger alert title +
+
+ ); +} diff --git a/components/src/next/stories/pf6/utils.tsx b/components/src/next/stories/pf6/utils.tsx new file mode 100644 index 00000000..4deee262 --- /dev/null +++ b/components/src/next/stories/pf6/utils.tsx @@ -0,0 +1,63 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { useEffect, useState } from 'react'; +import type { MutableRefObject, ForwardedRef, ReactElement, ReactNode, RefObject } from 'react'; + +export const PF_FONT = + '"RedHatText", "Red Hat Text", "Overpass", -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif'; + +export function useDarkMode(elementRef: RefObject): boolean { + const [isDark, setIsDark] = useState(false); + + useEffect(() => { + const el = elementRef.current; + if (!el) return undefined; + const modeEl = el.closest('[data-perses-mode]'); + if (!modeEl) return undefined; + const update = (): void => setIsDark(modeEl.getAttribute('data-perses-mode') === 'dark'); + update(); + const observer = new MutationObserver(update); + observer.observe(modeEl, { attributes: true, attributeFilter: ['data-perses-mode'] }); + return (): void => observer.disconnect(); + }, [elementRef]); + + return isDark; +} + +export function mergeRefs( + innerRef: MutableRefObject, + outerRef: ForwardedRef, +): (node: T | null) => void { + return (node: T | null): void => { + innerRef.current = node; + if (typeof outerRef === 'function') { + outerRef(node); + } else if (outerRef) { + (outerRef as MutableRefObject).current = node; + } + }; +} + +export function PfDivider(): ReactElement { + return
; +} + +export function PfRow({ children, label }: { children: ReactNode; label?: string }): ReactElement { + return ( +
+ {label && {label}} + {children} +
+ ); +} diff --git a/components/src/utils/transform-data.test.ts b/components/src/utils/transform-data.test.ts index 5d82eca9..d09156c1 100644 --- a/components/src/utils/transform-data.test.ts +++ b/components/src/utils/transform-data.test.ts @@ -346,4 +346,108 @@ describe('Join By Column Transform', () => { const output = transformData(input, [joinTransform]); expect(output).toEqual(result); }); + + it('applies PivotByLabel to build a time × label matrix', () => { + const input: Array> = [ + { timestamp: 100, farm_short: 'FARM_B', value: 0 }, + { timestamp: 100, farm_short: 'FARM_A', value: 3 }, + { timestamp: 200, farm_short: 'FARM_A', value: 7 }, + { timestamp: 200, farm_short: 'FARM_B', value: 1 }, + { timestamp: 300, farm_short: 'FARM_A', value: 12 }, + // FARM_B missing at t=300 → sparse cell + ]; + + const pivot: Transform = { + kind: 'PivotByLabel', + spec: { + columnLabel: 'farm_short', + rowField: 'timestamp', + valueField: 'value', + rowColumnName: 'Time', + }, + }; + + const output = transformData(input, [pivot]); + // Newest timestamp first + expect(output).toEqual([ + { Time: 300, FARM_A: 12 }, + { Time: 200, FARM_A: 7, FARM_B: 1 }, + { Time: 100, FARM_A: 3, FARM_B: 0 }, + ]); + }); + + it('PivotByLabel disabled is a no-op', () => { + const input: Array> = [{ timestamp: 1, farm_short: 'A', value: 5 }]; + const pivot: Transform = { + kind: 'PivotByLabel', + spec: { columnLabel: 'farm_short', disabled: true }, + }; + const output = transformData(input, [pivot]); + expect(output).toEqual([{ farm_short: 'A', timestamp: 1, value: 5 }]); + }); + + it('PivotByLabel treats empty rowField/valueField as defaults', () => { + const input: Array> = [ + { timestamp: 10, farm_short: 'X', value: 1 }, + { timestamp: 10, farm_short: 'Y', value: 2 }, + ]; + const pivot: Transform = { + kind: 'PivotByLabel', + spec: { + columnLabel: 'farm_short', + rowField: '', + valueField: ' ', + rowColumnName: '', + }, + }; + const output = transformData(input, [pivot]); + expect(output).toEqual([{ timestamp: 10, X: 1, Y: 2 }]); + }); + + it('PivotByLabel disambiguates label colliding with row column name', () => { + const input: Array> = [{ timestamp: 1, farm_short: 'Time', value: 42 }]; + const pivot: Transform = { + kind: 'PivotByLabel', + spec: { + columnLabel: 'farm_short', + rowField: 'timestamp', + valueField: 'value', + rowColumnName: 'Time', + }, + }; + const output = transformData(input, [pivot]); + expect(output).toEqual([{ Time: 1, 'Time (value)': 42 }]); + }); + + it('PivotByLabel does not treat inherited Object keys as cells', () => { + const input: Array> = [ + { timestamp: 1, farm_short: 'A', value: 9 }, + // sparse: no B at t=1 + ]; + const pivot: Transform = { + kind: 'PivotByLabel', + spec: { columnLabel: 'farm_short', rowColumnName: 'Time' }, + }; + const output = transformData(input, [pivot]); + expect(output[0]).toEqual({ Time: 1, A: 9 }); + expect(Object.prototype.hasOwnProperty.call(output[0], 'toString')).toBe(false); + }); + + it('PivotByLabel skips empty / whitespace-only labels', () => { + const input: Array> = [ + { timestamp: 100, farm_short: '', value: 0 }, + { timestamp: 100, farm_short: ' ', value: 1 }, + { timestamp: 100, farm_short: 'A', value: 3 }, + { timestamp: 200, farm_short: 'A', value: 7 }, + ]; + const pivot: Transform = { + kind: 'PivotByLabel', + spec: { columnLabel: 'farm_short', rowColumnName: 'Time' }, + }; + const output = transformData(input, [pivot]); + expect(output).toEqual([ + { Time: 200, A: 7 }, + { Time: 100, A: 3 }, + ]); + }); }); diff --git a/components/src/utils/transform-data.ts b/components/src/utils/transform-data.ts index 31006152..f88fb15e 100644 --- a/components/src/utils/transform-data.ts +++ b/components/src/utils/transform-data.ts @@ -203,6 +203,98 @@ export function applyMergeSeriesTransform(data: Array>): return result; } +/** Treat empty string like omitted (editor / CUE can emit ""). */ +function nonEmpty(s: string | undefined, fallback: string): string { + return s?.trim() || fallback; +} + +/** Resolve column key including MergeSeries suffixes ("value #2"). */ +function resolvePivotKey(row: Record, base: string): string | undefined { + if (Object.hasOwn(row, base)) return base; + return Object.keys(row).find((k) => k === base || k.startsWith(base + ' #') || k.startsWith(base + '#')); +} + +/** + * Pivot: rows grouped by rowField, dynamic columns from columnLabel values. + * Last value wins on duplicate (time, label). + */ +export function applyPivotByLabelTransform( + data: Array>, + columnLabel: string, + rowField = 'timestamp', + valueField = 'value', + rowColumnName?: string, +): Array> { + if (!columnLabel || data.length === 0) { + return data; + } + + const rowFieldName = nonEmpty(rowField, 'timestamp'); + const valueFieldName = nonEmpty(valueField, 'value'); + const rowCol = nonEmpty(rowColumnName, rowFieldName); + + const labelSet = new Set(); + const groups = new Map>(); + + for (const row of data) { + const rowKeyName = resolvePivotKey(row, rowFieldName); + const labelKeyName = resolvePivotKey(row, columnLabel); + const valueKeyName = resolvePivotKey(row, valueFieldName); + if (rowKeyName === undefined || labelKeyName === undefined) { + continue; + } + + const rowKey = row[rowKeyName]; + const label = row[labelKeyName]; + if (rowKey === undefined || rowKey === null || label === undefined || label === null) { + continue; + } + + // Avoid clobbering the row identity column when a series label equals rowCol. + // Skip blank labels (empty string / whitespace-only) — not meaningful column headers. + let labelStr = String(label).trim(); + if (!labelStr) { + continue; + } + if (labelStr === rowCol) { + labelStr = `${labelStr} (value)`; + } + labelSet.add(labelStr); + const groupId = String(rowKey); + + let out = groups.get(groupId); + if (!out) { + out = { [rowCol]: rowKey }; + groups.set(groupId, out); + } + if (valueKeyName !== undefined) { + out[labelStr] = row[valueKeyName]; + } + } + + // Fresh copy from Set — mutate with sort() (no need for toSorted extra copy). + const labels = [...labelSet]; + labels.sort((a, b) => a.localeCompare(b)); + const entries = [...groups.entries()]; + entries.sort((a, b) => { + const va = a[1][rowCol]; + const vb = b[1][rowCol]; + if (typeof va === 'number' && typeof vb === 'number') { + return vb - va; + } + return String(vb).localeCompare(String(va)); + }); + return entries.map(([, row]) => { + const ordered: Record = { [rowCol]: row[rowCol] }; + for (const lab of labels) { + if (Object.hasOwn(row, lab)) { + ordered[lab] = row[lab]; + } + } + return ordered; + }); +} + /* * Transforms query data with the given transforms */ @@ -211,10 +303,15 @@ export function transformData( transforms: Transform[], ): Array> { let result: Array> = data; + // Only skip final alpha sort when the last *enabled* transform is PivotByLabel + // (pivot already orders: row column first, then labels). Intermediate pivots must + // not leave skipAlphaSort stuck true for later transforms. + let lastEnabledKind: Transform['kind'] | undefined; // Apply transforms by their orders for (const transform of transforms ?? []) { if (transform.spec.disabled) continue; + lastEnabledKind = transform.kind; switch (transform.kind) { case 'JoinByColumnValue': { @@ -239,9 +336,25 @@ export function transformData( result = applyMergeSeriesTransform(result); break; } + case 'PivotByLabel': { + if (transform.spec.columnLabel) { + result = applyPivotByLabelTransform( + result, + transform.spec.columnLabel, + nonEmpty(transform.spec.rowField, 'timestamp'), + nonEmpty(transform.spec.valueField, 'value'), + transform.spec.rowColumnName, + ); + } + break; + } } } + if (lastEnabledKind === 'PivotByLabel') { + return result; + } + // Ordering data column alphabetically result = result.map((row) => { return Object.keys(row) diff --git a/components/src/utils/variable-interpolation.ts b/components/src/utils/variable-interpolation.ts index fca23940..4729cd0a 100644 --- a/components/src/utils/variable-interpolation.ts +++ b/components/src/utils/variable-interpolation.ts @@ -243,3 +243,71 @@ export function replaceVariablesForDisplay(text: string, variableState: Variable } return replaceVariables(text, displayState); } + +/** + * Replace dashboard variables in a URL, including those nested inside + * percent-encoded query parameters (e.g. Explore `data=%24var`). + * + * 1. `replaceVariables` on the raw string (unencoded `$var` still works). + * 2. Parse query params (URLSearchParams decodes once), expand each value, + * rebuild with `append` so repeated keys are preserved. + * 3. Keep the original path/prefix before `?` so relative targets are unchanged + * (`?data=…`, `explore?…`, not forced `/…`). + */ +export function replaceVariablesInUrl(url: string, variableState: VariableStateMap): string { + let result = replaceVariables(url, variableState); + + try { + const isAbsolute = /^https?:\/\//i.test(result); + const isProtocolRelative = result.startsWith('//'); + // Skip non-http schemes (mailto:, etc.) — only expand via step 1. + const hasNonHttpScheme = /^[a-z][a-z0-9+.-]*:/i.test(result); + if (!isAbsolute && !isProtocolRelative && hasNonHttpScheme) { + return result; + } + + const parseInput = isProtocolRelative ? `http:${result}` : result; + const parsedUrl = new URL(parseInput, isAbsolute || isProtocolRelative ? undefined : 'http://perses.local'); + + // Rebuild query in original pair order so searchParams key order is stable. + const originalEntries = Array.from(parsedUrl.searchParams.entries()); + let changed = false; + const replacedEntries = originalEntries.map(([key, value]) => { + const replacedValue = replaceVariables(value, variableState); + if (replacedValue !== value) { + changed = true; + } + return [key, replacedValue] as const; + }); + + if (!changed) { + return result; + } + + const keysToClear = [...new Set(originalEntries.map(([key]) => key))]; + for (const key of keysToClear) { + parsedUrl.searchParams.delete(key); + } + for (const [key, value] of replacedEntries) { + parsedUrl.searchParams.append(key, value); + } + + if (isAbsolute) { + return parsedUrl.href; + } + if (isProtocolRelative) { + return `//${parsedUrl.host}${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`; + } + + // Relative: preserve original substring before ?/# (do not force leading /). + const q = result.indexOf('?'); + const h = result.indexOf('#'); + let baseEnd = result.length; + if (q >= 0) baseEnd = q; + else if (h >= 0) baseEnd = h; + const base = result.slice(0, baseEnd); + return `${base}${parsedUrl.search}${parsedUrl.hash}`; + } catch { + return result; + } +} diff --git a/components/src/utils/variable-interpolation.url.test.ts b/components/src/utils/variable-interpolation.url.test.ts new file mode 100644 index 00000000..d0b10bc4 --- /dev/null +++ b/components/src/utils/variable-interpolation.url.test.ts @@ -0,0 +1,98 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { describe, expect, it } from 'vitest'; + +import type { VariableStateMap } from './variable-interpolation'; +import { replaceVariablesInUrl } from './variable-interpolation'; + +describe('replaceVariablesInUrl', () => { + const vars: VariableStateMap = { + var: { value: 'my-value', loading: false }, + phase: { value: 'prd', loading: false }, + }; + + it('replaces $var in plain path/query', () => { + expect(replaceVariablesInUrl('/projects/demo/dashboards/x?var-var=$var', vars)).toBe( + '/projects/demo/dashboards/x?var-var=my-value', + ); + }); + + it('replaces $var nested inside Explore data= JSON (percent-encoded)', () => { + const data = JSON.stringify({ + tab: 'graph', + queries: [ + { + kind: 'TimeSeriesQuery', + spec: { + plugin: { + kind: 'PrometheusTimeSeriesQuery', + spec: { + query: 'topk(5, sum by(job) (rate(up{instance=~"$var", env=~"$phase"}[3m])))', + }, + }, + }, + }, + ], + }); + const url = `/explore?explorer=Prometheus-PrometheusExplorer&data=${encodeURIComponent(data)}`; + const out = replaceVariablesInUrl(url, vars); + // searchParams.get already returns a decoded value — do not decodeURIComponent again. + const decoded = new URL(out, 'http://local').searchParams.get('data')!; + expect(decoded).toContain('my-value'); + expect(decoded).toContain('prd'); + expect(decoded).not.toContain('$var'); + expect(decoded).not.toContain('$phase'); + }); + + it('preserves repeated query parameter keys', () => { + const url = '/path?tag=$var&tag=static&other=1'; + const out = replaceVariablesInUrl(url, vars); + const sp = new URL(out, 'http://local').searchParams; + expect(sp.getAll('tag')).toEqual(['my-value', 'static']); + expect(sp.get('other')).toBe('1'); + }); + + it('preserves query parameter pair order when expanding values', () => { + // Distinct keys in a deliberate order — expansion must not shuffle them. + const url = '/path?z=1&a=$var&m=keep&b=$phase'; + const out = replaceVariablesInUrl(url, vars); + const keys = [...new URL(out, 'http://local').searchParams.keys()]; + expect(keys).toEqual(['z', 'a', 'm', 'b']); + expect(out).toBe('/path?z=1&a=my-value&m=keep&b=prd'); + }); + + it('leaves absolute URLs absolute', () => { + const url = 'https://example.com/explore?q=$var'; + const out = replaceVariablesInUrl(url, vars); + expect(out).toBe('https://example.com/explore?q=my-value'); + }); + + it('preserves relative path without forcing a leading slash', () => { + expect(replaceVariablesInUrl('explore?q=$var', vars)).toBe('explore?q=my-value'); + }); + + it('preserves query-only relative URLs', () => { + // %24var is encoded $var — expanded after decode + expect(replaceVariablesInUrl('?data=%24var', vars)).toBe('?data=my-value'); + }); + + it('leaves URLs without variables unchanged', () => { + const url = '/explore?explorer=Prometheus-PrometheusExplorer&data=%7B%22tab%22%3A%22graph%22%7D'; + expect(replaceVariablesInUrl(url, vars)).toBe(url); + }); + + it('leaves mailto and other non-http schemes to plain replaceVariables only', () => { + expect(replaceVariablesInUrl('mailto:ops@$var.example', vars)).toBe('mailto:ops@my-value.example'); + }); +}); diff --git a/components/tsconfig.json b/components/tsconfig.json index abaf587a..3193cdf4 100644 --- a/components/tsconfig.json +++ b/components/tsconfig.json @@ -3,7 +3,8 @@ "include": ["src"], "compilerOptions": { "paths": { - "@perses-dev/components": ["./src"] + "@perses-dev/components": ["./src"], + "@perses-dev/components/next": ["./src/next"] } } } diff --git a/cue/common/transform.cue b/cue/common/transform.cue index 804ebb0f..131a1bc9 100644 --- a/cue/common/transform.cue +++ b/cue/common/transform.cue @@ -58,4 +58,16 @@ import ( } } -#transform: #joinByColumnValueTransform | #mergeColumnsTransform | #mergeIndexedColumnsTransform | #mergeSeries | #extractColumnFieldsTransform +// Pivot multi-series samples into time × label matrix (Grafana groupingToMatrix parity). +#pivotByLabelTransform: { + kind: "PivotByLabel" + spec: { + columnLabel: strings.MinRunes(1) + rowField?: string + valueField?: string + rowColumnName?: string + disabled?: bool + } +} + +#transform: #joinByColumnValueTransform | #mergeColumnsTransform | #mergeIndexedColumnsTransform | #mergeSeries | #extractColumnFieldsTransform | #pivotByLabelTransform diff --git a/dashboards/package.json b/dashboards/package.json index da791ef2..a22c7fbe 100644 --- a/dashboards/package.json +++ b/dashboards/package.json @@ -1,6 +1,6 @@ { "name": "@perses-dev/dashboards", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "description": "The dashboards feature in Perses", "license": "Apache-2.0", "homepage": "https://github.com/perses/perses/blob/main/README.md", @@ -29,15 +29,17 @@ "lint:fix": "oxlint --fix src" }, "dependencies": { - "@perses-dev/components": "0.55.0-beta.8", - "@perses-dev/plugin-system": "0.55.0-beta.8", + "@dnd-kit/dom": "^0.4.0", + "@dnd-kit/react": "^0.4.0", + "@perses-dev/client": "0.55.0-beta.11", + "@perses-dev/components": "0.55.0-beta.11", + "@perses-dev/plugin-system": "0.55.0-beta.11", "@perses-dev/spec": "0.3.0-beta.8", - "@perses-dev/client": "0.55.0-beta.8", + "@snapgridjs/react": "^0.10.0", "@tanstack/hotkeys": "^0.8.0", "@tanstack/react-hotkeys": "^0.9.1", "immer": "^10.1.1", "mdi-material-ui": "^7.9.2", - "react-grid-layout": "^1.3.4", "react-hook-form": "^7.87.0", "react-intersection-observer": "^9.4.0", "use-immer": "^0.11.0", @@ -47,7 +49,6 @@ "zustand": "^4.3.3" }, "devDependencies": { - "@types/react-grid-layout": "^1.3.6", "history": "^5.3.0" }, "peerDependencies": { diff --git a/dashboards/src/components/Dashboard/Dashboard.tsx b/dashboards/src/components/Dashboard/Dashboard.tsx index c6e23d6e..6de25683 100644 --- a/dashboards/src/components/Dashboard/Dashboard.tsx +++ b/dashboards/src/components/Dashboard/Dashboard.tsx @@ -14,10 +14,11 @@ import type { BoxProps } from '@mui/material'; import { Box } from '@mui/material'; import { ErrorBoundary, ErrorAlert } from '@perses-dev/components'; +import { SnapGridGroup } from '@snapgridjs/react'; import type { ReactElement } from 'react'; import { useRef } from 'react'; -import { usePanelGroupIds } from '../../context'; +import { usePanelGroupIds, useViewPanelGroup } from '../../context'; import type { EmptyDashboardProps } from '../EmptyDashboard'; import { EmptyDashboard } from '../EmptyDashboard'; import { GridLayout } from '../GridLayout'; @@ -39,10 +40,13 @@ const HEADER_HEIGHT = 165; // Approximate height of the header in dashboard view */ export function Dashboard({ emptyDashboardProps, panelOptions, ...boxProps }: DashboardProps): ReactElement { const panelGroupIds = usePanelGroupIds(); + const viewPanelItemId = useViewPanelGroup(); const boxRef = useRef(null); const isEmpty = !panelGroupIds.length; - const dashboardTopPosition = boxRef.current?.getBoundingClientRect().top ?? HEADER_HEIGHT; - const panelFullHeight = window.innerHeight - dashboardTopPosition - window.scrollY; + // Only the viewed panel needs this; measuring on every render would force a reflow and re-layout every group. + const panelFullHeight = viewPanelItemId + ? window.innerHeight - (boxRef.current?.getBoundingClientRect().top ?? HEADER_HEIGHT) - window.scrollY + : undefined; return ( @@ -52,15 +56,17 @@ export function Dashboard({ emptyDashboardProps, panelOptions, ...boxProps }: Da )} - {!isEmpty && - panelGroupIds.map((panelGroupId) => ( - - ))} + + {!isEmpty && + panelGroupIds.map((panelGroupId) => ( + + ))} + ); diff --git a/dashboards/src/components/DashboardToolbar/DashboardToolbar.tsx b/dashboards/src/components/DashboardToolbar/DashboardToolbar.tsx index 2d1eb512..bb3556f3 100644 --- a/dashboards/src/components/DashboardToolbar/DashboardToolbar.tsx +++ b/dashboards/src/components/DashboardToolbar/DashboardToolbar.tsx @@ -28,7 +28,9 @@ import { DownloadButton } from '../DownloadButton'; import { EditButton } from '../EditButton'; import { EditJsonButton } from '../EditJsonButton'; import { LinksDisplay } from '../LinksDisplay'; +import { LockDashboardButton } from '../LockDashboardButton'; import { SaveDashboardButton } from '../SaveDashboardButton'; +import { UpdatePluginsButton } from '../UpdatePluginsButton'; import { EditVariablesButton } from '../Variables'; export interface DashboardToolbarProps { @@ -40,6 +42,14 @@ export interface DashboardToolbarProps { isAnnotationEnabled: boolean; isDatasourceEnabled: boolean; isLinksEnabled?: boolean; + /** + * When true, add a button that locks/unlocks the dashboard: pins every plugin it uses to an exact version or unpin all versions. + */ + isLockModeAvailable?: boolean; + /** + * When true, add a button will open a drawer that shows the plugins that can be updated and allows the user to update them. + */ + isUpdateButtonAvailable?: boolean; timezone: string; onEditButtonClick: () => void; onCancelButtonClick: () => void; @@ -56,6 +66,8 @@ export const DashboardToolbar = (props: DashboardToolbarProps): ReactElement => isAnnotationEnabled, isDatasourceEnabled, isLinksEnabled = true, + isLockModeAvailable = false, + isUpdateButtonAvailable = false, timezone: toolbarTimezone, onEditButtonClick, onCancelButtonClick, @@ -106,6 +118,8 @@ export const DashboardToolbar = (props: DashboardToolbarProps): ReactElement => {isLinksEnabled && } + {isUpdateButtonAvailable && } + {isLockModeAvailable && } ) : ( - <> - {isBiggerThanSm && ( - - - - )} - + isBiggerThanSm && ( + + + + ) )} { - if (isFirstRender) { - setIsFirstRender(false); - } - }, [isFirstRender]); - return ( - + {props.children} - + ); } -/** - * These are the classes needed by react-grid-layout from their CSS stylesheet. - */ -const ReactGridLayoutContainer = styled('section')(({ theme }) => ({ - '& .react-grid-layout': { - position: 'relative', - transition: 'height 200ms ease', - }, - '& .react-grid-item': { - transition: 'all 200ms ease', - transitionProperty: 'left, top', - }, - '& .react-grid-item img': { - pointerEvents: 'none', - userSelect: 'none', - }, - '& .react-grid-item.cssTransforms': { - transitionProperty: 'transform', - }, - '& .react-grid-item.resizing': { - zIndex: 1, - willChange: 'width, height', - }, - '& .react-grid-item.react-draggable-dragging': { - transition: 'none', - zIndex: 3, - willChange: 'transform', - }, - '& .react-grid-item.dropping': { - visibility: 'hidden', - }, - '& .react-grid-item.react-grid-placeholder': { - background: theme.palette.primary.main, +const SnapgridContainer = styled('section')(({ theme }) => ({ + '& + &': { marginTop: theme.spacing(1) }, + '& .snapgrid-item > div': { height: '100%' }, + '& .snapgrid-item img': { pointerEvents: 'none', userSelect: 'none' }, + '& .snapgrid-placeholder': { + background: `${theme.palette.primary.main} !important`, + borderColor: `${theme.palette.primary.main} !important`, opacity: 0.2, - transitionDuration: '100ms', - zIndex: 2, - userSelect: 'none', - WebkitUserSelect: 'none', - MozUserSelect: 'none', - msUserSelect: 'none', - OUserSelect: 'none', - }, - - '& .react-grid-item > .react-resizable-handle': { - position: 'absolute', - width: '20px', - height: '20px', - }, - '& .react-grid-item > .react-resizable-handle::after': { - content: '""', - position: 'absolute', - right: '3px', - bottom: '3px', - width: '5px', - height: '5px', - borderRight: `2px solid ${theme.palette.text.secondary}`, - borderBottom: `2px solid ${theme.palette.text.secondary}`, - }, - - '& .react-resizable-hide > .react-resizable-handle': { - display: 'none', - }, - - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-sw': { - bottom: '0', - left: '0', - cursor: 'sw-resize', - transform: 'rotate(90deg)', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-se': { - bottom: '0', - right: '0', - cursor: 'se-resize', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-nw': { - top: '0', - left: '0', - cursor: 'nw-resize', - transform: 'rotate(180deg)', }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-ne': { - top: '0', - right: '0', - cursor: 'ne-resize', - transform: 'rotate(270deg)', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-w, &.react-grid-item > .react-resizable-handle.react-resizable-handle-e': - { - top: '50%', - marginTop: '-10px', - cursor: 'ew-resize', + '& .snapgrid-resize-handle--se': { + right: '0 !important', + bottom: '0 !important', + width: '20px !important', + height: '20px !important', + '&::after': { + content: '""', + position: 'absolute', + right: 3, + bottom: 3, + width: 5, + height: 5, + borderRight: `2px solid ${theme.palette.text.secondary}`, + borderBottom: `2px solid ${theme.palette.text.secondary}`, }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-w': { - left: '0', - transform: 'rotate(135deg)', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-e': { - right: '0', - transform: 'rotate(315deg)', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-n, &.react-grid-item > .react-resizable-handle.react-resizable-handle-s': - { - left: '50%', - marginLeft: '-10px', - cursor: 'ns-resize', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-n': { - top: '0', - transform: 'rotate(225deg)', - }, - '& .react-grid-item > .react-resizable-handle.react-resizable-handle-s': { - bottom: '0', - transform: 'rotate(45deg)', - }, - '& .react-resizable': { - position: 'relative', - }, - '& .react-resizable-handle': { - position: 'absolute', - width: '20px', - height: '20px', - backgroundRepeat: 'no-repeat', - backgroundOrigin: 'content-box', - boxSizing: 'border-box', - backgroundImage: `url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+')`, - backgroundPosition: 'bottom right', - padding: '0 3px 3px 0', - }, - '& .react-resizable-handle-sw': { - bottom: '0', - left: '0', - cursor: 'sw-resize', - transform: 'rotate(90deg)', - }, - '& .react-resizable-handle-se': { - bottom: '0', - right: '0', - cursor: 'se-resize', - }, - '& .react-resizable-handle-nw': { - top: '0', - left: '0', - cursor: 'nw-resize', - transform: 'rotate(180deg)', - }, - '& .react-resizable-handle-ne': { - top: '0', - right: '0', - cursor: 'ne-resize', - transform: 'rotate(270deg)', - }, - '& .react-resizable-handle-w, .react-resizable-handle-e': { - top: '50%', - marginTop: '-10px', - cursor: 'ew-resize', - }, - '& .react-resizable-handle-w': { - left: '0', - transform: 'rotate(135deg)', - }, - '& .react-resizable-handle-e': { - right: '0', - transform: 'rotate(315deg)', - }, - '& .react-resizable-handle-n, .react-resizable-handle-s': { - left: '50%', - marginLeft: '-10px', - cursor: 'ns-resize', - }, - '& .react-resizable-handle-n': { - top: '0', - transform: 'rotate(225deg)', - }, - '& .react-resizable-handle-s': { - bottom: '0', - transform: 'rotate(45deg)', }, })); diff --git a/dashboards/src/components/GridLayout/GridItemContent.tsx b/dashboards/src/components/GridLayout/GridItemContent.tsx index 9fb98e9d..976ccd41 100644 --- a/dashboards/src/components/GridLayout/GridItemContent.tsx +++ b/dashboards/src/components/GridLayout/GridItemContent.tsx @@ -106,7 +106,10 @@ export function GridItemContent(props: GridItemContentProps): ReactElement { // map TimeSeriesQueryDefinition to Definition const suggestedStepMs = useSuggestedStepMs(width); - const { data: plugin } = usePlugin('Panel', panelDefinition.spec.plugin.kind); + const { data: plugin } = usePlugin('Panel', panelDefinition.spec.plugin.kind, { + version: panelDefinition.spec.plugin.metadata?.version, + registry: panelDefinition.spec.plugin.metadata?.registry, + }); const pluginQueryOptions = typeof plugin?.queryOptions === 'function' diff --git a/dashboards/src/components/GridLayout/GridItemRenderer.test.tsx b/dashboards/src/components/GridLayout/GridItemRenderer.test.tsx new file mode 100644 index 00000000..af0386db --- /dev/null +++ b/dashboards/src/components/GridLayout/GridItemRenderer.test.tsx @@ -0,0 +1,91 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { useVariableValues, VariableContext } from '@perses-dev/plugin-system'; +import { render, screen } from '@testing-library/react'; +import type { ReactElement } from 'react'; +import { useMemo } from 'react'; + +import { DEFAULT_MARGIN } from '../../constants'; +import { useViewPanelGroup } from '../../context'; +import type { PanelGroupItemId } from '../../model'; +import type { RepeatItemMeta } from '../../utils'; +import type { GridItemContentProps } from './GridItemContent'; +import { GridItemRenderer } from './GridItemRenderer'; + +vi.mock('../../context', () => ({ useViewPanelGroup: vi.fn() })); + +// Keep the repeat layout and variable providers real, without loading panel plugins. +vi.mock('./GridItemContent', () => ({ + GridItemContent: ({ width }: GridItemContentProps): ReactElement => { + const variables = useVariableValues(); + const style = useMemo(() => ({ width }), [width]); + return
; + }, +})); + +const repeatItemMeta: RepeatItemMeta = { + itemRepeatVariable: { value: 'instance', alignment: 'horizontal', maxPer: 3 }, + values: ['first', 'second', 'third'], + totalValues: 3, + numberOfRows: 1, +}; +const variableContext = { state: { instance: { value: repeatItemMeta.values, loading: false } } }; + +function renderRepeatedPanel(groupRepeatVariable?: [string, string]): ReactElement { + return ( + + + + ); +} + +describe('GridItemRenderer', () => { + it.each([{ groupRepeatVariable: undefined }, { groupRepeatVariable: ['region', 'west'] }] satisfies Array<{ + groupRepeatVariable?: [string, string]; + }>)( + 'uses the full width for a fullscreen repeated panel and restores columns on exit (group: $groupRepeatVariable)', + ({ groupRepeatVariable }) => { + vi.mocked(useViewPanelGroup).mockReturnValue(undefined); + const { rerender } = render(renderRepeatedPanel(groupRepeatVariable)); + const repeatedWidth = Math.floor((1200 - 2 * DEFAULT_MARGIN) / 3); + expect(screen.getAllByRole('region')).toHaveLength(3); + expect(screen.getByRole('region', { name: 'second' })).toHaveStyle({ width: `${repeatedWidth}px` }); + + const viewedPanel: PanelGroupItemId = { + panelGroupId: 0, + panelGroupItemLayoutId: 'panel', + repeatVariable: { panel: ['instance', 'second'], group: groupRepeatVariable }, + }; + vi.mocked(useViewPanelGroup).mockReturnValue(viewedPanel); + rerender(renderRepeatedPanel(groupRepeatVariable)); + + expect(screen.getAllByRole('region')).toHaveLength(1); + const panel = screen.getByRole('region', { name: 'second' }); + expect(panel).toHaveStyle({ width: '1200px' }); + expect(panel.parentElement).toHaveStyle({ width: 'calc((100% - 0px) / 1)' }); + + vi.mocked(useViewPanelGroup).mockReturnValue(undefined); + rerender(renderRepeatedPanel(groupRepeatVariable)); + expect(screen.getAllByRole('region')).toHaveLength(3); + expect(screen.getByRole('region', { name: 'second' })).toHaveStyle({ width: `${repeatedWidth}px` }); + }, + ); +}); diff --git a/dashboards/src/components/GridLayout/GridItemRenderer.tsx b/dashboards/src/components/GridLayout/GridItemRenderer.tsx index 3f785772..8a4bcffa 100644 --- a/dashboards/src/components/GridLayout/GridItemRenderer.tsx +++ b/dashboards/src/components/GridLayout/GridItemRenderer.tsx @@ -67,7 +67,7 @@ export function GridItemRenderer({ panelRepeatVariable={{ name: panelRepeatVariable.value, values: effectiveValues, - maxPer: getPerRowCount(panelRepeatVariable), + maxPer: viewPanelItemId?.repeatVariable?.panel ? 1 : getPerRowCount(panelRepeatVariable), }} groupRepeatVariable={groupRepeatVariable} width={width} diff --git a/dashboards/src/components/GridLayout/GridLayout.tsx b/dashboards/src/components/GridLayout/GridLayout.tsx index b88996fb..899bb3c7 100644 --- a/dashboards/src/components/GridLayout/GridLayout.tsx +++ b/dashboards/src/components/GridLayout/GridLayout.tsx @@ -14,12 +14,10 @@ import type { PanelGroupId } from '@perses-dev/plugin-system'; import { useVariableValues } from '@perses-dev/plugin-system'; import type { ReactElement } from 'react'; -import { useState } from 'react'; -import type { Layout, Layouts } from 'react-grid-layout'; +import { useCallback } from 'react'; -import { GRID_LAYOUT_SMALL_BREAKPOINT } from '../../constants'; import { useEditMode, usePanelGroup, usePanelGroupActions, useViewPanelGroup } from '../../context'; -import type { PanelGroupDefinition } from '../../model'; +import type { PanelGroupDefinition, PanelGroupItemLayout } from '../../model'; import type { PanelOptions } from '../Panel'; import { FixedValueVariableProvider } from '../Variables'; import type { RowProps } from './Row'; @@ -41,37 +39,16 @@ export function GridLayout(props: GridLayoutProps): ReactElement { const viewPanelItemId = useViewPanelGroup(); const { isEditMode } = useEditMode(); - const [gridColWidth, setGridColWidth] = useState(0); - const hasViewPanel = viewPanelItemId?.panelGroupId === panelGroupId; // current panelGroup contains the panel extended? - const handleLayoutChange = (currentLayout: Layout[], allLayouts: Layouts): void => { - // Using the value from `allLayouts` instead of `currentLayout` because of - // a bug in react-layout-grid where `currentLayout` does not adjust properly - // when going to a smaller breakpoint and then back to a larger breakpoint. - // https://github.com/react-grid-layout/react-grid-layout/issues/1663 - const smallLayout = allLayouts[GRID_LAYOUT_SMALL_BREAKPOINT]; - if (smallLayout && !hasViewPanel) { - updatePanelGroupLayouts(smallLayout); - } - }; - - /** - * Calculate the column width so we can determine the width of each panel for suggested step ms - * https://github.com/react-grid-layout/react-grid-layout/blob/master/lib/calculateUtils.js#L14-L35 - */ - const handleWidthChange = ( - containerWidth: number, - margin: [number, number], - cols: number, - containerPadding: [number, number], - ): void => { - const marginX = margin[0]; - const marginWidth = marginX * (cols - 1); - const containerPaddingWidth = containerPadding[0] * 2; - // exclude margin and padding from total width - setGridColWidth((containerWidth - marginWidth - containerPaddingWidth) / cols); - }; + const handleLayoutChange = useCallback( + (layout: PanelGroupItemLayout[]): void => { + if (isEditMode && !hasViewPanel) { + updatePanelGroupLayouts(layout); + } + }, + [hasViewPanel, isEditMode, updatePanelGroupLayouts], + ); return ( <> @@ -79,24 +56,20 @@ export function GridLayout(props: GridLayoutProps): ReactElement { ) : ( )} @@ -114,12 +87,10 @@ export function RepeatGridLayout({ repeatVariableName, panelGroupId, groupDefinition, - gridColWidth, panelFullHeight, panelOptions, isEditMode = false, onLayoutChange, - onWidthChange, }: RepeatGridLayoutProps): ReactElement | null { const variables = useVariableValues(); const variable = variables[repeatVariableName]; @@ -130,12 +101,10 @@ export function RepeatGridLayout({ ); } @@ -151,12 +120,10 @@ export function RepeatGridLayout({ diff --git a/dashboards/src/components/GridLayout/Row.test.tsx b/dashboards/src/components/GridLayout/Row.test.tsx new file mode 100644 index 00000000..b114af66 --- /dev/null +++ b/dashboards/src/components/GridLayout/Row.test.tsx @@ -0,0 +1,128 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type * as PluginSystemModule from '@perses-dev/plugin-system'; +import type * as SnapgridModule from '@snapgridjs/react'; +import { GridLayout as SnapgridLayout, useContainerWidth } from '@snapgridjs/react'; +import type { GridLayoutProps } from '@snapgridjs/react'; +import { act, render } from '@testing-library/react'; + +import { useViewPanelGroup } from '../../context'; +import type { PanelGroupDefinition, PanelGroupItemLayout } from '../../model'; +import { Row } from './Row'; + +vi.mock('@snapgridjs/react', async (importOriginal) => ({ + ...(await importOriginal()), + GridLayout: vi.fn(() => null), + useContainerWidth: vi.fn(), +})); +vi.mock('@perses-dev/plugin-system', async (importOriginal) => ({ + ...(await importOriginal()), + useVariableValues: vi.fn(() => ({ instance: { value: ['a', 'b', 'c', 'd'], loading: false } })), +})); +vi.mock('../../context', () => ({ + useViewPanelGroup: vi.fn(), + useRepeatVariableMaxValues: vi.fn(), +})); +vi.mock('./GridItemRenderer', () => ({ GridItemRenderer: vi.fn(() => null) })); + +function gridProps(): GridLayoutProps { + const props = vi.mocked(SnapgridLayout).mock.lastCall?.[0]; + if (!props) throw new Error('Grid was not rendered'); + return props; +} + +const groupDefinition: PanelGroupDefinition = { + id: 0, + isCollapsed: false, + itemLayouts: [{ i: 'panel', x: 0, y: 0, w: 12, h: 3 }], + itemPanelKeys: { panel: 'panel' }, +}; +const containerRef = vi.fn(); + +beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(useViewPanelGroup).mockReturnValue(undefined); + vi.mocked(useContainerWidth).mockReturnValue({ width: 400, mounted: true, containerRef }); +}); + +describe('Row responsive editing', () => { + it.each([ + { width: 400, repeated: false }, + { width: 1200, repeated: false }, + { width: 400, repeated: true }, + { width: 1200, repeated: true }, + ])('persists a resize at $width px (repeated: $repeated)', ({ width, repeated }) => { + vi.mocked(useContainerWidth).mockReturnValue({ width, mounted: true, containerRef }); + const repeatVariable = repeated ? { value: 'instance', maxPer: 2 } : undefined; + const group: PanelGroupDefinition = { + ...groupDefinition, + itemLayouts: groupDefinition.itemLayouts.map((item) => ({ ...item, repeatVariable })), + }; + const onLayoutChange = vi.fn<(layout: PanelGroupItemLayout[]) => void>(); + const props = { panelGroupId: 0, groupDefinition: group, isEditMode: true, onLayoutChange }; + const { rerender } = render(); + + expect(gridProps().isResizable).toBe(true); + expect(gridProps().gridConfig?.cols).toBe(24); + expect(gridProps().layout[0]).toMatchObject({ x: 0, y: 0, w: 12, h: repeated ? 7 : 3 }); + + // Supply the layout emitted by Snapgrid after dragging the resize handle. + const item = gridProps().layout[0]; + if (!item) throw new Error('Panel was not rendered'); + const resized = [{ ...item, w: 9, h: repeated ? 11 : 5 }]; + act(() => gridProps().onLayoutChange?.(resized)); + expect(onLayoutChange).toHaveBeenCalledWith([expect.objectContaining({ i: 'panel', x: 0, y: 0, w: 9, h: 5 })]); + expect(onLayoutChange.mock.calls[0]?.[0][0]?.repeatVariable).toEqual(repeatVariable); + const updatedProps = { + ...props, + groupDefinition: { ...group, itemLayouts: onLayoutChange.mock.calls[0]?.[0] ?? [] }, + }; + rerender(); + expect(gridProps().layout[0]).toMatchObject({ w: 9, h: repeated ? 11 : 5 }); + + // Crossing the breakpoint must preserve the resized dimensions. + vi.mocked(useContainerWidth).mockReturnValue({ width: width === 400 ? 1200 : 400, mounted: true, containerRef }); + rerender(); + expect(gridProps().layout[0]).toMatchObject({ w: 9, h: repeated ? 11 : 5 }); + expect(onLayoutChange).toHaveBeenCalledTimes(1); + }); + + it('stacks panels when viewing and restores saved positions when editing on a narrow screen', () => { + const group: PanelGroupDefinition = { + ...groupDefinition, + itemLayouts: [ + { i: 'panel', x: 0, y: 0, w: 12, h: 3 }, + { i: 'second', x: 12, y: 0, w: 12, h: 3 }, + ], + itemPanelKeys: { panel: 'panel', second: 'second' }, + }; + const onLayoutChange = vi.fn(); + const props = { panelGroupId: 0, groupDefinition: group, onLayoutChange }; + const { rerender } = render(); + expect(gridProps().gridConfig?.cols).toBe(2); + expect(gridProps().isResizable).toBe(false); + expect(gridProps().layout).toEqual([ + expect.objectContaining({ x: 0, y: 0, w: 2 }), + expect.objectContaining({ x: 0, y: 3, w: 2 }), + ]); + + rerender(); + expect(gridProps().gridConfig?.cols).toBe(24); + expect(gridProps().layout).toEqual([ + expect.objectContaining({ x: 0, y: 0, w: 12 }), + expect.objectContaining({ x: 12, y: 0, w: 12 }), + ]); + expect(onLayoutChange).not.toHaveBeenCalled(); + }); +}); diff --git a/dashboards/src/components/GridLayout/Row.tsx b/dashboards/src/components/GridLayout/Row.tsx index 6a3b4fa6..7789ca05 100644 --- a/dashboards/src/components/GridLayout/Row.tsx +++ b/dashboards/src/components/GridLayout/Row.tsx @@ -14,49 +14,52 @@ import { Collapse, useTheme } from '@mui/material'; import type { PanelGroupId } from '@perses-dev/plugin-system'; import { useVariableValues } from '@perses-dev/plugin-system'; +import type { Layout } from '@snapgridjs/react'; +import { GridLayout as SnapgridLayout, useContainerWidth, useResponsiveLayout } from '@snapgridjs/react'; import type { ReactElement } from 'react'; -import { useEffect, useMemo, useState } from 'react'; -import type { Layout, Layouts } from 'react-grid-layout'; -import { Responsive, WidthProvider } from 'react-grid-layout'; +import { useMemo, useState } from 'react'; -import { DEFAULT_MARGIN, GRID_LAYOUT_COLS, GRID_LAYOUT_SMALL_BREAKPOINT, ROW_HEIGHT } from '../../constants'; +import { DEFAULT_MARGIN, GRID_LAYOUT_COLS, ROW_HEIGHT } from '../../constants'; import { useRepeatVariableMaxValues, useViewPanelGroup } from '../../context'; import type { PanelGroupDefinition, PanelGroupItemLayout } from '../../model'; -import { buildRepeatMeta, restoreRepeatLayouts } from '../../utils'; +import { + buildRepeatMeta, + compactLayout, + decodeGridItemId, + encodeGridItemId, + restoreRepeatItemLayout, +} from '../../utils'; import type { PanelOptions } from '../Panel/Panel'; import { GridContainer } from './GridContainer'; import { GridItemRenderer } from './GridItemRenderer'; import { GridTitle } from './GridTitle'; +const GRID_MARGIN: [number, number] = [DEFAULT_MARGIN, DEFAULT_MARGIN]; +const GRID_PADDING: [number, number] = [0, 10]; +const DRAG_CONFIG = { handle: '.drag-handle' }; +// Editing uses persisted coordinates at every width so a resize survives the next render. +const EDIT_GRID_COLS = { sm: GRID_LAYOUT_COLS.sm, xxs: GRID_LAYOUT_COLS.sm }; + export interface RowProps { panelGroupId: PanelGroupId; groupDefinition: PanelGroupDefinition; - gridColWidth: number; panelFullHeight?: number; panelOptions?: PanelOptions; isEditMode?: boolean; - onLayoutChange?: (currentLayout: Layout[], allLayouts: Layouts) => void; - onWidthChange?: ( - containerWidth: number, - margin: [number, number], - cols: number, - containerPadding: [number, number], - ) => void; + onLayoutChange?: (layout: PanelGroupItemLayout[]) => void; repeatVariable?: [string, string]; } export function Row({ panelGroupId, groupDefinition, - gridColWidth, panelFullHeight, panelOptions, isEditMode = false, onLayoutChange, - onWidthChange, repeatVariable, }: RowProps): ReactElement { - const ResponsiveGridLayout = useMemo(() => WidthProvider(Responsive), []); + const { width, containerRef } = useContainerWidth(); const theme = useTheme(); const viewPanelItemId = useViewPanelGroup(); const variableValues = useVariableValues(); @@ -85,99 +88,132 @@ export function Row({ // If there is a panel in view mode, we should hide the grid if the panel is not in the current group. const isGridDisplayed = !viewPanelItemId || hasViewPanel; - // TODO: handle it without useEffect - useEffect(() => { - if (hasViewPanel) { - setIsOpen(true); - } - }, [hasViewPanel]); - // Item layout is override if there is a panel in view mode const itemLayouts: PanelGroupItemLayout[] = useMemo(() => { if (itemLayoutViewed) { - return expandedItemLayouts.map((itemLayout) => { - if (itemLayout.i === itemLayoutViewed) { - const rowTitleHeight = 40 + 8; // 40 is the height of the row title and 8 is the margin height - return { - ...itemLayout, - h: Math.round(((panelFullHeight ?? window.innerHeight) - rowTitleHeight) / (ROW_HEIGHT + DEFAULT_MARGIN)), // Viewed panel should take the full height remaining - i: itemLayoutViewed, - w: 48, - x: 0, - y: 0, - } as PanelGroupItemLayout; - } - return itemLayout; - }); + const viewedItem = expandedItemLayouts.find((item) => item.i === itemLayoutViewed); + if (!viewedItem) return []; + const rowTitleHeight = 40 + 8; // 40 is the height of the row title and 8 is the margin height + return [ + { + ...viewedItem, + h: Math.max( + 1, + Math.round(((panelFullHeight ?? window.innerHeight) - rowTitleHeight) / (ROW_HEIGHT + DEFAULT_MARGIN)), + ), + w: GRID_LAYOUT_COLS.sm, + x: 0, + y: 0, + }, + ]; } - return expandedItemLayouts; + // Snapgrid renders a controlled layout as-is: resolve overlaps caused by expanded repeat panels. + return compactLayout(expandedItemLayouts); }, [expandedItemLayouts, itemLayoutViewed, panelFullHeight]); + const layouts = useMemo( + () => ({ sm: itemLayouts.map((item) => ({ ...item, i: encodeGridItemId(item.i, repeatVariable) })) }), + [itemLayouts, repeatVariable], + ); + const breakpoints = useMemo(() => ({ sm: theme.breakpoints.values.sm, xxs: 0 }), [theme.breakpoints.values.sm]); + const { layout: responsiveLayout, cols } = useResponsiveLayout({ + width, + layouts, + breakpoints, + cols: isEditMode ? EDIT_GRID_COLS : GRID_LAYOUT_COLS, + }); + // Column width in px (margins and padding excluded); panels derive their suggested step from it. + const gridColWidth = (width - GRID_MARGIN[0] * (cols - 1) - GRID_PADDING[0] * 2) / cols; + const gridConfig = useMemo( + () => ({ cols, rowHeight: ROW_HEIGHT, margin: GRID_MARGIN, containerPadding: GRID_PADDING }), + [cols], + ); + const handleLayoutChange = useMemo(() => { - if (!onLayoutChange) { - return undefined; - } - return (currentLayout: Layout[], allLayouts: Layouts): void => { - const restored = restoreRepeatLayouts(currentLayout, allLayouts, repeatMeta); - onLayoutChange(restored.currentLayout, restored.allLayouts); + if (!onLayoutChange) return undefined; + return (currentLayout: Layout): void => { + const canonicalLayout = currentLayout.map((item) => { + const id = decodeGridItemId(item.i); + const layout: PanelGroupItemLayout = { + ...item, + i: id, + }; + const meta = repeatMeta.get(id); + return meta ? restoreRepeatItemLayout(layout, meta) : layout; + }); + onLayoutChange(canonicalLayout); }; }, [onLayoutChange, repeatMeta]); + // Keep later groups stationary while Snapgrid previews removing a tile from this group. + const gridStyle = useMemo( + () => + isEditMode + ? { + minHeight: Math.max( + ROW_HEIGHT * 3, + responsiveLayout.reduce((bottom, item) => Math.max(bottom, item.y + item.h), 0) * + (ROW_HEIGHT + DEFAULT_MARGIN) - + DEFAULT_MARGIN + + GRID_PADDING[1] * 2, + ), + } + : undefined, + [isEditMode, responsiveLayout], + ); + + const containerSx = useMemo( + () => ({ + display: isGridDisplayed ? 'block' : 'none', + height: itemLayoutViewed ? `${panelFullHeight}px` : 'unset', + overflow: itemLayoutViewed ? 'hidden' : 'unset', + }), + [isGridDisplayed, itemLayoutViewed, panelFullHeight], + ); + const collapse = useMemo( + () => + groupDefinition.isCollapsed === undefined + ? undefined + : { + isOpen: isOpen || hasViewPanel, + onToggleOpen: (): void => setIsOpen((current) => !current), + }, + [groupDefinition.isCollapsed, isOpen, hasViewPanel], + ); + return ( - + {groupDefinition.title && ( - setIsOpen((current) => !current) } - } - /> + )} - - - {itemLayouts.map(({ i, w }) => ( -
- -
- ))} -
+ +
+ + {itemLayouts.map(({ i, w }) => ( +
+ +
+ ))} +
+
); diff --git a/dashboards/src/components/LinksDisplay/LinksDisplay.tsx b/dashboards/src/components/LinksDisplay/LinksDisplay.tsx index f982e02d..ca1af6cc 100644 --- a/dashboards/src/components/LinksDisplay/LinksDisplay.tsx +++ b/dashboards/src/components/LinksDisplay/LinksDisplay.tsx @@ -14,7 +14,7 @@ import type { Theme } from '@mui/material'; import { IconButton, Link as LinkComponent, Menu, MenuItem, Chip, capitalize, Stack } from '@mui/material'; import { InfoTooltip } from '@perses-dev/components'; -import { useReplaceVariablesInString } from '@perses-dev/plugin-system'; +import { useReplaceVariablesInString, useReplaceVariablesInUrl } from '@perses-dev/plugin-system'; import type { Link } from '@perses-dev/spec'; import LaunchIcon from 'mdi-material-ui/Launch'; import type { MouseEvent, ReactElement } from 'react'; @@ -164,9 +164,12 @@ function LinkMenuItem({ link }: { link: Link }): ReactElement { } function useLink(link: Link): Link { - const url = useReplaceVariablesInString(link.url) ?? link.url; + // Name/tooltip: plain string interpolation (unencoded $var). const name = useReplaceVariablesInString(link.name); const tooltip = useReplaceVariablesInString(link.tooltip); + // URL: URL-aware interpolation (also expands %24var inside query params). + const interpolatedUrl = useReplaceVariablesInUrl(link.renderVariables === false ? undefined : link.url); + const url = link.renderVariables === false ? link.url : (interpolatedUrl ?? link.url); if (link.renderVariables === false) { return link; diff --git a/dashboards/src/components/LockDashboardButton/LockDashboardButton.tsx b/dashboards/src/components/LockDashboardButton/LockDashboardButton.tsx new file mode 100644 index 00000000..589a3583 --- /dev/null +++ b/dashboards/src/components/LockDashboardButton/LockDashboardButton.tsx @@ -0,0 +1,112 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Button, Tooltip } from '@mui/material'; +import { Dialog } from '@perses-dev/components'; +import { useListPluginMetadata } from '@perses-dev/plugin-system'; +import LockOpenOutline from 'mdi-material-ui/LockOpenOutline'; +import LockOutline from 'mdi-material-ui/LockOutline'; +import type { ReactElement } from 'react'; +import { useCallback, useMemo, useState } from 'react'; + +import { useDashboard } from '../../context/useDashboard'; +import { + applyPluginVersions, + buildLatestPluginVersions, + isDashboardLocked, + removePluginVersions, +} from '../../utils/pluginVersioning'; + +/** + * Toolbar button that "locks" or "unlocks" the dashboard. + * + * Locking pins every plugin definition (panels, queries, variables, datasources, annotations) to the latest version + * currently available in the Perses instance, by setting `plugin.metadata.version`. Unlocking removes that pinned + * version so the plugins float on the latest available version again. + * + * A dashboard can also be versioned partially (a single panel pinned from the panel editor, for instance). In that case + * both actions are offered: locking completes the pinning, unlocking clears it. + * + * Both actions are confirmed through a dialog explaining their consequences before the dashboard is updated. + */ +export function LockDashboardButton(): ReactElement { + const { dashboard, setDashboard } = useDashboard(); + const { data: pluginMetadata, isLoading } = useListPluginMetadata(); + const [pendingAction, setPendingAction] = useState<'lock' | 'unlock' | undefined>(undefined); + + const isLocked = useMemo(() => isDashboardLocked(dashboard), [dashboard]); + + const closeConfirmation = useCallback((): void => setPendingAction(undefined), []); + + const handleConfirm = useCallback((): void => { + if (pendingAction === 'unlock') { + setDashboard(removePluginVersions(dashboard)); + } else if (pendingAction === 'lock') { + setDashboard(applyPluginVersions(dashboard, buildLatestPluginVersions(pluginMetadata ?? []))); + } + setPendingAction(undefined); + }, [dashboard, pendingAction, pluginMetadata, setDashboard]); + + const isUnlockAction = pendingAction === 'unlock'; + const confirmLabel = isUnlockAction ? 'Unlock' : 'Lock'; + + return ( + <> + {isLocked ? ( + + + + + + ) : ( + + + + + + )} + + + {isUnlockAction ? 'Unlock Dashboard' : 'Lock Dashboard'} + + + {isUnlockAction + ? 'Unlocking removes the plugin versions pinned on this dashboard. Its panels, queries, variables, datasources and annotations will use the latest plugin versions available in this Perses instance, so their behavior may change when those plugins are updated.' + : 'Locking pins every plugin used by this dashboard (panels, queries, variables, datasources and annotations) to the latest version currently available in this Perses instance. The dashboard keeps using those exact versions, even after the plugins are updated. Plugins that are not installed in this instance cannot be pinned.'} + {' The change only applies once you save the dashboard.'} + + + {confirmLabel} + Cancel + + + + ); +} diff --git a/dashboards/src/components/LockDashboardButton/index.ts b/dashboards/src/components/LockDashboardButton/index.ts new file mode 100644 index 00000000..724e1345 --- /dev/null +++ b/dashboards/src/components/LockDashboardButton/index.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './LockDashboardButton'; diff --git a/dashboards/src/components/Panel/Panel.tsx b/dashboards/src/components/Panel/Panel.tsx index 7a1fe2c1..3772330f 100644 --- a/dashboards/src/components/Panel/Panel.tsx +++ b/dashboards/src/components/Panel/Panel.tsx @@ -136,7 +136,12 @@ export const Panel = memo(function Panel(props: PanelProps) { } try { - const plugin = await getPlugin({ kind: 'Panel', name: panelPluginKind }); + const plugin = await getPlugin({ + kind: 'Panel', + name: panelPluginKind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); // More defensive checking for plugin and actions if ( @@ -173,7 +178,7 @@ export const Panel = memo(function Panel(props: PanelProps) { }; loadPluginActions(); - }, [definition.spec.plugin.kind, panelPropsForActions, getPlugin]); + }, [definition.spec.plugin, panelPropsForActions, getPlugin]); const handleMouseEnter: CardProps['onMouseEnter'] = (e) => { onMouseEnter?.(e); diff --git a/dashboards/src/components/Panel/PanelActions.tsx b/dashboards/src/components/Panel/PanelActions.tsx index df49c615..4833b984 100644 --- a/dashboards/src/components/Panel/PanelActions.tsx +++ b/dashboards/src/components/Panel/PanelActions.tsx @@ -260,8 +260,8 @@ export const PanelActions: React.FC = ({ return ( theme.palette.background.default }}> - - + + @@ -421,6 +421,7 @@ export const OverflowMenu: React.FC< }, ]} sx={{ + zIndex: 6, // Must be higher than PanelHeader zIndex (5) backgroundColor: (theme) => theme.palette.background.paper, borderRadius: 1, boxShadow: (theme) => theme.shadows[4], diff --git a/dashboards/src/components/Panel/PanelContent.tsx b/dashboards/src/components/Panel/PanelContent.tsx index 14f3b47c..249a20a1 100644 --- a/dashboards/src/components/Panel/PanelContent.tsx +++ b/dashboards/src/components/Panel/PanelContent.tsx @@ -32,7 +32,11 @@ export interface PanelContentProps extends Omit, 'queryR */ export function PanelContent(props: PanelContentProps): ReactElement { const { panelPluginKind, definition, queryResults, spec, contentDimensions } = props; - const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', panelPluginKind, { useErrorBoundary: true }); + const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', panelPluginKind, { + useErrorBoundary: true, + version: definition?.spec.plugin.metadata?.version, + registry: definition?.spec.plugin.metadata?.registry, + }); // Show fullsize skeleton if the panel plugin is loading. if (isPanelLoading) { diff --git a/dashboards/src/components/Panel/PanelPluginLoader.tsx b/dashboards/src/components/Panel/PanelPluginLoader.tsx index 209a231c..b89eef44 100644 --- a/dashboards/src/components/Panel/PanelPluginLoader.tsx +++ b/dashboards/src/components/Panel/PanelPluginLoader.tsx @@ -27,7 +27,11 @@ interface PanelPluginProps extends PanelProps { */ export function PanelPluginLoader(props: PanelPluginProps): ReactElement { const { kind, spec, contentDimensions, definition, queryResults } = props; - const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', kind, { useErrorBoundary: true }); + const { data: plugin, isLoading: isPanelLoading } = usePlugin('Panel', kind, { + useErrorBoundary: true, + version: definition?.spec.plugin.metadata?.version, + registry: definition?.spec.plugin.metadata?.registry, + }); const PanelComponent = plugin?.PanelComponent; const supportedQueryTypes = plugin?.supportedQueryTypes || []; // Clear out the queryResults parameter for plugins which don't support any query types diff --git a/dashboards/src/components/PanelDrawer/PanelEditorForm.tsx b/dashboards/src/components/PanelDrawer/PanelEditorForm.tsx index 4ac18880..f1d54fff 100644 --- a/dashboards/src/components/PanelDrawer/PanelEditorForm.tsx +++ b/dashboards/src/components/PanelDrawer/PanelEditorForm.tsx @@ -23,7 +23,7 @@ import { } from '@perses-dev/components'; import type { PanelEditorValues } from '@perses-dev/plugin-system'; import { PluginKindSelect, usePluginEditor, useValidationSchemas } from '@perses-dev/plugin-system'; -import type { PanelDefinition } from '@perses-dev/spec'; +import type { Definition, PanelDefinition, UnknownSpec } from '@perses-dev/spec'; import type { ReactElement } from 'react'; import { useCallback, useEffect, useState } from 'react'; import type { SubmitHandler } from 'react-hook-form'; @@ -62,17 +62,26 @@ export function PanelEditorForm(props: PanelEditorFormProps): ReactElement { mode: 'onBlur', defaultValues: initialValues, }); + const pluginMetadata = plugin.metadata; // Use common plugin editor logic even though we've split the inputs up in this form const pluginEditor = usePluginEditor({ pluginTypes: ['Panel'], - value: { selection: { kind: plugin.kind, type: 'Panel' }, spec: plugin.spec }, - onChange: (plugin) => { - form.setValue('panelDefinition.spec.plugin', { kind: plugin.selection.kind, spec: plugin.spec }); - setPlugin({ - kind: plugin.selection.kind, - spec: plugin.spec, - }); + // Carry the current pin so that editing the options doesn't silently drop it, and so the options editor is loaded + // from the pinned implementation. + value: { selection: { kind: plugin.kind, type: 'Panel', metadata: pluginMetadata }, spec: plugin.spec }, + onChange: (next) => { + // Persist the selected version/registry (if any) as plugin metadata so the panel uses that exact implementation. + // When nothing is selected (a single version/registry is available), metadata is omitted so the latest version + // of the default registry is used. + const metadata = next.selection.metadata; + const nextPlugin: Definition = { + kind: next.selection.kind, + ...(metadata?.version || metadata?.registry ? { metadata } : {}), + spec: next.spec, + }; + form.setValue('panelDefinition.spec.plugin', nextPlugin); + setPlugin(nextPlugin); }, onHideQueryEditorChange: (isHidden) => { setQueries(undefined, isHidden); @@ -217,16 +226,18 @@ export function PanelEditorForm(props: PanelEditorFormProps): ReactElement { { - field.onChange(event.kind); - pluginEditor.onSelectionChange(event); + value={{ type: 'Panel', kind: watchedPluginKind, metadata: pluginMetadata }} + onChange={(selection) => { + field.onChange(selection.kind); + pluginEditor.onSelectionChange(selection); }} /> )} diff --git a/dashboards/src/components/UpdatePluginsButton/UpdatePluginsButton.tsx b/dashboards/src/components/UpdatePluginsButton/UpdatePluginsButton.tsx new file mode 100644 index 00000000..5323f2a6 --- /dev/null +++ b/dashboards/src/components/UpdatePluginsButton/UpdatePluginsButton.tsx @@ -0,0 +1,75 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Badge, Button, Tooltip } from '@mui/material'; +import { useListPluginMetadata } from '@perses-dev/plugin-system'; +import UpdateIcon from 'mdi-material-ui/Update'; +import type { ReactElement } from 'react'; +import { useMemo, useState } from 'react'; + +import { useDashboard } from '../../context/useDashboard'; +import type { OutdatedPlugin } from '../../utils/pluginVersioning'; +import { buildLatestPluginVersions, findOutdatedPlugins, updatePluginVersions } from '../../utils/pluginVersioning'; +import { UpdatePluginsDrawer } from '../UpdatePluginsDrawer'; + +/** + * Toolbar button shown when at least one plugin pinned by the dashboard has a newer version installed. Opens a drawer to + * review and select which plugins to update. + * + * This is not reserved to fully locked dashboards: versioning can be enforced partially (a single panel pinned from the + * panel editor, for instance) and those pins are just as worth updating. + */ +export function UpdatePluginsButton(): ReactElement | null { + const { dashboard, setDashboard } = useDashboard(); + const { data: pluginMetadata } = useListPluginMetadata(); + const [isDrawerOpen, setDrawerOpen] = useState(false); + + const outdatedPlugins = useMemo( + () => findOutdatedPlugins(dashboard, buildLatestPluginVersions(pluginMetadata ?? [])), + [dashboard, pluginMetadata], + ); + + const handleUpdate = (plugins: OutdatedPlugin[]): void => { + setDashboard(updatePluginVersions(dashboard, plugins)); + setDrawerOpen(false); + }; + + // Nothing to update: don't render the button at all. + if (outdatedPlugins.length === 0) { + return null; + } + + return ( + <> + + + + + + setDrawerOpen(false)} + /> + + ); +} diff --git a/dashboards/src/components/UpdatePluginsButton/index.ts b/dashboards/src/components/UpdatePluginsButton/index.ts new file mode 100644 index 00000000..469eb747 --- /dev/null +++ b/dashboards/src/components/UpdatePluginsButton/index.ts @@ -0,0 +1,14 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './UpdatePluginsButton'; diff --git a/dashboards/src/components/UpdatePluginsDrawer/PanelVersionDiff.tsx b/dashboards/src/components/UpdatePluginsDrawer/PanelVersionDiff.tsx new file mode 100644 index 00000000..13d57791 --- /dev/null +++ b/dashboards/src/components/UpdatePluginsDrawer/PanelVersionDiff.tsx @@ -0,0 +1,94 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Alert, Box, Chip, Stack, Typography } from '@mui/material'; +import { ErrorAlert, ErrorBoundary } from '@perses-dev/components'; +import { DataQueriesProvider } from '@perses-dev/plugin-system'; +import type { PanelDefinition } from '@perses-dev/spec'; +import type { ReactElement } from 'react'; +import { useMemo } from 'react'; + +import { Panel } from '../Panel/Panel'; + +const PREVIEW_HEIGHT = 260; + +export interface PanelVersionDiffProps { + /** The panel used as a representative example of the plugin being updated. */ + panelDefinition: PanelDefinition; + /** The version currently pinned in the dashboard spec. */ + currentVersion: string; + /** The latest available version the plugin would be updated to. */ + latestVersion: string; + /** The registry the plugin is pinned to, when the definition pins one. */ + registry?: string; +} + +/** Returns a copy of the panel definition with its panel plugin pinned to the given version/registry. */ +function withPluginVersion(panelDefinition: PanelDefinition, version: string, registry?: string): PanelDefinition { + const next = structuredClone(panelDefinition); + next.spec.plugin.metadata = { ...next.spec.plugin.metadata, version, ...(registry ? { registry } : {}) }; + return next; +} + +/** + * Renders the same panel twice, side by side: once with the plugin version currently pinned in the dashboard, and once + * with the latest available version. This lets users spot new features or rendering regressions before updating. + */ +export function PanelVersionDiff(props: PanelVersionDiffProps): ReactElement { + const { panelDefinition, currentVersion, latestVersion, registry } = props; + + const currentDefinition = useMemo( + () => withPluginVersion(panelDefinition, currentVersion, registry), + [panelDefinition, currentVersion, registry], + ); + const latestDefinition = useMemo( + () => withPluginVersion(panelDefinition, latestVersion, registry), + [panelDefinition, latestVersion, registry], + ); + + const queries = panelDefinition.spec.queries ?? []; + + return ( + + + Preview based on panel "{panelDefinition.spec.display?.name ?? 'Untitled'}" + + {/* Both sides share a single queries provider: only the panel plugin version differs, so the data is the same. */} + + + + + + + + + + + + + + + + + + + + + {queries.length === 0 && ( + + This panel has no query, the preview only reflects rendering differences. + + )} + + ); +} diff --git a/dashboards/src/components/UpdatePluginsDrawer/UpdatePluginsDrawer.tsx b/dashboards/src/components/UpdatePluginsDrawer/UpdatePluginsDrawer.tsx new file mode 100644 index 00000000..e4728185 --- /dev/null +++ b/dashboards/src/components/UpdatePluginsDrawer/UpdatePluginsDrawer.tsx @@ -0,0 +1,212 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { + Box, + Button, + Checkbox, + Chip, + Collapse, + Divider, + FormControlLabel, + IconButton, + Stack, + Typography, +} from '@mui/material'; +import { Drawer, ErrorAlert, ErrorBoundary } from '@perses-dev/components'; +import ArrowRight from 'mdi-material-ui/ArrowRight'; +import ChevronDown from 'mdi-material-ui/ChevronDown'; +import ChevronUp from 'mdi-material-ui/ChevronUp'; +import type { ReactElement } from 'react'; +import { useMemo, useState } from 'react'; + +import { useDashboard } from '../../context/useDashboard'; +import type { OutdatedPlugin } from '../../utils/pluginVersioning'; +import { getOutdatedPluginId } from '../../utils/pluginVersioning'; +import { PanelVersionDiff } from './PanelVersionDiff'; + +export interface UpdatePluginsDrawerProps { + isOpen: boolean; + /** The plugins pinned to a version older than the latest available one. */ + outdatedPlugins: OutdatedPlugin[]; + /** Called with the plugins the user selected for update. */ + onUpdate: (plugins: OutdatedPlugin[]) => void; + onClose: () => void; +} + +/** + * Drawer listing every plugin the dashboard pins to an outdated version, letting the user pick which ones to update to + * their latest available version. Panel plugins can be expanded to show a side-by-side preview of a representative + * panel rendered with the current and the new plugin version. + */ +export function UpdatePluginsDrawer(props: UpdatePluginsDrawerProps): ReactElement { + const { isOpen, outdatedPlugins, onUpdate, onClose } = props; + const { dashboard } = useDashboard(); + const panels = dashboard.spec.panels ?? {}; + + // Selected plugin ids. Everything starts unselected so updating is always an explicit action. + // Sets, because these ids are looked up once per rendered row. + const [selectedIds, setSelectedIds] = useState>(new Set()); + const [expandedIds, setExpandedIds] = useState>(new Set()); + + const allIds = useMemo( + () => new Set(outdatedPlugins.map((plugin) => getOutdatedPluginId(plugin))), + [outdatedPlugins], + ); + const selectedCount = selectedIds.size; + const isAllSelected = allIds.size > 0 && selectedCount === allIds.size; + const isPartiallySelected = selectedCount > 0 && !isAllSelected; + + const toggleAll = (): void => { + setSelectedIds(isAllSelected ? new Set() : new Set(allIds)); + }; + + const toggleId = (setIds: typeof setSelectedIds, id: string): void => { + setIds((prev) => { + const next = new Set(prev); + if (!next.delete(id)) { + next.add(id); + } + return next; + }); + }; + + const resetSelection = (): void => { + setSelectedIds(new Set()); + setExpandedIds(new Set()); + }; + + const handleUpdate = (): void => { + const selection = outdatedPlugins.filter((plugin) => selectedIds.has(getOutdatedPluginId(plugin))); + // The parent closes the drawer without going through `handleClose`, so reset here too: otherwise a partial update + // would leave stale selections behind and re-enable Update on plugins that are already up to date. + resetSelection(); + onUpdate(selection); + }; + + const handleClose = (): void => { + resetSelection(); + onClose(); + }; + + return ( + + + theme.spacing(1, 2), + borderBottom: (theme) => `1px solid ${theme.palette.divider}`, + }} + > + Update plugins + + + + + + + theme.spacing(2) }}> + + The following plugins are pinned to an older version than the one installed. Select the plugins you want to + update to their latest version. + + + + } + label={isAllSelected ? 'Unselect all' : 'Select all'} + /> + + + }> + {outdatedPlugins.map((plugin) => { + const id = getOutdatedPluginId(plugin); + const isExpanded = expandedIds.has(id); + // Only panel plugins can be previewed, and only if we found a panel using them. + const examplePanel = + plugin.pluginType === 'Panel' && plugin.examplePanelKey ? panels[plugin.examplePanelKey] : undefined; + + return ( + + + toggleId(setSelectedIds, id)} + inputProps={{ 'aria-label': `Select ${plugin.kind}` }} + /> + + + {plugin.kind} + + {plugin.occurrences > 1 && ( + + {plugin.occurrences} usages + + )} + + + + {plugin.currentVersion} + + + + {plugin.latestVersion} + + + + {examplePanel && ( + toggleId(setExpandedIds, id)} + aria-label={isExpanded ? `Hide preview of ${plugin.kind}` : `Show preview of ${plugin.kind}`} + aria-expanded={isExpanded} + > + {isExpanded ? : } + + )} + + + {examplePanel && ( + + + + + + + + )} + + ); + })} + + + + + ); +} diff --git a/dashboards/src/components/UpdatePluginsDrawer/index.ts b/dashboards/src/components/UpdatePluginsDrawer/index.ts new file mode 100644 index 00000000..c31f70d6 --- /dev/null +++ b/dashboards/src/components/UpdatePluginsDrawer/index.ts @@ -0,0 +1,15 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './UpdatePluginsDrawer'; +export * from './PanelVersionDiff'; diff --git a/dashboards/src/components/index.ts b/dashboards/src/components/index.ts index 65df3f48..6b1c8423 100644 --- a/dashboards/src/components/index.ts +++ b/dashboards/src/components/index.ts @@ -28,6 +28,7 @@ export * from './EditJsonButton'; export * from './EmptyDashboard'; export * from './GridLayout'; export * from './LeaveDialog'; +export * from './LockDashboardButton'; export * from './Panel'; export * from './PanelDrawer'; export * from './PanelGroupDialog'; @@ -35,4 +36,6 @@ export * from './QuerySummaryTable'; export * from './QueryViewerDialog'; export * from './SaveChangesConfirmationDialog'; export * from './SaveDashboardButton'; +export * from './UpdatePluginsButton'; +export * from './UpdatePluginsDrawer'; export * from './Variables'; diff --git a/dashboards/src/context/DashboardProvider/dashboard-provider-api.ts b/dashboards/src/context/DashboardProvider/dashboard-provider-api.ts index 080ef0fb..5562ea93 100644 --- a/dashboards/src/context/DashboardProvider/dashboard-provider-api.ts +++ b/dashboards/src/context/DashboardProvider/dashboard-provider-api.ts @@ -131,7 +131,7 @@ const selectPanelGroupActions: ({ openAddPanel, updatePanelGroupLayouts, }: DashboardStoreState) => { - updatePanelGroupLayouts: (panelGroupId: PanelGroupId, itemLayouts: PanelGroupDefinition['itemLayouts']) => void; + updatePanelGroupLayouts: (panelGroupId: PanelGroupId, itemLayouts: PanelGroupItemLayout[]) => void; openEditPanelGroup: (panelGroupId: PanelGroupId) => void; openAddPanel: (panelGroupId?: PanelGroupId) => void; deletePanelGroup: (panelGroupId: PanelGroupId) => void; diff --git a/dashboards/src/context/DashboardProvider/panel-group-slice.test.ts b/dashboards/src/context/DashboardProvider/panel-group-slice.test.ts new file mode 100644 index 00000000..c16ebe27 --- /dev/null +++ b/dashboards/src/context/DashboardProvider/panel-group-slice.test.ts @@ -0,0 +1,166 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { LayoutDefinition } from '@perses-dev/spec'; +import { createStore } from 'zustand'; +import type { StoreApi } from 'zustand'; +import { devtools } from 'zustand/middleware'; +import { immer } from 'zustand/middleware/immer'; + +import type { PanelGroupSlice } from './panel-group-slice'; +import { createPanelGroupSlice } from './panel-group-slice'; + +const layouts: LayoutDefinition[] = [ + { + kind: 'Grid', + spec: { + items: [ + { + x: 0, + y: 0, + width: 12, + height: 4, + content: { $ref: '#/spec/panels/cpu' }, + repeatVariable: { value: 'instance', maxPer: 2 }, + }, + { x: 0, y: 4, width: 12, height: 3, content: { $ref: '#/spec/panels/memory' } }, + ], + }, + }, + { kind: 'Grid', spec: { items: [] } }, +]; + +function setup(definitions: LayoutDefinition[] = layouts): { + store: ReturnType; + sourceId: number; + destinationId: number; +} { + const store = createPanelGroupStore(definitions); + const [sourceId, destinationId] = store.getState().panelGroupOrder; + if (sourceId === undefined || destinationId === undefined) throw new Error('Missing test groups'); + return { store, sourceId, destinationId }; +} + +function createPanelGroupStore(definitions: LayoutDefinition[]): StoreApi { + return createStore()(immer(devtools(createPanelGroupSlice(definitions)))); +} + +it.each(['source first', 'destination first'])('moves panel references and repeat settings (%s)', (order) => { + const { store, sourceId, destinationId } = setup(); + const { updatePanelGroupLayouts, panelGroups } = store.getState(); + const [panel, remaining] = panelGroups[sourceId]?.itemLayouts ?? []; + if (!panel || !remaining) throw new Error('Missing test panels'); + const sourceLayout = [{ ...remaining, y: 0 }]; + // A drag reports the displayed height of a repeated panel, not its saved single-panel height. + const destinationLayout = [{ ...panel, x: 12, y: 0, h: 9 }]; + if (order === 'source first') { + updatePanelGroupLayouts(sourceId, sourceLayout); + updatePanelGroupLayouts(destinationId, destinationLayout); + } else { + updatePanelGroupLayouts(destinationId, destinationLayout); + updatePanelGroupLayouts(sourceId, sourceLayout); + } + const next = store.getState().panelGroups; + expect(next[sourceId]?.itemLayouts).toEqual(sourceLayout); + expect(next[sourceId]?.itemPanelKeys).toEqual({ [remaining.i]: 'memory' }); + expect(next[destinationId]?.itemLayouts).toEqual([{ ...panel, x: 12, y: 0 }]); + expect(next[destinationId]?.itemPanelKeys).toEqual({ [panel.i]: 'cpu' }); + // Moving the last panel back leaves an empty, valid group. + updatePanelGroupLayouts(destinationId, []); + updatePanelGroupLayouts(sourceId, [...sourceLayout, { ...panel, y: 3 }]); + expect(store.getState().panelGroups[destinationId]?.itemLayouts).toEqual([]); + expect(store.getState().panelGroups[destinationId]?.itemPanelKeys).toEqual({}); +}); + +it('persists resizing without losing repeat settings or panel references', () => { + const { store, sourceId } = setup(); + const group = store.getState().panelGroups[sourceId]; + if (!group) throw new Error('Missing test group'); + const next = group.itemLayouts.map(({ repeatVariable: _repeatVariable, ...layout }) => ({ ...layout, h: 6 })); + store.getState().updatePanelGroupLayouts(sourceId, next); + expect(store.getState().panelGroups[sourceId]?.itemLayouts[0]).toMatchObject({ + h: 6, + repeatVariable: { value: 'instance', maxPer: 2 }, + }); + expect(store.getState().panelGroups[sourceId]?.itemPanelKeys).toEqual(group.itemPanelKeys); +}); + +it.each(['moving row first', 'receiving row first'])( + 'reflows a panel moved between two rows of the same repeated group (%s)', + (order) => { + const { store, sourceId } = setup(); + const [panel, remaining] = store.getState().panelGroups[sourceId]?.itemLayouts ?? []; + if (!panel || !remaining) throw new Error('Missing test panels'); + // The row the panel left reports the compacted layout without it; the receiving row reports it dropped on top. + const movingRowLayout = [{ ...remaining, y: 0 }]; + const receivingRowLayout = [ + { ...panel, x: 0, y: 0 }, + { ...remaining, y: 4 }, + ]; + const { updatePanelGroupLayouts } = store.getState(); + if (order === 'moving row first') { + updatePanelGroupLayouts(sourceId, movingRowLayout); + updatePanelGroupLayouts(sourceId, receivingRowLayout); + } else { + updatePanelGroupLayouts(sourceId, receivingRowLayout); + updatePanelGroupLayouts(sourceId, movingRowLayout); + } + const itemLayouts = store.getState().panelGroups[sourceId]?.itemLayouts ?? []; + expect(itemLayouts).toHaveLength(2); + expect(itemLayouts.find((item) => item.i === panel.i)).toMatchObject({ + h: 4, + repeatVariable: panel.repeatVariable, + }); + expect(itemLayouts.find((item) => item.i === remaining.i)).toMatchObject({ h: 3 }); + const [first, second] = itemLayouts; + const overlaps = first && second && first.y < second.y + second.h && second.y < first.y + first.h; + expect(overlaps).toBe(false); + expect(store.getState().panelGroups[sourceId]?.itemPanelKeys).toEqual({ + [panel.i]: 'cpu', + [remaining.i]: 'memory', + }); + }, +); + +it('reflows items around a received repeated panel restored to its base height', () => { + const [source] = layouts; + if (!source) throw new Error('Missing test layout'); + const { store, sourceId, destinationId } = setup([ + source, + { + kind: 'Grid', + spec: { items: [{ x: 0, y: 0, width: 24, height: 2, content: { $ref: '#/spec/panels/other' } }] }, + }, + ]); + const [panel] = store.getState().panelGroups[sourceId]?.itemLayouts ?? []; + const [other] = store.getState().panelGroups[destinationId]?.itemLayouts ?? []; + if (!panel || !other) throw new Error('Missing test panels'); + // The destination grid laid out `other` below the expanded (h: 9) preview of the repeated panel. + store.getState().updatePanelGroupLayouts(destinationId, [ + { ...panel, x: 0, y: 0, h: 9 }, + { ...other, y: 9 }, + ]); + expect(store.getState().panelGroups[destinationId]?.itemLayouts).toEqual([ + { ...panel, x: 0, y: 0 }, + { ...other, y: 4 }, + ]); +}); + +it('rejects an unknown received item without modifying either group', () => { + const { store, destinationId } = setup(); + const before = store.getState().panelGroups; + expect(() => + store.getState().updatePanelGroupLayouts(destinationId, [{ i: 'missing', x: 0, y: 0, w: 12, h: 4 }]), + ).toThrow('Cannot find panel'); + expect(store.getState().panelGroups).toBe(before); +}); diff --git a/dashboards/src/context/DashboardProvider/panel-group-slice.ts b/dashboards/src/context/DashboardProvider/panel-group-slice.ts index f4e0c446..8500ad22 100644 --- a/dashboards/src/context/DashboardProvider/panel-group-slice.ts +++ b/dashboards/src/context/DashboardProvider/panel-group-slice.ts @@ -17,7 +17,9 @@ import { getPanelKeyFromRef } from '@perses-dev/spec'; import type { WritableDraft } from 'immer'; import type { StateCreator } from 'zustand'; -import type { PanelGroupDefinition } from '../../model'; +import { GRID_LAYOUT_COLS } from '../../constants'; +import type { PanelGroupDefinition, PanelGroupItemLayout } from '../../model'; +import { compactLayout } from '../../utils'; import type { Middleware } from './common'; import { generateId } from './common'; @@ -41,9 +43,10 @@ export interface PanelGroupSlice { swapPanelGroups: (xIndex: number, yIndex: number) => void; /** - * Update the item layouts for a panel group when, for example, a panel is moved or resized. + * Commit a grid gesture, transferring panel references and repeat settings for received items. + * Source removals are completed by the receiving grid so either callback order preserves metadata. */ - updatePanelGroupLayouts: (panelGroupId: PanelGroupId, itemLayouts: PanelGroupDefinition['itemLayouts']) => void; + updatePanelGroupLayouts: (panelGroupId: PanelGroupId, itemLayouts: PanelGroupItemLayout[]) => void; } /** @@ -78,10 +81,42 @@ export function createPanelGroupSlice( updatePanelGroupLayouts(panelGroupId, itemLayouts): void { set((state) => { const group = state.panelGroups[panelGroupId]; - if (group === undefined) { + if (!group) { throw new Error(`Cannot find panel group ${panelGroupId}`); } - group.itemLayouts = itemLayouts; + const nextLayouts = new Map(); + for (const layout of itemLayouts) { + const existing = group.itemLayouts.find((item) => item.i === layout.i); + if (existing) { + nextLayouts.set(layout.i, { ...existing, ...layout, repeatVariable: existing.repeatVariable }); + continue; + } + const source = Object.values(state.panelGroups).find((candidate) => + candidate.itemLayouts.some((item) => item.i === layout.i), + ); + const original = source?.itemLayouts.find((item) => item.i === layout.i); + const panelKey = source?.itemPanelKeys[layout.i]; + if (!source || !original || panelKey === undefined) { + throw new Error(`Cannot find panel for grid item ${layout.i}`); + } + // A received repeated panel carries an expanded display height. Keep its base height. + nextLayouts.set(layout.i, { + ...original, + x: Math.min(layout.x, GRID_LAYOUT_COLS.sm - original.w), + y: layout.y, + }); + group.itemPanelKeys[layout.i] = panelKey; + source.itemLayouts = source.itemLayouts.filter((item) => item.i !== layout.i); + delete source.itemPanelKeys[layout.i]; + } + // Snapgrid calls both grids independently. Retain outgoing metadata until the receiver commits. + for (const layout of group.itemLayouts) { + if (!nextLayouts.has(layout.i)) { + nextLayouts.set(layout.i, layout); + } + } + // Retained items and received items restored to their base height may overlap: reflow them. + group.itemLayouts = compactLayout([...nextLayouts.values()]); }); }, }); diff --git a/dashboards/src/context/DatasourceStoreProvider.tsx b/dashboards/src/context/DatasourceStoreProvider.tsx index 7c629067..0923268f 100644 --- a/dashboards/src/context/DatasourceStoreProvider.tsx +++ b/dashboards/src/context/DatasourceStoreProvider.tsx @@ -131,10 +131,13 @@ export function DatasourceStoreProvider(props: DatasourceStoreProviderProps): Re const getDatasourceClient = useCallback( async function getClient(selector: DatasourceSelector): Promise { const { kind } = selector; - const [{ spec, proxyUrl }, plugin] = await Promise.all([ - findDatasource(selector), - getPlugin({ kind: 'Datasource', name: kind }), - ]); + const { spec, proxyUrl } = await findDatasource(selector); + const plugin = await getPlugin({ + kind: 'Datasource', + name: kind, + version: spec.plugin.metadata?.version, + registry: spec.plugin.metadata?.registry, + }); // allows extending client const client = plugin.createClient(spec.plugin.spec, { proxyUrl }) as Client; diff --git a/dashboards/src/test/setup-tests.ts b/dashboards/src/test/setup-tests.ts index 3b828544..ac88acb1 100644 --- a/dashboards/src/test/setup-tests.ts +++ b/dashboards/src/test/setup-tests.ts @@ -23,3 +23,19 @@ vi.mock('echarts/core'); // Tell react-intersection-observer that everything should be considered in-view for tests (see package documentation // for other options) defaultFallbackInView(true); + +// jsdom has no layout engine, so provide the observer API required by dnd-kit. +if (typeof ResizeObserver === 'undefined') { + vi.stubGlobal( + 'ResizeObserver', + class { + observe(): void {} + unobserve(): void {} + disconnect(): void {} + }, + ); +} + +if (typeof PointerEvent === 'undefined') { + vi.stubGlobal('PointerEvent', MouseEvent); +} diff --git a/dashboards/src/utils/gridLayoutUtils.test.ts b/dashboards/src/utils/gridLayoutUtils.test.ts new file mode 100644 index 00000000..89c8faf6 --- /dev/null +++ b/dashboards/src/utils/gridLayoutUtils.test.ts @@ -0,0 +1,73 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { PanelGroupItemLayout } from '../model'; +import { compactLayout, decodeGridItemId, encodeGridItemId } from './gridLayoutUtils'; + +describe('compactLayout', () => { + it('pushes items below an item that grew taller', () => { + const repeated: PanelGroupItemLayout = { + i: 'a', + x: 0, + y: 0, + w: 12, + h: 9, + repeatVariable: { value: 'instance' }, + }; + const below: PanelGroupItemLayout = { i: 'b', x: 0, y: 4, w: 12, h: 3 }; + const beside: PanelGroupItemLayout = { i: 'c', x: 12, y: 4, w: 12, h: 3 }; + + const result = compactLayout([repeated, below, beside]); + + expect(result[0]).toBe(repeated); + expect(result[1]).toEqual({ ...below, y: 9 }); + expect(result[2]).toEqual({ ...beside, y: 0 }); + }); + + it('removes vertical gaps and keeps horizontal positions', () => { + const layout: PanelGroupItemLayout[] = [ + { i: 'a', x: 6, y: 5, w: 6, h: 2 }, + { i: 'b', x: 0, y: 10, w: 6, h: 2 }, + ]; + + expect(compactLayout(layout)).toEqual([ + { i: 'a', x: 6, y: 0, w: 6, h: 2 }, + { i: 'b', x: 0, y: 0, w: 6, h: 2 }, + ]); + }); + + it('returns the same item references when nothing moves', () => { + const layout: PanelGroupItemLayout[] = [ + { i: 'a', x: 0, y: 0, w: 12, h: 2 }, + { i: 'b', x: 0, y: 2, w: 12, h: 2 }, + ]; + + const result = compactLayout(layout); + + expect(result[0]).toBe(layout[0]); + expect(result[1]).toBe(layout[1]); + }); +}); + +describe('grid item ids', () => { + it('round-trips ids containing the separator and encoded characters', () => { + const id = 'panel|with%weird chars'; + expect(decodeGridItemId(encodeGridItemId(id))).toBe(id); + expect(decodeGridItemId(encodeGridItemId(id, ['instance', 'host|1']))).toBe(id); + }); + + it('produces distinct tile ids per repeat value', () => { + expect(encodeGridItemId('a', ['instance', '1'])).not.toBe(encodeGridItemId('a', ['instance', '2'])); + expect(encodeGridItemId('a')).not.toBe(encodeGridItemId('a', ['instance', '1'])); + }); +}); diff --git a/dashboards/src/utils/gridLayoutUtils.ts b/dashboards/src/utils/gridLayoutUtils.ts new file mode 100644 index 00000000..5bec02f4 --- /dev/null +++ b/dashboards/src/utils/gridLayoutUtils.ts @@ -0,0 +1,56 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { verticalCompactor } from '@snapgridjs/react'; + +import { GRID_LAYOUT_COLS } from '../constants'; +import type { PanelGroupItemLayout, PanelGroupItemLayoutId } from '../model'; + +const GRID_ITEM_ID_SEPARATOR = '|'; + +/** + * Moves overlapping items down so that no two items share the same cells, then pulls every item + * up as far as possible to remove vertical gaps (same behavior as react-grid-layout's `compactType="vertical"`). + * + * react-grid-layout did this automatically on every render. Snapgrid renders the layout exactly as given, + * so we have to do it ourselves whenever the stored layout may contain overlaps, for example: + * - a repeated panel is expanded into one item per variable value, all sharing the original `x`/`y`; + * - a duplicated panel is inserted right below its reference, on top of whatever was there; + * - a panel dropped from another group lands on cells already occupied in the receiving group. + * + * Positions are computed in the persisted 24 column grid, and only `x`/`y` are rewritten so that + * extra fields such as `repeatVariable` are kept on the returned items. + */ +export function compactLayout(layout: PanelGroupItemLayout[]): PanelGroupItemLayout[] { + const compacted = verticalCompactor.compact(layout, GRID_LAYOUT_COLS.sm); + return layout.map((item, index) => { + const next = compacted[index]; + if (!next || (next.x === item.x && next.y === item.y)) return item; + return { ...item, x: next.x, y: next.y }; + }); +} + +/** + * Builds the id of a rendered grid tile. Repeated groups render the same persisted item once per + * variable value, but dnd-kit needs a unique id per tile. + */ +export function encodeGridItemId(id: PanelGroupItemLayoutId, repeatVariable?: [string, string]): string { + return `${encodeURIComponent(id)}${GRID_ITEM_ID_SEPARATOR}${encodeURIComponent(JSON.stringify(repeatVariable ?? []))}`; +} + +/** + * Extracts the persisted item id from a rendered grid tile id. + */ +export function decodeGridItemId(gridItemId: string): PanelGroupItemLayoutId { + return decodeURIComponent(gridItemId.split(GRID_ITEM_ID_SEPARATOR)[0] ?? gridItemId); +} diff --git a/dashboards/src/utils/index.ts b/dashboards/src/utils/index.ts index a370c5cd..f821efa9 100644 --- a/dashboards/src/utils/index.ts +++ b/dashboards/src/utils/index.ts @@ -12,4 +12,6 @@ // limitations under the License. export * from './panelUtils'; +export * from './pluginVersioning'; export * from './repeatLayoutUtils'; +export * from './gridLayoutUtils'; diff --git a/dashboards/src/utils/pluginVersioning.test.ts b/dashboards/src/utils/pluginVersioning.test.ts new file mode 100644 index 00000000..5f0df094 --- /dev/null +++ b/dashboards/src/utils/pluginVersioning.test.ts @@ -0,0 +1,340 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { DashboardResource } from '@perses-dev/client'; +import type { PluginMetadataWithModule } from '@perses-dev/plugin-system'; + +import type { LatestPluginVersions } from './pluginVersioning'; +import { + applyPluginVersions, + buildLatestPluginVersions, + findOutdatedPlugins, + getOutdatedPluginId, + getPluginIdentityKey, + isDashboardLocked, + removePluginVersions, + updatePluginVersions, +} from './pluginVersioning'; + +function buildMetadata( + kind: string, + name: string, + moduleVersion: string, + options?: { pluginVersion?: string; registry?: string }, +): PluginMetadataWithModule { + return { + kind, + metadata: options?.pluginVersion ? { version: options.pluginVersion } : undefined, + spec: { name, display: { name } }, + module: { name: `${name}-module`, version: moduleVersion, registry: options?.registry }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; +} + +/** Build the version map used by `applyPluginVersions` from a plain `pluginType:kind -> version` record. */ +function buildVersions(entries: Array<[pluginType: string, kind: string, version: string]>): LatestPluginVersions { + return new Map(entries.map(([pluginType, kind, version]) => [getPluginIdentityKey({ pluginType, kind }), version])); +} + +/** Every plugin of the test dashboard, pinned to the same version. */ +function allPluginsAt(version: string): LatestPluginVersions { + return buildVersions([ + ['Panel', 'TimeSeriesChart', version], + ['TimeSeriesQuery', 'PrometheusTimeSeriesQuery', version], + ['Variable', 'PrometheusLabelValuesVariable', version], + ['Datasource', 'PrometheusDatasource', version], + ['Annotation', 'TempoAnnotation', version], + ]); +} + +function buildDashboard(): DashboardResource { + return { + kind: 'Dashboard', + metadata: { name: 'test', project: 'perses', version: 0, createdAt: '', updatedAt: '' }, + spec: { + duration: '1h', + variables: [ + { + kind: 'ListVariable', + spec: { + name: 'foo', + allowMultiple: false, + allowAllValue: false, + plugin: { kind: 'PrometheusLabelValuesVariable', spec: {} }, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + { + kind: 'TextVariable', + spec: { name: 'bar', value: 'baz' }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + ], + layouts: [], + panels: { + panel1: { + kind: 'Panel', + spec: { + display: { name: 'Panel 1' }, + plugin: { kind: 'TimeSeriesChart', spec: {} }, + queries: [ + { + kind: 'TimeSeriesQuery', + spec: { plugin: { kind: 'PrometheusTimeSeriesQuery', spec: {} } }, + }, + ], + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + }, + datasources: { + ds1: { + default: true, + plugin: { kind: 'PrometheusDatasource', spec: {} }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + }, + annotations: [ + { + display: { name: 'anno' }, + plugin: { kind: 'TempoAnnotation', spec: {} }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any, + ], + }, + }; +} + +describe('buildLatestPluginVersions', () => { + test('keeps the highest version per plugin identity and prefers plugin-level version', () => { + const versions = buildLatestPluginVersions([ + buildMetadata('Panel', 'TimeSeriesChart', '0.1.0'), + buildMetadata('Panel', 'TimeSeriesChart', '0.3.0'), + buildMetadata('Panel', 'TimeSeriesChart', '0.2.0'), + buildMetadata('TimeSeriesQuery', 'PrometheusTimeSeriesQuery', '1.0.0', { pluginVersion: '2.0.0' }), + ]); + expect(versions.get(getPluginIdentityKey({ pluginType: 'Panel', kind: 'TimeSeriesChart' }))).toBe('0.3.0'); + // plugin-level version wins over module version + expect( + versions.get(getPluginIdentityKey({ pluginType: 'TimeSeriesQuery', kind: 'PrometheusTimeSeriesQuery' })), + ).toBe('2.0.0'); + }); + + test('a pre-release never wins over its stable release', () => { + const versions = buildLatestPluginVersions([ + buildMetadata('Panel', 'TimeSeriesChart', '1.0.0'), + buildMetadata('Panel', 'TimeSeriesChart', '1.0.0-beta'), + ]); + expect(versions.get(getPluginIdentityKey({ pluginType: 'Panel', kind: 'TimeSeriesChart' }))).toBe('1.0.0'); + }); + + test('the same kind in two registries keeps a version per registry', () => { + const versions = buildLatestPluginVersions([ + buildMetadata('Panel', 'TimeSeriesChart', '1.0.0', { registry: 'a' }), + buildMetadata('Panel', 'TimeSeriesChart', '2.0.0', { registry: 'b' }), + ]); + expect(versions.get(getPluginIdentityKey({ pluginType: 'Panel', kind: 'TimeSeriesChart', registry: 'a' }))).toBe( + '1.0.0', + ); + expect(versions.get(getPluginIdentityKey({ pluginType: 'Panel', kind: 'TimeSeriesChart', registry: 'b' }))).toBe( + '2.0.0', + ); + // Without a pinned registry, the latest version across registries is used. + expect(versions.get(getPluginIdentityKey({ pluginType: 'Panel', kind: 'TimeSeriesChart' }))).toBe('2.0.0'); + }); + + test('the same kind under two plugin types is versioned independently', () => { + const versions = buildLatestPluginVersions([ + buildMetadata('Panel', 'Shared', '1.0.0'), + buildMetadata('Variable', 'Shared', '2.0.0'), + ]); + expect(versions.get(getPluginIdentityKey({ pluginType: 'Panel', kind: 'Shared' }))).toBe('1.0.0'); + expect(versions.get(getPluginIdentityKey({ pluginType: 'Variable', kind: 'Shared' }))).toBe('2.0.0'); + }); +}); + +describe('applyPluginVersions / removePluginVersions / isDashboardLocked', () => { + const versions = buildVersions([ + ['Panel', 'TimeSeriesChart', '1.0.0'], + ['TimeSeriesQuery', 'PrometheusTimeSeriesQuery', '1.1.0'], + ['Variable', 'PrometheusLabelValuesVariable', '1.2.0'], + ['Datasource', 'PrometheusDatasource', '1.3.0'], + ['Annotation', 'TempoAnnotation', '1.4.0'], + ]); + + test('a fresh dashboard is not locked', () => { + expect(isDashboardLocked(buildDashboard())).toBe(false); + }); + + test('applies versions to every plugin definition and marks the dashboard as locked', () => { + const dashboard = buildDashboard(); + const locked = applyPluginVersions(dashboard, versions); + + // original is untouched (deep clone) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((dashboard.spec.panels.panel1 as any).spec.plugin.metadata).toBeUndefined(); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((locked.spec.panels.panel1 as any).spec.plugin.metadata.version).toBe('1.0.0'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((locked.spec.panels.panel1 as any).spec.queries[0].spec.plugin.metadata.version).toBe('1.1.0'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((locked.spec.variables[0] as any).spec.plugin.metadata.version).toBe('1.2.0'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((locked.spec.datasources!.ds1 as any).plugin.metadata.version).toBe('1.3.0'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((locked.spec.annotations![0] as any).plugin.metadata.version).toBe('1.4.0'); + expect(isDashboardLocked(locked)).toBe(true); + }); + + test('removePluginVersions reverts the lock', () => { + const locked = applyPluginVersions(buildDashboard(), versions); + const unlocked = removePluginVersions(locked); + + expect(isDashboardLocked(unlocked)).toBe(false); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((unlocked.spec.panels.panel1 as any).spec.plugin.metadata).toBeUndefined(); + }); + + test('plugins without an available version are left unpinned', () => { + const partial = applyPluginVersions(buildDashboard(), buildVersions([['Panel', 'TimeSeriesChart', '1.0.0']])); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((partial.spec.panels.panel1 as any).spec.plugin.metadata.version).toBe('1.0.0'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((partial.spec.datasources!.ds1 as any).plugin.metadata).toBeUndefined(); + }); + + test('a partially pinned dashboard is pinned but not locked', () => { + const partial = applyPluginVersions(buildDashboard(), buildVersions([['Panel', 'TimeSeriesChart', '1.0.0']])); + expect(isDashboardLocked(partial)).toBe(false); + }); + + test('the `latest` sentinel does not count as a pin', () => { + const sentinel = applyPluginVersions(buildDashboard(), allPluginsAt('latest')); + expect(isDashboardLocked(sentinel)).toBe(false); + }); +}); + +describe('findOutdatedPlugins / updatePluginVersions', () => { + const latest = buildVersions([ + ['Panel', 'TimeSeriesChart', '2.0.0'], + ['TimeSeriesQuery', 'PrometheusTimeSeriesQuery', '1.5.0'], + ['Variable', 'PrometheusLabelValuesVariable', '1.2.0'], + ['Datasource', 'PrometheusDatasource', '1.3.0'], + ['Annotation', 'TempoAnnotation', '1.4.0'], + ]); + + // Lock everything to an older version so every plugin is outdated. + const lockedOld = (): DashboardResource => applyPluginVersions(buildDashboard(), allPluginsAt('1.0.0')); + + test('an unpinned dashboard reports nothing as outdated', () => { + expect(findOutdatedPlugins(buildDashboard(), latest)).toEqual([]); + }); + + test('a dashboard pinned to the latest versions reports nothing as outdated', () => { + const upToDate = applyPluginVersions(buildDashboard(), latest); + expect(findOutdatedPlugins(upToDate, latest)).toEqual([]); + }); + + test('detects outdated plugins with their type, versions and example panel', () => { + const outdated = findOutdatedPlugins(lockedOld(), latest); + const kinds = outdated.map((o) => o.kind).toSorted(); + expect(kinds).toEqual([ + 'PrometheusDatasource', + 'PrometheusLabelValuesVariable', + 'PrometheusTimeSeriesQuery', + 'TempoAnnotation', + 'TimeSeriesChart', + ]); + + expect(outdated.find((o) => o.kind === 'TimeSeriesChart')).toMatchObject({ + pluginType: 'Panel', + currentVersion: '1.0.0', + latestVersion: '2.0.0', + examplePanelKey: 'panel1', + }); + + // Query plugins carry their query type and the panel they belong to + expect(outdated.find((o) => o.kind === 'PrometheusTimeSeriesQuery')).toMatchObject({ + pluginType: 'TimeSeriesQuery', + examplePanelKey: 'panel1', + }); + // Non-panel plugins have no example panel + expect(outdated.find((o) => o.kind === 'PrometheusDatasource')?.examplePanelKey).toBeUndefined(); + }); + + test('the `latest` sentinel is not considered outdated', () => { + const dashboard = applyPluginVersions(buildDashboard(), allPluginsAt('latest')); + expect(findOutdatedPlugins(dashboard, latest)).toEqual([]); + }); + + test('a pre-release pin is not reported as newer than its stable release', () => { + const dashboard = applyPluginVersions(buildDashboard(), buildVersions([['Panel', 'TimeSeriesChart', '2.0.0-rc1']])); + expect(findOutdatedPlugins(dashboard, latest)).toMatchObject([ + { kind: 'TimeSeriesChart', currentVersion: '2.0.0-rc1', latestVersion: '2.0.0' }, + ]); + }); + + test('a pin on a plugin registry that has nothing newer is left alone', () => { + const dashboard = applyPluginVersions(buildDashboard(), buildVersions([['Panel', 'TimeSeriesChart', '1.0.0']])); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (dashboard.spec.panels.panel1 as any).spec.plugin.metadata.registry = 'other'; + // `latest` only knows about the registry-less identity, so nothing can be proposed for registry 'other'. + expect(findOutdatedPlugins(dashboard, latest)).toEqual([]); + }); + + test('only the selected plugins are updated', () => { + const dashboard = lockedOld(); + const outdated = findOutdatedPlugins(dashboard, latest); + const panelPlugin = outdated.find((o) => o.kind === 'TimeSeriesChart')!; + + const updated = updatePluginVersions(dashboard, [panelPlugin]); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((updated.spec.panels.panel1 as any).spec.plugin.metadata.version).toBe('2.0.0'); + // Not selected -> untouched + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((updated.spec.panels.panel1 as any).spec.queries[0].spec.plugin.metadata.version).toBe('1.0.0'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((updated.spec.datasources!.ds1 as any).plugin.metadata.version).toBe('1.0.0'); + + // The source dashboard is not mutated + // eslint-disable-next-line @typescript-eslint/no-explicit-any + expect((dashboard.spec.panels.panel1 as any).spec.plugin.metadata.version).toBe('1.0.0'); + }); + + test('updating every outdated plugin clears the outdated list', () => { + const dashboard = lockedOld(); + const updated = updatePluginVersions(dashboard, findOutdatedPlugins(dashboard, latest)); + expect(findOutdatedPlugins(updated, latest)).toEqual([]); + // The dashboard stays locked, just on newer versions + expect(isDashboardLocked(updated)).toBe(true); + }); + + test('updating with an empty selection returns the dashboard unchanged', () => { + const dashboard = lockedOld(); + expect(updatePluginVersions(dashboard, [])).toBe(dashboard); + }); + + test('getOutdatedPluginId distinguishes plugin type, kind, registry and version', () => { + expect(getOutdatedPluginId({ pluginType: 'Panel', kind: 'TimeSeriesChart', currentVersion: '1.0.0' })).toBe( + 'Panel:TimeSeriesChart::1.0.0', + ); + expect(getOutdatedPluginId({ pluginType: 'Panel', kind: 'TimeSeriesChart', currentVersion: '1.1.0' })).not.toBe( + getOutdatedPluginId({ pluginType: 'Panel', kind: 'TimeSeriesChart', currentVersion: '1.0.0' }), + ); + expect( + getOutdatedPluginId({ pluginType: 'Panel', kind: 'TimeSeriesChart', registry: 'a', currentVersion: '1.0.0' }), + ).not.toBe(getOutdatedPluginId({ pluginType: 'Panel', kind: 'TimeSeriesChart', currentVersion: '1.0.0' })); + }); +}); diff --git a/dashboards/src/utils/pluginVersioning.ts b/dashboards/src/utils/pluginVersioning.ts new file mode 100644 index 00000000..67fe14e2 --- /dev/null +++ b/dashboards/src/utils/pluginVersioning.ts @@ -0,0 +1,295 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { DashboardResource } from '@perses-dev/client'; +import type { PluginMetadataWithModule } from '@perses-dev/plugin-system'; +import { comparePluginVersions, LATEST_PLUGIN_VERSION } from '@perses-dev/plugin-system'; +import type { Definition } from '@perses-dev/spec'; + +/** + * The full runtime identity of a plugin: two plugins with the same kind but a different registry are different plugins, + * so a version can only be compared or applied within a single (plugin type, kind, registry) triplet. + */ +export interface PluginIdentity { + /** The plugin type (e.g. 'Panel', 'TimeSeriesQuery', 'Variable', ...). */ + pluginType: string; + /** The plugin kind/name (e.g. 'TimeSeriesChart'). */ + kind: string; + /** The registry the plugin comes from, when the definition pins one. */ + registry?: string; +} + +/** A stable string key for a {@link PluginIdentity}, usable as a Map key, React key or selection key. */ +export function getPluginIdentityKey(identity: PluginIdentity): string { + return `${identity.pluginType}:${identity.kind}:${identity.registry ?? ''}`; +} + +/** Context about where a plugin definition lives inside the dashboard spec. */ +interface PluginDefinitionContext { + /** The plugin type (e.g. 'Panel', 'TimeSeriesQuery', 'Variable', ...). */ + pluginType: string; + /** Key of the panel the definition belongs to, for panel plugins and panel query plugins. */ + panelKey?: string; +} + +/** + * Visit every plugin definition contained in a dashboard spec, invoking the provided callback with the definition, its + * plugin type and (when relevant) the key of the panel it belongs to. Covers panel plugins, panel query plugins, + * list-variable plugins, datasource plugins and annotation plugins. + */ +function visitPluginDefinitions( + dashboard: DashboardResource, + visitor: (definition: Definition, context: PluginDefinitionContext) => void, +): void { + const spec = dashboard.spec; + + for (const [panelKey, panel] of Object.entries(spec.panels ?? {})) { + if (panel?.spec?.plugin) { + visitor(panel.spec.plugin, { pluginType: 'Panel', panelKey }); + } + for (const query of panel?.spec?.queries ?? []) { + // For a query definition, `query.kind` is the query plugin type (e.g. 'TimeSeriesQuery'). + if (query?.spec?.plugin && query.kind) { + visitor(query.spec.plugin, { pluginType: query.kind, panelKey }); + } + } + } + + // Only list variables reference a plugin. + for (const variable of spec.variables ?? []) { + if (variable?.kind === 'ListVariable' && variable.spec?.plugin) { + visitor(variable.spec.plugin, { pluginType: 'Variable' }); + } + } + + for (const datasource of Object.values(spec.datasources ?? {})) { + if (datasource?.plugin) { + visitor(datasource.plugin, { pluginType: 'Datasource' }); + } + } + + for (const annotation of spec.annotations ?? []) { + if (annotation?.plugin) { + visitor(annotation.plugin, { pluginType: 'Annotation' }); + } + } +} + +/** Returns the identity of a plugin definition found at the given place in the dashboard spec. */ +function getDefinitionIdentity(definition: Definition, context: PluginDefinitionContext): PluginIdentity { + return { pluginType: context.pluginType, kind: definition.kind, registry: definition.metadata?.registry }; +} + +/** + * Returns the exact version a definition is pinned to, or `undefined` when it floats on the latest available version. + * The `latest` sentinel is explicitly not a pin: the plugin registry resolves it dynamically. + */ +function getPinnedVersion(definition: Definition): string | undefined { + const version = definition.metadata?.version; + return version && version !== LATEST_PLUGIN_VERSION ? version : undefined; +} + +/** + * Extract the version associated with a piece of plugin metadata, preferring the plugin-level version and falling back + * to the containing module's version. + */ +function getMetadataVersion(metadata: PluginMetadataWithModule): string | undefined { + return metadata.metadata?.version ?? metadata.module?.version; +} + +/** Extract the registry a piece of plugin metadata comes from, if any. */ +function getMetadataRegistry(metadata: PluginMetadataWithModule): string | undefined { + return metadata.metadata?.registry ?? metadata.module?.registry; +} + +/** + * The latest version available in the instance for a given plugin identity. + */ +export type LatestPluginVersions = Map; + +/** + * Build a map of plugin identity (plugin type + kind + registry) to the latest version currently available in the + * instance, based on the installed plugin metadata returned by the plugin registry. + * + * Each identity is indexed twice: once with its registry, and once without it. The registry-less entry is what a + * definition that does not pin a registry resolves to, matching how the plugin registry loads it. + */ +export function buildLatestPluginVersions(pluginMetadata: PluginMetadataWithModule[]): LatestPluginVersions { + const versions: LatestPluginVersions = new Map(); + + const keepLatest = (key: string, version: string): void => { + const existing = versions.get(key); + if (existing === undefined || comparePluginVersions(version, existing) > 0) { + versions.set(key, version); + } + }; + + for (const metadata of pluginMetadata) { + const kind = metadata.spec?.name; + const version = getMetadataVersion(metadata); + if (!kind || !version) { + continue; + } + const registry = getMetadataRegistry(metadata); + // A definition without a pinned registry resolves to the latest version across every registry. + keepLatest(getPluginIdentityKey({ pluginType: metadata.kind, kind }), version); + if (registry) { + keepLatest(getPluginIdentityKey({ pluginType: metadata.kind, kind, registry }), version); + } + } + + return versions; +} + +/** A plugin definition pinned to a version older than the latest one available in the instance. */ +export interface OutdatedPlugin extends PluginIdentity { + /** The version currently pinned in the dashboard spec. */ + currentVersion: string; + /** The latest version available in the instance. */ + latestVersion: string; + /** Number of definitions in the dashboard pinned to the outdated version. */ + occurrences: number; + /** + * Key of the first panel using this plugin. Set for panel plugins and panel query plugins, and used to render a + * before/after preview of a representative panel. + */ + examplePanelKey?: string; +} + +/** + * A stable identity for an outdated plugin entry, usable as a React key or selection key. + */ +export function getOutdatedPluginId(plugin: PluginIdentity & Pick): string { + return `${getPluginIdentityKey(plugin)}:${plugin.currentVersion}`; +} + +/** + * Find every plugin in the dashboard that is pinned to a version older than the latest version available in the + * instance. Definitions without a pinned version are ignored: they already float on the latest version. + */ +export function findOutdatedPlugins( + dashboard: DashboardResource, + latestVersions: LatestPluginVersions, +): OutdatedPlugin[] { + const outdated = new Map(); + + visitPluginDefinitions(dashboard, (definition, context) => { + const currentVersion = getPinnedVersion(definition); + if (!currentVersion) { + return; + } + const identity = getDefinitionIdentity(definition, context); + const latestVersion = latestVersions.get(getPluginIdentityKey(identity)); + if (!latestVersion || comparePluginVersions(latestVersion, currentVersion) <= 0) { + return; + } + + const id = getOutdatedPluginId({ ...identity, currentVersion }); + const existing = outdated.get(id); + if (existing) { + existing.occurrences += 1; + existing.examplePanelKey ??= context.panelKey; + return; + } + outdated.set(id, { + ...identity, + currentVersion, + latestVersion, + occurrences: 1, + examplePanelKey: context.panelKey, + }); + }); + + return [...outdated.values()].toSorted( + (a, b) => a.pluginType.localeCompare(b.pluginType) || a.kind.localeCompare(b.kind), + ); +} + +/** + * Return a copy of the dashboard where only the provided outdated plugins are re-pinned to their latest version. Any + * other plugin definition (including other versions of the same kind) is left untouched. + */ +export function updatePluginVersions(dashboard: DashboardResource, plugins: OutdatedPlugin[]): DashboardResource { + if (plugins.length === 0) { + return dashboard; + } + const targets = new Map(plugins.map((plugin) => [getOutdatedPluginId(plugin), plugin.latestVersion])); + const next = structuredClone(dashboard); + visitPluginDefinitions(next, (definition, context) => { + const currentVersion = getPinnedVersion(definition); + if (!currentVersion) { + return; + } + const id = getOutdatedPluginId({ ...getDefinitionIdentity(definition, context), currentVersion }); + const latestVersion = targets.get(id); + if (latestVersion) { + definition.metadata = { ...definition.metadata, version: latestVersion }; + } + }); + return next; +} + +/** + * Return a copy of the dashboard with every plugin definition pinned to its latest available version. Plugin + * definitions whose identity is not present in the version map are left untouched, which means the dashboard is only + * fully locked if every plugin it uses is installed (see {@link isDashboardLocked}). + */ +export function applyPluginVersions(dashboard: DashboardResource, versions: LatestPluginVersions): DashboardResource { + const next = structuredClone(dashboard); + visitPluginDefinitions(next, (definition, context) => { + const version = versions.get(getPluginIdentityKey(getDefinitionIdentity(definition, context))); + if (version) { + definition.metadata = { ...definition.metadata, version }; + } + }); + return next; +} + +/** + * Return a copy of the dashboard with the pinned version removed from every plugin definition. The `metadata` object is + * dropped entirely when it no longer holds any information. + */ +export function removePluginVersions(dashboard: DashboardResource): DashboardResource { + const next = structuredClone(dashboard); + visitPluginDefinitions(next, (definition) => { + if (definition.metadata === undefined) { + return; + } + const { version: _version, ...rest } = definition.metadata; + if (Object.keys(rest).length === 0) { + delete definition.metadata; + } else { + definition.metadata = rest; + } + }); + return next; +} + +/** + * A dashboard is "locked" when *every* plugin definition it contains is pinned to an exact version, which is the + * invariant the lock action establishes. A dashboard where only some definitions are pinned is versioned partially: the + * remaining plugins still float on the latest version, so it is not locked and the Lock action stays available. + * + * The `latest` sentinel does not count as a pin: the plugin registry resolves it dynamically, so it enforces nothing. + */ +export function isDashboardLocked(dashboard: DashboardResource): boolean { + let total = 0; + let pinned = 0; + visitPluginDefinitions(dashboard, (definition) => { + total += 1; + if (getPinnedVersion(definition)) { + pinned += 1; + } + }); + return total > 0 && pinned === total; +} diff --git a/dashboards/src/utils/repeatLayoutUtils.test.ts b/dashboards/src/utils/repeatLayoutUtils.test.ts index ac45d10e..9dcc8d44 100644 --- a/dashboards/src/utils/repeatLayoutUtils.test.ts +++ b/dashboards/src/utils/repeatLayoutUtils.test.ts @@ -22,7 +22,6 @@ import { getPerRowCount, getRepeatVariableValues, restoreRepeatItemLayout, - restoreRepeatLayouts, } from './repeatLayoutUtils'; const makeVariableState = (options: string[], selected?: string[]): VariableStateMap[string] => ({ @@ -217,42 +216,6 @@ describe('restoreRepeatItemLayout', () => { }); }); -describe('restoreRepeatLayouts', () => { - const repeatVariable: RepeatVariable = { value: 'env', alignment: 'horizontal', maxPer: 2 }; - const meta = new Map([ - [ - 'repeat-panel', - { itemRepeatVariable: repeatVariable, values: ['prod', 'staging', 'dev'], totalValues: 3, numberOfRows: 2 }, - ], - ]); - - const expandedLayout = { i: 'repeat-panel', x: 0, y: 0, w: 12, h: 13 }; - const plainLayout = { i: 'plain-panel', x: 12, y: 0, w: 12, h: 4 }; - - test('restores h for repeat items in currentLayout', () => { - const { currentLayout } = restoreRepeatLayouts([expandedLayout, plainLayout], {}, meta); - expect(currentLayout.find((l) => l.i === 'repeat-panel')?.h).toBe(6); - expect(currentLayout.find((l) => l.i === 'plain-panel')?.h).toBe(4); - }); - - test('restores h for repeat items in allLayouts', () => { - const { allLayouts } = restoreRepeatLayouts([], { sm: [expandedLayout, plainLayout] }, meta); - expect(allLayouts['sm']?.find((l) => l.i === 'repeat-panel')?.h).toBe(6); - expect(allLayouts['sm']?.find((l) => l.i === 'plain-panel')?.h).toBe(4); - }); - - test('restores all breakpoints in allLayouts', () => { - const { allLayouts } = restoreRepeatLayouts([], { sm: [expandedLayout], xxs: [expandedLayout] }, meta); - expect(allLayouts['sm']?.[0]?.h).toBe(6); - expect(allLayouts['xxs']?.[0]?.h).toBe(6); - }); - - test('leaves allLayouts empty when no breakpoints provided', () => { - const { allLayouts } = restoreRepeatLayouts([expandedLayout], {}, meta); - expect(Object.keys(allLayouts)).toHaveLength(0); - }); -}); - describe('buildRepeatMeta', () => { const variables: VariableStateMap = { env: makeVariableState(['prod', 'staging', 'dev']), diff --git a/dashboards/src/utils/repeatLayoutUtils.ts b/dashboards/src/utils/repeatLayoutUtils.ts index 68ef2dfa..dcf344c8 100644 --- a/dashboards/src/utils/repeatLayoutUtils.ts +++ b/dashboards/src/utils/repeatLayoutUtils.ts @@ -13,7 +13,6 @@ import type { VariableStateMap } from '@perses-dev/plugin-system'; import { DEFAULT_MAX_PER_ROW, DEFAULT_REPEAT_ALIGNMENT } from '@perses-dev/plugin-system'; -import type { Layout, Layouts } from 'react-grid-layout'; import { DEFAULT_MARGIN, ROW_HEIGHT } from '../constants'; import type { PanelGroupItemLayout, RepeatVariable } from '../model'; @@ -84,7 +83,7 @@ export interface RepeatItemMeta { /** * Restores a layout item to its single-item height and re-attaches repeatVariable after - * react-grid-layout reports back an expanded (total) height. Used when persisting layouts, + * the grid reports back an expanded (total) height. Used when persisting layouts, * including after a user resize in edit mode. */ export function restoreRepeatItemLayout(layout: PanelGroupItemLayout, meta: RepeatItemMeta): PanelGroupItemLayout { @@ -95,26 +94,6 @@ export function restoreRepeatItemLayout(layout: PanelGroupItemLayout, meta: Repe }; } -/** - * Applies restoreRepeatItemLayout to all repeat items in currentLayout and allLayouts using - * the provided meta map. Non-repeat items are returned unchanged. - */ -export function restoreRepeatLayouts( - currentLayout: Layout[], - allLayouts: Layouts, - repeatMeta: Map, -): { currentLayout: PanelGroupItemLayout[]; allLayouts: Layouts } { - const restore = (layout: Layout): PanelGroupItemLayout => { - const meta = repeatMeta.get(layout.i); - return meta ? restoreRepeatItemLayout(layout, meta) : layout; - }; - const restoredAllLayouts: Layouts = {}; - for (const [breakpoint, layouts] of Object.entries(allLayouts)) { - restoredAllLayouts[breakpoint] = layouts.map(restore); - } - return { currentLayout: currentLayout.map(restore), allLayouts: restoredAllLayouts }; -} - /** * Builds a map from layout item id to repeat metadata and a list of layouts with * expanded heights for repeat-variable items. Non-repeat items are returned unchanged. diff --git a/dashboards/src/views/ViewDashboard/DashboardApp.tsx b/dashboards/src/views/ViewDashboard/DashboardApp.tsx index 54eff94c..2f2d9a7f 100644 --- a/dashboards/src/views/ViewDashboard/DashboardApp.tsx +++ b/dashboards/src/views/ViewDashboard/DashboardApp.tsx @@ -46,6 +46,10 @@ export interface DashboardAppProps { isDatasourceEnabled: boolean; disableShortcuts?: boolean; isCreating?: boolean; + // If true, add a button that locks/unlocks the dashboard: pins every plugin it uses to an exact version or unpin all versions. + isLockModeAvailable?: boolean; + // If true, add a button will open a drawer that shows the plugins that can be updated and allows the user to update them. + isUpdateButtonAvailable?: boolean; isInitialVariableSticky?: boolean; // If true, browser confirmation dialog will be shown when navigating away with unsaved changes (closing tab, ...). isLeavingConfirmDialogEnabled?: boolean; @@ -75,6 +79,8 @@ const DashboardAppContent = (props: DashboardAppProps): ReactElement => { isCreating, isInitialVariableSticky, isLeavingConfirmDialogEnabled, + isLockModeAvailable, + isUpdateButtonAvailable, dashboardTitleComponent, userPreferenceTimezone, onSave, @@ -159,6 +165,8 @@ const DashboardAppContent = (props: DashboardAppProps): ReactElement => { isVariableEnabled={isVariableEnabled} isAnnotationEnabled={isAnnotationEnabled} isDatasourceEnabled={isDatasourceEnabled} + isLockModeAvailable={isLockModeAvailable} + isUpdateButtonAvailable={isUpdateButtonAvailable} onEditButtonClick={onEditButtonClick} onCancelButtonClick={onCancelButtonClick} /> diff --git a/dashboards/src/views/ViewDashboard/ViewDashboard.tsx b/dashboards/src/views/ViewDashboard/ViewDashboard.tsx index 23151a74..b8fb66f1 100644 --- a/dashboards/src/views/ViewDashboard/ViewDashboard.tsx +++ b/dashboards/src/views/ViewDashboard/ViewDashboard.tsx @@ -57,6 +57,8 @@ export function ViewDashboard(props: ViewDashboardProps): ReactElement { isCreating, isInitialVariableSticky, isLeavingConfirmDialogEnabled, + isLockModeAvailable, + isUpdateButtonAvailable, dashboardTitleComponent, onSave, onDiscard, @@ -151,6 +153,8 @@ export function ViewDashboard(props: ViewDashboardProps): ReactElement { isCreating={isCreating} isInitialVariableSticky={isInitialVariableSticky} isLeavingConfirmDialogEnabled={isLeavingConfirmDialogEnabled} + isLockModeAvailable={isLockModeAvailable} + isUpdateButtonAvailable={isUpdateButtonAvailable} dashboardTitleComponent={dashboardTitleComponent} onSave={onSave} onDiscard={onDiscard} diff --git a/design-tokens/package.json b/design-tokens/package.json new file mode 100644 index 00000000..41ed588a --- /dev/null +++ b/design-tokens/package.json @@ -0,0 +1,47 @@ +{ + "name": "@perses-dev/design-tokens", + "version": "0.54.0", + "description": "Perses design tokens for ui components", + "license": "Apache-2.0", + "homepage": "https://github.com/perses/perses/blob/main/README.md", + "repository": { + "type": "git", + "url": "git+https://github.com/perses/perses.git" + }, + "bugs": { + "url": "https://github.com/perses/perses/issues" + }, + "type": "module", + "module": "dist/index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./css": "./dist/css/index.css", + "./css/reset": "./dist/css/reset.css", + "./css/tokens": "./dist/css/tokens.css", + "./css/semantic": "./dist/css/semantic.css" + }, + "sideEffects": [ + "*.css" + ], + "scripts": { + "clean": "rimraf dist/", + "build": "concurrently \"npm:build:*\"", + "build:esm": "swc ./src -d dist --strip-leading-paths --config-file ../.swcrc --ignore '**/test/**'", + "build:types": "tsc --project tsconfig.build.json", + "build:css": "mkdir -p dist/css && cp -f src/css/*.css dist/css/", + "type-check": "tsc --noEmit", + "start": "concurrently -P \"npm:build:* -- {*}\" -- --watch", + "test": "cross-env TZ=UTC vitest run", + "test:watch": "cross-env TZ=UTC vitest", + "lint": "oxlint src", + "lint:fix": "oxlint --fix src" + }, + "files": [ + "dist" + ] +} diff --git a/design-tokens/src/colors.ts b/design-tokens/src/colors.ts new file mode 100644 index 00000000..c880ef48 --- /dev/null +++ b/design-tokens/src/colors.ts @@ -0,0 +1,129 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export type HexColor = `#${string}`; + +export interface PersesColor { + 50: HexColor; + 100: HexColor; + 150: HexColor; + 200: HexColor; + 300: HexColor; + 400: HexColor; + 500: HexColor; + 600: HexColor; + 700: HexColor; + 800: HexColor; + 850: HexColor; + 900: HexColor; + 950: HexColor; +} + +export const blue: PersesColor = { + 50: '#e3f2fd', + 100: '#bbdefb', + 150: '#a5d4fa', + 200: '#90caf9', + 300: '#64b5f6', + 400: '#42a5f5', + 500: '#2196f3', + 600: '#1e88e5', + 700: '#1976d2', + 800: '#1565c0', + 850: '#1156b0', + 900: '#0d47a1', + 950: '#062350', +}; + +export const green: PersesColor = { + 50: '#e8f5e9', + 100: '#c8e6c9', + 150: '#b7deb8', + 200: '#a5d6a7', + 300: '#81c784', + 400: '#66bb6a', + 500: '#4caf50', + 600: '#43a047', + 700: '#388e3c', + 800: '#2e7d32', + 850: '#256e29', + 900: '#1b5e20', + 950: '#0e2f10', +}; + +export const gray: PersesColor = { + 50: '#fafafa', + 100: '#f5f5f5', + 150: '#f0f0f0', + 200: '#eeeeee', + 300: '#e0e0e0', + 400: '#bdbdbd', + 500: '#9e9e9e', + 600: '#757575', + 700: '#616161', + 800: '#424242', + 850: '#303030', + 900: '#212121', + 950: '#121212', +}; + +export const orange: PersesColor = { + 50: '#fff3e0', + 100: '#ffe0b2', + 150: '#ffd699', + 200: '#ffcc80', + 300: '#ffb74d', + 400: '#ffa726', + 500: '#ff9800', + 600: '#fb8c00', + 700: '#f57c00', + 800: '#ef6c00', + 850: '#ea5e00', + 900: '#e65100', + 950: '#732900', +}; + +export const purple: PersesColor = { + 50: '#efe9fd', + 100: '#e0d2fc', + 150: '#d0bcfa', + 200: '#c1a6f8', + 300: '#a179f5', + 400: '#824df1', + 500: '#6320ee', + 600: '#4f1abe', + 700: '#3b138f', + 800: '#280d5f', + 850: '#1e0a47', + 900: '#140630', + 950: '#0a0318', +}; + +export const red: PersesColor = { + 50: '#ffebee', + 100: '#ffcdd2', + 150: '#f7b3b6', + 200: '#ef9a9a', + 300: '#e57373', + 400: '#ef5350', + 500: '#f44336', + 600: '#e53935', + 700: '#d32f2f', + 800: '#c62828', + 850: '#be2222', + 900: '#b71c1c', + 950: '#5c0e0e', +}; + +export const white = '#FFFFFF' as HexColor; +export const black = '#000000' as HexColor; diff --git a/design-tokens/src/css/index.css b/design-tokens/src/css/index.css new file mode 100644 index 00000000..8749d048 --- /dev/null +++ b/design-tokens/src/css/index.css @@ -0,0 +1,20 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.reset, perses.tokens, perses.semantic; + +@import './reset.css'; +@import './tokens.css'; +@import './semantic.css'; diff --git a/design-tokens/src/css/reset.css b/design-tokens/src/css/reset.css new file mode 100644 index 00000000..d211b250 --- /dev/null +++ b/design-tokens/src/css/reset.css @@ -0,0 +1,28 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.reset { + *, + *::before, + *::after { + box-sizing: border-box; + } + + body { + margin: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} diff --git a/design-tokens/src/css/semantic.css b/design-tokens/src/css/semantic.css new file mode 100644 index 00000000..d62f298d --- /dev/null +++ b/design-tokens/src/css/semantic.css @@ -0,0 +1,175 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.semantic { + /* + * Elevation hierarchy (lowest → highest): + * bg-default — page/app background (base level) + * bg-surface — raised surfaces: cards, panels, dialogs + * bg-sunken — recessed areas: code blocks, inset regions + * bg-overlay — floating surfaces: tooltips, popovers, dropdowns + * bg-backdrop — semi-transparent scrim behind modals + * + * Other backgrounds: + * bg-navigation — sidebar/nav area (brand-tinted) + * + * Border: + * border-default — general-purpose border color + */ + + /* ---- Light mode (default) ---- */ + :root { + /* Background: Elevation */ + --perses-bg-default: var(--perses-color-white); + --perses-bg-surface: var(--perses-color-gray-50); + --perses-bg-sunken: var(--perses-color-gray-200); + --perses-bg-overlay: var(--perses-color-gray-100); + --perses-bg-backdrop: rgba(21, 23, 33, 0.75); + --perses-bg-navigation: var(--perses-color-blue-150); + + /* Border */ + --perses-border-default: var(--perses-color-gray-100); + + /* Text */ + --perses-text-primary: var(--perses-color-gray-800); + --perses-text-secondary: var(--perses-color-gray-700); + --perses-text-disabled: var(--perses-color-gray-300); + --perses-text-link: var(--perses-color-blue-500); + --perses-text-link-hover: var(--perses-color-blue-600); + --perses-text-navigation: var(--perses-color-gray-800); + --perses-text-accent: var(--perses-color-gray-700); + --perses-text-on-solid: var(--perses-color-white); + + /* Status: Primary */ + --perses-status-bg-primary: var(--perses-color-blue-50); + --perses-status-bg-primary-hover: var(--perses-color-blue-800); + --perses-status-text-primary: var(--perses-color-blue-900); + --perses-status-border-primary: var(--perses-color-blue-200); + --perses-status-icon-primary: var(--perses-color-blue-700); + --perses-status-solid-primary: var(--perses-color-blue-700); + + /* Status: Secondary */ + --perses-status-bg-secondary: var(--perses-color-gray-50); + --perses-status-bg-secondary-hover: var(--perses-color-gray-800); + --perses-status-text-secondary: var(--perses-color-gray-700); + --perses-status-border-secondary: var(--perses-color-gray-200); + --perses-status-icon-secondary: var(--perses-color-gray-600); + --perses-status-solid-secondary: var(--perses-color-gray-600); + + /* Status: Error */ + --perses-status-bg-error: var(--perses-color-red-50); + --perses-status-bg-error-hover: var(--perses-color-red-800); + --perses-status-text-error: var(--perses-color-red-900); + --perses-status-border-error: var(--perses-color-red-200); + --perses-status-icon-error: var(--perses-color-red-700); + --perses-status-solid-error: var(--perses-color-red-700); + + /* Status: Warning */ + --perses-status-bg-warning: var(--perses-color-orange-50); + --perses-status-bg-warning-hover: var(--perses-color-orange-800); + --perses-status-text-warning: var(--perses-color-orange-900); + --perses-status-border-warning: var(--perses-color-orange-200); + --perses-status-icon-warning: var(--perses-color-orange-700); + --perses-status-solid-warning: var(--perses-color-orange-700); + + /* Status: Success */ + --perses-status-bg-success: var(--perses-color-green-50); + --perses-status-bg-success-hover: var(--perses-color-green-800); + --perses-status-text-success: var(--perses-color-green-900); + --perses-status-border-success: var(--perses-color-green-200); + --perses-status-icon-success: var(--perses-color-green-800); + --perses-status-solid-success: var(--perses-color-green-800); + + /* Status: Info */ + --perses-status-bg-info: var(--perses-color-blue-50); + --perses-status-bg-info-hover: var(--perses-color-blue-800); + --perses-status-text-info: var(--perses-color-blue-900); + --perses-status-border-info: var(--perses-color-blue-200); + --perses-status-icon-info: var(--perses-color-blue-700); + --perses-status-solid-info: var(--perses-color-blue-700); + } + + /* ---- Dark mode: explicit (data attribute) ---- */ + [data-perses-mode='dark'] { + /* Background: Elevation */ + --perses-bg-default: var(--perses-color-gray-900); + --perses-bg-surface: var(--perses-color-gray-850); + --perses-bg-sunken: var(--perses-color-gray-800); + --perses-bg-overlay: var(--perses-color-gray-600); + --perses-bg-backdrop: rgba(10, 12, 16, 0.85); + --perses-bg-navigation: var(--perses-color-gray-850); + + /* Border */ + --perses-border-default: var(--perses-color-gray-600); + + /* Text */ + --perses-text-primary: var(--perses-color-white); + --perses-text-secondary: var(--perses-color-gray-50); + --perses-text-disabled: var(--perses-color-gray-600); + --perses-text-link: var(--perses-color-blue-400); + --perses-text-link-hover: var(--perses-color-blue-700); + --perses-text-navigation: var(--perses-color-white); + --perses-text-accent: var(--perses-color-gray-400); + --perses-text-on-solid: var(--perses-color-white); + + /* Status: Primary */ + --perses-status-bg-primary: var(--perses-color-blue-900); + --perses-status-bg-primary-hover: var(--perses-color-blue-850); + --perses-status-text-primary: var(--perses-color-blue-200); + --perses-status-border-primary: var(--perses-color-blue-700); + --perses-status-icon-primary: var(--perses-color-blue-400); + --perses-status-solid-primary: var(--perses-color-blue-400); + + /* Status: Secondary */ + --perses-status-bg-secondary: var(--perses-color-gray-850); + --perses-status-bg-secondary-hover: var(--perses-color-gray-800); + --perses-status-text-secondary: var(--perses-color-gray-200); + --perses-status-border-secondary: var(--perses-color-gray-700); + --perses-status-icon-secondary: var(--perses-color-gray-400); + --perses-status-solid-secondary: var(--perses-color-gray-400); + + /* Status: Error */ + --perses-status-bg-error: var(--perses-color-red-900); + --perses-status-bg-error-hover: var(--perses-color-red-850); + --perses-status-text-error: var(--perses-color-red-200); + --perses-status-border-error: var(--perses-color-red-700); + --perses-status-icon-error: var(--perses-color-red-400); + --perses-status-solid-error: var(--perses-color-red-400); + + /* Status: Warning */ + --perses-status-bg-warning: var(--perses-color-orange-900); + --perses-status-bg-warning-hover: var(--perses-color-orange-850); + --perses-status-text-warning: var(--perses-color-orange-200); + --perses-status-border-warning: var(--perses-color-orange-700); + --perses-status-icon-warning: var(--perses-color-orange-400); + --perses-status-solid-warning: var(--perses-color-orange-400); + + /* Status: Success */ + --perses-status-bg-success: var(--perses-color-green-900); + --perses-status-bg-success-hover: var(--perses-color-green-850); + --perses-status-text-success: var(--perses-color-green-200); + --perses-status-border-success: var(--perses-color-green-700); + --perses-status-icon-success: var(--perses-color-green-400); + --perses-status-solid-success: var(--perses-color-green-400); + + /* Status: Info */ + --perses-status-bg-info: var(--perses-color-blue-900); + --perses-status-bg-info-hover: var(--perses-color-blue-850); + --perses-status-text-info: var(--perses-color-blue-200); + --perses-status-border-info: var(--perses-color-blue-700); + --perses-status-icon-info: var(--perses-color-blue-400); + --perses-status-solid-info: var(--perses-color-blue-400); + } +} diff --git a/design-tokens/src/css/tokens.css b/design-tokens/src/css/tokens.css new file mode 100644 index 00000000..d783818f --- /dev/null +++ b/design-tokens/src/css/tokens.css @@ -0,0 +1,155 @@ +/* + * Copyright The Perses Authors + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer perses.tokens { + :root { + /* ---- Colors: Blue ---- */ + --perses-color-blue-50: #e3f2fd; + --perses-color-blue-100: #bbdefb; + --perses-color-blue-150: #a5d4fa; + --perses-color-blue-200: #90caf9; + --perses-color-blue-300: #64b5f6; + --perses-color-blue-400: #42a5f5; + --perses-color-blue-500: #2196f3; + --perses-color-blue-600: #1e88e5; + --perses-color-blue-700: #1976d2; + --perses-color-blue-800: #1565c0; + --perses-color-blue-850: #1156b0; + --perses-color-blue-900: #0d47a1; + --perses-color-blue-950: #062350; + + /* ---- Colors: Green ---- */ + --perses-color-green-50: #e8f5e9; + --perses-color-green-100: #c8e6c9; + --perses-color-green-150: #b7deb8; + --perses-color-green-200: #a5d6a7; + --perses-color-green-300: #81c784; + --perses-color-green-400: #66bb6a; + --perses-color-green-500: #4caf50; + --perses-color-green-600: #43a047; + --perses-color-green-700: #388e3c; + --perses-color-green-800: #2e7d32; + --perses-color-green-850: #256e29; + --perses-color-green-900: #1b5e20; + --perses-color-green-950: #0e2f10; + + /* ---- Colors: Gray ---- */ + --perses-color-gray-50: #fafafa; + --perses-color-gray-100: #f5f5f5; + --perses-color-gray-150: #f0f0f0; + --perses-color-gray-200: #eeeeee; + --perses-color-gray-300: #e0e0e0; + --perses-color-gray-400: #bdbdbd; + --perses-color-gray-500: #9e9e9e; + --perses-color-gray-600: #757575; + --perses-color-gray-700: #616161; + --perses-color-gray-800: #424242; + --perses-color-gray-850: #303030; + --perses-color-gray-900: #212121; + --perses-color-gray-950: #121212; + + /* ---- Colors: Orange ---- */ + --perses-color-orange-50: #fff3e0; + --perses-color-orange-100: #ffe0b2; + --perses-color-orange-150: #ffd699; + --perses-color-orange-200: #ffcc80; + --perses-color-orange-300: #ffb74d; + --perses-color-orange-400: #ffa726; + --perses-color-orange-500: #ff9800; + --perses-color-orange-600: #fb8c00; + --perses-color-orange-700: #f57c00; + --perses-color-orange-800: #ef6c00; + --perses-color-orange-850: #ea5e00; + --perses-color-orange-900: #e65100; + --perses-color-orange-950: #732900; + + /* ---- Colors: Purple ---- */ + --perses-color-purple-50: #efe9fd; + --perses-color-purple-100: #e0d2fc; + --perses-color-purple-150: #d0bcfa; + --perses-color-purple-200: #c1a6f8; + --perses-color-purple-300: #a179f5; + --perses-color-purple-400: #824df1; + --perses-color-purple-500: #6320ee; + --perses-color-purple-600: #4f1abe; + --perses-color-purple-700: #3b138f; + --perses-color-purple-800: #280d5f; + --perses-color-purple-850: #1e0a47; + --perses-color-purple-900: #140630; + --perses-color-purple-950: #0a0318; + + /* ---- Colors: Red ---- */ + --perses-color-red-50: #ffebee; + --perses-color-red-100: #ffcdd2; + --perses-color-red-150: #f7b3b6; + --perses-color-red-200: #ef9a9a; + --perses-color-red-300: #e57373; + --perses-color-red-400: #ef5350; + --perses-color-red-500: #f44336; + --perses-color-red-600: #e53935; + --perses-color-red-700: #d32f2f; + --perses-color-red-800: #c62828; + --perses-color-red-850: #be2222; + --perses-color-red-900: #b71c1c; + --perses-color-red-950: #5c0e0e; + + /* ---- Colors: Common ---- */ + --perses-color-white: #ffffff; + --perses-color-black: #000000; + + /* ---- Spacing (rem) ---- */ + --perses-spacing-0: 0; + --perses-spacing-xs: 0.25rem; + --perses-spacing-sm: 0.5rem; + --perses-spacing-md: 0.75rem; + --perses-spacing-lg: 1rem; + --perses-spacing-xl: 1.25rem; + --perses-spacing-2xl: 1.5rem; + --perses-spacing-3xl: 2rem; + --perses-spacing-4xl: 3rem; + + /* ---- Border Radius ---- */ + --perses-radius-none: 0; + --perses-radius-sm: 2px; + --perses-radius-md: 4px; + --perses-radius-lg: 8px; + --perses-radius-xl: 12px; + --perses-radius-full: 9999px; + + /* ---- Typography ---- */ + --perses-font-family: + Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + + --perses-font-weight-light: 300; + --perses-font-weight-regular: 400; + --perses-font-weight-medium: 600; + --perses-font-weight-bold: 700; + + --perses-font-size-xs: 0.75rem; + --perses-font-size-sm: 0.875rem; + --perses-font-size-md: 1rem; + --perses-font-size-lg: 1.25rem; + --perses-font-size-xl: 1.5rem; + --perses-font-size-2xl: 2rem; + --perses-font-size-3xl: 2.5rem; + --perses-font-size-4xl: 3rem; + + --perses-line-height-tight: 1.2; + --perses-line-height-compact: 1.3; + --perses-line-height-normal: 1.4; + --perses-line-height-relaxed: 1.5; + } +} diff --git a/design-tokens/src/index.ts b/design-tokens/src/index.ts new file mode 100644 index 00000000..d627d721 --- /dev/null +++ b/design-tokens/src/index.ts @@ -0,0 +1,16 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export * from './types'; +export { tokens } from './tokens'; +export { blue, green, gray, orange, purple, red, white, black } from './colors'; diff --git a/design-tokens/src/test/consistency.test.ts b/design-tokens/src/test/consistency.test.ts new file mode 100644 index 00000000..77264aa7 --- /dev/null +++ b/design-tokens/src/test/consistency.test.ts @@ -0,0 +1,61 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { readFileSync } from 'fs'; +import { resolve } from 'path'; + +import { tokens } from '../tokens'; + +const cssDir = resolve(__dirname, '../css'); +const readCss = (f: string): string => readFileSync(resolve(cssDir, f), 'utf-8'); + +function extractCssVarDefinitions(...files: string[]): Set { + const vars = new Set(); + for (const file of files) { + const css = readCss(file); + for (const match of css.matchAll(/^\s*(--perses-[\w-]+)\s*:/gm)) { + vars.add(match[1]!); + } + } + return vars; +} + +function extractTokenVarRefs(obj: Record): Set { + const vars = new Set(); + for (const value of Object.values(obj)) { + if (typeof value === 'string') { + const match = value.match(/^var\((--perses-[\w-]+)\)$/); + if (match) vars.add(match[1]!); + } else if (typeof value === 'object' && value !== null) { + for (const v of extractTokenVarRefs(value as Record)) { + vars.add(v); + } + } + } + return vars; +} + +describe('token ↔ CSS consistency', () => { + const cssVars = extractCssVarDefinitions('tokens.css', 'semantic.css'); + const tokenVars = extractTokenVarRefs(tokens as unknown as Record); + + it('every CSS variable has a corresponding tokens entry', () => { + const missing = [...cssVars].filter((v) => !tokenVars.has(v)).sort(); + expect(missing).toEqual([]); + }); + + it('every tokens entry references a defined CSS variable', () => { + const missing = [...tokenVars].filter((v) => !cssVars.has(v)).sort(); + expect(missing).toEqual([]); + }); +}); diff --git a/design-tokens/src/test/css.test.ts b/design-tokens/src/test/css.test.ts new file mode 100644 index 00000000..e7ed3883 --- /dev/null +++ b/design-tokens/src/test/css.test.ts @@ -0,0 +1,117 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { readFileSync } from 'fs'; +import { resolve } from 'path'; + +import { blue, green, gray, orange, purple, red, white, black } from '../colors'; +import type { PersesColor } from '../colors'; + +const cssDir = resolve(__dirname, '../css'); + +const readCss = (filename: string): string => readFileSync(resolve(cssDir, filename), 'utf-8'); + +describe('CSS layer declarations', () => { + it('index.css declares layer order', () => { + const css = readCss('index.css'); + expect(css).toContain('@layer perses.reset, perses.tokens, perses.semantic'); + }); + + it('reset.css uses @layer perses.reset', () => { + const css = readCss('reset.css'); + expect(css).toContain('@layer perses.reset'); + }); + + it('tokens.css uses @layer perses.tokens', () => { + const css = readCss('tokens.css'); + expect(css).toContain('@layer perses.tokens'); + }); + + it('semantic.css uses @layer perses.semantic', () => { + const css = readCss('semantic.css'); + expect(css).toContain('@layer perses.semantic'); + }); +}); + +describe('CSS primitive color variables', () => { + const tokensCss = readCss('tokens.css'); + const tokensCssUpper = tokensCss.toUpperCase(); + + const hues: Array<[string, PersesColor]> = [ + ['blue', blue], + ['green', green], + ['gray', gray], + ['orange', orange], + ['purple', purple], + ['red', red], + ]; + + const stops = [50, 100, 150, 200, 300, 400, 500, 600, 700, 800, 850, 900, 950] as const; + + it.each(hues)('tokens.css defines all %s color variables', (hue, colorObj) => { + for (const stop of stops) { + expect(tokensCss).toContain(`--perses-color-${hue}-${stop}`); + expect(tokensCssUpper).toContain(colorObj[stop].toUpperCase()); + } + }); + + it('tokens.css defines white and black', () => { + expect(tokensCss).toContain('--perses-color-white'); + expect(tokensCss).toContain('--perses-color-black'); + expect(tokensCssUpper).toContain(white.toUpperCase()); + expect(tokensCssUpper).toContain(black.toUpperCase()); + }); +}); + +describe('CSS semantic variables', () => { + const semanticCss = readCss('semantic.css'); + + it('defines light mode defaults on :root', () => { + expect(semanticCss).toContain(':root {'); + expect(semanticCss).toContain('--perses-bg-default'); + expect(semanticCss).toContain('--perses-text-primary'); + }); + + it('defines dark mode via data attribute', () => { + expect(semanticCss).toContain(`[data-perses-mode='dark']`); + }); + + it('has all background semantic tokens', () => { + const bgTokens = ['default', 'surface', 'sunken', 'overlay', 'backdrop', 'navigation']; + for (const name of bgTokens) { + expect(semanticCss).toContain(`--perses-bg-${name}`); + } + }); + + it('has border semantic token', () => { + expect(semanticCss).toContain('--perses-border-default'); + }); + + it('has all text semantic tokens', () => { + const textTokens = ['primary', 'secondary', 'disabled', 'link', 'link-hover', 'navigation', 'accent']; + for (const name of textTokens) { + expect(semanticCss).toContain(`--perses-text-${name}`); + } + }); + + it('has all status tokens with property-scoped naming', () => { + const roles = ['primary', 'secondary', 'error', 'warning', 'success', 'info']; + const properties = ['bg', 'text', 'border', 'icon']; + for (const role of roles) { + for (const prop of properties) { + expect(semanticCss).toContain(`--perses-status-${prop}-${role}`); + } + expect(semanticCss).toContain(`--perses-status-bg-${role}-hover`); + } + }); +}); diff --git a/design-tokens/src/test/tokens.test.ts b/design-tokens/src/test/tokens.test.ts new file mode 100644 index 00000000..899c15ea --- /dev/null +++ b/design-tokens/src/test/tokens.test.ts @@ -0,0 +1,132 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { blue, green, gray, orange, purple, red, white, black } from '../colors'; +import { tokens } from '../tokens'; + +const HEX_PATTERN = /^#[0-9A-Fa-f]{6}$/; + +describe('color constants', () => { + const colorEntries = [ + ['blue', blue], + ['green', green], + ['gray', gray], + ['orange', orange], + ['purple', purple], + ['red', red], + ] as const; + + it.each(colorEntries)('%s has valid hex values for all stops', (_name, color) => { + const stops = [50, 100, 150, 200, 300, 400, 500, 600, 700, 800, 850, 900, 950] as const; + for (const stop of stops) { + expect(color[stop]).toMatch(HEX_PATTERN); + } + }); + + it('white and black are valid hex', () => { + expect(white).toMatch(HEX_PATTERN); + expect(black).toMatch(HEX_PATTERN); + }); +}); + +describe('tokens object', () => { + it('produces correct var() strings for primitive colors', () => { + expect(tokens.color.blue[500]).toBe('var(--perses-color-blue-500)'); + expect(tokens.color.gray[100]).toBe('var(--perses-color-gray-100)'); + expect(tokens.color.red[50]).toBe('var(--perses-color-red-50)'); + expect(tokens.color.white).toBe('var(--perses-color-white)'); + expect(tokens.color.black).toBe('var(--perses-color-black)'); + }); + + it('produces correct var() strings for semantic background tokens', () => { + expect(tokens.bg.default).toBe('var(--perses-bg-default)'); + expect(tokens.bg.surface).toBe('var(--perses-bg-surface)'); + expect(tokens.bg.sunken).toBe('var(--perses-bg-sunken)'); + expect(tokens.bg.overlay).toBe('var(--perses-bg-overlay)'); + expect(tokens.bg.backdrop).toBe('var(--perses-bg-backdrop)'); + expect(tokens.bg.navigation).toBe('var(--perses-bg-navigation)'); + }); + + it('produces correct var() strings for semantic border tokens', () => { + expect(tokens.border.default).toBe('var(--perses-border-default)'); + }); + + it('produces correct var() strings for semantic text tokens', () => { + expect(tokens.text.primary).toBe('var(--perses-text-primary)'); + expect(tokens.text.link).toBe('var(--perses-text-link)'); + expect(tokens.text.disabled).toBe('var(--perses-text-disabled)'); + }); + + it('produces correct var() strings for status tokens', () => { + expect(tokens.status.success.bg).toBe('var(--perses-status-bg-success)'); + expect(tokens.status.success.bgHover).toBe('var(--perses-status-bg-success-hover)'); + expect(tokens.status.success.text).toBe('var(--perses-status-text-success)'); + expect(tokens.status.success.border).toBe('var(--perses-status-border-success)'); + expect(tokens.status.success.icon).toBe('var(--perses-status-icon-success)'); + + expect(tokens.status.error.bg).toBe('var(--perses-status-bg-error)'); + expect(tokens.status.error.text).toBe('var(--perses-status-text-error)'); + expect(tokens.status.warning.border).toBe('var(--perses-status-border-warning)'); + expect(tokens.status.info.icon).toBe('var(--perses-status-icon-info)'); + expect(tokens.status.primary.bg).toBe('var(--perses-status-bg-primary)'); + expect(tokens.status.secondary.bgHover).toBe('var(--perses-status-bg-secondary-hover)'); + }); + + it('has all 6 status roles with 5 properties each', () => { + const roles = ['primary', 'secondary', 'error', 'warning', 'success', 'info'] as const; + const properties = ['bg', 'bgHover', 'text', 'border', 'icon'] as const; + for (const role of roles) { + for (const prop of properties) { + expect(tokens.status[role][prop]).toBeDefined(); + expect(tokens.status[role][prop]).toMatch(/^var\(--perses-status-/); + } + } + }); + + it('produces correct var() strings for spacing tokens', () => { + expect(tokens.spacing[0]).toBe('var(--perses-spacing-0)'); + expect(tokens.spacing.xs).toBe('var(--perses-spacing-xs)'); + expect(tokens.spacing.sm).toBe('var(--perses-spacing-sm)'); + expect(tokens.spacing.md).toBe('var(--perses-spacing-md)'); + expect(tokens.spacing.lg).toBe('var(--perses-spacing-lg)'); + expect(tokens.spacing.xl).toBe('var(--perses-spacing-xl)'); + expect(tokens.spacing['2xl']).toBe('var(--perses-spacing-2xl)'); + expect(tokens.spacing['3xl']).toBe('var(--perses-spacing-3xl)'); + expect(tokens.spacing['4xl']).toBe('var(--perses-spacing-4xl)'); + }); + + it('produces correct var() strings for radius tokens', () => { + expect(tokens.radius.none).toBe('var(--perses-radius-none)'); + expect(tokens.radius.md).toBe('var(--perses-radius-md)'); + expect(tokens.radius.full).toBe('var(--perses-radius-full)'); + }); + + it('produces correct var() strings for typography tokens', () => { + expect(tokens.font.family).toBe('var(--perses-font-family)'); + expect(tokens.font.weight.bold).toBe('var(--perses-font-weight-bold)'); + expect(tokens.font.size.xs).toBe('var(--perses-font-size-xs)'); + expect(tokens.font.size.sm).toBe('var(--perses-font-size-sm)'); + expect(tokens.font.size.md).toBe('var(--perses-font-size-md)'); + expect(tokens.font.size['2xl']).toBe('var(--perses-font-size-2xl)'); + expect(tokens.font.lineHeight.tight).toBe('var(--perses-line-height-tight)'); + expect(tokens.font.lineHeight.compact).toBe('var(--perses-line-height-compact)'); + expect(tokens.font.lineHeight.normal).toBe('var(--perses-line-height-normal)'); + expect(tokens.font.lineHeight.relaxed).toBe('var(--perses-line-height-relaxed)'); + }); + + it('has all expected top-level categories', () => { + expect(Object.keys(tokens)).toEqual( + expect.arrayContaining(['color', 'bg', 'border', 'text', 'status', 'spacing', 'radius', 'font']), + ); + }); +}); diff --git a/design-tokens/src/test/type-assertions.ts b/design-tokens/src/test/type-assertions.ts new file mode 100644 index 00000000..4f4c7b1a --- /dev/null +++ b/design-tokens/src/test/type-assertions.ts @@ -0,0 +1,62 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Compile-time type assertions: if a token var name is missing from +// PersesTokenVar, `npm run type-check` will fail here. +// This file is never executed — it only needs to pass tsc. + +import type { tokens } from '../tokens'; +import type { PersesTokenVar } from '../types'; + +type ExtractVar = T extends `var(${infer V})` ? V : never; + +type AssertAssignable = T; + +// Verify that the var() references in the tokens object produce variable names +// that are assignable to PersesTokenVar. If a token references a CSS variable +// not covered by PersesTokenVar, tsc will emit an error on this line. +type _BgVars = AssertAssignable, PersesTokenVar>; +type _BgSurface = AssertAssignable, PersesTokenVar>; +type _BgSunken = AssertAssignable, PersesTokenVar>; +type _BgOverlay = AssertAssignable, PersesTokenVar>; +type _BgBackdrop = AssertAssignable, PersesTokenVar>; +type _BgNav = AssertAssignable, PersesTokenVar>; + +type _BorderDefault = AssertAssignable, PersesTokenVar>; + +type _TextPrimary = AssertAssignable, PersesTokenVar>; +type _TextSecondary = AssertAssignable, PersesTokenVar>; +type _TextDisabled = AssertAssignable, PersesTokenVar>; +type _TextLink = AssertAssignable, PersesTokenVar>; +type _TextLinkHover = AssertAssignable, PersesTokenVar>; +type _TextNav = AssertAssignable, PersesTokenVar>; +type _TextAccent = AssertAssignable, PersesTokenVar>; + +type _SpacingXs = AssertAssignable, PersesTokenVar>; +type _SpacingLg = AssertAssignable, PersesTokenVar>; + +type _RadiusMd = AssertAssignable, PersesTokenVar>; +type _RadiusFull = AssertAssignable, PersesTokenVar>; + +type _FontFamily = AssertAssignable, PersesTokenVar>; +type _FontWeightBold = AssertAssignable, PersesTokenVar>; +type _FontSizeSm = AssertAssignable, PersesTokenVar>; +type _LineHeightTight = AssertAssignable, PersesTokenVar>; + +type _StatusErrorBg = AssertAssignable, PersesTokenVar>; +type _StatusSuccessText = AssertAssignable, PersesTokenVar>; +type _StatusWarningBorder = AssertAssignable, PersesTokenVar>; +type _StatusInfoIcon = AssertAssignable, PersesTokenVar>; + +type _ColorBlue500 = AssertAssignable, PersesTokenVar>; +type _ColorWhite = AssertAssignable, PersesTokenVar>; diff --git a/design-tokens/src/tokens.ts b/design-tokens/src/tokens.ts new file mode 100644 index 00000000..a11e0c89 --- /dev/null +++ b/design-tokens/src/tokens.ts @@ -0,0 +1,134 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { ColorHue, StatusRole } from './types'; + +const colorScale = (hue: ColorHue) => + ({ + 50: `var(--perses-color-${hue}-50)`, + 100: `var(--perses-color-${hue}-100)`, + 150: `var(--perses-color-${hue}-150)`, + 200: `var(--perses-color-${hue}-200)`, + 300: `var(--perses-color-${hue}-300)`, + 400: `var(--perses-color-${hue}-400)`, + 500: `var(--perses-color-${hue}-500)`, + 600: `var(--perses-color-${hue}-600)`, + 700: `var(--perses-color-${hue}-700)`, + 800: `var(--perses-color-${hue}-800)`, + 850: `var(--perses-color-${hue}-850)`, + 900: `var(--perses-color-${hue}-900)`, + 950: `var(--perses-color-${hue}-950)`, + }) as const; + +const statusRole = (role: StatusRole) => + ({ + bg: `var(--perses-status-bg-${role})`, + bgHover: `var(--perses-status-bg-${role}-hover)`, + text: `var(--perses-status-text-${role})`, + border: `var(--perses-status-border-${role})`, + icon: `var(--perses-status-icon-${role})`, + solid: `var(--perses-status-solid-${role})`, + }) as const; + +export const tokens = { + color: { + blue: colorScale('blue'), + green: colorScale('green'), + gray: colorScale('gray'), + orange: colorScale('orange'), + purple: colorScale('purple'), + red: colorScale('red'), + white: 'var(--perses-color-white)', + black: 'var(--perses-color-black)', + }, + + bg: { + default: 'var(--perses-bg-default)', + surface: 'var(--perses-bg-surface)', + sunken: 'var(--perses-bg-sunken)', + overlay: 'var(--perses-bg-overlay)', + backdrop: 'var(--perses-bg-backdrop)', + navigation: 'var(--perses-bg-navigation)', + }, + + border: { + default: 'var(--perses-border-default)', + }, + + text: { + primary: 'var(--perses-text-primary)', + secondary: 'var(--perses-text-secondary)', + disabled: 'var(--perses-text-disabled)', + link: 'var(--perses-text-link)', + linkHover: 'var(--perses-text-link-hover)', + navigation: 'var(--perses-text-navigation)', + accent: 'var(--perses-text-accent)', + onSolid: 'var(--perses-text-on-solid)', + }, + + status: { + primary: statusRole('primary'), + secondary: statusRole('secondary'), + error: statusRole('error'), + warning: statusRole('warning'), + success: statusRole('success'), + info: statusRole('info'), + }, + + spacing: { + '0': 'var(--perses-spacing-0)', + xs: 'var(--perses-spacing-xs)', + sm: 'var(--perses-spacing-sm)', + md: 'var(--perses-spacing-md)', + lg: 'var(--perses-spacing-lg)', + xl: 'var(--perses-spacing-xl)', + '2xl': 'var(--perses-spacing-2xl)', + '3xl': 'var(--perses-spacing-3xl)', + '4xl': 'var(--perses-spacing-4xl)', + }, + + radius: { + none: 'var(--perses-radius-none)', + sm: 'var(--perses-radius-sm)', + md: 'var(--perses-radius-md)', + lg: 'var(--perses-radius-lg)', + xl: 'var(--perses-radius-xl)', + full: 'var(--perses-radius-full)', + }, + + font: { + family: 'var(--perses-font-family)', + weight: { + light: 'var(--perses-font-weight-light)', + regular: 'var(--perses-font-weight-regular)', + medium: 'var(--perses-font-weight-medium)', + bold: 'var(--perses-font-weight-bold)', + }, + size: { + xs: 'var(--perses-font-size-xs)', + sm: 'var(--perses-font-size-sm)', + md: 'var(--perses-font-size-md)', + lg: 'var(--perses-font-size-lg)', + xl: 'var(--perses-font-size-xl)', + '2xl': 'var(--perses-font-size-2xl)', + '3xl': 'var(--perses-font-size-3xl)', + '4xl': 'var(--perses-font-size-4xl)', + }, + lineHeight: { + tight: 'var(--perses-line-height-tight)', + compact: 'var(--perses-line-height-compact)', + normal: 'var(--perses-line-height-normal)', + relaxed: 'var(--perses-line-height-relaxed)', + }, + }, +} as const; diff --git a/design-tokens/src/types.ts b/design-tokens/src/types.ts new file mode 100644 index 00000000..d851df37 --- /dev/null +++ b/design-tokens/src/types.ts @@ -0,0 +1,91 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export type { HexColor, PersesColor } from './colors'; + +export type ColorStop = 50 | 100 | 150 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 850 | 900 | 950; + +export type ColorHue = 'blue' | 'green' | 'gray' | 'orange' | 'purple' | 'red'; + +export type PrimitiveColorVar = `--perses-color-${ColorHue}-${ColorStop}`; + +export type CommonColorVar = '--perses-color-white' | '--perses-color-black'; + +export type SemanticBgVar = + | '--perses-bg-default' + | '--perses-bg-surface' + | '--perses-bg-sunken' + | '--perses-bg-overlay' + | '--perses-bg-backdrop' + | '--perses-bg-navigation'; + +export type SemanticBorderVar = '--perses-border-default'; + +export type SemanticTextVar = + | '--perses-text-primary' + | '--perses-text-secondary' + | '--perses-text-disabled' + | '--perses-text-link' + | '--perses-text-link-hover' + | '--perses-text-navigation' + | '--perses-text-accent' + | '--perses-text-on-solid'; + +export type StatusRole = 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'info'; + +export type StatusBgVar = `--perses-status-bg-${StatusRole}` | `--perses-status-bg-${StatusRole}-hover`; + +export type StatusTextVar = `--perses-status-text-${StatusRole}`; + +export type StatusBorderVar = `--perses-status-border-${StatusRole}`; + +export type StatusIconVar = `--perses-status-icon-${StatusRole}`; + +export type StatusSolidVar = `--perses-status-solid-${StatusRole}`; + +export type SpacingScale = '0' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl'; + +export type SpacingVar = `--perses-spacing-${SpacingScale}`; + +export type RadiusVar = `--perses-radius-${'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'}`; + +export type FontSizeScale = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl'; + +export type FontSizeVar = `--perses-font-size-${FontSizeScale}`; + +export type LineHeightScale = 'tight' | 'compact' | 'normal' | 'relaxed'; + +export type LineHeightVar = `--perses-line-height-${LineHeightScale}`; + +export type FontVar = + | '--perses-font-family' + | `--perses-font-weight-${'light' | 'regular' | 'medium' | 'bold'}` + | FontSizeVar + | LineHeightVar; + +export type PersesTokenVar = + | PrimitiveColorVar + | CommonColorVar + | SemanticBgVar + | SemanticBorderVar + | SemanticTextVar + | StatusBgVar + | StatusTextVar + | StatusBorderVar + | StatusIconVar + | StatusSolidVar + | SpacingVar + | RadiusVar + | FontVar; + +export type PersesMode = 'light' | 'dark'; diff --git a/design-tokens/tsconfig.build.json b/design-tokens/tsconfig.build.json new file mode 100644 index 00000000..e477966e --- /dev/null +++ b/design-tokens/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/*.stories.*", "**/*.test.*", "**/stories/*", "**/test/*"], + "compilerOptions": { + "emitDeclarationOnly": true, + "declaration": true, + "preserveWatchOutput": true + } +} diff --git a/design-tokens/tsconfig.json b/design-tokens/tsconfig.json new file mode 100644 index 00000000..806aa79a --- /dev/null +++ b/design-tokens/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + } +} diff --git a/design-tokens/vitest.config.ts b/design-tokens/vitest.config.ts new file mode 100644 index 00000000..a0354072 --- /dev/null +++ b/design-tokens/vitest.config.ts @@ -0,0 +1,20 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { resolve } from 'node:path'; + +import { definePackageVitestConfig } from '../vitest.shared'; + +export default definePackageVitestConfig({ + packageDir: resolve(__dirname), +}); diff --git a/explore/package.json b/explore/package.json index ef6e6588..6e0b61cb 100644 --- a/explore/package.json +++ b/explore/package.json @@ -1,6 +1,6 @@ { "name": "@perses-dev/explore", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "description": "The explore feature in Perses", "license": "Apache-2.0", "homepage": "https://github.com/perses/perses/blob/main/README.md", @@ -30,11 +30,11 @@ }, "dependencies": { "@nexucis/fuzzy": "^0.5.1", - "@perses-dev/components": "0.55.0-beta.8", - "@perses-dev/dashboards": "0.55.0-beta.8", - "@perses-dev/plugin-system": "0.55.0-beta.8", + "@perses-dev/components": "0.55.0-beta.11", + "@perses-dev/dashboards": "0.55.0-beta.11", + "@perses-dev/plugin-system": "0.55.0-beta.11", "mdi-material-ui": "^7.9.2", - "qs": "^6.14.0", + "qs": "6.16.0", "react-virtuoso": "^4.12.2", "use-query-params": "^2.2.1", "use-resize-observer": "^9.0.0" diff --git a/package-lock.json b/package-lock.json index 89d5cfcc..0a98aa12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "perses-shared", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "perses-shared", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "workspaces": [ "components", "dashboards", + "design-tokens", "plugin-system", "explore", "client" @@ -49,7 +50,7 @@ }, "client": { "name": "@perses-dev/client", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "license": "Apache-2.0", "dependencies": { "@perses-dev/spec": "0.3.0-beta.8", @@ -61,20 +62,22 @@ }, "components": { "name": "@perses-dev/components", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "license": "Apache-2.0", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.4.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3", + "@base-ui/react": "^1.0.0", "@codemirror/lang-json": "^6.0.1", "@date-fns/tz": "^1.4.1", "@fontsource/inter": "^5.0.0", "@mui/x-date-pickers": "^7.23.1", - "@perses-dev/client": "0.55.0-beta.8", + "@perses-dev/client": "0.55.0-beta.11", "@perses-dev/spec": "0.3.0-beta.8", "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/react-table": "^8.20.5", "@uiw/react-codemirror": "^4.19.1", + "clsx": "^2.1.1", "date-fns": "^4.1.0", "echarts": "5.5.0", "immer": "^10.1.1", @@ -88,31 +91,59 @@ "react-virtuoso": "^4.12.2" }, "devDependencies": { - "@types/lodash": "^4.17.20" + "@ladle/react": "^4.0.0", + "@types/lodash": "^4.17.20", + "copyfiles": "^2.4.1" }, "peerDependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^6.1.10", + "@perses-dev/design-tokens": "^0.54.0", "lodash": "^4.17.21", - "react": "^18.3.0", - "react-dom": "^18.3.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "components/node_modules/mathjs": { + "version": "10.6.4", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-10.6.4.tgz", + "integrity": "sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.18.6", + "complex.js": "^2.1.1", + "decimal.js": "^10.3.1", + "escape-latex": "^1.2.0", + "fraction.js": "^4.2.0", + "javascript-natural-sort": "^0.7.1", + "seedrandom": "^3.0.5", + "tiny-emitter": "^2.1.0", + "typed-function": "^2.1.0" + }, + "bin": { + "mathjs": "bin/cli.js" + }, + "engines": { + "node": ">= 14" } }, "dashboards": { "name": "@perses-dev/dashboards", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "license": "Apache-2.0", "dependencies": { - "@perses-dev/client": "0.55.0-beta.8", - "@perses-dev/components": "0.55.0-beta.8", - "@perses-dev/plugin-system": "0.55.0-beta.8", + "@dnd-kit/dom": "^0.4.0", + "@dnd-kit/react": "^0.4.0", + "@perses-dev/client": "0.55.0-beta.11", + "@perses-dev/components": "0.55.0-beta.11", + "@perses-dev/plugin-system": "0.55.0-beta.11", "@perses-dev/spec": "0.3.0-beta.8", + "@snapgridjs/react": "^0.10.0", "@tanstack/hotkeys": "^0.8.0", "@tanstack/react-hotkeys": "^0.9.1", "immer": "^10.1.1", "mdi-material-ui": "^7.9.2", - "react-grid-layout": "^1.3.4", "react-hook-form": "^7.87.0", "react-intersection-observer": "^9.4.0", "use-immer": "^0.11.0", @@ -122,7 +153,6 @@ "zustand": "^4.3.3" }, "devDependencies": { - "@types/react-grid-layout": "^1.3.6", "history": "^5.3.0" }, "peerDependencies": { @@ -132,43 +162,37 @@ "react-dom": "^18.3.0" } }, - "dashboards/node_modules/@tanstack/hotkeys": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@tanstack/hotkeys/-/hotkeys-0.8.0.tgz", - "integrity": "sha512-vqH7X9nb0MTJ/O08++dB5bP9jgj4+BIPOUu/U+6myG86lDsirZSVSobpq5UQpE7nBuk62i8eIYeOhd+OMl/UrA==", - "license": "MIT", - "dependencies": { - "@tanstack/store": "^0.11.0" + "dashboards/node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": ">=18" + "node": ">= 14.6" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "url": "https://github.com/sponsors/eemeli" } }, - "dashboards/node_modules/@tanstack/store": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.11.0.tgz", - "integrity": "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } + "design-tokens": { + "name": "@perses-dev/design-tokens", + "version": "0.54.0", + "license": "Apache-2.0" }, "explore": { "name": "@perses-dev/explore", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "license": "Apache-2.0", "dependencies": { "@nexucis/fuzzy": "^0.5.1", - "@perses-dev/components": "0.55.0-beta.8", - "@perses-dev/dashboards": "0.55.0-beta.8", - "@perses-dev/plugin-system": "0.55.0-beta.8", + "@perses-dev/components": "0.55.0-beta.11", + "@perses-dev/dashboards": "0.55.0-beta.11", + "@perses-dev/plugin-system": "0.55.0-beta.11", "mdi-material-ui": "^7.9.2", - "qs": "^6.14.0", + "qs": "6.16.0", "react-virtuoso": "^4.12.2", "use-query-params": "^2.2.1", "use-resize-observer": "^9.0.0" @@ -224,12 +248,12 @@ } }, "node_modules/@atlaskit/pragmatic-drag-and-drop-hitbox": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop-hitbox/-/pragmatic-drag-and-drop-hitbox-1.1.0.tgz", - "integrity": "sha512-JWt6eVp6Br2FPHRM8s0dUIHQk/jFInGP1f3ti5CdtM1Ji5/pt8Akm44wDC063Gv2i5RGseixtbW0z/t6RYtbdg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@atlaskit/pragmatic-drag-and-drop-hitbox/-/pragmatic-drag-and-drop-hitbox-1.2.0.tgz", + "integrity": "sha512-eWJvvuHZOC4Yk+Li7QpS+JM2F/I50/3PhMvEcyvcHbXI0FP0kCDD1MiF8Hv7uSOxpk5JNqKoOmK8e1ncOzTgqA==", "license": "Apache-2.0", "dependencies": { - "@atlaskit/pragmatic-drag-and-drop": "^1.6.0", + "@atlaskit/pragmatic-drag-and-drop": "^1.8.0", "@babel/runtime": "^7.0.0" } }, @@ -247,14 +271,72 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/generator": { + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, "license": "MIT", "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -263,6 +345,33 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-globals": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", @@ -285,6 +394,34 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", @@ -303,14 +440,38 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/parser": { + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, "license": "MIT", "dependencies": { + "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -318,10 +479,42 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -342,17 +535,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", + "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", + "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/types": "^7.29.8", "debug": "^4.3.1" }, "engines": { @@ -360,9 +553,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -372,6 +565,66 @@ "node": ">=6.9.0" } }, + "node_modules/@base-ui/react": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.8.0.tgz", + "integrity": "sha512-P0/1sxo6SBVZOklKMIedvTWqw2s2IQzi9x5bIVsXu980cuSOD4NeuRSs+/L7LZQfDkZP/uRZyGPyfFl/B1oH+Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.7", + "@base-ui/utils": "0.4.0", + "@floating-ui/react-dom": "^2.1.9", + "@floating-ui/utils": "^0.2.12", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } + } + }, + "node_modules/@base-ui/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-bO9fz25kKtPf+aZVyfQrC0PDmJdmVni31W2hCS5/Owb+inwdIL3XU26pCPRPlt4LSxZrBgLwubXQXQlKaFEZzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.7", + "@floating-ui/utils": "^0.2.12", + "reselect": "^5.2.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@borewit/text-codec": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", @@ -384,9 +637,9 @@ } }, "node_modules/@codemirror/autocomplete": { - "version": "6.20.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.2.tgz", - "integrity": "sha512-G5FPkgIiLjOgZMjqVjvuKQ1rGPtHogLldJr33eFJdVLtmwY+giGrlv/ewljLz6b9BSQLkjxuwBc6g6omDM+YxQ==", + "version": "6.20.3", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz", + "integrity": "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -396,13 +649,13 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz", - "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.11.1.tgz", + "integrity": "sha512-O/4hG3SC1YwcmQ0d2UVNDs+AsaNWd1iHVxbTeEBuqH+6bExAiPK3iS/BvpY6rZGURALv4ZD3sIgcCmRvw3ehBg==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.6.0", + "@codemirror/state": "^6.7.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } @@ -418,9 +671,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz", - "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.4.tgz", + "integrity": "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -432,9 +685,9 @@ } }, "node_modules/@codemirror/lint": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.6.tgz", - "integrity": "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A==", + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.7.tgz", + "integrity": "sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -443,9 +696,9 @@ } }, "node_modules/@codemirror/search": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz", - "integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.2.tgz", + "integrity": "sha512-gUYkYhT2+n/+VGZ+8EzE5WFkYZUZYm1VOKDudIsNqh42uRVQJ0a6Yss9sdKT3MeOYfuL1N6AZA57oza0Oyr0LA==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -454,9 +707,9 @@ } }, "node_modules/@codemirror/state": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz", - "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.5.tgz", + "integrity": "sha512-QjLbZmY1Au3JiRrDVYFLRD0BZ3SOKS9pR3yjIkd7u27YY8TFD9/Q9fhPnLV5l1mHFSo3hHU/N31vpwEJOx4owQ==", "license": "MIT", "dependencies": { "@marijn/find-cluster-break": "^1.0.0" @@ -475,12 +728,12 @@ } }, "node_modules/@codemirror/view": { - "version": "6.43.0", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.0.tgz", - "integrity": "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA==", + "version": "6.43.12", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.12.tgz", + "integrity": "sha512-Nv0vxQ19NAqvB/c2pFzjIzFlzzJl7jmdtNkwOwGbn0Ks9mFAzibvumz7cQem5cRsFA2cEw2fg+uHZGbcHupLQQ==", "license": "MIT", "dependencies": { - "@codemirror/state": "^6.6.0", + "@codemirror/state": "^6.7.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" @@ -754,9 +1007,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -767,13 +1020,13 @@ "aix" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -784,13 +1037,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -801,13 +1054,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -818,13 +1071,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -835,13 +1088,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -852,13 +1105,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -869,13 +1122,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -886,13 +1139,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -903,13 +1156,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -920,13 +1173,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -937,13 +1190,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -954,13 +1207,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -971,13 +1224,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -988,13 +1241,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -1005,13 +1258,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -1022,13 +1275,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -1039,7 +1292,7 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/netbsd-arm64": { @@ -1049,9 +1302,8 @@ "cpu": [ "arm64" ], - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, "os": [ "netbsd" ], @@ -1060,9 +1312,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -1073,7 +1325,7 @@ "netbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/openbsd-arm64": { @@ -1083,9 +1335,8 @@ "cpu": [ "arm64" ], - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, "os": [ "openbsd" ], @@ -1094,9 +1345,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -1107,7 +1358,7 @@ "openbsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/openharmony-arm64": { @@ -1117,9 +1368,8 @@ "cpu": [ "arm64" ], - "dev": true, + "extraneous": true, "license": "MIT", - "optional": true, "os": [ "openharmony" ], @@ -1128,9 +1378,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -1141,13 +1391,13 @@ "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -1158,13 +1408,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -1175,13 +1425,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -1192,13 +1442,51 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, "node_modules/@fontsource/inter": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", - "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.3.0.tgz", + "integrity": "sha512-RofMylZmjlJEfELXeNHFWBRcSs75rGU/6bV2S2jfnvv/3rPXPGe0LgUJTklcHZ9lM4OZmAVFhcJPnACfb91A3g==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" @@ -1315,57 +1603,115 @@ } } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@inquirer/ansi": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.8.tgz", + "integrity": "sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.3.2.tgz", + "integrity": "sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==", + "dev": true, + "license": "MIT", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { - "node": ">=12" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@inquirer/core": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.3.tgz", + "integrity": "sha512-wsSy0sznmXwkty+2PzZwx00Cazc/E0r0B7mAzdGROz2Ct+DFZXaK7WDjGZvgjRldxH5ZhFVfF2lgkYrqgOw2KA==", "dev": true, "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, "engines": { - "node": ">=12" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/@inquirer/figures": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.9.tgz", + "integrity": "sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==", "dev": true, "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/type": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz", + "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", "dependencies": { - "ansi-regex": "^6.2.2" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/@jest/diff-sequences": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.4.0.tgz", - "integrity": "sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", "dev": true, "license": "MIT", "engines": { @@ -1373,22 +1719,22 @@ } }, "node_modules/@jest/expect-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.4.1.tgz", - "integrity": "sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.1.tgz", + "integrity": "sha512-WcRWhHQdTMRDpyWKZ/6MINBmovI7zeD+bL8wFjCncRV3NQOwKy1X45IfyblfHR4k/XciIlNEdFL9QjFO+HNKOg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0" + "@jest/get-type": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", "dev": true, "license": "MIT", "engines": { @@ -1396,23 +1742,39 @@ } }, "node_modules/@jest/pattern": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.4.0.tgz", - "integrity": "sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", - "jest-regex-util": "30.4.0" + "jest-regex-util": "30.5.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/react-is-19": { + "name": "react-is", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/schemas": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", - "integrity": "sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", "dev": true, "license": "MIT", "dependencies": { @@ -1423,14 +1785,14 @@ } }, "node_modules/@jest/types": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.4.1.tgz", - "integrity": "sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.4.0", - "@jest/schemas": "30.4.1", + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", @@ -1441,6 +1803,23 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1451,6 +1830,17 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -1461,9 +1851,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -1489,64 +1879,326 @@ "dev": true, "license": "MIT" }, - "node_modules/@lezer/common": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", - "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", - "license": "MIT" + "node_modules/@ladle/react": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@ladle/react/-/react-4.1.2.tgz", + "integrity": "sha512-6nMIPCsnkGCjIRz5kpRojJyieqcFPsq34QeqJp5mFpT1xFeX7sKwdCpQJ92d5ORsejmxTyp9gkQA+AXG3i3AGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.6", + "@babel/core": "^7.24.6", + "@babel/generator": "^7.24.6", + "@babel/parser": "^7.24.6", + "@babel/template": "^7.24.6", + "@babel/traverse": "^7.24.6", + "@babel/types": "^7.24.6", + "@ladle/react-context": "^1.0.1", + "@mdx-js/mdx": "^3.0.1", + "@mdx-js/react": "^3.0.1", + "@vitejs/plugin-react": "^4.3.0", + "@vitejs/plugin-react-swc": "^3.7.0", + "axe-core": "^4.9.1", + "boxen": "^7.1.1", + "chokidar": "^3.6.0", + "classnames": "^2.5.1", + "commander": "^12.1.0", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "get-port": "^7.1.0", + "globby": "^14.0.1", + "history": "^5.3.0", + "koa": "^2.15.3", + "koa-connect": "^2.1.0", + "lodash.merge": "^4.6.2", + "msw": "^2.3.0", + "open": "^10.1.0", + "prism-react-renderer": "^2.3.1", + "prop-types": "^15.8.1", + "query-string": "^9.0.0", + "react-hotkeys-hook": "^4.5.0", + "react-inspector": "^6.0.2", + "rehype-class-names": "^2.0.0", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.0", + "source-map": "^0.7.4", + "vfile": "^6.0.1", + "vite": "^5.2.12", + "vite-tsconfig-paths": "^4.3.2" + }, + "bin": { + "ladle": "lib/cli/cli.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } }, - "node_modules/@lezer/highlight": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", - "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "node_modules/@ladle/react-context": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@ladle/react-context/-/react-context-1.0.1.tgz", + "integrity": "sha512-xVQ8siyOEQG6e4Knibes1uA3PTyXnqiMmfSmd5pIbkzeDty8NCBtYHhTXSlfmcDNEsw/G8OzNWo4VbyQAVDl2A==", + "dev": true, "license": "MIT", - "dependencies": { - "@lezer/common": "^1.3.0" + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" } }, - "node_modules/@lezer/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", - "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "node_modules/@ladle/react/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "license": "MIT", "dependencies": { - "@lezer/common": "^1.2.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/@lezer/lr": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", - "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "node_modules/@ladle/react/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, "license": "MIT", - "dependencies": { - "@lezer/common": "^1.0.0" + "engines": { + "node": ">=18" } }, - "node_modules/@marijn/find-cluster-break": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", - "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", - "license": "MIT" - }, - "node_modules/@module-federation/bridge-react-webpack-plugin": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-2.8.1.tgz", - "integrity": "sha512-w/+d+OjtzT6sa0b3elBcCw6uw+6l8JDOtMIyWzx1lNNuV9IPhq2pgSLXEVEHdIo77r4zgQAktm9kUfCzjO0VrQ==", + "node_modules/@ladle/react/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", - "dependencies": { - "@module-federation/sdk": "2.8.1" + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@module-federation/cli": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/cli/-/cli-2.8.1.tgz", - "integrity": "sha512-DZo0f3gTN7bKoqw/KM5Kj4qIKeF3bfQwCq7fgf2Gnd+jfZPY4otVy7nbRxFmtdienEhqzcmFFWJUPH/cOkyMqg==", + "node_modules/@ladle/react/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/@ladle/react/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@ladle/react/node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "deprecated": "unmaintained", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@ladle/react/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "extraneous": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@ladle/react/node_modules/vite-tsconfig-paths": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.3.2.tgz", + "integrity": "sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/@lezer/common": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz", + "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==", + "license": "MIT" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz", + "integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz", + "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.4.tgz", + "integrity": "sha512-Wy0V7+SGUjnF9/TkiM1hKVDPj7jKXduPNboMVtHTA8dySMURWqfg/JZ9E2Sq8JgSJmkl7k7Qe9FLeMSrSraWmQ==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@module-federation/bridge-react-webpack-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-2.9.0.tgz", + "integrity": "sha512-hv3fuQkGERQ/COBKTVbFV1GWovReSg/bzJzDuxWR1F84h6NYtbYMWQqX8Egvb7HKMtn9Rflzw0GeaLr8F08vDg==", + "license": "MIT", + "dependencies": { + "@module-federation/sdk": "2.9.0" + } + }, + "node_modules/@module-federation/cli": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/cli/-/cli-2.9.0.tgz", + "integrity": "sha512-r9RdlLRy3zWxuWQRonif48xdDu1reBGx18QpkZwLQ4JfSrOARjycNIGY2Y7QaUw7dedzxyee4FtKFeX/kOVLYQ==", "license": "MIT", "dependencies": { - "@module-federation/dts-plugin": "2.8.1", - "@module-federation/sdk": "2.8.1", + "@module-federation/dts-plugin": "2.9.0", + "@module-federation/sdk": "2.9.0", "commander": "11.1.0", "jiti": "2.4.2" }, @@ -1567,18 +2219,18 @@ } }, "node_modules/@module-federation/dts-plugin": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-2.8.1.tgz", - "integrity": "sha512-JM8g76KzhhH44kHvM2JPJ5FIlQDwUNzw0vvq5EDSo/znNUmUEuSrfTssukCKg1nqnBGWLohjIV0LOOhLdCknoQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-2.9.0.tgz", + "integrity": "sha512-uMGqEG/p9odG2BVr7WRbBe2OgrvzBd3LPzcp5WP+bm3djBdUJ4PZ3ozqKp6qpy+NFnlh6vnM815Xn6AXkKy1Vw==", "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.8.1", - "@module-federation/managers": "2.8.1", - "@module-federation/sdk": "2.8.1", - "@module-federation/third-party-dts-extractor": "2.8.1", + "@module-federation/error-codes": "2.9.0", + "@module-federation/managers": "2.9.0", + "@module-federation/sdk": "2.9.0", + "@module-federation/third-party-dts-extractor": "2.9.0", "adm-zip": "0.6.0", "isomorphic-ws": "5.0.0", - "undici": "7.28.0", + "undici": "7.29.0", "ws": "8.21.0" }, "peerDependencies": { @@ -1591,23 +2243,44 @@ } } }, + "node_modules/@module-federation/dts-plugin/node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@module-federation/enhanced": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-2.8.1.tgz", - "integrity": "sha512-QHlvm+poXVPkIPK0C8Ras36peZA9CxRp43deSQcArBZ6uEsZTGGm07ohDxRLzVO7kYXR6dE56gIAN9fqa9Fhgg==", - "license": "MIT", - "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "2.8.1", - "@module-federation/cli": "2.8.1", - "@module-federation/dts-plugin": "2.8.1", - "@module-federation/error-codes": "2.8.1", - "@module-federation/inject-external-runtime-core-plugin": "2.8.1", - "@module-federation/managers": "2.8.1", - "@module-federation/manifest": "2.8.1", - "@module-federation/rspack": "2.8.1", - "@module-federation/runtime-tools": "2.8.1", - "@module-federation/sdk": "2.8.1", - "@module-federation/webpack-bundler-runtime": "2.8.1", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-2.9.0.tgz", + "integrity": "sha512-Jd/JHoFL9fNKL4Nnzo/9hf6FD/oQo3gKpE8xt6EGuhxmrvg6wM0radPtqgHiSSWLMW7CiXr2agNjKvquKd83rw==", + "license": "MIT", + "dependencies": { + "@module-federation/bridge-react-webpack-plugin": "2.9.0", + "@module-federation/cli": "2.9.0", + "@module-federation/dts-plugin": "2.9.0", + "@module-federation/error-codes": "2.9.0", + "@module-federation/inject-external-runtime-core-plugin": "2.9.0", + "@module-federation/managers": "2.9.0", + "@module-federation/manifest": "2.9.0", + "@module-federation/rspack": "2.9.0", + "@module-federation/runtime-tools": "2.9.0", + "@module-federation/sdk": "2.9.0", + "@module-federation/webpack-bundler-runtime": "2.9.0", "schema-utils": "4.3.0", "tapable": "2.3.0" }, @@ -1631,120 +2304,54 @@ } } }, - "node_modules/@module-federation/enhanced/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@module-federation/enhanced/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/@module-federation/enhanced/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/@module-federation/enhanced/node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@module-federation/enhanced/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/@module-federation/error-codes": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-2.8.1.tgz", - "integrity": "sha512-0mQ+bWt1LRCZyURx3g2b8G+aAlvk8iXIgrp3Jit/75blrlVda/eVqnHz1L+YOxwkP3xSrdbUb4423AoWti31ZQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-2.9.0.tgz", + "integrity": "sha512-IGpd+VRlji3NyGOGGTsk7YEmPRKcDoBK4YHqIuP+OQwyb2YhHCUHO2vW9RXeQxCuKwi+c6xkTweRYG+Umy+0Zw==", "license": "MIT" }, "node_modules/@module-federation/inject-external-runtime-core-plugin": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/inject-external-runtime-core-plugin/-/inject-external-runtime-core-plugin-2.8.1.tgz", - "integrity": "sha512-xpqjWaLw4KbPW4CMRDRiGjH08/ABdPc9z4fRuPiFYA4loNYrjFWALRe2QA6W90SAew/d5RQ6QchO/wuhrzy3dw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/inject-external-runtime-core-plugin/-/inject-external-runtime-core-plugin-2.9.0.tgz", + "integrity": "sha512-k3wCSZsY21HjYQ61wmIJUQleOgcHgqx/sX4qXYw0XnJnzHuFo64rzMvgr+TuBIgZ1peAQtfILLlTnWyTRjtZHw==", "license": "MIT", "peerDependencies": { - "@module-federation/runtime-tools": "2.8.1" + "@module-federation/runtime-tools": "2.9.0" } }, "node_modules/@module-federation/managers": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-2.8.1.tgz", - "integrity": "sha512-bHRooIgplIFNLH42eM3g21b2apM/a7lMG1EwifUxT4A4AobS42H08KGdYITdKJcrgowx3D7PhYndiwtHFI03zQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-2.9.0.tgz", + "integrity": "sha512-8KhB2PF4g+M0hGaethU1H4GVWabLn5sF5TvnM6VxgAcDL4TfLY8aC/YobAXHG/SV0jpU5lsGe6s6xy6ccV0MQw==", "license": "MIT", "dependencies": { - "@module-federation/sdk": "2.8.1" + "@module-federation/sdk": "2.9.0" } }, "node_modules/@module-federation/manifest": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-2.8.1.tgz", - "integrity": "sha512-1NOd4J1sJrTpl7M1NYsdUtjSR2Eu3R//r+w51KC9XhAZkxWse0+uPphGdeiUqCOVgAAWjKreckY+xnEmG6Kqig==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-2.9.0.tgz", + "integrity": "sha512-Zhm9luVOw9XPou50eTwsvdgr208CszoQ6cGORQDCPAMhjpGb5oYFtilJ+LKW7hQ1LktD15bEZmGhC1anvgXEiQ==", "license": "MIT", "dependencies": { - "@module-federation/dts-plugin": "2.8.1", - "@module-federation/managers": "2.8.1", - "@module-federation/sdk": "2.8.1" + "@module-federation/dts-plugin": "2.9.0", + "@module-federation/managers": "2.9.0", + "@module-federation/sdk": "2.9.0" } }, "node_modules/@module-federation/rspack": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-2.8.1.tgz", - "integrity": "sha512-jJYkARn1U1M92CbiLyoaP7+tNKh8YzzOTMSGzbdj6okTtWK0Z9ImyVoKEnAnjnLP1nbQjkPEaojkR2D2IQFhLw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-2.9.0.tgz", + "integrity": "sha512-9zSlmQYKRHKVWqhlZSMyjstp2A3VVrQV2Of8mrF5NXhngFemNx7Hw35+MTo+gsRfF5glpN8bAzLyIokRUo1Cog==", "license": "MIT", "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "2.8.1", - "@module-federation/dts-plugin": "2.8.1", - "@module-federation/inject-external-runtime-core-plugin": "2.8.1", - "@module-federation/managers": "2.8.1", - "@module-federation/manifest": "2.8.1", - "@module-federation/runtime-tools": "2.8.1", - "@module-federation/sdk": "2.8.1" + "@module-federation/bridge-react-webpack-plugin": "2.9.0", + "@module-federation/dts-plugin": "2.9.0", + "@module-federation/inject-external-runtime-core-plugin": "2.9.0", + "@module-federation/managers": "2.9.0", + "@module-federation/manifest": "2.9.0", + "@module-federation/runtime-tools": "2.9.0", + "@module-federation/sdk": "2.9.0" }, "peerDependencies": { "@rspack/core": "^0.7.0 || ^1.0.0 || ^2.0.0-0", @@ -1761,59 +2368,84 @@ } }, "node_modules/@module-federation/runtime": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-2.8.1.tgz", - "integrity": "sha512-+xpq/r6Om4plbGJisZp6/rl7usEUlQszz34E+JUKgl9uW3QIRzVgxwOAzGiF7U+dqOKxMqmiq+nTJwK2wAwteA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-2.9.0.tgz", + "integrity": "sha512-3cyAav0hWP+dNvB7qrcK9CKxQn+JvkbRvLtZz3zS2g0EyxtDFDjgbHY0Afcf7oHf8IHhKeEdzb/3Kjr1Pjmr7A==", "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.8.1", - "@module-federation/runtime-core": "2.8.1", - "@module-federation/sdk": "2.8.1" + "@module-federation/error-codes": "2.9.0", + "@module-federation/runtime-core": "2.9.0", + "@module-federation/sdk": "2.9.0" } }, "node_modules/@module-federation/runtime-core": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-2.8.1.tgz", - "integrity": "sha512-Dif+3u7fvq6qBATFIv5qB7ay6Rgo2HNzhaNOt1yRfpVXjiJqQ3UPnHZ+TLP9znkXiZvg6Bg5W9EV2ZX4nH2S0w==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-2.9.0.tgz", + "integrity": "sha512-dLykRYfpbEJBTdk2NlbNoVVTB196O3qujawTBguLABJkPCWETJNk60NR1yZO34eI+DTH+eGwHU3m7FddAWnbnw==", "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.8.1", - "@module-federation/sdk": "2.8.1" + "@module-federation/error-codes": "2.9.0", + "@module-federation/sdk": "2.9.0" } }, "node_modules/@module-federation/runtime-tools": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-2.8.1.tgz", - "integrity": "sha512-CIQ9dPqWOiitXKCYqgHXfr0hehtxsZDfiuFaesJAJnXtqkM5+nVkkBNkY07cDV5wOi00/aiOhEWYoCcz+cRQtQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-2.9.0.tgz", + "integrity": "sha512-u2puqsaHiw1bVvLNk1uh98iPo6UzaBuci/aTvOFwKvbT/RF18C3vGGnm+ShHPKQEnoN6ctPtnygyOZDPR+8cgg==", "license": "MIT", "dependencies": { - "@module-federation/runtime": "2.8.1", - "@module-federation/webpack-bundler-runtime": "2.8.1" + "@module-federation/runtime": "2.9.0", + "@module-federation/webpack-bundler-runtime": "2.9.0" } }, "node_modules/@module-federation/sdk": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-2.8.1.tgz", - "integrity": "sha512-3EVljiNilY2pFIG2RO4KNCC6gIPnYc9J+p5U6Nn8D5X3PtJeEcPyBvKGttxZnSLlXCi+YXQfgexBOfnkvEuzuQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-2.9.0.tgz", + "integrity": "sha512-IMjObgBGQTXd33jTTCYcxvz8iOQGLsZ2QIPOj90rDxuBtJsN4WJwYyXqligrhY/e5p/BipUPdbIgKmWL7zFhTw==", "license": "MIT" }, "node_modules/@module-federation/third-party-dts-extractor": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-2.8.1.tgz", - "integrity": "sha512-6ulu7vqv5wyM5YWwxjUHzZ+8Sg6e+/vn+gskiUBs6EPqe/w3XMdRoUrFjAI3EW62xi0e0xbWLsjbQs9jCAj8ig==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-2.9.0.tgz", + "integrity": "sha512-R1Xuqnqzw6wQxWV3yU9fX1FydXAeZF2TNVFAVo1N1oLBA2j5y7aUO/Fc3VSNgd9/gxMzJgTVBdA+nMiD2SFCgg==", "license": "MIT" }, "node_modules/@module-federation/webpack-bundler-runtime": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-2.8.1.tgz", - "integrity": "sha512-dGFlrTLimhxpHohysx/qPRuIRaAiutqFfX0xFzDchEkY0DXpS2sOhuJ2foNcCIQK/FKFJW1YeaaIUkZ5FWMcOg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-2.9.0.tgz", + "integrity": "sha512-MdU6NQibT57MaJG3KPBjC30IVBrz5eU7IcjHoVDYnMh7OmASw3stagBu7hYjdMTP31luNdtzUn85s9axvdwTlw==", + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "2.9.0", + "@module-federation/runtime": "2.9.0", + "@module-federation/sdk": "2.9.0" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.41.9", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.9.tgz", + "integrity": "sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==", + "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.8.1", - "@module-federation/runtime": "2.8.1", - "@module-federation/sdk": "2.8.1" + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" } }, + "node_modules/@mswjs/interceptors/node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true, + "license": "MIT" + }, "node_modules/@mui/core-downloads-tracker": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.5.0.tgz", @@ -1875,7 +2507,7 @@ } } }, - "node_modules/@mui/material/node_modules/@mui/private-theming": { + "node_modules/@mui/private-theming": { "version": "6.4.9", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.9.tgz", "integrity": "sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==", @@ -1903,7 +2535,7 @@ } } }, - "node_modules/@mui/material/node_modules/@mui/styled-engine": { + "node_modules/@mui/styled-engine": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.5.0.tgz", "integrity": "sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==", @@ -1938,7 +2570,7 @@ } } }, - "node_modules/@mui/material/node_modules/@mui/system": { + "node_modules/@mui/system": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.5.0.tgz", "integrity": "sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==", @@ -1979,229 +2611,6 @@ } } }, - "node_modules/@mui/material/node_modules/react-is": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", - "license": "MIT", - "peer": true - }, - "node_modules/@mui/private-theming": { - "version": "7.3.11", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.11.tgz", - "integrity": "sha512-9B+YKms0fRHbNrqp9tOT/DNbNnU5gyvJ1o3qAGXfq8GmZcbJnE3At9x07Zr/o0pkhzg4aDdwXVqe4+AcgtOCPA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6", - "@mui/utils": "^7.3.11", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming/node_modules/@mui/types": { - "version": "7.4.12", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.12.tgz", - "integrity": "sha512-iKNAF2u9PzSIj40CjvKJWxFXJo122jXVdrmdh0hMYd+FR+NuJMkr/L88XwWLCRiJ5P1j+uyac25+Kp6YC4hu6w==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming/node_modules/@mui/utils": { - "version": "7.3.11", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.11.tgz", - "integrity": "sha512-XTjGnifwteg71/ij+0e7Y7d+hwyntMYP5wPoA/g2drdGH+Flkvjwy0OfrVpKBbaOvofq4zU/LIyUZyKgmWu18g==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6", - "@mui/types": "^7.4.12", - "@types/prop-types": "^15.7.15", - "clsx": "^2.1.1", - "prop-types": "^15.8.1", - "react-is": "^19.2.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming/node_modules/react-is": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", - "license": "MIT", - "peer": true - }, - "node_modules/@mui/styled-engine": { - "version": "7.3.10", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.10.tgz", - "integrity": "sha512-WxE9SiF8xskAQqGjsp0poXCkCqsoXFEsSr0HBXfApmGHR+DBnXRp+z46Vsltg4gpPM4Z96DeAQRpeAOnhNg7Ng==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6", - "@emotion/cache": "^11.14.0", - "@emotion/serialize": "^1.3.3", - "@emotion/sheet": "^1.4.0", - "csstype": "^3.2.3", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } - } - }, - "node_modules/@mui/system": { - "version": "7.3.11", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.11.tgz", - "integrity": "sha512-7izwGWdNawAKpBKcRlx7f2gFnAAjmASBWvMcyX4YYEeLOFsbfGRbUYGInvnAcUeql3rPxI7F9Ft4oY2OLRz44g==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6", - "@mui/private-theming": "^7.3.11", - "@mui/styled-engine": "^7.3.10", - "@mui/types": "^7.4.12", - "@mui/utils": "^7.3.11", - "clsx": "^2.1.1", - "csstype": "^3.2.3", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/system/node_modules/@mui/types": { - "version": "7.4.12", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.12.tgz", - "integrity": "sha512-iKNAF2u9PzSIj40CjvKJWxFXJo122jXVdrmdh0hMYd+FR+NuJMkr/L88XwWLCRiJ5P1j+uyac25+Kp6YC4hu6w==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/system/node_modules/@mui/utils": { - "version": "7.3.11", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.11.tgz", - "integrity": "sha512-XTjGnifwteg71/ij+0e7Y7d+hwyntMYP5wPoA/g2drdGH+Flkvjwy0OfrVpKBbaOvofq4zU/LIyUZyKgmWu18g==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.28.6", - "@mui/types": "^7.4.12", - "@types/prop-types": "^15.7.15", - "clsx": "^2.1.1", - "prop-types": "^15.8.1", - "react-is": "^19.2.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/system/node_modules/react-is": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", - "license": "MIT", - "peer": true - }, "node_modules/@mui/types": { "version": "7.2.24", "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", @@ -2246,12 +2655,6 @@ } } }, - "node_modules/@mui/utils/node_modules/react-is": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", - "license": "MIT" - }, "node_modules/@mui/x-date-pickers": { "version": "7.29.4", "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.29.4.tgz", @@ -2346,6 +2749,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2499,6 +2905,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2516,6 +2925,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2533,6 +2945,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2550,6 +2965,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2567,6 +2985,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2584,6 +3005,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2601,6 +3025,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2703,6 +3130,69 @@ "integrity": "sha512-+swL9itqBe1rx5Pr8ihaIS7STOeFI90HpOFF8y/3wo3ryTxKs0Hf4xc+wiA4yi9nrY4wo3VC8HJOxNiekSBE4w==", "license": "MIT" }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-3.0.0.tgz", + "integrity": "sha512-XW375UK8/9SqUVNVa6M0yEy8+iTi4QN5VZ7aZuRFQmy76LRwI9wy5F4YIBU6T+eTe2/DNDo8tqu8RHlwLHM6RA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, "node_modules/@oxc-parser/binding-android-arm-eabi": { "version": "0.143.0", "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.143.0.tgz", @@ -2830,6 +3320,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2847,6 +3340,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2864,6 +3360,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2881,6 +3380,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2898,6 +3400,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2915,6 +3420,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2932,6 +3440,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2949,6 +3460,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3163,6 +3677,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3180,6 +3697,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3197,6 +3717,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3214,6 +3737,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3231,6 +3757,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3248,6 +3777,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3265,6 +3797,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3282,6 +3817,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3486,6 +4024,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3503,6 +4044,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3520,6 +4064,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3537,6 +4084,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3554,6 +4104,9 @@ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3571,6 +4124,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3588,6 +4144,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3605,6 +4164,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3694,6 +4256,10 @@ "resolved": "dashboards", "link": true }, + "node_modules/@perses-dev/design-tokens": { + "resolved": "design-tokens", + "link": true + }, "node_modules/@perses-dev/explore": { "resolved": "explore", "link": true @@ -3713,87 +4279,332 @@ "zod": "^4.5.4" } }, - "node_modules/@perses-dev/spec/node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" + "node": ">=14" } }, - "node_modules/@perses-dev/spec/node_modules/mathjs": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.2.0.tgz", - "integrity": "sha512-UAQzSVob9rNLdGpqcFMYmSu9dkuLYy7Lr2hBEQS5SHQdknA9VppJz3cy2KkpMzTODunad6V6cNv+5kOLsePLow==", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.26.10", - "complex.js": "^2.2.5", - "decimal.js": "^10.4.3", - "escape-latex": "^1.2.0", - "fraction.js": "^5.2.1", - "javascript-natural-sort": "^0.7.1", - "seedrandom": "^3.0.5", - "tiny-emitter": "^2.1.0", - "typed-function": "^4.2.1" - }, - "bin": { - "mathjs": "bin/cli.js" - }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@preact/signals-core": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.14.4.tgz", + "integrity": "sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.4", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.4.tgz", + "integrity": "sha512-q7j5geK7xs3UJSdm9/iytUNclBnLmYx1EnSeCFXHPeutdqgIMeFeHtUZgS3EhlKxdBEAu8OwtJCwmLrEzpSs7Q==", + "devOptional": true, + "license": "MIT", "engines": { - "node": ">= 18" + "node": ">=14.0.0" } }, - "node_modules/@perses-dev/spec/node_modules/typed-function": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.2.tgz", - "integrity": "sha512-VwaXim9Gp1bngi/q3do8hgttYn2uC3MoT/gfuMWylnj1IeZBUAyPddHZlo1K05BDoj8DYPpMdiHqH1dDYdJf2A==", + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz", + "integrity": "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz", + "integrity": "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz", + "integrity": "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@remix-run/router": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", - "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==", - "devOptional": true, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz", + "integrity": "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz", + "integrity": "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz", + "integrity": "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz", + "integrity": "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz", + "integrity": "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz", + "integrity": "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz", + "integrity": "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz", + "integrity": "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz", + "integrity": "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz", + "integrity": "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz", + "integrity": "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz", + "integrity": "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", - "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.3.tgz", + "integrity": "sha512-w3Jnvi1ocaVm/c7yVPpfB98XeSRBMyzp6njL5MVVbGyXjpmUkN+s6Hp4t0PqhGCCaI1ZHMKXt/w0lA1RCaLVcw==", "cpu": [ "arm" ], @@ -3805,9 +4616,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", - "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.3.tgz", + "integrity": "sha512-uI/ESiaIbbRYAEhzy8PCUWDp1hB0bjAqM06mW9flOoNO4Q8DQpeoREhBR5Hegfl+wpXiguyJv6XSPzEN7OxyHQ==", "cpu": [ "arm64" ], @@ -3819,9 +4630,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", - "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.3.tgz", + "integrity": "sha512-oxhrd1jmXLwWZ83eQYDXxuqRdkqkzrjR3JobKeuUyfdNZo11FuQIvqEOZhyIT7OBHxXoGslDDjN0cQcM6T0TqQ==", "cpu": [ "arm64" ], @@ -3833,9 +4644,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", - "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.3.tgz", + "integrity": "sha512-7/YiIMghVE8DrxKvNdorAaJVdriOFgOIpdStnPx8ppx5zfTwC3jBCSEAIzB7JD5404m65THl6H93UTTVUvypmg==", "cpu": [ "x64" ], @@ -3847,9 +4658,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", - "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.3.tgz", + "integrity": "sha512-GXFZRRoMAytaI5z6N3Zhfw0WL18Q0M8r95D5hlC4GqE/lGk8pbSJNUBoOWDfbm6dTciqHj2nU87tI5f6XhQiOg==", "cpu": [ "arm64" ], @@ -3861,9 +4672,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", - "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.3.tgz", + "integrity": "sha512-77W+8X3ddYgPxUpB8nZFQs2Mq+wc4HVlcSRtApXLjYBcnPMkttrSnU8VwKQjeWYhMsITHFs5cWBQ8vz1Q+5RHQ==", "cpu": [ "x64" ], @@ -3875,13 +4686,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", - "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.3.tgz", + "integrity": "sha512-FVkwK+iUC+mq+GipVK46rRVticfAPtvPUNlqlGXUDxdVk/UGjQiiiUVPUrEXdSpU2ufU0XxLGyTqDtBidDOVmg==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3889,13 +4703,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", - "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.3.tgz", + "integrity": "sha512-+aGU1t3398yQOVj1Bz8o3e+KtswxAPvO+mtxtNdfXYMkXIHu7XhhkCD7/DEH9q8tF8uhDnMWvfpUKI8y1sZJsg==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3903,13 +4720,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", - "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.3.tgz", + "integrity": "sha512-cR0kjpRXR2KJ2oQK8E2KTPtphs+b9hZ8IhTZubNryt/RsqgdOZBQ2Zq0q5UedtiIi0rs3jVhJh55RE1ZHUVGUA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3917,13 +4737,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", - "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.3.tgz", + "integrity": "sha512-y1RYi4Q3/9ByVWSSt9kX2ustE0B7kFYbJ6zZdVZVyqopZs3yhCTwRfrjIX4vezUJInma/Gs6BOFDJg7yZmJ0IQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3931,13 +4754,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", - "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.3.tgz", + "integrity": "sha512-DNhEA5viIj3Z5bZLE4z4oV8N5ozWqDwyt7T6KG7VdLDJ0nW+rNOYlphBl4/3HQkK75qipPLsVOfStHHOwN9WSg==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3945,13 +4771,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", - "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.3.tgz", + "integrity": "sha512-17gQCqrIpXBX2Cmi9/TygnVOqGbzsba/iaqcYSL8FY7lNugg+7AiYNs5c5nKWD+NRQha36Sa0CqkJqH4XVHwnQ==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3959,13 +4788,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", - "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.3.tgz", + "integrity": "sha512-6LwVnZRIyINpdku/yOcI8Tm9YqLmhHK5emmlOOnW9tO0SYEm1FmKPcsSAGp0NBlqR2P04xaND4jvN6sTHqhq8A==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3973,13 +4805,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", - "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.3.tgz", + "integrity": "sha512-xMUqkTXlEUtI/p5AAukMwBRr1enU3efsTeF+bskeFfk8t1C9rcC8sLREcZXmTfAXEbvRdJVSonVJez3TMlbR3w==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3987,13 +4822,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", - "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.3.tgz", + "integrity": "sha512-S3E94co9F9WRRqEaUoQZ38K1gCz6KiM+nL7/3ijq7fDGF3OznjS5TasgYITlvl27GQKtu4lOAOsr5MFwkijvOA==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4001,13 +4839,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", - "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.3.tgz", + "integrity": "sha512-1QtRDwG42x5BJI3s9mxu5rEjDnfbSnk20HQ9/ylTAYnSwYwxMVb+Vgu34wzzTQ7ogqBybebgQNUDAvZVQ38DbA==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4015,13 +4856,16 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", - "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.3.tgz", + "integrity": "sha512-BQhejF6ZXOpxbngiNTP12GCGQeaDVL2QXGeBVViKIYzFHM5RKxTxwUMB1fr1BeNFphFMpnRqC5QSXFSa4z6UQw==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4029,13 +4873,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", - "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.3.tgz", + "integrity": "sha512-SXagRwnI2Wlwlitllu59UK/nGVbD1CKPcNqDplHwIC4BqJcpXFjD32d1R/RbuISa95HdQrZM3/7v4bKiowFaLA==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4043,13 +4890,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", - "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.3.tgz", + "integrity": "sha512-2IPozoEALRCziGqE8O9KMK60PMu5TS1huv4fwoeCexj+WjmcwFtX9CTOVbfXCUqcELAubEwRFPYlzb/WvwY2HQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4057,9 +4907,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", - "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.3.tgz", + "integrity": "sha512-AoxqosUHT9IX54hFn2TiN6A7d6ZKTtE6pd2bqWtqkkNJ6HJGaU6FRouGX8L1O7R/ZwsnCnpQrHzb4pDEx+UHRQ==", "cpu": [ "x64" ], @@ -4071,9 +4921,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", - "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.3.tgz", + "integrity": "sha512-d+CaftKgmkFBzCwezMqqy1d0QNNYugqLCMcYVQWBy5SS2YfeMP8Q8ripkgx9O8IyBXXLHrJ+aaCV4U96usv6Yg==", "cpu": [ "arm64" ], @@ -4085,9 +4935,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", - "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.3.tgz", + "integrity": "sha512-xXlDF6nR1eOuXbdDy5Hl5fmtY7teUDevF/k0O7IPoZe4Tpmdv+lgdE5JRsnhQtt37ql9P0VF2kAN9a0OCZdo+Q==", "cpu": [ "arm64" ], @@ -4099,9 +4949,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", - "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.3.tgz", + "integrity": "sha512-YtXAgLN+JP7Ay6qG3eWhc7IHMQPzLc8r3uvhAvlJIoCz/4Q32+Bl9Fmnywidh8v1GOIMmymjovfqY9ETAtysvA==", "cpu": [ "ia32" ], @@ -4113,9 +4963,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", - "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.3.tgz", + "integrity": "sha512-WuWtSJRNo549vzcfZyEgfqb6zeSgn1F+UE5kQ+BCjzz0W4MGCjntUHkZVc1VRuAM7+ULaSyhiPxD1spyewFvkQ==", "cpu": [ "x64" ], @@ -4127,9 +4977,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", - "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.3.tgz", + "integrity": "sha512-+lIKX7O0+IGe7WuhATaAMMeT7B76vfhXH/l9wLQL+nvyhbw2ohYCKIdWL56JfDu75CWt5oKRP4QFH/jkMtBquA==", "cpu": [ "x64" ], @@ -4196,6 +5046,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4224,6 +5077,9 @@ "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4252,6 +5108,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4266,6 +5125,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4284,45 +5146,11 @@ "optional": true, "peer": true, "dependencies": { - "@emnapi/core": "1.11.2", - "@emnapi/runtime": "1.11.2", + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", "@napi-rs/wasm-runtime": "1.1.6" } }, - "node_modules/@rspack/binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@rspack/binding-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@rspack/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@rspack/binding-win32-arm64-msvc": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.1.7.tgz", @@ -4408,9 +5236,9 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.34.49", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", - "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", "devOptional": true, "license": "MIT" }, @@ -4440,6 +5268,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@snapgridjs/core": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@snapgridjs/core/-/core-0.10.0.tgz", + "integrity": "sha512-OZmf6aa2qDMlCQIOsSZScjgCtq3Z9valZyKcTHjNj+G8oemFjxjoJVRkwSRyGk5hH5JlPf2B6n58iOACa23V6A==", + "license": "MIT", + "dependencies": { + "react-grid-layout": "~2.2.3" + } + }, + "node_modules/@snapgridjs/dnd": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@snapgridjs/dnd/-/dnd-0.10.0.tgz", + "integrity": "sha512-2JqZ2XnrKuQQZzjgGkzWG7jssEHrNM4QFeYrrujl6kVmrOBafDrlYfMj53Zc50d8cdrnVbPrdOaQtfeGXxMmHA==", + "license": "MIT", + "dependencies": { + "@snapgridjs/core": "0.10.0" + }, + "peerDependencies": { + "@dnd-kit/abstract": "^0.4.0", + "@dnd-kit/collision": "^0.4.0", + "@dnd-kit/dom": "^0.4.0" + } + }, + "node_modules/@snapgridjs/react": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@snapgridjs/react/-/react-0.10.0.tgz", + "integrity": "sha512-MdJbd7BsWwg9Aj0Hy71tgOZv+jlK9SC99QtaqRF3+doRzf3H1KtwRuP1O3tUBYTFiDFU+keD0OtgpIXszqpMFA==", + "license": "MIT", + "dependencies": { + "@snapgridjs/core": "0.10.0", + "@snapgridjs/dnd": "0.10.0" + }, + "peerDependencies": { + "@dnd-kit/dom": "^0.4.0", + "@dnd-kit/react": "^0.4.0", + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -4500,15 +5367,15 @@ } }, "node_modules/@swc/core": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.33.tgz", - "integrity": "sha512-jOlwnFV2xhuuZeAUILGFULeR6vDPfijEJ57evfocwznQldLU3w2cZ9bSDryY9ip+AsM3r1NJKzf47V2NXebkeQ==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.16.2.tgz", + "integrity": "sha512-95I4kiSMeveI/Mhi+tE4fiWcWLUMfzfKrk0jtr8LRMqHgOgq+xHS+zExkDqoO4b5OeeuXHMWVdD5MeP3X6sULw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.26" + "@swc/types": "^0.1.28" }, "engines": { "node": ">=10" @@ -4518,18 +5385,18 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.15.33", - "@swc/core-darwin-x64": "1.15.33", - "@swc/core-linux-arm-gnueabihf": "1.15.33", - "@swc/core-linux-arm64-gnu": "1.15.33", - "@swc/core-linux-arm64-musl": "1.15.33", - "@swc/core-linux-ppc64-gnu": "1.15.33", - "@swc/core-linux-s390x-gnu": "1.15.33", - "@swc/core-linux-x64-gnu": "1.15.33", - "@swc/core-linux-x64-musl": "1.15.33", - "@swc/core-win32-arm64-msvc": "1.15.33", - "@swc/core-win32-ia32-msvc": "1.15.33", - "@swc/core-win32-x64-msvc": "1.15.33" + "@swc/core-darwin-arm64": "1.16.2", + "@swc/core-darwin-x64": "1.16.2", + "@swc/core-linux-arm-gnueabihf": "1.16.2", + "@swc/core-linux-arm64-gnu": "1.16.2", + "@swc/core-linux-arm64-musl": "1.16.2", + "@swc/core-linux-ppc64-gnu": "1.16.2", + "@swc/core-linux-s390x-gnu": "1.16.2", + "@swc/core-linux-x64-gnu": "1.16.2", + "@swc/core-linux-x64-musl": "1.16.2", + "@swc/core-win32-arm64-msvc": "1.16.2", + "@swc/core-win32-ia32-msvc": "1.16.2", + "@swc/core-win32-x64-msvc": "1.16.2" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" @@ -4541,9 +5408,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.33.tgz", - "integrity": "sha512-N+L0uXhuO7FIfzqwgxmzv0zIpV0qEp8wPX3QQs2p4atjMoywup2JTeDlXPw+z9pWJGCae3JjM+tZ6myclI+2gA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.16.2.tgz", + "integrity": "sha512-i/j0HNbnn79qnTVPicvay92Nark8fW8NQqn1e2mGERjUXNpBV0+SwQxlRpk2zBhn6laJ8PDI6Kn1nHZhnz3LCA==", "cpu": [ "arm64" ], @@ -4558,9 +5425,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.33.tgz", - "integrity": "sha512-/Il4QHSOhV4FekbsDtkrNmKbsX26oSysvgrRswa/RYOHXAkwXDbB4jaeKq6PsJLSPkzJ2KzQ061gtBnk0vNHfA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.16.2.tgz", + "integrity": "sha512-HrwqHyEyHVXO3qTk8EkNK7/b6sOZSEoNh+pot6RdE5x0LbNqfo8LtJUvi3UTXr+5ja/o5HbJdW80eCXo+NjbiA==", "cpu": [ "x64" ], @@ -4575,9 +5442,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.33.tgz", - "integrity": "sha512-C64hBnBxq4viOPQ8hlx+2lJ23bzZBGnjw7ryALmS+0Q3zHmwO8lw1/DArLENw4Q18/0w5wdEO1k3m1wWNtKGqQ==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.16.2.tgz", + "integrity": "sha512-MdXi83Z/gGp1LIrg+h7HKxiul/z/Bty/ZJSvYAFqDl9zteC1XLSAZdScquKtXPp50rdyXqritTDCqQBhwVfZKA==", "cpu": [ "arm" ], @@ -4592,13 +5459,16 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.33.tgz", - "integrity": "sha512-TRJfnJbX3jqpxRDRoieMzRiCBS5jOmXNb3iQXmcgjFEHKLnAgK1RZRU8Cq1MsPqO4jAJp/ld1G4O3fXuxv85uw==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.16.2.tgz", + "integrity": "sha512-/jcTmK6Ktz3owM3YtiKvjofV6p3VpHnYzTIrOGwDIOsDigRAAVuZ8east33wYO/7UTdKYFlyHNnJNT0WJqOA3Q==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4609,13 +5479,16 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.33.tgz", - "integrity": "sha512-il7tYM+CpUNzieQbwAjFT1P8zqAhmGWNAGhQZBnxurXZ0aNn+5nqYFTEUKNZl7QibtT0uQXzTZrNGHCIj6Y1Og==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.16.2.tgz", + "integrity": "sha512-4gFarKaFnlJTSlJYKmMhV4u+3YE4uYfiydpBoYjmgQhCf9lAieOq+WilZaK9vVSHeqLuQpTEiGULZqAdsRX5Dw==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4626,13 +5499,16 @@ } }, "node_modules/@swc/core-linux-ppc64-gnu": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.33.tgz", - "integrity": "sha512-ZtNBwN0Z7CFj9Il0FcPaKdjgP7URyKu/3RfH46vq+0paOBqLj4NYldD6Qo//Duif/7IOtAraUfDOmp0PLAufog==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.16.2.tgz", + "integrity": "sha512-syqSLGd6KlZ1PciNzs6bIUlhOuFztZufebOHaERjc4N4SqNZxyqYd4I+jj/EfOYnpe0kNjccn9HJLN1p5dz3+w==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4643,13 +5519,16 @@ } }, "node_modules/@swc/core-linux-s390x-gnu": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.33.tgz", - "integrity": "sha512-De1IyajoOmhOYYjw/lx66bKlyDpHZTueqwpDrWgf5O7T6d1ODeJJO9/OqMBmrBQc5C+dNnlmIufHsp4QVCWufA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.16.2.tgz", + "integrity": "sha512-ZBBLK+ewGyXLzWeMS7wbKtWBdnif6etn7xvPY/iOfbdsjX/+bgkp1pQt2lWF2wlu2hXYZuhJ/tHZE/QR8/apzg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4660,13 +5539,16 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.33.tgz", - "integrity": "sha512-mGTH0YxmUN+x6vRN/I6NOk5X0ogNktkwPnJ94IMvR7QjhRDwL0O8RXEDhyUM0YtwWrryBOqaJQBX4zruxEPRGw==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.16.2.tgz", + "integrity": "sha512-LyHJgxCA4Tje0ysBMbEb0tt/ie8kgUKoFE3JAKFhpevmTmhYEoC0H9s47WuDsqiFckF1ITUguZIXJG6K5e0dvg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4677,13 +5559,16 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.33.tgz", - "integrity": "sha512-hj628ZkSEJf6zMf5VMbYrG2O6QqyTIp2qwY6VlCjvIa9lAEZ5c2lfPblCLVGYubTeLJDxadLB/CxqQYOQABeEQ==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.16.2.tgz", + "integrity": "sha512-PghXJlVM1cgtLfNUR1vxFo1z+PDRAe8cWAJlZZ7spmeiN7BospGXg/MHUg7oNSgwSX7Zo//YKv9P5yD9apsFJQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4694,9 +5579,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.33.tgz", - "integrity": "sha512-GV2oohtN2/5+KSccl86VULu3aT+LrISC8uzgSq0FRnikpD+Zwc+sBlXmoKQ+Db6jI57ITUOIB8jRkdGMABC29g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.16.2.tgz", + "integrity": "sha512-StTOSefYBxemvNYYUI3UmO1a8y+hSPjjfHogC2TEHL+Z1PlEBim/XtLas5rS04jAzT9RrNmbtX911SZ42H9jSQ==", "cpu": [ "arm64" ], @@ -4711,9 +5596,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.33.tgz", - "integrity": "sha512-gtyvzSNR8DHKfFEA2uqb8Ld1myqi6uEg2jyeUq3ikn5ytYs7H8RpZYC8mdy4NXr8hfcdJfCLXPlYaqqfBXpoEQ==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.16.2.tgz", + "integrity": "sha512-fycER209DYIzsibpTMC+chND05OfOjgztWL9U8OE6/uUlsOUZH3eh98isBLEnOymYUhlJLEt5++W1+KL/FOh5Q==", "cpu": [ "ia32" ], @@ -4728,9 +5613,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.15.33", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.33.tgz", - "integrity": "sha512-d6fRqQSkJI+kmMEBWaDQ7TMl8+YjLYbwRUPZQ9DY0ORBJeTzOrG0twvfvlZ2xgw6jA0ScQKgfBm4vHLSLl5Hqg==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.16.2.tgz", + "integrity": "sha512-cSd1z6ivSrJPVr+moVwOHWjeKy6TpO4/Shwcv5KCrKYXCccxwh4pRy1C3fDioNx2PF1jPZWHKZjtXt+Be9VbaQ==", "cpu": [ "x64" ], @@ -4752,9 +5637,9 @@ "license": "Apache-2.0" }, "node_modules/@swc/types": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", - "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.28.tgz", + "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4762,12 +5647,12 @@ } }, "node_modules/@tanstack/hotkeys": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@tanstack/hotkeys/-/hotkeys-0.7.1.tgz", - "integrity": "sha512-YHVO1z6wnvUCu7bg870Kv5k2D+FIuIOSIcbN0dAmTTsJ3mLMDLwcTVx0qVaq+SZp1B514JJTqGVstvUp85yIpQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@tanstack/hotkeys/-/hotkeys-0.8.0.tgz", + "integrity": "sha512-vqH7X9nb0MTJ/O08++dB5bP9jgj4+BIPOUu/U+6myG86lDsirZSVSobpq5UQpE7nBuk62i8eIYeOhd+OMl/UrA==", "license": "MIT", "dependencies": { - "@tanstack/store": "^0.9.3" + "@tanstack/store": "^0.11.0" }, "engines": { "node": ">=18" @@ -4824,6 +5709,32 @@ "react-dom": ">=16.8" } }, + "node_modules/@tanstack/react-hotkeys/node_modules/@tanstack/hotkeys": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@tanstack/hotkeys/-/hotkeys-0.7.1.tgz", + "integrity": "sha512-YHVO1z6wnvUCu7bg870Kv5k2D+FIuIOSIcbN0dAmTTsJ3mLMDLwcTVx0qVaq+SZp1B514JJTqGVstvUp85yIpQ==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "^0.9.3" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-hotkeys/node_modules/@tanstack/store": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", + "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/react-query": { "version": "4.44.0", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.44.0.tgz", @@ -4869,6 +5780,16 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@tanstack/react-store/node_modules/@tanstack/store": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", + "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/react-table": { "version": "8.21.3", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", @@ -4890,9 +5811,9 @@ } }, "node_modules/@tanstack/store": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", - "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.11.1.tgz", + "integrity": "sha512-mzTOBhypOuDJAy/D8n2MfUZ1HFkXnmSETviRyhqEC8LUE7/IZQExOTxMANj3KjTofYTkFNpBY67qaVrT41YccA==", "license": "MIT", "funding": { "type": "github", @@ -4913,9 +5834,9 @@ } }, "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.2.tgz", + "integrity": "sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4955,24 +5876,10 @@ "yarn": ">=1" } }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.3.tgz", + "integrity": "sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==", "dev": true, "license": "MIT", "dependencies": { @@ -5040,9 +5947,9 @@ "license": "MIT" }, "node_modules/@turbo/darwin-64": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/@turbo/darwin-64/-/darwin-64-2.9.14.tgz", - "integrity": "sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@turbo/darwin-64/-/darwin-64-2.10.13.tgz", + "integrity": "sha512-m5DBcpkxmcKpEJHHFUfqf9GLUjSmw3cDnBJM9nghPW3kjCNb5OyNKmzG7/yT5x5AwzOO+HMwKN+UI4iVKL87YA==", "cpu": [ "x64" ], @@ -5054,9 +5961,9 @@ ] }, "node_modules/@turbo/darwin-arm64": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/@turbo/darwin-arm64/-/darwin-arm64-2.9.14.tgz", - "integrity": "sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@turbo/darwin-arm64/-/darwin-arm64-2.10.13.tgz", + "integrity": "sha512-vfKPvSuoY8BJGj8M8yN+a7aq1g+CejbEacDSDlJLDkSbPN3J/U1DbYAmPG8Ype5XvImI0SgfvUhIorNnFj67zw==", "cpu": [ "arm64" ], @@ -5068,9 +5975,9 @@ ] }, "node_modules/@turbo/linux-64": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/@turbo/linux-64/-/linux-64-2.9.14.tgz", - "integrity": "sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@turbo/linux-64/-/linux-64-2.10.13.tgz", + "integrity": "sha512-Zp0N5M6j9iEjJtFLTA2L+52TLuYy0VbXT3zLZzfMeqqdKSUJ7pDo2pA1NhqjoQcF2dIsktZ8xZRW3pGI6T81fw==", "cpu": [ "x64" ], @@ -5078,13 +5985,14 @@ "license": "MIT", "optional": true, "os": [ + "android", "linux" ] }, "node_modules/@turbo/linux-arm64": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/@turbo/linux-arm64/-/linux-arm64-2.9.14.tgz", - "integrity": "sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@turbo/linux-arm64/-/linux-arm64-2.10.13.tgz", + "integrity": "sha512-M8XcfWdS2D4EP3wzd5ehUyCANucMIOsRE6gZuV0Mr2NIn+FpsUjXFCh7r9HY7GnNcjXH4tUnT76OsCDg2c0Fng==", "cpu": [ "arm64" ], @@ -5092,13 +6000,14 @@ "license": "MIT", "optional": true, "os": [ + "android", "linux" ] }, "node_modules/@turbo/windows-64": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/@turbo/windows-64/-/windows-64-2.9.14.tgz", - "integrity": "sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@turbo/windows-64/-/windows-64-2.10.13.tgz", + "integrity": "sha512-QFd3KBMpBBCc31TbxMnxgdBivie8lxJXV8EqmanH8fg8l2e1BdCLWpZJbxk48VNvcF4LHUnwO0FJOq+veKN1cw==", "cpu": [ "x64" ], @@ -5110,9 +6019,9 @@ ] }, "node_modules/@turbo/windows-arm64": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/@turbo/windows-arm64/-/windows-arm64-2.9.14.tgz", - "integrity": "sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g==", + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/@turbo/windows-arm64/-/windows-arm64-2.10.13.tgz", + "integrity": "sha512-rM+cFO1P8iAHXdasOdMyK9nDk0UGII7VEFLIA8+jwv/+rh48pnVBbF2OSjJDBOw57pxNLIOEDA0JyKcarTBcIw==", "cpu": [ "arm64" ], @@ -5124,9 +6033,9 @@ ] }, "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", "license": "MIT", "optional": true, "peer": true, @@ -5134,6 +6043,14 @@ "tslib": "^2.4.0" } }, + "node_modules/@tybys/wasm-util/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true, + "peer": true + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -5141,6 +6058,51 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -5152,6 +6114,16 @@ "assertion-error": "^2.0.1" } }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -5173,6 +6145,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -5232,16 +6224,16 @@ } }, "node_modules/@types/jest/node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -5254,16 +6246,40 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", - "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", + "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", + "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "24.13.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", - "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "version": "24.13.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.5.tgz", + "integrity": "sha512-TXyindR+lBr22aJIdMQzCFHPHR6cR4js838mRDCSz5hOKWZvZwsXSSiXDmjRj4iJmgl+sR9O+1mkoVBSMadNug==", "dev": true, "license": "MIT", "dependencies": { @@ -5276,6 +6292,13 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "license": "MIT" }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -5290,9 +6313,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.29", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.29.tgz", - "integrity": "sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg==", + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -5309,16 +6332,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/react-grid-layout": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.6.tgz", - "integrity": "sha512-Cw7+sb3yyjtmxwwJiXtEXcu5h4cgs+sCGkHwHXsFmPyV30bf14LeD/fa2LwQovuD2HWxCcjIdNhDlcYGj95qGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-transition-group": { "version": "4.4.12", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", @@ -5329,12 +6342,22 @@ } }, "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", "dev": true, "license": "MIT" }, + "node_modules/@types/set-cookie-parser": { + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.10.tgz", + "integrity": "sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -5342,6 +6365,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/statuses": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", + "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.9", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", @@ -5352,6 +6382,13 @@ "@types/jest": "*" } }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", @@ -5370,9 +6407,9 @@ "license": "MIT" }, "node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "version": "8.70.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.0.tgz", + "integrity": "sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==", "dev": true, "license": "MIT", "engines": { @@ -5704,9 +6741,9 @@ } }, "node_modules/@uiw/codemirror-extensions-basic-setup": { - "version": "4.25.10", - "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.10.tgz", - "integrity": "sha512-P3vytLlpE62KYSWrMUnwDCv2lvaQDuDZzyj03mHntuHo5bSl34fRZpjTY3kQTPGuXHxkGSYpoPFFj+hMTqaaMQ==", + "version": "4.25.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.25.11.tgz", + "integrity": "sha512-otyFa+n9IOYtEjaKOxPedHkj15fTPUF21wdR9pv0GpZPfuGl27cvmcv6+tognbRu9VvEcsHKE+ESoszeo3KfTw==", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -5731,16 +6768,16 @@ } }, "node_modules/@uiw/react-codemirror": { - "version": "4.25.10", - "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.25.10.tgz", - "integrity": "sha512-DzgSMwM5qzB7v1FIb4gEeriYt67iiay756/HIOM9mAbeOVK0MO7rqefHf0O5c0269pJKMW7AH9FjclExD23V9w==", + "version": "4.25.11", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.25.11.tgz", + "integrity": "sha512-DYVFAKLX+F/4JS9N/7xexh+TICrlncwkX9HKKInrP1bwO0tSfc3k0GB6oawTYhelVKh20cX3TuRx+NJSkVXuMw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.6", "@codemirror/commands": "^6.1.0", "@codemirror/state": "^6.1.1", "@codemirror/theme-one-dark": "^6.0.0", - "@uiw/codemirror-extensions-basic-setup": "4.25.10", + "@uiw/codemirror-extensions-basic-setup": "4.25.11", "codemirror": "^6.0.0" }, "funding": { @@ -5756,6 +6793,58 @@ "react-dom": ">=17.0.0" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz", + "integrity": "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.27", + "@swc/core": "^1.12.11" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@vitest/expect": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz", @@ -5774,33 +6863,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/mocker": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", - "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.11", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, "node_modules/@vitest/pretty-format": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", @@ -5877,22 +6939,22 @@ "license": "MIT" }, "node_modules/@xhmikosr/archive-type": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@xhmikosr/archive-type/-/archive-type-8.0.1.tgz", - "integrity": "sha512-toXuiWChyfOpEiCPsIw6HGHaNji5LVkvB6EREL548vGWr+hGaehwxG4LzN20vm9aGFXwnA/Jty8yW2/SmV+1zQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/archive-type/-/archive-type-8.1.0.tgz", + "integrity": "sha512-EXOjEbnZFE5c/nFMf4FOrEURVanzHpnkPYmnmr78u02/8hAhE0FMq8p9TK1IM0/bFr5VcyBUY0gfLm8f7dKy+Q==", "dev": true, "license": "MIT", "dependencies": { - "file-type": "^21.3.0" + "file-type": "^21.3.4" }, "engines": { "node": ">=20" } }, "node_modules/@xhmikosr/bin-check": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@xhmikosr/bin-check/-/bin-check-8.2.1.tgz", - "integrity": "sha512-DNruLq+kalxcE7JeDxtqrN9kyWjLW8VqsQPLRTwD1t9ck/1rF4qBL0mX5Fe2/xLOMjo5wPb67BNX2kSAhzfLjA==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@xhmikosr/bin-check/-/bin-check-8.2.2.tgz", + "integrity": "sha512-Y/b0YJoCDda6DCFj8ikks06GrEWDsz/3vdgGLeectV9p+YJc76YugRjtqFdd2KTf2rnEPjalL2hcXP+x2KcSLQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5904,15 +6966,15 @@ } }, "node_modules/@xhmikosr/bin-wrapper": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@xhmikosr/bin-wrapper/-/bin-wrapper-14.2.3.tgz", - "integrity": "sha512-F8Sr2O2aqwYfoXTafemRNAYDG4xwBTaHJpAo9YVnnnRXHLP9gkb+HYDsFoCAsCneS3/J7BOfeYnxxlUCicLqjg==", + "version": "14.5.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/bin-wrapper/-/bin-wrapper-14.5.1.tgz", + "integrity": "sha512-UZUuTYWxeAbTIiRKKEAmV3csoE36B3CGFZrYYn87+bSEBTyJ32p5gx5Gmj5HOgyOtioFUypbOZ1V5M/l/VoePw==", "dev": true, "license": "MIT", "dependencies": { - "@xhmikosr/bin-check": "^8.2.1", - "@xhmikosr/downloader": "^16.1.2", - "@xhmikosr/os-filter-obj": "^4.0.0", + "@xhmikosr/bin-check": "^8.2.2", + "@xhmikosr/downloader": "^16.3.1", + "@xhmikosr/os-filter-obj": "^4.1.0", "binary-version-check": "^6.1.0" }, "engines": { @@ -5920,16 +6982,16 @@ } }, "node_modules/@xhmikosr/decompress": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress/-/decompress-11.1.3.tgz", - "integrity": "sha512-NiyhJq6z7ERsYghcnXZUI6ooDXgZtoB+G9eUsYhfSM4VLp2rKx9UxhKI1NEf1PqosrNPxG3bnSsr2UBVbNurlg==", + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress/-/decompress-11.1.4.tgz", + "integrity": "sha512-ZbYL7SAfY37/TMpopqBR3mQiuQ76kI/RNpN4q82YHSw/UxktZNy8P4wgiKPSrTImMAWRaUG8UK1pgEa56YdLaw==", "dev": true, "license": "MIT", "dependencies": { - "@xhmikosr/decompress-tar": "^9.0.1", - "@xhmikosr/decompress-tarbz2": "^9.0.1", + "@xhmikosr/decompress-tar": "^9.0.2", + "@xhmikosr/decompress-tarbz2": "^9.0.2", "@xhmikosr/decompress-targz": "^9.0.1", - "@xhmikosr/decompress-unzip": "^8.1.1", + "@xhmikosr/decompress-unzip": "^8.2.1", "graceful-fs": "^4.2.11", "strip-dirs": "^3.0.0" }, @@ -5938,13 +7000,13 @@ } }, "node_modules/@xhmikosr/decompress-tar": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tar/-/decompress-tar-9.0.1.tgz", - "integrity": "sha512-4AkVR1SoqTxYY22IRRYKDeLirPIDGqMqYsqgjKYuwhgRcBb+yDP4t5Xph33UCzL/nahK/aADmlMEjTNstbX7kw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tar/-/decompress-tar-9.0.2.tgz", + "integrity": "sha512-8nPZ6lZ3ExhsSxi/X/PMB3K+Vtsuxk43HowxYpxw4AsCHTYqFBXwC8B3Y+M/meaUOGOVm+2tFNUAfWGRjBt+Ww==", "dev": true, "license": "MIT", "dependencies": { - "file-type": "^21.3.0", + "file-type": "^21.3.4", "is-stream": "^4.0.1", "tar-stream": "3.1.7" }, @@ -5953,14 +7015,14 @@ } }, "node_modules/@xhmikosr/decompress-tarbz2": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tarbz2/-/decompress-tarbz2-9.0.1.tgz", - "integrity": "sha512-aFONnsbqEOuXudvK7V7wB8dcEAKR389oUYQfZhrQZA8OtogJpDjrUAvEH3Qlc9yFqTU6r5/svTEcRwtXhoIJbQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-tarbz2/-/decompress-tarbz2-9.0.2.tgz", + "integrity": "sha512-m0DvZhE7remCxtS8xY2iHSjivT4v+iyYDdfNoeuu8Nm+7g8xEXdLKSyDEicu4u1ImJLLGEfjMuTLera/F6UGWw==", "dev": true, "license": "MIT", "dependencies": { - "@xhmikosr/decompress-tar": "^9.0.0", - "file-type": "^21.3.0", + "@xhmikosr/decompress-tar": "^9.0.1", + "file-type": "^21.3.4", "is-stream": "^4.0.1", "seek-bzip": "^2.0.0", "unbzip2-stream": "^1.4.3" @@ -5985,34 +7047,33 @@ } }, "node_modules/@xhmikosr/decompress-unzip": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-unzip/-/decompress-unzip-8.1.1.tgz", - "integrity": "sha512-/B+Z0qJflGn5UEtmMZ2qeKeXwexOycxaibYhMOyLcRPJriXs4IkoSngVUVZXLYViu9TdHyFWynC6NB4EWBg8cg==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/decompress-unzip/-/decompress-unzip-8.2.1.tgz", + "integrity": "sha512-2MS94QnmXQwjkKN8WyFiu1sU7J3rcWJcMze4kRYsX7tN+CXpUGECgkh4YSOhujpkWPuVlFudIziJHO/TxOqkQQ==", "dev": true, "license": "MIT", "dependencies": { "file-type": "^21.3.4", "get-stream": "^9.0.1", - "yauzl": "^3.3.0" + "yauzl": "^3.4.0" }, "engines": { "node": ">=20" } }, "node_modules/@xhmikosr/downloader": { - "version": "16.1.2", - "resolved": "https://registry.npmjs.org/@xhmikosr/downloader/-/downloader-16.1.2.tgz", - "integrity": "sha512-31KQzQ6p4Rwnbo/gwTe4/Z+hVRcC8YoH/8f5xl+so1Oqqah5u1R3CGte8od+wOyNVfZ77DFijwy1umHk2NT6ZQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@xhmikosr/downloader/-/downloader-16.3.1.tgz", + "integrity": "sha512-M67dvznaFbsvoqhGT4FsHWysaXXQ8386OViGZm0WOyQS3apW9p16WgvHp9nWj2vfKQAR2ZdqIBPNCHSM5rKSCg==", "dev": true, "license": "MIT", "dependencies": { - "@xhmikosr/archive-type": "^8.0.1", - "@xhmikosr/decompress": "^11.1.1", - "content-disposition": "^1.1.0", + "@xhmikosr/archive-type": "^8.1.0", + "@xhmikosr/decompress": "^11.1.4", + "content-disposition": "^2.0.1", "ext-name": "^5.0.0", "file-type": "^21.3.4", - "filenamify": "^7.0.1", - "get-stream": "^9.0.1", + "filenamify": "^7.0.2", "got": "^14.6.6" }, "engines": { @@ -6020,18 +7081,55 @@ } }, "node_modules/@xhmikosr/os-filter-obj": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@xhmikosr/os-filter-obj/-/os-filter-obj-4.0.0.tgz", - "integrity": "sha512-CBJYipR5lrtQQZl9ylarWyh1qhcs/tMy9ydSHte/Hefn3ev8NMvS3ss+eqiXEoBr2wBVgKj2qjcViXO9P/8K4A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@xhmikosr/os-filter-obj/-/os-filter-obj-4.1.0.tgz", + "integrity": "sha512-y5ArHvQ7BVule/+L9yE2nYMhceiJhgsqo58lOfnisQ7bg+Kjfmkgr7JBuVFiTkl+ErdShpp829QstZQyLugl8g==", "dev": true, "license": "MIT", "dependencies": { - "arch": "^3.0.0" + "system-architecture": "^1.0.0" }, "engines": { "node": ">=20" } }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/adm-zip": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", @@ -6051,6 +7149,22 @@ "node": ">= 14" } }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -6068,28 +7182,63 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6116,26 +7265,32 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/arch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-3.0.0.tgz", - "integrity": "sha512-AmIAC+Wtm2AU8lGfTtHsw0Y9Qtftx2YXEEtiBP10xFUtMOA+sHHx6OAddyL52mUKh1vsXQ6/w1mVDptZCyUt4Q==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/aria-query": { "version": "5.3.0", @@ -6157,6 +7312,26 @@ "node": ">=12" } }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "dev": true, + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/axe-core": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.13.0.tgz", + "integrity": "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -6172,6 +7347,17 @@ "npm": ">=6" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6180,9 +7366,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", - "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz", + "integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -6215,6 +7401,30 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.24", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.24.tgz", + "integrity": "sha512-hYrgxie335U08WqICoGqKRzV1HFXv6zdxwJE4ekCb80CM9a0SVVsN4QPwT67RraRo+9h8IATk6uxHJw7QSkdOg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bcp-47-match": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/bignumber.js": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", @@ -6224,6 +7434,19 @@ "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/binary-version": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/binary-version/-/binary-version-7.1.0.tgz", @@ -6367,16 +7590,106 @@ "integrity": "sha512-PJvH288AWQhKs2v9zyfYdPzlPqf5bXbGMmhmUIY9x4dAUGIWgomO771oBQNwJnMQSnUIXhKu6sgzpBRXTlvb8Q==", "license": "MIT" }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/brace-expansion": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.3.tgz", - "integrity": "sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -6402,14 +7715,20 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/byte-counter": { @@ -6425,6 +7744,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -6454,16 +7787,6 @@ "node": ">=18" } }, - "node_modules/cacheable-request/node_modules/keyv": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", - "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@keyv/serialize": "^1.1.1" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -6502,20 +7825,65 @@ "node": ">=6" } }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "license": "MIT", "dependencies": { @@ -6523,10 +7891,67 @@ "supports-color": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://paulmillr.com/funding/" } }, "node_modules/ci-info": { @@ -6545,6 +7970,107 @@ "node": ">=8" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -6554,6 +8080,17 @@ "node": ">=6" } }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, "node_modules/codemirror": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz", @@ -6569,6 +8106,17 @@ "@codemirror/view": "^6.0.0" } }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6589,6 +8137,17 @@ "dev": true, "license": "MIT" }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -6612,10 +8171,17 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, "node_modules/concurrently": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.4.tgz", - "integrity": "sha512-trZql+7l/0+WRAsAnEdctr4+iiOS6ZrViI6H8QWcCF9MFS/LT0dKpe8vluB1to6it+OxSI4VospFTIFMW8DJRw==", + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.5.tgz", + "integrity": "sha512-JaP/CoftUrCcAFW/g//RbgEGwlelnEae6cfBLgH6ZdO6s8jPkn6p9SB9u6pdVxYXoiSnFqseOlHfrEfF82TVOg==", "dev": true, "license": "MIT", "dependencies": { @@ -6637,191 +8203,246 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/concurrently/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/concurrently/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/concurrently/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/concurrently/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/concurrently/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "node_modules/content-disposition": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", + "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", "dev": true, "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/concurrently/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, + "license": "MIT", "engines": { - "node": ">=20" + "node": ">= 0.6" } }, - "node_modules/concurrently/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", "dev": true, "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/concurrently/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "node_modules/cookies": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.9.2.tgz", + "integrity": "sha512-8BIbcC6tPZMv2/PD4PrB3CtKks7LmAWhA7FRZK/6/b/WJ2RUz00KCga7gq50S4/RhZ22kxefRFGgsuts0v3eoA==", "dev": true, "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, "engines": { - "node": ">=18" + "node": ">= 0.8" + } + }, + "node_modules/copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" } }, - "node_modules/concurrently/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "node_modules/copyfiles/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/copyfiles/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/copyfiles/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/copyfiles/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "*" } }, - "node_modules/concurrently/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "node_modules/copyfiles/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" + "node": ">=8" } }, - "node_modules/concurrently/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "node_modules/copyfiles/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" + "node": ">=8" } }, - "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "node_modules/copyfiles/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/convert-hrtime": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", - "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "node_modules/copyfiles/node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "node_modules/copyfiles/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, "license": "MIT" }, "node_modules/cosmiconfig": { @@ -6840,19 +8461,10 @@ "node": ">=10" } }, - "node_modules/cosmiconfig/node_modules/yaml": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, "node_modules/crelt": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", - "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", + "integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==", "license": "MIT" }, "node_modules/cross-env": { @@ -6889,6 +8501,23 @@ "node": ">= 8" } }, + "node_modules/css-selector-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz", + "integrity": "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, "node_modules/css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", @@ -6931,9 +8560,9 @@ } }, "node_modules/date-fns": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.2.1.tgz", - "integrity": "sha512-37RhSdxaG1suen6VDCza6rNrQfooyQh57HFVPwQGEq2QWliVLzPQZ8Oa017weOu+HZCnzI7N3Pf/wyoBKfEqrA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", "license": "MIT", "funding": { "type": "github", @@ -6972,6 +8601,30 @@ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "license": "MIT" }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decode-uri-component": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.5.0.tgz", + "integrity": "sha512-1BiQVoK8C9gUbQU6NzAtO/tkz2qOFpEObMWpcFvhx4fYnj4Oc5yzaJN/LD36ihkVUdXyh5ZekzX+yM+ty/SrPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, "node_modules/decompress-response": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz", @@ -6988,6 +8641,73 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -6998,6 +8718,17 @@ "node": ">=6" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -7008,6 +8739,34 @@ "node": ">=8" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/direction": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", + "dev": true, + "license": "MIT", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", @@ -7056,11 +8815,19 @@ "zrender": "5.5.0" } }, - "node_modules/echarts/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.430", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.430.tgz", + "integrity": "sha512-e1QEj72Y4zd8RlNZVmoTg+iCOSVwpk05IOiiQwdrkwCSVlZfPthevErhE+nckGd2YbsXfp1SkisznhGVIXP2NQ==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -7069,6 +8836,16 @@ "dev": true, "license": "MIT" }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -7110,16 +8887,16 @@ } }, "node_modules/es-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", - "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -7128,10 +8905,44 @@ "node": ">= 0.4" } }, - "node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7139,35 +8950,32 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18" + "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -7180,6 +8988,13 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, "node_modules/escape-latex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", @@ -7253,6 +9068,104 @@ "node": ">=4.0" } }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.1.tgz", + "integrity": "sha512-B0np3dcdxqILX5e9nEi5/Fr4K7gL4oYFVPV1zRa2e9wRCbQoZZNWOZFYyoInvXUPJXBXjss+QXlWLJChDEHDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -7301,18 +9214,18 @@ } }, "node_modules/expect": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.4.1.tgz", - "integrity": "sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.1.tgz", + "integrity": "sha512-m8YrYgvKe9+9gEnWEuKz+qCGfHqkrff7PPfyDnOFkjsfYRKqiYyOxDFMFieCGAuhtk/VNm63tvNgKZVzVy+Hvg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.4.1", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.4.1", - "jest-message-util": "30.4.1", - "jest-mock": "30.4.1", - "jest-util": "30.4.1" + "@jest/expect-utils": "30.5.1", + "@jest/get-type": "30.5.0", + "jest-matcher-utils": "30.5.1", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.1", + "jest-util": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -7355,6 +9268,13 @@ "node": ">=4" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7374,6 +9294,40 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, "node_modules/fast-uri": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", @@ -7390,6 +9344,26 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -7444,9 +9418,9 @@ } }, "node_modules/filename-reserved-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.0.tgz", - "integrity": "sha512-9ZT504KxEQDamsOogZImAWGEN24R1uFAxU3ZS4AZqn2ooidmN68Olh7n4/RcA4lLatZztjA0ZSuxeLHVoCc8JA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.1.tgz", + "integrity": "sha512-qUet2faQFKvtvVUsEf7wCrTURwxBOIZpspsLHGifw9QCWk55ITE2FrG8XhfQqG/uxMA1xEGFVQbL+Yfm0O94+Q==", "dev": true, "license": "MIT", "engines": { @@ -7457,13 +9431,13 @@ } }, "node_modules/filenamify": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.1.tgz", - "integrity": "sha512-9b4rfnaX2MkJCgp27wypV6DAMvj4WMOSgJ+TdcpJIO84Dql+Cv6iJjdG4XDTLubOWkfNiBv3joO59sau/TXw+Q==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.3.tgz", + "integrity": "sha512-Pf0dwHrWs1GcIK15ps304fmxp2AOcfNR6vOIMvCPEy6ZztKYxzRQHlOuPVWo2HRjbCLHaRTY+kD8n3RbQ0A/fw==", "dev": true, "license": "MIT", "dependencies": { - "filename-reserved-regex": "^4.0.0" + "filename-reserved-regex": "^4.0.1" }, "engines": { "node": ">=20" @@ -7472,6 +9446,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz", + "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -7535,6 +9535,23 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -7572,6 +9589,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -7619,6 +9656,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-port": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.2.0.tgz", + "integrity": "sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -7657,55 +9707,152 @@ "dev": true, "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "node_modules/goober": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz", - "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==", + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, "license": "MIT", - "peerDependencies": { - "csstype": "^3.0.10" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/got": { - "version": "14.6.6", - "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", - "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "node_modules/globby/node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "dev": true, "license": "MIT", - "dependencies": { + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/goober": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz", + "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", + "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "dev": true, + "license": "MIT", + "dependencies": { "@sindresorhus/is": "^7.0.1", "byte-counter": "^0.1.0", "cacheable-lookup": "^7.0.0", @@ -7726,16 +9873,6 @@ "url": "https://github.com/sindresorhus/got?sponsor=1" } }, - "node_modules/got/node_modules/keyv": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", - "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@keyv/serialize": "^1.1.1" - } - }, "node_modules/got/node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", @@ -7756,6 +9893,16 @@ "dev": true, "license": "ISC" }, + "node_modules/graphql": { + "version": "16.14.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.2.tgz", + "integrity": "sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7778,10 +9925,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -7790,6 +9953,258 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-classnames": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-classnames/-/hast-util-classnames-3.0.0.tgz", + "integrity": "sha512-tI3JjoGDEBVorMAWK4jNRsfLMYmih1BUOG3VV36pH36njs1IEl7xkNrVTD2mD2yYHmQCa5R/fj61a8IAF4bRaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-select": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz", + "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "bcp-47-match": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "css-selector-parser": "^3.0.0", + "devlop": "^1.0.0", + "direction": "^2.0.0", + "hast-util-has-property": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "nth-check": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/headers-polyfill": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-5.0.1.tgz", + "integrity": "sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/set-cookie-parser": "^2.4.10", + "set-cookie-parser": "^3.0.1" + } + }, "node_modules/history": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", @@ -7809,6 +10224,12 @@ "react-is": "^16.7.0" } }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -7822,6 +10243,31 @@ "node": ">=18" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", + "integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-equal": "~1.0.1", + "http-errors": "~1.8.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -7829,6 +10275,33 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -7915,6 +10388,16 @@ ], "license": "BSD-3-Clause" }, + "node_modules/ignore": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz", + "integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/immer": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", @@ -7951,6 +10434,32 @@ "node": ">=8" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "dev": true, + "license": "MIT" + }, "node_modules/inspect-with-kind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz", @@ -7961,11 +10470,50 @@ "kind-of": "^6.0.2" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/is-core-module": { "version": "2.16.2", @@ -7982,6 +10530,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -7992,6 +10577,86 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -8012,6 +10677,25 @@ "dev": true, "license": "MIT" }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", @@ -8038,6 +10722,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", @@ -8080,110 +10787,144 @@ "license": "MIT" }, "node_modules/jest-diff": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.4.1.tgz", - "integrity": "sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.1.tgz", + "integrity": "sha512-e3cNNMpv8Kh20MjjphTXs+3Vz7DQyLM1nft7KJhnh46atFhjVJRa+0Hq0beywuwsACtMQUBihQkFl8zxb7gt1Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.4.0", - "@jest/get-type": "30.1.0", + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", "chalk": "^4.1.2", - "pretty-format": "30.4.1" + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/jest-diff/node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-diff/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jest-matcher-utils": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.4.1.tgz", - "integrity": "sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.1.tgz", + "integrity": "sha512-aroZVqwOz/wC2y6pC+obgFWKV9viaQWQTTSB6W5H55+egtUczIfXR/rxExTv92xD/ADYwpqaYfVWx1aqwKg7FA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.1.0", + "@jest/get-type": "30.5.0", "chalk": "^4.1.2", - "jest-diff": "30.4.1", - "pretty-format": "30.4.1" + "jest-diff": "30.5.1", + "pretty-format": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jest-message-util": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.4.1.tgz", - "integrity": "sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", + "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-util": "30.4.1", + "jest-util": "30.5.1", "picomatch": "^4.0.3", - "pretty-format": "30.4.1", + "pretty-format": "30.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -8191,54 +10932,72 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.4.1.tgz", - "integrity": "sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/schemas": "30.4.1", - "ansi-styles": "^5.2.0", - "react-is-18": "npm:react-is@^18.3.1", - "react-is-19": "npm:react-is@^19.2.5" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jest-mock": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.4.1.tgz", - "integrity": "sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.1.tgz", + "integrity": "sha512-9fVjc3leUpGID2/by/LU4Dvdcp7PFh9LlxS3QRWK3ABm+KtvEVsG/AEGeLY3gKOZsjkBxyfwGltoAVlW7dygHg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/expect-utils": "30.5.1", + "@jest/types": "30.5.1", "@types/node": "*", - "jest-util": "30.4.1" + "jest-util": "30.5.1" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-regex-util": { - "version": "30.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.4.0.tgz", - "integrity": "sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==", + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", "dev": true, "license": "MIT", "engines": { @@ -8246,13 +11005,13 @@ } }, "node_modules/jest-util": { - "version": "30.4.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.4.1.tgz", - "integrity": "sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==", + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.4.1", + "@jest/types": "30.5.1", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -8263,6 +11022,23 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -8336,35 +11112,153 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", "dev": true, - "license": "MPL-2.0", + "license": "MIT", "dependencies": { - "detect-libc": "^2.0.3" + "tsscmp": "1.0.6" }, "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", + "node": ">= 0.6" + } + }, + "node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/koa": { + "version": "2.16.4", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.4.tgz", + "integrity": "sha512-3An0GCLDSR34tsCO4H8Tef8Pp2ngtaZDAZnsWJYelqXUK5wyiHvGItgK/xcSkmHLSTn1Jcho1mRQs2ehRzvKKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.9.0", + "debug": "^4.3.2", + "delegates": "^1.0.0", + "depd": "^2.0.0", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^2.0.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + }, + "engines": { + "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" + } + }, + "node_modules/koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/koa-connect": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/koa-connect/-/koa-connect-2.1.1.tgz", + "integrity": "sha512-ejvbGKYS6di4LUSS+6E+Z5ZVev9RqThLm3NfZjb9QHZMASLvnr4eDTImKcGlQXFrtVpMTyTovZ+Hcl6JbBuFNA==", + "dev": true, + "license": "MIT" + }, + "node_modules/koa-convert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", + "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", + "dev": true, + "license": "MIT", + "dependencies": { + "co": "^4.6.0", + "koa-compose": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/koa/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", @@ -8489,6 +11383,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8510,6 +11407,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8531,6 +11431,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8552,6 +11455,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -8619,6 +11525,24 @@ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -8644,6 +11568,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -8695,6 +11629,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -8705,1516 +11663,1739 @@ } }, "node_modules/mathjs": { - "version": "10.6.4", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-10.6.4.tgz", - "integrity": "sha512-omQyvRE1jIy+3k2qsqkWASOcd45aZguXZDckr3HtnTYyXk5+2xpVfC3kATgbO2Srjxlqww3TVdhD0oUdZ/hiFA==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.2.0.tgz", + "integrity": "sha512-UAQzSVob9rNLdGpqcFMYmSu9dkuLYy7Lr2hBEQS5SHQdknA9VppJz3cy2KkpMzTODunad6V6cNv+5kOLsePLow==", "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.18.6", - "complex.js": "^2.1.1", - "decimal.js": "^10.3.1", + "@babel/runtime": "^7.26.10", + "complex.js": "^2.2.5", + "decimal.js": "^10.4.3", "escape-latex": "^1.2.0", - "fraction.js": "^4.2.0", + "fraction.js": "^5.2.1", "javascript-natural-sort": "^0.7.1", "seedrandom": "^3.0.5", "tiny-emitter": "^2.1.0", - "typed-function": "^2.1.0" + "typed-function": "^4.2.1" }, "bin": { "mathjs": "bin/cli.js" }, "engines": { - "node": ">= 14" + "node": ">= 18" } }, - "node_modules/mdi-material-ui": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-7.9.4.tgz", - "integrity": "sha512-bk+3A6ogY3r/TveGgD/PRhFkqctG3XmPPm5rTuj81aoYuv1xw4T3Ml+A/PsrCWhbgicZbGbC6r0jYg5vcFTTXQ==", + "node_modules/mathjs/node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "license": "MIT", - "peerDependencies": { - "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, + "node_modules/mathjs/node_modules/typed-function": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.2.tgz", + "integrity": "sha512-VwaXim9Gp1bngi/q3do8hgttYn2uC3MoT/gfuMWylnj1IeZBUAyPddHZlo1K05BDoj8DYPpMdiHqH1dDYdJf2A==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 18" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/normalize-url": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", - "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=14.16" + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/notistack": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/notistack/-/notistack-3.0.2.tgz", - "integrity": "sha512-0R+/arLYbK5Hh7mEfR2adt0tyXJcCC9KkA2hc56FeWik2QN6Bm/S4uW+BjzDARsJth5u06nTjelSw/VSnB1YEA==", + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dev": true, "license": "MIT", "dependencies": { - "clsx": "^1.1.0", - "goober": "^2.0.33" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=12.0.0", - "npm": ">=6.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/notistack" + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/notistack/node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/numbro": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/numbro/-/numbro-2.5.0.tgz", - "integrity": "sha512-xDcctDimhzko/e+y+Q2/8i3qNC9Svw1QgOkSkQoO0kIPI473tR9QRbo2KP88Ty9p8WbPy+3OpTaAIzehtuHq+A==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, "license": "MIT", "dependencies": { - "bignumber.js": "^8 || ^9" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdi-material-ui": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/mdi-material-ui/-/mdi-material-ui-7.9.4.tgz", + "integrity": "sha512-bk+3A6ogY3r/TveGgD/PRhFkqctG3XmPPm5rTuj81aoYuv1xw4T3Ml+A/PsrCWhbgicZbGbC6r0jYg5vcFTTXQ==", + "license": "MIT", + "peerDependencies": { + "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 0.6" } }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "dev": true, "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } ], "license": "MIT", - "engines": { - "node": ">=12.20.0" + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "dev": true, "license": "MIT", "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/oxc-parser": { - "version": "0.143.0", - "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.143.0.tgz", - "integrity": "sha512-ov0NzaDCOInknS7mP1cwKdJERt3utPW8ldjtdUXQ8Ty0GEFD08wk422vCUN0d7pST6kqtV7dxoI9w1Zi0l/9TA==", + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "^0.143.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxc-parser/binding-android-arm-eabi": "0.143.0", - "@oxc-parser/binding-android-arm64": "0.143.0", - "@oxc-parser/binding-darwin-arm64": "0.143.0", - "@oxc-parser/binding-darwin-x64": "0.143.0", - "@oxc-parser/binding-freebsd-x64": "0.143.0", - "@oxc-parser/binding-linux-arm-gnueabihf": "0.143.0", - "@oxc-parser/binding-linux-arm-musleabihf": "0.143.0", - "@oxc-parser/binding-linux-arm64-gnu": "0.143.0", - "@oxc-parser/binding-linux-arm64-musl": "0.143.0", - "@oxc-parser/binding-linux-ppc64-gnu": "0.143.0", - "@oxc-parser/binding-linux-riscv64-gnu": "0.143.0", - "@oxc-parser/binding-linux-riscv64-musl": "0.143.0", - "@oxc-parser/binding-linux-s390x-gnu": "0.143.0", - "@oxc-parser/binding-linux-x64-gnu": "0.143.0", - "@oxc-parser/binding-linux-x64-musl": "0.143.0", - "@oxc-parser/binding-openharmony-arm64": "0.143.0", - "@oxc-parser/binding-win32-arm64-msvc": "0.143.0", - "@oxc-parser/binding-win32-ia32-msvc": "0.143.0", - "@oxc-parser/binding-win32-x64-msvc": "0.143.0" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/oxfmt": { - "version": "0.55.0", - "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.55.0.tgz", - "integrity": "sha512-jSj2wCTakwgPMxkfiVZX0jf+nX+Nz6xlyAZjqNE0qXTFdCBPYlP6JAN+ODjmealw7DXBjOzYbdsqwBMAZnPZ6A==", + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "dev": true, "license": "MIT", "dependencies": { - "tinypool": "2.1.0" - }, - "bin": { - "oxfmt": "bin/oxfmt" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxfmt/binding-android-arm-eabi": "0.55.0", - "@oxfmt/binding-android-arm64": "0.55.0", - "@oxfmt/binding-darwin-arm64": "0.55.0", - "@oxfmt/binding-darwin-x64": "0.55.0", - "@oxfmt/binding-freebsd-x64": "0.55.0", - "@oxfmt/binding-linux-arm-gnueabihf": "0.55.0", - "@oxfmt/binding-linux-arm-musleabihf": "0.55.0", - "@oxfmt/binding-linux-arm64-gnu": "0.55.0", - "@oxfmt/binding-linux-arm64-musl": "0.55.0", - "@oxfmt/binding-linux-ppc64-gnu": "0.55.0", - "@oxfmt/binding-linux-riscv64-gnu": "0.55.0", - "@oxfmt/binding-linux-riscv64-musl": "0.55.0", - "@oxfmt/binding-linux-s390x-gnu": "0.55.0", - "@oxfmt/binding-linux-x64-gnu": "0.55.0", - "@oxfmt/binding-linux-x64-musl": "0.55.0", - "@oxfmt/binding-openharmony-arm64": "0.55.0", - "@oxfmt/binding-win32-arm64-msvc": "0.55.0", - "@oxfmt/binding-win32-ia32-msvc": "0.55.0", - "@oxfmt/binding-win32-x64-msvc": "0.55.0" - }, - "peerDependencies": { - "svelte": "^5.0.0", - "vite-plus": "*" - }, - "peerDependenciesMeta": { - "svelte": { - "optional": true - }, - "vite-plus": { - "optional": true - } + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/oxlint": { - "version": "1.70.0", - "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.70.0.tgz", - "integrity": "sha512-D6JgHtzkhRwvEC+A0Nw5AEc5bk8x5i1pHzvZIEf/a0C4hOzmAACNGtkDGPyFaxxX3ZVGxCPeig3P3rMM8XU3/g==", + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "dev": true, "license": "MIT", - "bin": { - "oxlint": "bin/oxlint" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/Boshen" + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "optionalDependencies": { - "@oxlint/binding-android-arm-eabi": "1.70.0", - "@oxlint/binding-android-arm64": "1.70.0", - "@oxlint/binding-darwin-arm64": "1.70.0", - "@oxlint/binding-darwin-x64": "1.70.0", - "@oxlint/binding-freebsd-x64": "1.70.0", - "@oxlint/binding-linux-arm-gnueabihf": "1.70.0", - "@oxlint/binding-linux-arm-musleabihf": "1.70.0", - "@oxlint/binding-linux-arm64-gnu": "1.70.0", - "@oxlint/binding-linux-arm64-musl": "1.70.0", - "@oxlint/binding-linux-ppc64-gnu": "1.70.0", - "@oxlint/binding-linux-riscv64-gnu": "1.70.0", - "@oxlint/binding-linux-riscv64-musl": "1.70.0", - "@oxlint/binding-linux-s390x-gnu": "1.70.0", - "@oxlint/binding-linux-x64-gnu": "1.70.0", - "@oxlint/binding-linux-x64-musl": "1.70.0", - "@oxlint/binding-openharmony-arm64": "1.70.0", - "@oxlint/binding-win32-arm64-msvc": "1.70.0", - "@oxlint/binding-win32-ia32-msvc": "1.70.0", - "@oxlint/binding-win32-x64-msvc": "1.70.0" - }, - "peerDependencies": { - "oxlint-tsgolint": ">=0.22.1", - "vite-plus": "*" - }, - "peerDependenciesMeta": { - "oxlint-tsgolint": { - "optional": true - }, - "vite-plus": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/oxlint-plugin-react-doctor": { - "version": "0.9.12", - "resolved": "https://registry.npmjs.org/oxlint-plugin-react-doctor/-/oxlint-plugin-react-doctor-0.9.12.tgz", - "integrity": "sha512-BplcCUU/tGByFGgY1YIax6evUmjk0K8zOGGrdPs3A3dqamrzjUvVuJdYpM1Ftyt/B5fFx6+VwRrWi3YZbIz4VQ==", + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "dev": true, - "license": "SEE LICENSE IN LICENSE", + "license": "MIT", "dependencies": { - "@shaderfrog/glsl-parser": "^7.0.1", - "@typescript-eslint/types": "^8.59.3", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "lightningcss": "^1.33.0", - "oxc-parser": "^0.143.0" + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^20.19.0 || >=22.13.0" - } - }, - "node_modules/p-cancelable": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", - "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-event": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", - "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", "dev": true, "license": "MIT", "dependencies": { - "p-timeout": "^6.1.2" - }, - "engines": { - "node": ">=16.17" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/p-timeout": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", - "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "dev": true, - "license": "ISC" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pathe": { + "node_modules/micromark-factory-mdx-expression": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/piscina": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.9.3.tgz", - "integrity": "sha512-3e3ka9QCE8RJ5I9uszdAADZnkcYi21cqmF3gxox3u884N72qpFHCsIVhHt8cEQ9t3Auq/NqoiCEuhxlxxQuDWA==", + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "optionalDependencies": { - "@napi-rs/nice": "^1.0.1" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "dev": true, "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.17", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "parse-ms": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", - "license": "BSD-3-Clause", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/raf-schd": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", - "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "node_modules/react-colorful": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.7.0.tgz", - "integrity": "sha512-fuesYIemttah97XmsIHmz4OORDHiSFzyc9HMAIrCHJou2jaRQmL8cFJ76K4zQhhj8jzwOBlOi4BaGTjjOZCfTg==", + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-draggable": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.5.0.tgz", - "integrity": "sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "clsx": "^2.1.1", - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "react": ">= 16.3.0", - "react-dom": ">= 16.3.0" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/react-error-boundary": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", - "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "react": ">=16.13.1" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/react-grid-layout": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.5.3.tgz", - "integrity": "sha512-KaG6IbjD6fYhagUtIvOzhftXG+ViKZjCjADe86X1KHl7C/dsBN2z0mi14nbvZKTkp0RKiil9RPcJBgq3LnoA8g==", + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { - "clsx": "^2.1.1", - "fast-equals": "^4.0.3", - "prop-types": "^15.8.1", - "react-draggable": "^4.4.6", - "react-resizable": "^3.0.5", - "resize-observer-polyfill": "^1.5.1" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, - "peerDependencies": { - "react": ">= 16.3.0", - "react-dom": ">= 16.3.0" + "engines": { + "node": ">=8.6" } }, - "node_modules/react-hook-form": { - "version": "7.87.0", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.87.0.tgz", - "integrity": "sha512-zhFzWvLxNHH+8839OnZcUxgMZw88ah2jZWDWvKWgF3Tpbnd0vKL+dlcuU3nZVWESZQjd81EW8K+wU+cYfYAc0w==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=8.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-hook-form" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18 || ^19" - } - }, - "node_modules/react-intersection-observer": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz", - "integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==", - "license": "MIT", - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/react-is-18": { - "name": "react-is", - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-is-19": { - "name": "react-is", - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.6.tgz", - "integrity": "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==", - "dev": true, - "license": "MIT" - }, - "node_modules/react-refresh": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.16.0.tgz", - "integrity": "sha512-FPvF2XxTSikpJxcr+bHut2H4gJ17+18Uy20D5/F+SKzFap62R3cM5wH6b8WN3LyGSYeQilLEcJcR1fjBSI2S1A==", + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/react-resizable": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.2.0.tgz", - "integrity": "sha512-3NKQ0SLZV7rs3LQHeXlOzDSRQfFrkX6TVet77/Qk03zqiZyee37b7N8/gwDJAA8UUjRz7PdWCCy49hcso45SMQ==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { - "prop-types": "15.x", - "react-draggable": "^4.5.0" + "mime-db": "1.52.0" }, - "peerDependencies": { - "react": ">= 16.3", - "react-dom": ">= 16.3" + "engines": { + "node": ">= 0.6" } }, - "node_modules/react-router": { - "version": "6.30.4", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz", - "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==", - "devOptional": true, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.3" - }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" + "node": ">= 0.6" } }, - "node_modules/react-router-dom": { - "version": "6.30.4", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz", - "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==", - "devOptional": true, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.3", - "react-router": "6.30.4" - }, "engines": { - "node": ">=14.0.0" + "node": ">=12" }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "license": "BSD-3-Clause", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-virtuoso": { - "version": "4.18.7", - "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.7.tgz", - "integrity": "sha512-xNF5zDGEEIMB7cKwcen/pLig0YDf6OnfFrVgKFa7sHPf9fRem0CaLshyObbBcP88jzn0enavL39EgplgdyT21g==", + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, "license": "MIT", - "peerDependencies": { - "react": ">=16 || >=17 || >= 18 || >= 19", - "react-dom": ">=16 || >=17 || >= 18 || >=19" + "engines": { + "node": ">=4" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/remove-accents": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", - "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", - "license": "MIT" + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "node_modules/msw": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.15.0.tgz", + "integrity": "sha512-2wQAmKkQKxRuXvYJxVhPGG0wZNBQyD06oJvxqw90XqLvptdqxdlHrFUfEteKkpaNORX3Xzc+HtEl/q0nfmN2wQ==", + "dev": true, + "hasInstallScript": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "@inquirer/confirm": "^6.0.11", + "@mswjs/interceptors": "^0.41.3", + "@open-draft/deferred-promise": "^3.0.0", + "@types/statuses": "^2.0.6", + "cookie": "^1.1.1", + "graphql": "^16.13.2", + "headers-polyfill": "^5.0.1", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "rettime": "^0.11.11", + "statuses": "^2.0.2", + "strict-event-emitter": "^0.5.1", + "tough-cookie": "^6.0.1", + "type-fest": "^5.5.0", + "until-async": "^3.0.2", + "yargs": "^17.7.2" }, "bin": { - "resolve": "bin/resolve" + "msw": "cli/index.js" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "node_modules/msw/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/msw/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/msw/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/responselike": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz", - "integrity": "sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==", + "node_modules/msw/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "lowercase-keys": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "node_modules/msw/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=8" } }, - "node_modules/rollup": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", - "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "node_modules/msw/node_modules/tldts": { + "version": "7.4.13", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.13.tgz", + "integrity": "sha512-iHtaIWWIbMDkCeJdTBzZFGgbluE5J+oHlb2g7+oAz1S1gpuVpabRZdQyd471Vl8UUkcz2vXSL8xZH2kyCe8tfA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.9" + "tldts-core": "^7.4.13" }, "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@napi-rs/lzma-linux-x64-gnu": "1.5.1", - "@rollup/rollup-android-arm-eabi": "4.62.4", - "@rollup/rollup-android-arm64": "4.62.4", - "@rollup/rollup-darwin-arm64": "4.62.4", - "@rollup/rollup-darwin-x64": "4.62.4", - "@rollup/rollup-freebsd-arm64": "4.62.4", - "@rollup/rollup-freebsd-x64": "4.62.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", - "@rollup/rollup-linux-arm-musleabihf": "4.62.4", - "@rollup/rollup-linux-arm64-gnu": "4.62.4", - "@rollup/rollup-linux-arm64-musl": "4.62.4", - "@rollup/rollup-linux-loong64-gnu": "4.62.4", - "@rollup/rollup-linux-loong64-musl": "4.62.4", - "@rollup/rollup-linux-ppc64-gnu": "4.62.4", - "@rollup/rollup-linux-ppc64-musl": "4.62.4", - "@rollup/rollup-linux-riscv64-gnu": "4.62.4", - "@rollup/rollup-linux-riscv64-musl": "4.62.4", - "@rollup/rollup-linux-s390x-gnu": "4.62.4", - "@rollup/rollup-linux-x64-gnu": "4.62.4", - "@rollup/rollup-linux-x64-musl": "4.62.4", - "@rollup/rollup-openbsd-x64": "4.62.4", - "@rollup/rollup-openharmony-arm64": "4.62.4", - "@rollup/rollup-win32-arm64-msvc": "4.62.4", - "@rollup/rollup-win32-ia32-msvc": "4.62.4", - "@rollup/rollup-win32-x64-gnu": "4.62.4", - "@rollup/rollup-win32-x64-msvc": "4.62.4", - "fsevents": "~2.3.2" + "tldts": "bin/cli.js" } }, - "node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "node_modules/msw/node_modules/tldts-core": { + "version": "7.4.13", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.13.tgz", + "integrity": "sha512-mbYsrih5FRtGxs3Usvl/PqwJsNpp+jsmrdFviiK02teHDG0/HebBG/pqCylje3kzgXYzuLoHJF/0mz9W53t8Xg==", "dev": true, "license": "MIT" }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "node_modules/msw/node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", "dev": true, - "license": "Apache-2.0", + "license": "BSD-3-Clause", "dependencies": { - "tslib": "^2.1.0" + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "node_modules/msw/node_modules/type-fest": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.9.0.tgz", + "integrity": "sha512-yANm3Jr3GiJ1qgJlxGAVxTOIcEOk1rhQHamlXtnrCK7EHP4HeM9OGxtMg/W7HFdrVzw/ZWJKGVIJusVH85sLtw==", "dev": true, - "license": "ISC", + "license": "(MIT OR CC0-1.0)", "dependencies": { - "xmlchars": "^2.2.0" + "tagged-tag": "^1.0.0" }, "engines": { - "node": ">=v12.22.7" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "node_modules/msw/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/seedrandom": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", - "license": "MIT" - }, - "node_modules/seek-bzip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-2.0.0.tgz", - "integrity": "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==", + "node_modules/msw/node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", "dev": true, "license": "MIT", "dependencies": { - "commander": "^6.0.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, - "bin": { - "seek-bunzip": "bin/seek-bunzip", - "seek-table": "bin/seek-bzip-table" + "engines": { + "node": ">=12" } }, - "node_modules/seek-bzip/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "node_modules/msw/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "dev": true, "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "bin": { - "semver": "bin/semver.js" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=10" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.6" } }, - "node_modules/semver-truncate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", - "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "node_modules/node-releases": { + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", "dev": true, "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/serialize-query-params": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/serialize-query-params/-/serialize-query-params-2.0.4.tgz", - "integrity": "sha512-y9WzzDj3BsGgKLCh0ugiinufS//YqOfao/yVJjkXA4VLuyNCfHOLU/cbulGPxs3aeCqhvROw7qPL04JSZnCo0w==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" } }, - "node_modules/shebang-regex": { + "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/shell-quote": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", - "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "node_modules/notistack": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/notistack/-/notistack-3.0.2.tgz", + "integrity": "sha512-0R+/arLYbK5Hh7mEfR2adt0tyXJcCC9KkA2hc56FeWik2QN6Bm/S4uW+BjzDARsJth5u06nTjelSw/VSnB1YEA==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" + "clsx": "^1.1.0", + "goober": "^2.0.33" }, "engines": { - "node": ">= 0.4" + "node": ">=12.0.0", + "npm": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/notistack" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "node_modules/notistack/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "dev": true, + "node_modules/numbro": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/numbro/-/numbro-2.5.0.tgz", + "integrity": "sha512-xDcctDimhzko/e+y+Q2/8i3qNC9Svw1QgOkSkQoO0kIPI473tR9QRbo2KP88Ty9p8WbPy+3OpTaAIzehtuHq+A==", "license": "MIT", "dependencies": { - "is-plain-obj": "^1.0.0" + "bignumber.js": "^8 || ^9" }, "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "node_modules/nwsapi": { + "version": "2.2.27", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.27.tgz", + "integrity": "sha512-gQPNF78qebCQ6tvVFBYrvJdBNOrYZm90ZlXgpIFm06p6qHDHq/XC4TnJftN6OMbxVE0UTBAoRgcsDeJBBooITw==", "dev": true, - "license": "MIT", - "dependencies": { - "sort-keys": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/sort-keys/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "node_modules/obug": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", "dev": true, - "license": "BSD-3-Clause", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.20.0" } }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { - "escape-string-regexp": "^2.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "dev": true, - "license": "MIT" - }, - "node_modules/streamx": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", - "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" + "wrappy": "1" } }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "mimic-fn": "^4.0.0" }, "engines": { "node": ">=12" @@ -10223,494 +13404,608 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==", + "dev": true + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", "dev": true, "license": "MIT" }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/oxc-parser": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.143.0.tgz", + "integrity": "sha512-ov0NzaDCOInknS7mP1cwKdJERt3utPW8ldjtdUXQ8Ty0GEFD08wk422vCUN0d7pST6kqtV7dxoI9w1Zi0l/9TA==", "dev": true, "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.143.0" + }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.143.0", + "@oxc-parser/binding-android-arm64": "0.143.0", + "@oxc-parser/binding-darwin-arm64": "0.143.0", + "@oxc-parser/binding-darwin-x64": "0.143.0", + "@oxc-parser/binding-freebsd-x64": "0.143.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.143.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.143.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.143.0", + "@oxc-parser/binding-linux-arm64-musl": "0.143.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.143.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.143.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.143.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.143.0", + "@oxc-parser/binding-linux-x64-gnu": "0.143.0", + "@oxc-parser/binding-linux-x64-musl": "0.143.0", + "@oxc-parser/binding-openharmony-arm64": "0.143.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.143.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.143.0", + "@oxc-parser/binding-win32-x64-msvc": "0.143.0" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/oxfmt": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.55.0.tgz", + "integrity": "sha512-jSj2wCTakwgPMxkfiVZX0jf+nX+Nz6xlyAZjqNE0qXTFdCBPYlP6JAN+ODjmealw7DXBjOzYbdsqwBMAZnPZ6A==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.2.2" + "tinypool": "2.1.0" + }, + "bin": { + "oxfmt": "bin/oxfmt" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "url": "https://github.com/sponsors/Boshen" }, - "engines": { - "node": ">=8" + "optionalDependencies": { + "@oxfmt/binding-android-arm-eabi": "0.55.0", + "@oxfmt/binding-android-arm64": "0.55.0", + "@oxfmt/binding-darwin-arm64": "0.55.0", + "@oxfmt/binding-darwin-x64": "0.55.0", + "@oxfmt/binding-freebsd-x64": "0.55.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.55.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.55.0", + "@oxfmt/binding-linux-arm64-gnu": "0.55.0", + "@oxfmt/binding-linux-arm64-musl": "0.55.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.55.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.55.0", + "@oxfmt/binding-linux-riscv64-musl": "0.55.0", + "@oxfmt/binding-linux-s390x-gnu": "0.55.0", + "@oxfmt/binding-linux-x64-gnu": "0.55.0", + "@oxfmt/binding-linux-x64-musl": "0.55.0", + "@oxfmt/binding-openharmony-arm64": "0.55.0", + "@oxfmt/binding-win32-arm64-msvc": "0.55.0", + "@oxfmt/binding-win32-ia32-msvc": "0.55.0", + "@oxfmt/binding-win32-x64-msvc": "0.55.0" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + }, + "vite-plus": { + "optional": true + } } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/oxlint": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.70.0.tgz", + "integrity": "sha512-D6JgHtzkhRwvEC+A0Nw5AEc5bk8x5i1pHzvZIEf/a0C4hOzmAACNGtkDGPyFaxxX3ZVGxCPeig3P3rMM8XU3/g==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "bin": { + "oxlint": "bin/oxlint" }, "engines": { - "node": ">=8" - } - }, - "node_modules/strip-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-3.0.0.tgz", - "integrity": "sha512-I0sdgcFTfKQlUPZyAqPJmSG3HLO9rWDFnxonnIbskYNM3DwFOeTNB5KzVq3dA1GdRAc/25b5Y7UO2TQfKWw4aQ==", - "dev": true, - "license": "ISC", + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.70.0", + "@oxlint/binding-android-arm64": "1.70.0", + "@oxlint/binding-darwin-arm64": "1.70.0", + "@oxlint/binding-darwin-x64": "1.70.0", + "@oxlint/binding-freebsd-x64": "1.70.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.70.0", + "@oxlint/binding-linux-arm-musleabihf": "1.70.0", + "@oxlint/binding-linux-arm64-gnu": "1.70.0", + "@oxlint/binding-linux-arm64-musl": "1.70.0", + "@oxlint/binding-linux-ppc64-gnu": "1.70.0", + "@oxlint/binding-linux-riscv64-gnu": "1.70.0", + "@oxlint/binding-linux-riscv64-musl": "1.70.0", + "@oxlint/binding-linux-s390x-gnu": "1.70.0", + "@oxlint/binding-linux-x64-gnu": "1.70.0", + "@oxlint/binding-linux-x64-musl": "1.70.0", + "@oxlint/binding-openharmony-arm64": "1.70.0", + "@oxlint/binding-win32-arm64-msvc": "1.70.0", + "@oxlint/binding-win32-ia32-msvc": "1.70.0", + "@oxlint/binding-win32-x64-msvc": "1.70.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.22.1", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/oxlint-plugin-react-doctor": { + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/oxlint-plugin-react-doctor/-/oxlint-plugin-react-doctor-0.9.12.tgz", + "integrity": "sha512-BplcCUU/tGByFGgY1YIax6evUmjk0K8zOGGrdPs3A3dqamrzjUvVuJdYpM1Ftyt/B5fFx6+VwRrWi3YZbIz4VQ==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", "dependencies": { - "inspect-with-kind": "^1.0.5", - "is-plain-obj": "^1.1.0" + "@shaderfrog/glsl-parser": "^7.0.1", + "@typescript-eslint/types": "^8.59.3", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "lightningcss": "^1.33.0", + "oxc-parser": "^0.143.0" + }, + "engines": { + "node": "^20.19.0 || >=22.13.0" } }, - "node_modules/strip-dirs/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "node_modules/p-cancelable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=14.16" } }, - "node_modules/strip-final-newline": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "node_modules/p-event": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", "dev": true, "license": "MIT", + "dependencies": { + "p-timeout": "^6.1.2" + }, "engines": { - "node": ">=18" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", "dev": true, "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strtok3": { - "version": "10.3.5", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", - "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "license": "MIT", "dependencies": { - "@tokenizer/token": "^0.3.0" + "callsites": "^3.0.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "node": ">=6" } }, - "node_modules/style-mod": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", - "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", - "license": "MIT" - }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", - "license": "MIT" - }, - "node_modules/super-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.1.0.tgz", - "integrity": "sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==", + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "dev": true, "license": "MIT", "dependencies": { - "function-timeout": "^1.0.1", - "make-asynchronous": "^1.0.1", - "time-span": "^5.1.0" - }, - "engines": { - "node": ">=18" + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "dev": true, + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "dev": true, "license": "MIT", "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/tar-stream/node_modules/b4a": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", - "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "node_modules/text-decoder": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/text-decoder/node_modules/b4a": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", - "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, - "node_modules/time-span": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", - "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "convert-hrtime": "^5.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "license": "MIT" + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true, "license": "MIT" }, - "node_modules/tinyexec": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", - "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", - "dev": true, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, "engines": { - "node": ">=12.0.0" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/tinypool": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", - "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", + "node_modules/piscina": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.9.4.tgz", + "integrity": "sha512-RyBDr2VheQ8ZfH3N8SzQZHztqVyOtadTwLnUYof6gdj5161/eu2wNhCbGl5GHnNKDpnkicJYpKtL2J+y/gk6XA==", "dev": true, "license": "MIT", - "engines": { - "node": "^20.0.0 || >=22.0.0" + "optionalDependencies": { + "@napi-rs/nice": "^1.0.1" } }, - "node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, "engines": { - "node": ">=14.0.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.86" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, - "bin": { - "tldts": "bin/cli.js" + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/token-types": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", - "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "dependencies": { - "@borewit/text-codec": "^0.2.1", - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, "engines": { - "node": ">=14.16" + "node": ">=10" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT" + }, + "node_modules/pretty-ms": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", + "dev": true, + "license": "MIT", "dependencies": { - "tldts": "^6.1.32" + "parse-ms": "^4.0.0" }, "engines": { - "node": ">=16" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "node_modules/prism-react-renderer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", + "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.3.1" + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" }, - "engines": { - "node": ">=18" + "peerDependencies": { + "react": ">=16.0.0" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", - "bin": { - "tree-kill": "cli.js" + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "devOptional": true, - "license": "0BSD" + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" }, - "node_modules/turbo": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.9.14.tgz", - "integrity": "sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==", + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", "dev": true, "license": "MIT", - "bin": { - "turbo": "bin/turbo" - }, - "optionalDependencies": { - "@turbo/darwin-64": "2.9.14", - "@turbo/darwin-arm64": "2.9.14", - "@turbo/linux-64": "2.9.14", - "@turbo/linux-arm64": "2.9.14", - "@turbo/windows-64": "2.9.14", - "@turbo/windows-arm64": "2.9.14" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/typed-function": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.1.0.tgz", - "integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6" } }, - "node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc" + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { - "node": ">=16.20.0" + "node": ">=0.6" }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uint8array-extras": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", - "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "node_modules/query-string": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.5.1.tgz", + "integrity": "sha512-/zO3RwuRCMTIcEgq6YMv4OrtEE1XzBG7w5N6zc6ydYnkWYOWsnLI/5894hYEzfESfMOT4cHCsRTIdxsSl1KjGg==", "dev": true, "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.5.0", + "filter-obj": "^5.1.0", + "split-on-first": "^3.0.0" + }, "engines": { "node": ">=18" }, @@ -10718,308 +14013,3049 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", "license": "MIT" }, - "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "loose-envify": "^1.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/use-immer": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.11.0.tgz", - "integrity": "sha512-RNAqi3GqsWJ4bcCd4LMBgdzvPmTABam24DUaFiKfX9s3MSorNRz9RDZYJkllJoMHUxVLMDetwAuCDeyWNrp1yA==", + "node_modules/react-colorful": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.8.1.tgz", + "integrity": "sha512-oz68bhsnFWnpDf1ZR8daiQbYpXUnM2h2J6hl9Zg2rTpM/DU6vCqe1E+CpqmqLnJucMZetHZeifSAfJ+geN9lcA==", "license": "MIT", "peerDependencies": { - "immer": ">=8.0.0", - "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/use-query-params": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/use-query-params/-/use-query-params-2.2.2.tgz", - "integrity": "sha512-OwGab8u8/x2xZp9uSyBsx0kXlkR9IR436zbygsYVGikPYY3OJosvve6IJVGwIJPcfyb/YHwvPrUNu65/JR++Kw==", - "license": "ISC", + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { - "serialize-query-params": "^2.0.3" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "@reach/router": "^1.2.1", - "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "react-router-dom": ">=5" - }, - "peerDependenciesMeta": { - "@reach/router": { - "optional": true - }, - "react-router-dom": { - "optional": true - } + "react": "^18.3.1" } }, - "node_modules/use-resize-observer": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", - "integrity": "sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==", + "node_modules/react-draggable": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.7.1.tgz", + "integrity": "sha512-wa3tzfFnYt3yaZLuyU58fl1TNunfWfBekDgWhZA1+gb2jnp42wZ0ymuopR6M5kqDYmm4hKmzGlcKWjZf3Zb6RQ==", "license": "MIT", "dependencies": { - "@juggle/resize-observer": "^3.3.1" + "clsx": "^2.1.1", + "prop-types": "^15.8.1" }, "peerDependencies": { - "react": "16.8.0 - 18", - "react-dom": "16.8.0 - 18" + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "react": ">=16.13.1" } }, - "node_modules/vite": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", - "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", - "dev": true, + "node_modules/react-grid-layout": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.5.3.tgz", + "integrity": "sha512-KaG6IbjD6fYhagUtIvOzhftXG+ViKZjCjADe86X1KHl7C/dsBN2z0mi14nbvZKTkp0RKiil9RPcJBgq3LnoA8g==", "license": "MIT", "dependencies": { - "esbuild": "^0.27.0 || ^0.28.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" + "clsx": "^2.1.1", + "fast-equals": "^4.0.3", + "prop-types": "^15.8.1", + "react-draggable": "^4.4.6", + "react-resizable": "^3.1.3", + "resize-observer-polyfill": "^1.5.1" }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-hook-form": { + "version": "7.88.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.88.0.tgz", + "integrity": "sha512-QRaLOWhX93YCnMiRfnOFRSwWXZNt8qhm2JTZwypoDvKpSffTJHmpzMXt8U6PV5UThvL3IiiLDUWe2nHMtz6Mmw==", + "license": "MIT", "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18.0.0" }, "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } + "react": "^16.8.0 || ^17 || ^18 || ^19" } }, - "node_modules/vite-tsconfig-paths": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", - "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "node_modules/react-hotkeys-hook": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.6.2.tgz", + "integrity": "sha512-FmP+ZriY3EG59Ug/lxNfrObCnW9xQShgk7Nb83+CkpfkcCpfS95ydv+E9JuXA5cp8KtskU7LGlIARpkc92X22Q==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "globrex": "^0.1.2", - "tsconfck": "^3.0.3" - }, "peerDependencies": { - "vite": "*" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } + "react": ">=16.8.1", + "react-dom": ">=16.8.1" } }, - "node_modules/vite-tsconfig-paths/node_modules/tsconfck": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", - "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", - "deprecated": "unmaintained", + "node_modules/react-inspector": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", + "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", "dev": true, "license": "MIT", - "bin": { - "tsconfck": "bin/tsconfck.js" - }, - "engines": { - "node": "^18 || >=20" - }, "peerDependencies": { - "typescript": "^5.0.0" + "react": "^16.8.4 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-intersection-observer": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz", + "integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==", + "license": "MIT", + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "typescript": { + "react-dom": { "optional": true } } }, - "node_modules/vitest": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", - "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "node_modules/react-is": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.16.0.tgz", + "integrity": "sha512-FPvF2XxTSikpJxcr+bHut2H4gJ17+18Uy20D5/F+SKzFap62R3cM5wH6b8WN3LyGSYeQilLEcJcR1fjBSI2S1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-resizable": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.2.0.tgz", + "integrity": "sha512-3NKQ0SLZV7rs3LQHeXlOzDSRQfFrkX6TVet77/Qk03zqiZyee37b7N8/gwDJAA8UUjRz7PdWCCy49hcso45SMQ==", + "license": "MIT", + "dependencies": { + "prop-types": "15.x", + "react-draggable": "^4.5.0" + }, + "peerDependencies": { + "react": ">= 16.3", + "react-dom": ">= 16.3" + } + }, + "node_modules/react-router": { + "version": "6.30.6", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.6.tgz", + "integrity": "sha512-5HfK7k5im7LTOB0EqCQmfvy4C13G92Ssj1VTmouTK3AJvyjKTnFuCV0vcMAD/JS+JC4DvDIBRrlAeJIFjh5VWg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.6", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.6.tgz", + "integrity": "sha512-0RHKZz7wwffvkU+2MFVT2NnjK44ssLEV+m0CAJaS2Ksmorrwj7WxH00jO0SOCW26/tINUnJHToXblDs33I38YQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.4", + "react-router": "6.30.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/react-virtuoso": { + "version": "4.18.13", + "resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.13.tgz", + "integrity": "sha512-M4kP7zbV7JmLrnJYs0X2FBA8gnNlHisSYuKMyeJVYtWz31CAJeP57dgPJzfneUdKDKmL9SiqvcBQ32si8CfQSQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16 || >=17 || >= 18 || >= 19", + "react-dom": ">=16 || >=17 || >= 18 || >=19" + } + }, + "node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "extraneous": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rehype-class-names": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rehype-class-names/-/rehype-class-names-2.0.0.tgz", + "integrity": "sha512-jldCIiAEvXKdq8hqr5f5PzNdIDkvHC6zfKhwta9oRoMu7bn0W7qLES/JrrjBvr9rKz3nJ8x4vY1EWI+dhjHVZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-classnames": "^3.0.0", + "hast-util-select": "^6.0.0", + "unified": "^11.0.4" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reselect": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.3.0.tgz", + "integrity": "sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==", + "license": "MIT" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz", + "integrity": "sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rettime": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.11.11.tgz", + "integrity": "sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rolldown": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz", + "integrity": "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.150.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.9", + "@rolldown/binding-android-arm64": "1.2.9", + "@rolldown/binding-darwin-arm64": "1.2.9", + "@rolldown/binding-darwin-x64": "1.2.9", + "@rolldown/binding-freebsd-x64": "1.2.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", + "@rolldown/binding-linux-arm64-gnu": "1.2.9", + "@rolldown/binding-linux-arm64-musl": "1.2.9", + "@rolldown/binding-linux-ppc64-gnu": "1.2.9", + "@rolldown/binding-linux-s390x-gnu": "1.2.9", + "@rolldown/binding-linux-x64-gnu": "1.2.9", + "@rolldown/binding-linux-x64-musl": "1.2.9", + "@rolldown/binding-openharmony-arm64": "1.2.9", + "@rolldown/binding-win32-arm64-msvc": "1.2.9", + "@rolldown/binding-win32-x64-msvc": "1.2.9" + } + }, + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz", + "integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.63.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.3.tgz", + "integrity": "sha512-1i2XreiAoMMXuPGD6Msj2xWrMMkHojNRKivInxGQcg7/1KuPuYlfUutLyh4drnOxUTHX9cHI4wFoat8D/NKaBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.3", + "@rollup/rollup-android-arm64": "4.63.3", + "@rollup/rollup-darwin-arm64": "4.63.3", + "@rollup/rollup-darwin-x64": "4.63.3", + "@rollup/rollup-freebsd-arm64": "4.63.3", + "@rollup/rollup-freebsd-x64": "4.63.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.3", + "@rollup/rollup-linux-arm-musleabihf": "4.63.3", + "@rollup/rollup-linux-arm64-gnu": "4.63.3", + "@rollup/rollup-linux-arm64-musl": "4.63.3", + "@rollup/rollup-linux-loong64-gnu": "4.63.3", + "@rollup/rollup-linux-loong64-musl": "4.63.3", + "@rollup/rollup-linux-ppc64-gnu": "4.63.3", + "@rollup/rollup-linux-ppc64-musl": "4.63.3", + "@rollup/rollup-linux-riscv64-gnu": "4.63.3", + "@rollup/rollup-linux-riscv64-musl": "4.63.3", + "@rollup/rollup-linux-s390x-gnu": "4.63.3", + "@rollup/rollup-linux-x64-gnu": "4.63.3", + "@rollup/rollup-linux-x64-musl": "4.63.3", + "@rollup/rollup-openbsd-x64": "4.63.3", + "@rollup/rollup-openharmony-arm64": "4.63.3", + "@rollup/rollup-win32-arm64-msvc": "4.63.3", + "@rollup/rollup-win32-ia32-msvc": "4.63.3", + "@rollup/rollup-win32-x64-gnu": "4.63.3", + "@rollup/rollup-win32-x64-msvc": "4.63.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "license": "MIT" + }, + "node_modules/seek-bzip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-2.0.0.tgz", + "integrity": "sha512-SMguiTnYrhpLdk3PwfzHeotrcwi8bNV4iemL9tx9poR/yeaMYwB9VzR1w7b57DuWpuqR8n6oZboi0hj3AxZxQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^6.0.0" + }, + "bin": { + "seek-bunzip": "bin/seek-bunzip", + "seek-table": "bin/seek-bzip-table" + } + }, + "node_modules/seek-bzip/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-query-params": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/serialize-query-params/-/serialize-query-params-2.0.4.tgz", + "integrity": "sha512-y9WzzDj3BsGgKLCh0ugiinufS//YqOfao/yVJjkXA4VLuyNCfHOLU/cbulGPxs3aeCqhvROw7qPL04JSZnCo0w==", + "license": "ISC" + }, + "node_modules/set-cookie-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz", + "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", + "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/split-on-first": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz", + "integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/streamx": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", + "integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-3.0.0.tgz", + "integrity": "sha512-I0sdgcFTfKQlUPZyAqPJmSG3HLO9rWDFnxonnIbskYNM3DwFOeTNB5KzVq3dA1GdRAc/25b5Y7UO2TQfKWw4aQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "inspect-with-kind": "^1.0.5", + "is-plain-obj": "^1.1.0" + } + }, + "node_modules/strip-dirs/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "license": "MIT" + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/super-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.1.0.tgz", + "integrity": "sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-timeout": "^1.0.1", + "make-asynchronous": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/system-architecture": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-1.0.0.tgz", + "integrity": "sha512-0OJWD12D7XX3KUg1DYkMaTTjSTo2k/mhIYI3HlBlceXSMcJhW/1qO735fPKS5prcyjvn57Ub151vvASYXpQrEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream/node_modules/b4a": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.9.0.tgz", + "integrity": "sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-decoder/node_modules/b4a": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.9.0.tgz", + "integrity": "sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", + "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "devOptional": true, + "license": "0BSD" + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/turbo": { + "version": "2.10.13", + "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.10.13.tgz", + "integrity": "sha512-69MkPbjk+G8oyC7pC2DeBk0rPdbLz51wuH5eAT0Q4BVJkzq/b1XM4kUUidsARbmDjwIELSJwd1ezITULY9kWNw==", + "dev": true, + "license": "MIT", + "bin": { + "turbo": "bin/turbo" + }, + "optionalDependencies": { + "@turbo/darwin-64": "2.10.13", + "@turbo/darwin-arm64": "2.10.13", + "@turbo/linux-64": "2.10.13", + "@turbo/linux-arm64": "2.10.13", + "@turbo/windows-64": "2.10.13", + "@turbo/windows-arm64": "2.10.13" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-function": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.1.0.tgz", + "integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/until-async": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz", + "integrity": "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/kettanaito" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-immer": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.11.0.tgz", + "integrity": "sha512-RNAqi3GqsWJ4bcCd4LMBgdzvPmTABam24DUaFiKfX9s3MSorNRz9RDZYJkllJoMHUxVLMDetwAuCDeyWNrp1yA==", + "license": "MIT", + "peerDependencies": { + "immer": ">=8.0.0", + "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/use-query-params": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/use-query-params/-/use-query-params-2.2.2.tgz", + "integrity": "sha512-OwGab8u8/x2xZp9uSyBsx0kXlkR9IR436zbygsYVGikPYY3OJosvve6IJVGwIJPcfyb/YHwvPrUNu65/JR++Kw==", + "license": "ISC", + "dependencies": { + "serialize-query-params": "^2.0.3" + }, + "peerDependencies": { + "@reach/router": "^1.2.1", + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "react-router-dom": ">=5" + }, + "peerDependenciesMeta": { + "@reach/router": { + "optional": true + }, + "react-router-dom": { + "optional": true + } + } + }, + "node_modules/use-resize-observer": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", + "integrity": "sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==", + "license": "MIT", + "dependencies": { + "@juggle/resize-observer": "^3.3.1" + }, + "peerDependencies": { + "react": "16.8.0 - 18", + "react-dom": "16.8.0 - 18" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz", + "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite-tsconfig-paths/node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vite-tsconfig-paths/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "extraneous": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vitest": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "extraneous": true, + "license": "MIT", + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.11", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "extraneous": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/vitest/node_modules/vite": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", + "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.11", - "@vitest/mocker": "4.1.11", - "@vitest/pretty-format": "4.1.11", - "@vitest/runner": "4.1.11", - "@vitest/snapshot": "4.1.11", - "@vitest/spy": "4.1.11", - "@vitest/utils": "4.1.11", - "es-module-lexer": "^2.0.0", - "expect-type": "^1.3.0", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.6", + "tinyglobby": "^0.2.17" }, "bin": { - "vitest": "vitest.mjs" + "vite": "bin/vite.js" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.11", - "@vitest/browser-preview": "4.1.11", - "@vitest/browser-webdriverio": "4.1.11", - "@vitest/coverage-istanbul": "4.1.11", - "@vitest/coverage-v8": "4.1.11", - "@vitest/ui": "4.1.11", - "happy-dom": "*", - "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "@edge-runtime/vm": { + "@types/node": { "optional": true }, - "@opentelemetry/api": { + "@vitejs/devtools": { "optional": true }, - "@types/node": { + "esbuild": { "optional": true }, - "@vitest/browser-playwright": { + "jiti": { "optional": true }, - "@vitest/browser-preview": { + "less": { "optional": true }, - "@vitest/browser-webdriverio": { + "sass": { "optional": true }, - "@vitest/coverage-istanbul": { + "sass-embedded": { "optional": true }, - "@vitest/coverage-v8": { + "stylus": { "optional": true }, - "@vitest/ui": { + "sugarss": { "optional": true }, - "happy-dom": { + "terser": { "optional": true }, - "jsdom": { + "tsx": { "optional": true }, - "vite": { - "optional": false + "yaml": { + "optional": true } } }, + "node_modules/vitest/node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "extraneous": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", @@ -11039,6 +17075,17 @@ "node": ">=18" } }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/web-worker": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", @@ -11060,7 +17107,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", "dev": true, "license": "MIT", "dependencies": { @@ -11134,6 +17180,22 @@ "node": ">=8" } }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -11193,17 +17255,17 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { @@ -11219,26 +17281,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } + "license": "ISC" }, "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -11256,6 +17309,22 @@ } } }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -11273,6 +17342,16 @@ "dev": true, "license": "MIT" }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -11283,39 +17362,102 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "license": "ISC", - "bin": { - "yaml": "bin.mjs" + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">= 14.6" + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/eemeli" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/yauzl": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.3.1.tgz", - "integrity": "sha512-RNPCUkiE/ZgO4w8i9U5yDQVHaFDdnzaFANElRvpJteCspvmv2VqrRb9lvS6odVD+jqI/zDsxAHJVsafpcheVQQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", "dev": true, "license": "MIT", "dependencies": { - "buffer-crc32": "~0.2.3", "pend": "~1.2.0" }, "engines": { "node": ">=12" } }, + "node_modules/ylru": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.4.0.tgz", + "integrity": "sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", "dev": true, "license": "MIT", "engines": { @@ -11326,9 +17468,9 @@ } }, "node_modules/zod": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz", - "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", + "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -11343,12 +17485,6 @@ "tslib": "2.3.0" } }, - "node_modules/zrender/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" - }, "node_modules/zustand": { "version": "4.5.7", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", @@ -11377,17 +17513,29 @@ } } }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "plugin-system": { "name": "@perses-dev/plugin-system", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "license": "Apache-2.0", "dependencies": { - "@module-federation/enhanced": "^2.8.0", - "@perses-dev/client": "0.55.0-beta.8", - "@perses-dev/components": "0.55.0-beta.8", + "@module-federation/enhanced": "^2.9.0", + "@perses-dev/client": "0.55.0-beta.11", + "@perses-dev/components": "0.55.0-beta.11", "@perses-dev/spec": "0.3.0-beta.8", "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", + "fast-uri": "3.1.6", "immer": "^10.1.1", "react-hook-form": "^7.87.0", "semver": "^7.8.0", diff --git a/package.json b/package.json index 20f5bdcd..41eea92c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "perses-shared", "description": "Monorepo for the Perses UI shared packages", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "private": true, "type": "module", "engines": { @@ -27,6 +27,7 @@ "workspaces": [ "components", "dashboards", + "design-tokens", "plugin-system", "explore", "client" diff --git a/plugin-system/package.json b/plugin-system/package.json index 09b129ae..e6e9a379 100644 --- a/plugin-system/package.json +++ b/plugin-system/package.json @@ -1,6 +1,6 @@ { "name": "@perses-dev/plugin-system", - "version": "0.55.0-beta.8", + "version": "0.55.0-beta.11", "description": "The plugin feature in Pereses", "license": "Apache-2.0", "homepage": "https://github.com/perses/perses/blob/main/README.md", @@ -29,12 +29,13 @@ "lint:fix": "oxlint --fix src" }, "dependencies": { - "@module-federation/enhanced": "^2.8.0", - "@perses-dev/client": "0.55.0-beta.8", - "@perses-dev/components": "0.55.0-beta.8", + "@module-federation/enhanced": "^2.9.0", + "@perses-dev/client": "0.55.0-beta.11", + "@perses-dev/components": "0.55.0-beta.11", "@perses-dev/spec": "0.3.0-beta.8", "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", + "fast-uri": "3.1.6", "immer": "^10.1.1", "react-hook-form": "^7.87.0", "semver": "^7.8.0", diff --git a/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.test.tsx b/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.test.tsx new file mode 100644 index 00000000..c386805a --- /dev/null +++ b/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.test.tsx @@ -0,0 +1,88 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { QueryPluginType } from '@perses-dev/spec'; +import { render, waitFor, cleanup } from '@testing-library/react'; + +import { MultiQueryEditor } from './MultiQueryEditor'; + +// Resolve the default query plugin so useDefaultQueryDefinition() can build a +// complete default query definition (kind + plugin kind + initial options). +vi.mock('../../runtime', () => ({ + useListPluginMetadata: vi.fn(() => ({ + data: [{ kind: 'AlertsQuery', spec: { name: 'AlertManagerAlertsQuery' } }], + isLoading: false, + })), + usePlugin: vi.fn(() => ({ + data: { createInitialOptions: (): { active: boolean } => ({ active: true }) }, + isLoading: false, + })), + usePluginRegistry: vi.fn(() => ({ defaultPluginKinds: { AlertsQuery: 'AlertManagerAlertsQuery' } })), +})); + +// Keep the test focused on MultiQueryEditor's persistence logic, not the child editor's rendering. +vi.mock('./QueryEditorContainer', () => ({ + QueryEditorContainer: (): null => null, +})); + +describe('MultiQueryEditor', () => { + afterEach(() => { + vi.clearAllMocks(); + cleanup(); + }); + + it('persists the default query when the panel has no queries', async () => { + const onChange = vi.fn(); + + render( + , + ); + + await waitFor(() => { + expect(onChange).toHaveBeenCalledWith([ + { + kind: 'AlertsQuery', + spec: { + plugin: { kind: 'AlertManagerAlertsQuery', spec: { active: true } }, + }, + }, + ]); + }); + }); + + it('does not overwrite queries that already exist', async () => { + const onChange = vi.fn(); + const existing = { + kind: 'AlertsQuery', + spec: { plugin: { kind: 'AlertManagerAlertsQuery', spec: { active: false } } }, + }; + + render( + , + ); + + // Give any effects a chance to run before asserting no persistence happened. + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(onChange).not.toHaveBeenCalled(); + }); +}); diff --git a/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.tsx b/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.tsx index 14297493..75250903 100644 --- a/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.tsx +++ b/plugin-system/src/components/MultiQueryEditor/MultiQueryEditor.tsx @@ -16,7 +16,7 @@ import type { QueryDefinition, QueryPluginType } from '@perses-dev/spec'; import { produce } from 'immer'; import AddIcon from 'mdi-material-ui/Plus'; import type { ReactElement } from 'react'; -import { forwardRef, useState } from 'react'; +import { forwardRef, useEffect, useState } from 'react'; import type { QueryData } from '../../runtime'; import { useListPluginMetadata, usePlugin, usePluginRegistry } from '../../runtime'; @@ -89,6 +89,15 @@ export const MultiQueryEditor = forwardRef false)); + // When a panel has no queries, MultiQueryEditor displays a default query (see queryDefinitions below), but that + // default is only visual until the user interacts with it. Persist it so panels whose default query needs no user + // input (e.g. alerts/silences) still have a query saved, and therefore run in view mode. + useEffect(() => { + if (queries.length === 0 && !isLoading && defaultInitialQueryDefinition.spec.plugin.kind !== '') { + onChange([defaultInitialQueryDefinition]); + } + }, [queries.length, isLoading, defaultInitialQueryDefinition, onChange]); + // Query handlers const handleQueryChange = (index: number, queryDef: QueryDefinition): void => { onChange( diff --git a/plugin-system/src/components/PanelSpecEditor/PanelSpecEditor.tsx b/plugin-system/src/components/PanelSpecEditor/PanelSpecEditor.tsx index 6f54c4e6..208f9ee0 100644 --- a/plugin-system/src/components/PanelSpecEditor/PanelSpecEditor.tsx +++ b/plugin-system/src/components/PanelSpecEditor/PanelSpecEditor.tsx @@ -54,7 +54,14 @@ export const PanelSpecEditor = forwardRef onJSONChange, } = props; const { kind } = panelDefinition.spec.plugin; - const { data: plugin, isLoading, error } = usePlugin('Panel', kind); + const { + data: plugin, + isLoading, + error, + } = usePlugin('Panel', kind, { + version: panelDefinition.spec.plugin.metadata?.version, + registry: panelDefinition.spec.plugin.metadata?.registry, + }); const { queryResults } = useDataQueriesContext(); diff --git a/plugin-system/src/components/PluginEditor/plugin-editor-api.ts b/plugin-system/src/components/PluginEditor/plugin-editor-api.ts index e9b00ee6..496451fb 100644 --- a/plugin-system/src/components/PluginEditor/plugin-editor-api.ts +++ b/plugin-system/src/components/PluginEditor/plugin-editor-api.ts @@ -12,7 +12,7 @@ // limitations under the License. import type { BoxProps } from '@mui/material'; -import type { DatasourceSpec, UnknownSpec } from '@perses-dev/spec'; +import type { DatasourceSpec, PluginDefinitionMetadata, UnknownSpec } from '@perses-dev/spec'; import { produce } from 'immer'; import { useState, useRef, useEffect } from 'react'; @@ -25,6 +25,12 @@ import type { PluginSpecEditorProps } from '../PluginSpecEditor'; export interface PluginEditorSelection { type: PluginType; kind: string; + /** + * Optional plugin definition metadata (version and/or registry), matching the `metadata` field of a spec + * `Definition`. Only set when the user explicitly picks a specific version/registry of a plugin that has several of + * them available. When omitted, the latest available version is used. + */ + metadata?: PluginDefinitionMetadata; } export interface PluginEditorValue { @@ -124,7 +130,16 @@ export function usePluginEditor(props: UsePluginEditorProps): { } }, [value.selection, defaultPluginKind]); - const { data: plugin, isFetching, error } = usePlugin(pendingSelection?.type, pendingSelection?.kind || ''); + // Load the pending plugin honoring the pinned version/registry, so the initial options come from the exact + // implementation the definition will use rather than from the latest one. + const { + data: plugin, + isFetching, + error, + } = usePlugin(pendingSelection?.type, pendingSelection?.kind || '', { + version: pendingSelection?.metadata?.version, + registry: pendingSelection?.metadata?.registry, + }); useEffect(() => { // Nothing to do if no new plugin kind is pending diff --git a/plugin-system/src/components/PluginKindSelect/PluginKindSelect.tsx b/plugin-system/src/components/PluginKindSelect/PluginKindSelect.tsx index 0fa3fa75..b04bddcc 100644 --- a/plugin-system/src/components/PluginKindSelect/PluginKindSelect.tsx +++ b/plugin-system/src/components/PluginKindSelect/PluginKindSelect.tsx @@ -13,11 +13,13 @@ import type { TextFieldProps } from '@mui/material'; import { MenuItem, TextField } from '@mui/material'; +import type { PluginDefinitionMetadata } from '@perses-dev/spec'; import type { ReactElement } from 'react'; import { forwardRef, useCallback, useMemo } from 'react'; -import type { PluginType } from '../../model'; +import type { PluginMetadataWithModule, PluginType } from '../../model'; import { useListPluginMetadata } from '../../runtime'; +import { comparePluginVersions } from '../../utils'; import type { PluginEditorSelection } from '../PluginEditor'; export interface PluginKindSelectProps extends Omit { @@ -25,6 +27,104 @@ export interface PluginKindSelectProps extends Omit void; + /** + * When true, a plugin that has more than one version available is listed with a ` - Latest` option and + * once per version, labeled ` - `. Selecting a specific version sets `metadata.version` on the + * selection so it can be persisted on the definition, while selecting Latest leaves the version unpinned. A plugin + * with a single available version is listed without a version, so it keeps resolving to the latest one. Defaults to + * false. + */ + enableVersionSelection?: boolean; + /** + * When true, a plugin that is available in more than one registry is listed once per registry, labeled + * ` ()`. Selecting such an option sets `metadata.registry` on the selection. A plugin + * available in a single registry is listed without it. Defaults to false. + */ + enableRegistrySelection?: boolean; +} + +/** A plugin kind grouped with all of the variants it is installed under. */ +interface PluginKindGroup { + type: PluginType; + kind: string; + displayName: string; + /** Available variants, sorted from the newest version to the oldest. */ + variants: PluginDefinitionMetadata[]; + hasMultipleVersions: boolean; + hasMultipleRegistries: boolean; +} + +/** A selectable entry of the select input. */ +interface PluginKindOption { + selection: PluginEditorSelection; + label: string; + /** Stringified `selection`, used as the MUI Select option value. */ + value: string; +} + +function getVariant(metadata: PluginMetadataWithModule): PluginDefinitionMetadata { + return { + version: metadata.metadata?.version ?? metadata.module?.version, + registry: metadata.metadata?.registry ?? metadata.module?.registry, + }; +} + +function getVariantKey(variant: PluginDefinitionMetadata): string { + return `${variant.version ?? ''}:${variant.registry ?? ''}`; +} + +/** + * Build the selectable entries of a plugin kind. A version (resp. registry) is only part of the entries when the caller + * enabled its selection *and* the plugin is actually installed in more than one version (resp. registry): there is + * nothing to pick otherwise, and leaving it out keeps the definition floating on the latest version. + */ +function getGroupOptions( + group: PluginKindGroup, + enableVersionSelection: boolean, + enableRegistrySelection: boolean, +): PluginKindOption[] { + const showVersion = enableVersionSelection && group.hasMultipleVersions; + const showRegistry = enableRegistrySelection && group.hasMultipleRegistries; + + if (!showVersion && !showRegistry) { + const selection: PluginEditorSelection = { type: group.type, kind: group.kind }; + return [{ selection, label: group.displayName, value: selectionToOptionValue(selection) }]; + } + + const options: PluginKindOption[] = []; + const seen = new Set(); + if (showVersion) { + const selection: PluginEditorSelection = { type: group.type, kind: group.kind }; + options.push({ + selection, + label: `${group.displayName} - Latest`, + value: selectionToOptionValue(selection), + }); + seen.add(getVariantKey({})); + } + for (const variant of group.variants) { + const version = showVersion ? variant.version : undefined; + const registry = showRegistry ? variant.registry : undefined; + const metadata: PluginDefinitionMetadata = { + ...(version ? { version } : {}), + ...(registry ? { registry } : {}), + }; + // Variants that only differ on a field we don't display collapse into a single entry. + const key = getVariantKey({ version, registry }); + if (seen.has(key)) { + continue; + } + seen.add(key); + + const selection: PluginEditorSelection = { + type: group.type, + kind: group.kind, + ...(version || registry ? { metadata } : {}), + }; + const label = `${group.displayName}${version ? ` - ${version}` : ''}${registry ? ` (${registry})` : ''}`; + options.push({ selection, label, value: selectionToOptionValue(selection) }); + } + return options; } /** @@ -35,21 +135,77 @@ export interface PluginKindSelectProps extends Omit { - const { pluginTypes, value: propValue, onChange, filteredQueryPlugins, ...others } = props; + const { + pluginTypes, + value: propValue, + onChange, + filteredQueryPlugins, + enableVersionSelection = false, + enableRegistrySelection = false, + ...others + } = props; const { data, isLoading } = useListPluginMetadata(pluginTypes); const sortedData = useMemo(() => { - if (filteredQueryPlugins?.length) { - return data - ?.filter((i) => filteredQueryPlugins.includes(i.spec.name)) - ?.toSorted((a, b) => a.spec.display.name.localeCompare(b.spec.display.name)); + const filtered = filteredQueryPlugins?.length + ? data?.filter((i) => filteredQueryPlugins.includes(i.spec.name)) + : data; + return filtered?.toSorted((a, b) => a.spec.display.name.localeCompare(b.spec.display.name)); + }, [data, filteredQueryPlugins]); + + // Group the metadata by plugin kind, collecting all the variants each one is installed under (newest version first). + const kindGroups = useMemo(() => { + const groups = new Map(); + for (const metadata of sortedData ?? []) { + const key = `${metadata.kind}:${metadata.spec.name}`; + let group = groups.get(key); + if (group === undefined) { + group = { + type: metadata.kind, + kind: metadata.spec.name, + displayName: metadata.spec.display.name, + variants: [], + hasMultipleVersions: false, + hasMultipleRegistries: false, + }; + groups.set(key, group); + } + const variant = getVariant(metadata); + if (!group.variants.some((existing) => getVariantKey(existing) === getVariantKey(variant))) { + group.variants.push(variant); + } } + for (const group of groups.values()) { + group.variants = group.variants.toSorted((a, b) => comparePluginVersions(b.version ?? '', a.version ?? '')); + group.hasMultipleVersions = new Set(group.variants.map((v) => v.version ?? '')).size > 1; + group.hasMultipleRegistries = new Set(group.variants.map((v) => v.registry ?? '')).size > 1; + } + return [...groups.values()]; + }, [sortedData]); - return data?.toSorted((a, b) => a.spec.display.name.localeCompare(b.spec.display.name)); - }, [data, filteredQueryPlugins]); + const options = useMemo( + () => kindGroups.flatMap((group) => getGroupOptions(group, enableVersionSelection, enableRegistrySelection)), + [kindGroups, enableVersionSelection, enableRegistrySelection], + ); + + const labelsByValue = useMemo(() => new Map(options.map((option) => [option.value, option.label])), [options]); // Pass an empty value while options are still loading so MUI doesn't complain about us using an "out of range" value - const value = !propValue || isLoading ? '' : selectionToOptionValue(propValue); + const value = useMemo(() => { + if (!propValue || isLoading) { + return ''; + } + const optionValue = selectionToOptionValue(propValue); + if (labelsByValue.has(optionValue)) { + return optionValue; + } + // The definition is not pinned (or is pinned to something we don't list): fall back to the first entry of that + // plugin kind, which is the one that will actually be used, so the Select has a matching value. + const fallback = options.find( + (option) => option.selection.type === propValue.type && option.selection.kind === propValue.kind, + ); + return fallback?.value ?? optionValue; + }, [propValue, isLoading, labelsByValue, options]); const handleChange = (event: { target: { value: string } }): void => { onChange?.(optionValueToSelection(event.target.value)); @@ -60,11 +216,16 @@ export const PluginKindSelect = forwardRef((props: PluginKindSelectProps, ref): if (selected === '') { return ''; } - const selectedValue = optionValueToSelection(selected as string); - return sortedData?.find((v) => v.kind === selectedValue.type && v.spec.name === selectedValue.kind)?.spec.display - .name; + const optionValue = selected as string; + const label = labelsByValue.get(optionValue); + if (label !== undefined) { + return label; + } + const selectedValue = optionValueToSelection(optionValue); + return kindGroups.find((group) => group.type === selectedValue.type && group.kind === selectedValue.kind) + ?.displayName; }, - [sortedData], + [labelsByValue, kindGroups], ); // TODO: Does this need a loading indicator of some kind? @@ -80,13 +241,9 @@ export const PluginKindSelect = forwardRef((props: PluginKindSelectProps, ref): data-testid="plugin-kind-select" > {isLoading && Loading...} - {sortedData?.map((metadata) => ( - - {metadata.spec.display.name} + {options.map((option) => ( + + {option.label} ))} @@ -98,28 +255,44 @@ PluginKindSelect.displayName = 'PluginKindSelect'; const OPTION_VALUE_DELIMITER = '_____'; /** - * Given a PluginEditorSelection, - * returns a string value like `{type}_____{kind}` that can be used as a Select input value. + * Given a PluginEditorSelection, returns a string value like `{type}_____{kind}` that can be used as a Select input + * value. A pinned version and/or registry is appended as `{type}_____{kind}_____{version}_____{registry}`, with empty + * segments for the parts that are not pinned. * @param selector */ function selectionToOptionValue(selector: PluginEditorSelection): string { - return [selector.type, selector.kind].join(OPTION_VALUE_DELIMITER); + const { version, registry } = selector.metadata ?? {}; + const parts = [selector.type, selector.kind]; + if (version || registry) { + parts.push(version ?? ''); + } + if (registry) { + parts.push(registry); + } + return parts.join(OPTION_VALUE_DELIMITER); } /** - * Given an option value name like `{type}_____{kind}`, - * returns a PluginEditorSelection to be used by the query data model. + * Given an option value name like `{type}_____{kind}` or `{type}_____{kind}_____{version}_____{registry}`, returns a + * PluginEditorSelection to be used by the query data model. * @param optionValue */ function optionValueToSelection(optionValue: string): PluginEditorSelection { const words = optionValue.split(OPTION_VALUE_DELIMITER); const type = words[0] as PluginType | undefined; const kind = words[1]; + const version = words[2]; + const registry = words[3]; if (type === undefined || kind === undefined) { throw new Error('Invalid optionValue string'); } + const metadata: PluginDefinitionMetadata = { + ...(version ? { version } : {}), + ...(registry ? { registry } : {}), + }; return { type, kind, + ...(version || registry ? { metadata } : {}), }; } diff --git a/plugin-system/src/components/PluginKindSelect/PluginKindSelect.versions.test.tsx b/plugin-system/src/components/PluginKindSelect/PluginKindSelect.versions.test.tsx new file mode 100644 index 00000000..02c5835f --- /dev/null +++ b/plugin-system/src/components/PluginKindSelect/PluginKindSelect.versions.test.tsx @@ -0,0 +1,184 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import type { PluginModuleResource } from '../../model'; +import { dynamicImportPluginLoader } from '../../model'; +import type { PluginEditorSelection } from '../PluginEditor'; +import { PluginRegistry } from '../PluginRegistry'; +import type { PluginKindSelectProps } from './PluginKindSelect'; +import { PluginKindSelect } from './PluginKindSelect'; + +/** A plugin module exposing a single Panel plugin, installed under the given version/registry. */ +function buildResource(pluginName: string, version: string, registry?: string): PluginModuleResource { + return { + kind: 'PluginModule', + metadata: { name: `${pluginName}-${registry ?? 'default'}-${version}`, version, registry }, + spec: { + plugins: [{ kind: 'Panel', spec: { name: pluginName, display: { name: pluginName } } }], + }, + }; +} + +// `Multi` is installed in three versions, `Single` in only one, and `Registries` once per registry. +const RESOURCES: PluginModuleResource[] = [ + buildResource('Multi', '1.0.0'), + buildResource('Multi', '2.0.0'), + buildResource('Multi', '1.10.0'), + buildResource('Single', '1.0.0'), + buildResource('Registries', '1.0.0', 'alpha'), + buildResource('Registries', '2.0.0', 'beta'), +]; + +function renderSelect(props: Omit): void { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + const pluginLoader = dynamicImportPluginLoader( + RESOURCES.map((resource) => ({ + resource, + // The select only needs the metadata, never the implementation. + importPlugin: (): Promise> => Promise.resolve({}), + })), + ); + render( + + + + + , + ); +} + +/** Opens the select and waits for the options to be loaded, returning their labels in display order. */ +async function openSelect(): Promise { + userEvent.click(screen.getByRole('combobox')); + const options = await screen.findAllByTestId('option'); + return options.map((option) => option.textContent ?? ''); +} + +describe('PluginKindSelect version and registry selection', () => { + it('lists a single entry per plugin kind by default, even when several versions are installed', async () => { + renderSelect({ value: undefined }); + + const labels = await openSelect(); + // One entry per kind, de-duplicated: no version suffix and no duplicated option. + expect(labels).toEqual(['Multi', 'Registries', 'Single']); + }); + + it('lists Latest then each version, newest first, when version selection is enabled', async () => { + renderSelect({ value: undefined, enableVersionSelection: true }); + + const labels = await openSelect(); + // `Multi` has several versions so Latest and each pinned version are selectable. Pinned versions are ordered with + // semver (1.10.0 sorts above 1.0.0, which a lexicographic comparison would get wrong). `Single` has one version + // only, so it stays version-less and keeps floating on the latest. + expect(labels).toEqual([ + 'Multi - Latest', + 'Multi - 2.0.0', + 'Multi - 1.10.0', + 'Multi - 1.0.0', + 'Registries - Latest', + 'Registries - 2.0.0', + 'Registries - 1.0.0', + 'Single', + ]); + }); + + it('emits the selected version as definition metadata', async () => { + let selection: PluginEditorSelection | undefined = undefined; + renderSelect({ value: undefined, enableVersionSelection: true, onChange: (s) => (selection = s) }); + + await openSelect(); + userEvent.click(screen.getByRole('option', { name: 'Multi - 1.0.0' })); + + expect(selection).toStrictEqual({ type: 'Panel', kind: 'Multi', metadata: { version: '1.0.0' } }); + }); + + it('leaves the version unpinned when Latest is selected', async () => { + let selection: PluginEditorSelection | undefined = undefined; + renderSelect({ value: undefined, enableVersionSelection: true, onChange: (s) => (selection = s) }); + + await openSelect(); + userEvent.click(screen.getByRole('option', { name: 'Multi - Latest' })); + + expect(selection).toStrictEqual({ type: 'Panel', kind: 'Multi' }); + }); + + it('does not pin anything when the plugin only has one version', async () => { + let selection: PluginEditorSelection | undefined = undefined; + renderSelect({ value: undefined, enableVersionSelection: true, onChange: (s) => (selection = s) }); + + await openSelect(); + userEvent.click(screen.getByRole('option', { name: 'Single' })); + + expect(selection).toStrictEqual({ type: 'Panel', kind: 'Single' }); + }); + + it('shows the version an existing definition is pinned to', async () => { + renderSelect({ + value: { type: 'Panel', kind: 'Multi', metadata: { version: '1.0.0' } }, + enableVersionSelection: true, + }); + + expect(await screen.findByText('Multi - 1.0.0')).toBeInTheDocument(); + }); + + it('shows Latest when the definition is not pinned', async () => { + renderSelect({ value: { type: 'Panel', kind: 'Multi' }, enableVersionSelection: true }); + + expect(await screen.findByText('Multi - Latest')).toBeInTheDocument(); + }); + + it('keeps a pin the select does not list rather than dropping it silently', async () => { + let selection: PluginEditorSelection | undefined = undefined; + renderSelect({ + // Version selection is disabled, so no version option exists, yet the definition is pinned. + value: { type: 'Panel', kind: 'Multi', metadata: { version: '1.0.0' } }, + onChange: (s) => (selection = s), + }); + + // The displayed value falls back to the plugin kind, and nothing changes until the user picks another option. + expect(await screen.findByText('Multi')).toBeInTheDocument(); + expect(selection).toBeUndefined(); + }); + + it('lists one entry per registry, and emits it, when registry selection is enabled', async () => { + let selection: PluginEditorSelection | undefined = undefined; + renderSelect({ value: undefined, enableRegistrySelection: true, onChange: (s) => (selection = s) }); + + const labels = await openSelect(); + // Only `Registries` is available in more than one registry, so it is the only kind listed per registry. + expect(labels).toEqual(['Multi', 'Registries (beta)', 'Registries (alpha)', 'Single']); + + userEvent.click(screen.getByRole('option', { name: 'Registries (alpha)' })); + expect(selection).toStrictEqual({ type: 'Panel', kind: 'Registries', metadata: { registry: 'alpha' } }); + }); + + it('combines version and registry when both selections are enabled', async () => { + renderSelect({ value: undefined, enableVersionSelection: true, enableRegistrySelection: true }); + + const labels = await openSelect(); + expect(labels).toEqual([ + 'Multi - Latest', + 'Multi - 2.0.0', + 'Multi - 1.10.0', + 'Multi - 1.0.0', + 'Registries - Latest', + 'Registries - 2.0.0 (beta)', + 'Registries - 1.0.0 (alpha)', + 'Single', + ]); + }); +}); diff --git a/plugin-system/src/components/PluginRegistry/PluginRegistry.dev.test.tsx b/plugin-system/src/components/PluginRegistry/PluginRegistry.dev.test.tsx new file mode 100644 index 00000000..44e06ca3 --- /dev/null +++ b/plugin-system/src/components/PluginRegistry/PluginRegistry.dev.test.tsx @@ -0,0 +1,88 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen } from '@testing-library/react'; +import type { ReactElement, ReactNode } from 'react'; + +import type { PluginModuleResource } from '../../model'; +import { dynamicImportPluginLoader } from '../../model'; +import { usePlugin } from '../../runtime'; +import { PluginRegistry } from './PluginRegistry'; + +const PLUGIN_NAME = 'TestVariable'; + +/** Builds a plugin module resource exposing a single Variable plugin, tagged as dev or installed. */ +function buildResource(version: string, inDev: boolean): PluginModuleResource { + return { + kind: 'PluginModule', + metadata: { name: `Module-${version}`, version }, + ...(inDev ? { status: { isLoaded: true, inDev: true } } : {}), + spec: { + plugins: [ + { + kind: 'Variable', + spec: { name: PLUGIN_NAME, display: { name: PLUGIN_NAME } }, + }, + ], + }, + }; +} + +/** The plugin implementation carries a marker so tests can tell which module was loaded. */ +function buildModule(source: string): Record { + return { [PLUGIN_NAME]: { createInitialOptions: () => ({}), source } }; +} + +// A dev plugin on an OLDER version than the installed one: this is the `percli plugin start` case where the +// plugin's package.json version is behind the installed archives. +const devResource = buildResource('1.0.0', true); +const installedResource = buildResource('2.0.0', false); + +function renderWithLoader(children: ReactNode): void { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + const pluginLoader = dynamicImportPluginLoader([ + { + resource: installedResource, + importPlugin: (): Promise> => Promise.resolve(buildModule('installed')), + }, + { + resource: devResource, + importPlugin: (): Promise> => Promise.resolve(buildModule('dev')), + }, + ]); + render( + + {children} + , + ); +} + +function Consumer({ version }: { version?: string }): ReactElement { + const { data, isLoading, error } = usePlugin('Variable', PLUGIN_NAME, version ? { version } : undefined); + if (isLoading) return
loading
; + if (error) return
error: {error.message}
; + return
source: {(data as unknown as { source?: string })?.source}
; +} + +describe('PluginRegistry dev plugin precedence', () => { + it('prefers a plugin served in dev over a newer installed one when no version is pinned', async () => { + renderWithLoader(); + expect(await screen.findByText('source: dev', undefined, { timeout: 3000 })).toBeInTheDocument(); + }); + + it('still honors an explicitly pinned version instead of the dev plugin', async () => { + renderWithLoader(); + expect(await screen.findByText('source: installed', undefined, { timeout: 3000 })).toBeInTheDocument(); + }); +}); diff --git a/plugin-system/src/components/PluginRegistry/PluginRegistry.tsx b/plugin-system/src/components/PluginRegistry/PluginRegistry.tsx index e8549145..570b264f 100644 --- a/plugin-system/src/components/PluginRegistry/PluginRegistry.tsx +++ b/plugin-system/src/components/PluginRegistry/PluginRegistry.tsx @@ -24,7 +24,7 @@ import type { DefaultPluginKinds, } from '../../model'; import { PluginRegistryContext } from '../../runtime'; -import { useEvent } from '../../utils'; +import { comparePluginVersions, useEvent } from '../../utils'; import { resolvePluginKeys } from './getPluginSearchHelper'; import type { PluginCompoundKey } from './plugin-indexes'; import { usePluginIndexes } from './plugin-indexes'; @@ -35,6 +35,47 @@ export interface PluginRegistryProps { children?: ReactNode; } +/** + * Returns the indexed key of a plugin served by a local dev server for the given plugin type and kind, if any. + * Keys are `${kind}:${name}:${registry}:${version}`, so we match on the `kind:name:` prefix. + */ +function findDevPluginKey(devPluginKeys: Set, kind: string, name: string): string | undefined { + const prefix = `${kind}:${name}:`; + for (const key of devPluginKeys) { + if (key.startsWith(prefix)) { + return key; + } + } + return undefined; +} + +/** + * Returns the indexed keys (`${kind}:${name}:${registry}:${version}`) matching *every* field supplied in the query. + * `kind` and `name` are always compared; `registry` and `version` are only compared when they are set, so a + * version-only pin matches whatever registry the plugin happens to be installed under, and a registry-only pin never + * leaks into another registry. Results are ordered from the newest version to the oldest. + */ +function findMatchingPluginKeys( + allKeys: Iterable, + query: PluginCompoundKey, +): string[] { + const { kind, name, registry, version } = query; + const prefix = `${kind}:${name}:`; + const matches: Array<{ key: string; version: string }> = []; + + for (const key of allKeys) { + if (!key.startsWith(prefix)) continue; + const parts = key.split(':'); + if (parts.length !== 4) continue; + const [, , keyRegistry, keyVersion] = parts; + if (registry !== undefined && keyRegistry !== registry) continue; + if (version !== undefined && keyVersion !== version) continue; + matches.push({ key, version: keyVersion ?? '' }); + } + + return matches.toSorted((a, b) => comparePluginVersions(b.version, a.version)).map((match) => match.key); +} + /** * PluginRegistryContext provider that keeps track of all available plugins and provides an API for getting them or * querying the metadata about them. @@ -68,12 +109,24 @@ export function PluginRegistry(props: PluginRegistryProps): ReactElement { const getPlugin = useCallback( async (compoundKeyObj: PluginCompoundKey): Promise> => { const pluginIndexes = await getPluginIndexes(); - const { kind, name } = compoundKeyObj; + const { kind, name, version, registry } = compoundKeyObj; + const allKeys = pluginIndexes.pluginResourcesByNameKindRegistryVersion.keys(); - const candidateKeys = resolvePluginKeys( - pluginIndexes.pluginResourcesByNameKindRegistryVersion.keys(), - compoundKeyObj, - ); + let candidateKeys: string[]; + if (version || registry) { + // A pin is an exact constraint: only the plugins matching every supplied field are acceptable, and we never + // silently fall back to another version or another registry. + candidateKeys = findMatchingPluginKeys(allKeys, compoundKeyObj); + } else { + candidateKeys = resolvePluginKeys(allKeys, compoundKeyObj); + // Nothing pinned: a plugin served by a local dev server (`percli plugin start`) wins over installed archives, + // whatever their versions. Otherwise a dev plugin whose package version is lower than an installed archive would + // never be used, which defeats the purpose of running it in dev. + const devKey = findDevPluginKey(pluginIndexes.devPluginKeys, kind, name); + if (devKey) { + candidateKeys = [devKey, ...candidateKeys.filter((key) => key !== devKey)]; + } + } for (const resourceKey of candidateKeys) { const resource = pluginIndexes.pluginResourcesByNameKindRegistryVersion.get(resourceKey); @@ -88,14 +141,26 @@ export function PluginRegistry(props: PluginRegistryProps): ReactElement { if (versionlessPlugin) return versionlessPlugin as PluginImplementation; } - throw new Error(`A ${name} plugin for kind '${kind}' is not installed`); + const pins = [ + version ? `version '${version}'` : undefined, + registry ? `registry '${registry}'` : undefined, + ].filter((pin) => pin !== undefined); + throw new Error( + pins.length > 0 + ? `A ${name} plugin for kind '${kind}' with ${pins.join(' and ')} is not installed` + : `A ${name} plugin for kind '${kind}' is not installed`, + ); }, [getPluginIndexes, loadPluginModule], ); const listPluginMetadata = useCallback( - async (pluginTypes: PluginType[]) => { + async (pluginTypes?: PluginType[]) => { const pluginIndexes = await getPluginIndexes(); + if (pluginTypes === undefined) { + // No filter: return the metadata of every installed plugin, whatever its type. + return [...pluginIndexes.pluginMetadataByKind.values()].flat(); + } return pluginTypes.flatMap((type) => pluginIndexes.pluginMetadataByKind.get(type) ?? []); }, [getPluginIndexes], diff --git a/plugin-system/src/components/PluginRegistry/PluginRegistry.versions.test.tsx b/plugin-system/src/components/PluginRegistry/PluginRegistry.versions.test.tsx new file mode 100644 index 00000000..cb5258c5 --- /dev/null +++ b/plugin-system/src/components/PluginRegistry/PluginRegistry.versions.test.tsx @@ -0,0 +1,92 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen } from '@testing-library/react'; +import type { ReactElement, ReactNode } from 'react'; + +import type { PluginModuleResource } from '../../model'; +import { dynamicImportPluginLoader } from '../../model'; +import { usePlugin } from '../../runtime'; +import { PluginRegistry } from './PluginRegistry'; + +const PLUGIN_NAME = 'TestVariable'; + +/** A plugin module exposing a single Variable plugin, installed under the given version/registry. */ +function buildResource(version: string, registry?: string): PluginModuleResource { + return { + kind: 'PluginModule', + metadata: { name: `Module-${registry ?? 'default'}-${version}`, version, registry }, + spec: { + plugins: [{ kind: 'Variable', spec: { name: PLUGIN_NAME, display: { name: PLUGIN_NAME } } }], + }, + }; +} + +/** The plugin implementation carries a marker so tests can tell which module was loaded. */ +function buildModule(source: string): Record { + return { [PLUGIN_NAME]: { createInitialOptions: () => ({}), source } }; +} + +function renderConsumer(children: ReactNode, resources: Array<[PluginModuleResource, string]>): void { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + const pluginLoader = dynamicImportPluginLoader( + resources.map(([resource, source]) => ({ + resource, + importPlugin: (): Promise> => Promise.resolve(buildModule(source)), + })), + ); + render( + + {children} + , + ); +} + +function Consumer({ version, registry }: { version?: string; registry?: string }): ReactElement { + const { data, isLoading, error } = usePlugin('Variable', PLUGIN_NAME, { version, registry }); + if (isLoading) return
loading
; + if (error) return
error: {error.message}
; + return
source: {(data as unknown as { source?: string })?.source}
; +} + +describe('PluginRegistry version and registry pinning', () => { + it('resolves a version-only pin even when the plugin is installed under a named registry', async () => { + // A version-only pin is what the panel editor produces. The plugin only exists in the `corp` registry, so building + // a synthetic registry-less key would make it look missing. + renderConsumer(, [ + [buildResource('1.0.0', 'corp'), 'corp-1.0.0'], + [buildResource('2.0.0', 'corp'), 'corp-2.0.0'], + ]); + expect(await screen.findByText('source: corp-1.0.0', undefined, { timeout: 3000 })).toBeInTheDocument(); + }); + + it('never falls back to another version when a version is pinned', async () => { + renderConsumer(, [[buildResource('1.0.0'), 'v1']]); + expect(await screen.findByText(/^error:/, undefined, { timeout: 3000 })).toHaveTextContent("version '3.0.0'"); + }); + + it('never falls back to another registry when a registry is pinned', async () => { + renderConsumer(, [[buildResource('1.0.0', 'community'), 'community']]); + expect(await screen.findByText(/^error:/, undefined, { timeout: 3000 })).toHaveTextContent("registry 'corp'"); + }); + + it('resolves the latest version inside the pinned registry', async () => { + renderConsumer(, [ + [buildResource('1.0.0', 'corp'), 'corp-1.0.0'], + [buildResource('2.0.0', 'corp'), 'corp-2.0.0'], + [buildResource('9.0.0', 'community'), 'community-9.0.0'], + ]); + expect(await screen.findByText('source: corp-2.0.0', undefined, { timeout: 3000 })).toBeInTheDocument(); + }); +}); diff --git a/plugin-system/src/components/PluginRegistry/plugin-indexes.ts b/plugin-system/src/components/PluginRegistry/plugin-indexes.ts index f5498fd4..ec7f2dfb 100644 --- a/plugin-system/src/components/PluginRegistry/plugin-indexes.ts +++ b/plugin-system/src/components/PluginRegistry/plugin-indexes.ts @@ -31,6 +31,8 @@ export interface PluginIndexes { pluginResourcesByNameKindRegistryVersion: Map; // Plugin metadata by plugin type pluginMetadataByKind: Map; + // Subset of the keys above that are served by a local dev server (`percli plugin start`) + devPluginKeys: Set; } /** @@ -47,6 +49,7 @@ export function usePluginIndexes( // Create the two indexes from the installed plugins const pluginResourcesByNameKindRegistryVersion = new Map(); const pluginMetadataByKind = new Map(); + const devPluginKeys = new Set(); for (const resource of installedPlugins) { const { @@ -65,6 +68,9 @@ export function usePluginIndexes( ); } pluginResourcesByNameKindRegistryVersion.set(key, resource); + if (resource.status?.inDev) { + devPluginKeys.add(key); + } // Index the metadata by plugin type let list = pluginMetadataByKind.get(kind); @@ -79,6 +85,7 @@ export function usePluginIndexes( return { pluginResourcesByNameKindRegistryVersion, pluginMetadataByKind, + devPluginKeys, }; }); diff --git a/plugin-system/src/components/PluginSpecEditor/PluginSpecEditor.tsx b/plugin-system/src/components/PluginSpecEditor/PluginSpecEditor.tsx index 322ba474..9e52dd6c 100644 --- a/plugin-system/src/components/PluginSpecEditor/PluginSpecEditor.tsx +++ b/plugin-system/src/components/PluginSpecEditor/PluginSpecEditor.tsx @@ -36,12 +36,20 @@ function isDatasourcePlugin( export function PluginSpecEditor(props: PluginSpecEditorProps): ReactElement | null { const { - pluginSelection: { type: pluginType, kind: pluginKind }, + pluginSelection: { type: pluginType, kind: pluginKind, metadata: pluginMetadata }, value, testConnection, ...others } = props; - const { data: plugin, isLoading, error } = usePlugin(pluginType, pluginKind); + // Edit the exact implementation the definition is pinned to, so the options editor matches the saved spec schema. + const { + data: plugin, + isLoading, + error, + } = usePlugin(pluginType, pluginKind, { + version: pluginMetadata?.version, + registry: pluginMetadata?.registry, + }); if (error) { return ; diff --git a/plugin-system/src/components/Variables/variable-model.ts b/plugin-system/src/components/Variables/variable-model.ts index e10db02d..69738126 100644 --- a/plugin-system/src/components/Variables/variable-model.ts +++ b/plugin-system/src/components/Variables/variable-model.ts @@ -90,7 +90,10 @@ function resolveDependsOnVariables( } export function useListVariablePluginValues(definition: ListVariableDefinition): UseQueryResult { - const { data: variablePlugin } = usePlugin('Variable', definition.spec.plugin.kind); + const { data: variablePlugin } = usePlugin('Variable', definition.spec.plugin.kind, { + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const variablePluginCtx = useVariablePluginContext(); @@ -133,7 +136,11 @@ export function useResolveListVariableValues(variableDefinitions: VariableDefini const pluginResults = usePlugins( 'Variable', - listVariables.map((d) => ({ kind: d.spec.plugin.kind })), + listVariables.map((d) => ({ + kind: d.spec.plugin.kind, + version: d.spec.plugin.metadata?.version, + registry: d.spec.plugin.metadata?.registry, + })), ); // Resolved variable state. Updated by onFetched when queries resolve. diff --git a/plugin-system/src/model/plugins.ts b/plugin-system/src/model/plugins.ts index 5bdb7bd8..09bd66b7 100644 --- a/plugin-system/src/model/plugins.ts +++ b/plugin-system/src/model/plugins.ts @@ -62,12 +62,24 @@ export interface PluginModuleMetadata { registry?: string; } +/** + * Status of a module/package that contains plugins, as reported by the Perses server. + */ +export interface PluginModuleStatus { + isLoaded?: boolean; + /** + * True when the module is served by a local dev server (`percli plugin start`) instead of an installed archive. + */ + inDev?: boolean; +} + /** * Information about a module/package that contains plugins. */ export interface PluginModuleResource { kind: 'PluginModule'; metadata: PluginModuleMetadata; + status?: PluginModuleStatus; spec: PluginModuleSpec; } diff --git a/plugin-system/src/remote/PluginRuntime.tsx b/plugin-system/src/remote/PluginRuntime.tsx index 5d7b10a0..440743b3 100644 --- a/plugin-system/src/remote/PluginRuntime.tsx +++ b/plugin-system/src/remote/PluginRuntime.tsx @@ -137,43 +137,43 @@ const getPluginRuntime = (): ModuleFederation => { }, }, '@perses-dev/client': { - version: '0.55.0-beta.8', + version: '0.55.0-beta.11', lib: () => getHostSharedModule('@perses-dev/client'), shareConfig: { singleton: true, - requiredVersion: '^0.55.0-beta.8', + requiredVersion: '^0.55.0-beta.11', }, }, '@perses-dev/components': { - version: '0.55.0-beta.8', + version: '0.55.0-beta.11', lib: () => getHostSharedModule('@perses-dev/components'), shareConfig: { singleton: true, - requiredVersion: '^0.55.0-beta.8', + requiredVersion: '^0.55.0-beta.11', }, }, '@perses-dev/plugin-system': { - version: '0.55.0-beta.8', + version: '0.55.0-beta.11', lib: () => getHostSharedModule('@perses-dev/plugin-system'), shareConfig: { singleton: true, - requiredVersion: '^0.55.0-beta.8', + requiredVersion: '^0.55.0-beta.11', }, }, '@perses-dev/explore': { - version: '0.55.0-beta.8', + version: '0.55.0-beta.11', lib: () => getHostSharedModule('@perses-dev/explore'), shareConfig: { singleton: true, - requiredVersion: '^0.55.0-beta.8', + requiredVersion: '^0.55.0-beta.11', }, }, '@perses-dev/dashboards': { - version: '0.55.0-beta.8', + version: '0.55.0-beta.11', lib: () => getHostSharedModule('@perses-dev/dashboards'), shareConfig: { singleton: true, - requiredVersion: '^0.55.0-beta.8', + requiredVersion: '^0.55.0-beta.11', }, }, // Below are the shared modules that are used by the plugins and are loaded asynchronously on demand using get rather than lib. diff --git a/plugin-system/src/runtime/alerts-queries.ts b/plugin-system/src/runtime/alerts-queries.ts index a765b391..0cc41af2 100644 --- a/plugin-system/src/runtime/alerts-queries.ts +++ b/plugin-system/src/runtime/alerts-queries.ts @@ -35,7 +35,11 @@ export function useAlertsQueries(definitions: AlertsQueryDefinition[]): Array ({ kind: d.spec.plugin.kind })), + definitions.map((d) => ({ + kind: d.spec.plugin.kind, + version: d.spec.plugin.metadata?.version, + registry: d.spec.plugin.metadata?.registry, + })), ); return useQueries({ @@ -51,7 +55,12 @@ export function useAlertsQueries(definitions: AlertsQueryDefinition[]): Array => { - const plugin = await getPlugin({ kind: ALERTS_QUERY_KEY, name: alertsQueryKind }); + const plugin = await getPlugin({ + kind: ALERTS_QUERY_KEY, + name: alertsQueryKind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const data = await plugin.getAlertsData(definition.spec.plugin.spec, context, signal); return data; }, diff --git a/plugin-system/src/runtime/annotations.ts b/plugin-system/src/runtime/annotations.ts index 85f8fdef..84b23cf3 100644 --- a/plugin-system/src/runtime/annotations.ts +++ b/plugin-system/src/runtime/annotations.ts @@ -75,7 +75,11 @@ export function useAnnotations(definitions: AnnotationSpec[]): Array ({ kind: d.plugin.kind })), + definitions.map((d) => ({ + kind: d.plugin.kind, + version: d.plugin.metadata?.version, + registry: d.plugin.metadata?.registry, + })), ); // useQueries() handles data fetching from query plugins @@ -92,7 +96,12 @@ export function useAnnotations(definitions: AnnotationSpec[]): Array => { - const plugin = await getPlugin({ kind: ANNOTATION_KEY, name: annotationKind }); + const plugin = await getPlugin({ + kind: ANNOTATION_KEY, + name: annotationKind, + version: definition.plugin.metadata?.version, + registry: definition.plugin.metadata?.registry, + }); const data = await plugin.getAnnotationData(definition.plugin.spec, context, signal); return data; }, @@ -102,7 +111,10 @@ export function useAnnotations(definitions: AnnotationSpec[]): Array { - const { data: annotationPlugin } = usePlugin('Annotation', spec.plugin.kind); + const { data: annotationPlugin } = usePlugin('Annotation', spec.plugin.kind, { + version: spec.plugin.metadata?.version, + registry: spec.plugin.metadata?.registry, + }); const datasourceStore = useDatasourceStore(); const allVariables = useAllVariableValues(); diff --git a/plugin-system/src/runtime/log-queries.ts b/plugin-system/src/runtime/log-queries.ts index a9cd6d80..3c97fa22 100644 --- a/plugin-system/src/runtime/log-queries.ts +++ b/plugin-system/src/runtime/log-queries.ts @@ -48,7 +48,12 @@ export function useLogQueries(definitions: LogQueryDefinition[]): Array => { - const plugin = await getPlugin({ kind: LOG_QUERY_KEY, name: logQueryKind }); + const plugin = await getPlugin({ + kind: LOG_QUERY_KEY, + name: logQueryKind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const data = await plugin.getLogData(definition.spec.plugin.spec, context, signal); return data; }, diff --git a/plugin-system/src/runtime/plugin-registry.ts b/plugin-system/src/runtime/plugin-registry.ts index a388550a..52490a67 100644 --- a/plugin-system/src/runtime/plugin-registry.ts +++ b/plugin-system/src/runtime/plugin-registry.ts @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { BuiltinVariableDefinition } from '@perses-dev/spec'; +import type { BuiltinVariableDefinition, PluginDefinitionMetadata } from '@perses-dev/spec'; import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; import { useQueries, useQuery } from '@tanstack/react-query'; import { createContext, useContext } from 'react'; @@ -26,7 +26,7 @@ import type { export interface PluginRegistryContextType { getPlugin(compoundKey: PluginCompoundKey): Promise>; - listPluginMetadata(pluginTypes: PluginType[]): Promise; + listPluginMetadata(pluginTypes?: PluginType[]): Promise; defaultPluginKinds?: DefaultPluginKinds; } @@ -44,59 +44,94 @@ export function usePluginRegistry(): PluginRegistryContextType { return ctx; } +type UsePluginQueryKey = [string, PluginType | undefined, string, string, string]; + // Allows consumers to pass useQuery options from react-query when loading a plugin type UsePluginOptions = Omit< - UseQueryOptions, Error, PluginImplementation, [string, PluginType | undefined, string]>, + UseQueryOptions, Error, PluginImplementation, UsePluginQueryKey>, 'queryKey' | 'queryFn' ->; +> & { + /** Pin resolution to a specific plugin version. When omitted, the latest available version is used. */ + version?: string; + /** Pin resolution to a specific plugin registry. */ + registry?: string; +}; /** * Loads a plugin and returns the plugin implementation, along with loading/error state. + * + * When `options.version` is provided, the plugin is resolved with an exact version match: if that version is not + * installed, the query fails instead of silently falling back to the latest available version. */ export function usePlugin( pluginType: T | undefined, kind: string, options?: UsePluginOptions, ): UseQueryResult, Error> { + const { version, registry, ...queryOptions } = options ?? {}; // We never want to ask for a plugin when the kind isn't set yet, so disable those queries automatically - options = { - ...options, - enabled: (options?.enabled ?? true) && pluginType !== undefined && kind !== '', + const useQueryOptions = { + ...queryOptions, + enabled: (queryOptions.enabled ?? true) && pluginType !== undefined && kind !== '', }; const { getPlugin } = usePluginRegistry(); return useQuery({ - queryKey: ['getPlugin', pluginType, kind], - queryFn: () => getPlugin({ kind: pluginType!, name: kind }), - ...options, + queryKey: ['getPlugin', pluginType, kind, version ?? '', registry ?? ''], + queryFn: () => getPlugin({ kind: pluginType!, name: kind, version, registry }), + ...useQueryOptions, }); } +/** + * A plugin reference to load, optionally pinned to a specific version/registry. + */ +export interface UsePluginsItem extends PluginDefinitionMetadata { + kind: string; +} + +/** + * Full identity of a plugin to load. Two definitions pinned to different versions (or registries) of the same kind are + * distinct plugins and must be loaded independently. + */ +function getUsePluginsItemIdentity(plugin: UsePluginsItem): string { + return `${plugin.kind}:${plugin.version ?? ''}:${plugin.registry ?? ''}`; +} + /** * Loads a list of plugins and returns the plugin implementation, along with loading/error state. */ export function usePlugins( pluginType: T, - plugins: Array<{ kind: string }>, + plugins: UsePluginsItem[], ): Array>> { const { getPlugin } = usePluginRegistry(); - // useQueries() does not support queries with duplicate keys, therefore we de-duplicate the plugin kinds before running useQueries() + // useQueries() does not support queries with duplicate keys, therefore we de-duplicate the plugins before running useQueries() // This resolves the following warning in the JS console: "[QueriesObserver]: Duplicate Queries found. This might result in unexpected behavior." // https://github.com/TanStack/query/issues/8224#issuecomment-2523554831 // https://github.com/TanStack/query/issues/4187#issuecomment-1256336901 - const kinds = [...new Set(plugins.map((p) => p.kind))]; + const uniquePlugins = new Map(); + for (const p of plugins) { + const key = getUsePluginsItemIdentity(p); + if (!uniquePlugins.has(key)) { + uniquePlugins.set(key, p); + } + } + const uniqueKeys = [...uniquePlugins.keys()]; + const uniqueValues = [...uniquePlugins.values()]; const result: Array>> = useQueries({ - queries: kinds.map((kind) => { + queries: uniqueValues.map((p) => { return { - queryKey: ['getPlugin', pluginType, kind], - queryFn: () => getPlugin({ kind: pluginType, name: kind }), + queryKey: ['getPlugin', pluginType, p.kind, p.version ?? '', p.registry ?? ''], + queryFn: () => getPlugin({ kind: pluginType, name: p.kind, version: p.version, registry: p.registry }), }; }), }); - // Re-assemble array in original order - return plugins.map((p) => result[kinds.indexOf(p.kind)]!); + // Re-assemble array in original order. Index lookups go through a Map so this stays linear on large panels. + const indexByIdentity = new Map(uniqueKeys.map((key, index) => [key, index])); + return plugins.map((p) => result[indexByIdentity.get(getUsePluginsItemIdentity(p))!]!); } // Allow consumers to pass useQuery options from react-query when listing metadata @@ -106,15 +141,17 @@ type UseListPluginMetadataOptions = Omit< >; /** - * Gets a list of plugin metadata for the specified plugin type and returns it, along with loading/error state. + * Gets a list of plugin metadata for the specified plugin types and returns it, along with loading/error state. When + * `pluginTypes` is omitted, the metadata of every installed plugin is returned, whatever its type. */ export function useListPluginMetadata( - pluginTypes: PluginType[], + pluginTypes?: PluginType[], options?: UseListPluginMetadataOptions, ): UseQueryResult { const { listPluginMetadata } = usePluginRegistry(); return useQuery({ - queryKey: ['listPluginMetadata', pluginTypes], + // `['*']` marks the "every plugin type" query so it gets its own cache entry. + queryKey: ['listPluginMetadata', pluginTypes ?? ['*']], queryFn: () => listPluginMetadata(pluginTypes), ...options, }); diff --git a/plugin-system/src/runtime/profile-queries.ts b/plugin-system/src/runtime/profile-queries.ts index 109e595c..45325b97 100644 --- a/plugin-system/src/runtime/profile-queries.ts +++ b/plugin-system/src/runtime/profile-queries.ts @@ -48,7 +48,12 @@ export function useProfileQueries(definitions: ProfileQueryDefinition[]): Array< refetchOnReconnect: false, staleTime: Infinity, queryFn: async ({ signal }: { signal?: AbortSignal }): Promise => { - const plugin = await getPlugin({ kind: PROFILE_QUERY_KEY, name: profileQueryKind }); + const plugin = await getPlugin({ + kind: PROFILE_QUERY_KEY, + name: profileQueryKind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const data = await plugin.getProfileData(definition.spec.plugin.spec, context, signal); return data; }, diff --git a/plugin-system/src/runtime/silences-queries.ts b/plugin-system/src/runtime/silences-queries.ts index 3bd0dfad..e06cb5ee 100644 --- a/plugin-system/src/runtime/silences-queries.ts +++ b/plugin-system/src/runtime/silences-queries.ts @@ -35,7 +35,11 @@ export function useSilencesQueries(definitions: SilencesQueryDefinition[]): Arra const pluginLoaderResponse = usePlugins( 'SilencesQuery', - definitions.map((d) => ({ kind: d.spec.plugin.kind })), + definitions.map((d) => ({ + kind: d.spec.plugin.kind, + version: d.spec.plugin.metadata?.version, + registry: d.spec.plugin.metadata?.registry, + })), ); return useQueries({ @@ -51,7 +55,12 @@ export function useSilencesQueries(definitions: SilencesQueryDefinition[]): Arra refetchOnReconnect: false, staleTime: 60_000, queryFn: async ({ signal }: { signal?: AbortSignal }): Promise => { - const plugin = await getPlugin({ kind: SILENCES_QUERY_KEY, name: silencesQueryKind }); + const plugin = await getPlugin({ + kind: SILENCES_QUERY_KEY, + name: silencesQueryKind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const data = await plugin.getSilencesData(definition.spec.plugin.spec, context, signal); return data; }, diff --git a/plugin-system/src/runtime/time-series-queries.ts b/plugin-system/src/runtime/time-series-queries.ts index c0beb082..f9c3bf7b 100644 --- a/plugin-system/src/runtime/time-series-queries.ts +++ b/plugin-system/src/runtime/time-series-queries.ts @@ -82,7 +82,10 @@ export const useTimeSeriesQuery = ( options?: UseTimeSeriesQueryOptions, queryOptions?: QueryObserverOptions, ): UseQueryResult => { - const { data: plugin } = usePlugin(TIME_SERIES_QUERY_KEY, definition.spec.plugin.kind); + const { data: plugin } = usePlugin(TIME_SERIES_QUERY_KEY, definition.spec.plugin.kind, { + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const context = useTimeSeriesQueryContext(); const { queryEnabled, queryKey } = getQueryOptions({ plugin, definition, context }); return useQuery({ @@ -117,7 +120,11 @@ export function useTimeSeriesQueries( const pluginLoaderResponse = usePlugins( TIME_SERIES_QUERY_KEY, - definitions.map((d) => ({ kind: d.spec.plugin.kind })), + definitions.map((d) => ({ + kind: d.spec.plugin.kind, + version: d.spec.plugin.metadata?.version, + registry: d.spec.plugin.metadata?.registry, + })), ); return useQueries({ queries: definitions.map((definition, idx) => { @@ -132,7 +139,12 @@ export function useTimeSeriesQueries( staleTime: Infinity, queryKey: queryKey, queryFn: async ({ signal }: { signal: AbortSignal }): Promise => { - const plugin = await getPlugin({ kind: TIME_SERIES_QUERY_KEY, name: definition.spec.plugin.kind }); + const plugin = await getPlugin({ + kind: TIME_SERIES_QUERY_KEY, + name: definition.spec.plugin.kind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const data = await plugin.getTimeSeriesData(definition.spec.plugin.spec, context, signal); return data; }, diff --git a/plugin-system/src/runtime/trace-queries.ts b/plugin-system/src/runtime/trace-queries.ts index 630a243c..70cc28cb 100644 --- a/plugin-system/src/runtime/trace-queries.ts +++ b/plugin-system/src/runtime/trace-queries.ts @@ -35,7 +35,11 @@ export function useTraceQueries(definitions: TraceQueryDefinition[]): Array ({ kind: d.spec.plugin.kind })), + definitions.map((d) => ({ + kind: d.spec.plugin.kind, + version: d.spec.plugin.metadata?.version, + registry: d.spec.plugin.metadata?.registry, + })), ); // useQueries() handles data fetching from query plugins (e.g. traceQL queries, promQL queries) @@ -53,7 +57,12 @@ export function useTraceQueries(definitions: TraceQueryDefinition[]): Array => { - const plugin = await getPlugin({ kind: TRACE_QUERY_KEY, name: traceQueryKind }); + const plugin = await getPlugin({ + kind: TRACE_QUERY_KEY, + name: traceQueryKind, + version: definition.spec.plugin.metadata?.version, + registry: definition.spec.plugin.metadata?.registry, + }); const data = await plugin.getTraceData(definition.spec.plugin.spec, context, signal); return data; }, diff --git a/plugin-system/src/runtime/variables.ts b/plugin-system/src/runtime/variables.ts index 09789960..1223e0bb 100644 --- a/plugin-system/src/runtime/variables.ts +++ b/plugin-system/src/runtime/variables.ts @@ -12,7 +12,7 @@ // limitations under the License. import type { VariableOption, VariableState, VariableStateMap } from '@perses-dev/components'; -import { parseVariables, replaceVariables } from '@perses-dev/components'; +import { parseVariables, replaceVariables, replaceVariablesInUrl } from '@perses-dev/components'; import { immerable } from 'immer'; import { createContext, useContext, useMemo } from 'react'; @@ -174,3 +174,18 @@ export function useReplaceVariablesInString(str: string | undefined): string | u if (!str) return undefined; return replaceVariables(str, variableValues); } + +/** + * Convenience hook for replacing variables in a URL, including those nested + * inside percent-encoded query parameters (e.g. Explore `data=%24var`). + * Prefer this over {@link useReplaceVariablesInString} for link hrefs. + */ +export function useReplaceVariablesInUrl(url: string | undefined): string | undefined { + const variableValues = useAllVariableValues(); + return useMemo(() => { + if (url === undefined || url === '') { + return url; + } + return replaceVariablesInUrl(url, variableValues); + }, [url, variableValues]); +} diff --git a/plugin-system/src/utils/index.ts b/plugin-system/src/utils/index.ts index 113242ee..fa75cc9b 100644 --- a/plugin-system/src/utils/index.ts +++ b/plugin-system/src/utils/index.ts @@ -12,5 +12,6 @@ // limitations under the License. export * from './event'; +export * from './plugin-versions'; export * from './variables'; export * from './csv-export'; diff --git a/plugin-system/src/utils/plugin-versions.test.ts b/plugin-system/src/utils/plugin-versions.test.ts new file mode 100644 index 00000000..5da02896 --- /dev/null +++ b/plugin-system/src/utils/plugin-versions.test.ts @@ -0,0 +1,48 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { comparePluginVersions, sortPluginVersionsDesc } from './plugin-versions'; + +describe('comparePluginVersions', () => { + test.each([ + ['1.0.0', '1.0.0', 0], + ['1.2.0', '1.1.9', 1], + ['1.1.0', '1.2.0', -1], + ['v2.0.0', '1.9.9', 1], + // Numeric, not lexicographic, comparison of each segment + ['0.10.0', '0.9.0', 1], + ['1.10.0', '1.9.0', 1], + // A pre-release orders below its stable release + ['1.0.0-beta', '1.0.0', -1], + ['1.0.0-rc.2', '1.0.0-rc.1', 1], + // Loose forms the backend also accepts + ['1.0', '1.0.0', 0], + // Anything unparseable orders below a real version so it can never be picked as "the latest" + ['not-a-version', '0.0.1', -1], + ['0.0.1', 'not-a-version', 1], + ])('comparePluginVersions(%s, %s)', (a, b, expected) => { + expect(Math.sign(comparePluginVersions(a as string, b as string))).toBe(expected); + }); + + test('two unparseable versions are compared lexicographically', () => { + expect(Math.sign(comparePluginVersions('abc', 'abd'))).toBe(-1); + }); +}); + +describe('sortPluginVersionsDesc', () => { + test('sorts from newest to oldest without mutating the input', () => { + const versions = ['1.0.0', '2.0.0-rc1', '1.10.0', '2.0.0']; + expect(sortPluginVersionsDesc(versions)).toEqual(['2.0.0', '2.0.0-rc1', '1.10.0', '1.0.0']); + expect(versions).toEqual(['1.0.0', '2.0.0-rc1', '1.10.0', '2.0.0']); + }); +}); diff --git a/plugin-system/src/utils/plugin-versions.ts b/plugin-system/src/utils/plugin-versions.ts new file mode 100644 index 00000000..427d1496 --- /dev/null +++ b/plugin-system/src/utils/plugin-versions.ts @@ -0,0 +1,58 @@ +// Copyright The Perses Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { SemVer } from 'semver'; +import { coerce, compare, parse } from 'semver'; + +/** + * Sentinel version meaning "the latest version available in the Perses instance". It mirrors the backend + * `plugin.LatestVersion` constant. A plugin definition using it is not pinned to an exact version: the plugin registry + * resolves it dynamically at load time. + */ +export const LATEST_PLUGIN_VERSION = 'latest'; + +/** + * Parse a plugin version with semver, tolerating the loose forms the backend also accepts (a leading `v`, a missing + * patch segment, ...). Returns `null` when the value cannot be understood as a version at all. + */ +function parsePluginVersion(version: string): SemVer | null { + return parse(version, { loose: true }) ?? coerce(version); +} + +/** + * Compare two plugin version strings with semver semantics, the same way the Perses backend orders plugin versions. + * Returns a positive number when `a` is greater than `b`, a negative number when it is lower, and 0 when they are equal. + * + * Pre-releases order below their stable release (`1.0.0-beta` < `1.0.0`), as semver mandates. Versions that cannot be + * parsed at all always order below parseable ones, and are compared lexicographically between themselves, so an + * unexpected value can never be picked as "the latest version". + */ +export function comparePluginVersions(a: string, b: string): number { + const parsedA = parsePluginVersion(a); + const parsedB = parsePluginVersion(b); + if (parsedA && parsedB) { + return compare(parsedA, parsedB); + } + if (parsedA) { + return 1; + } + if (parsedB) { + return -1; + } + return a.localeCompare(b); +} + +/** Return a new array of versions sorted from newest to oldest, using {@link comparePluginVersions}. */ +export function sortPluginVersionsDesc(versions: string[]): string[] { + return versions.toSorted((a, b) => comparePluginVersions(b, a)); +}