diff --git a/apps/client/src/features/app-settings/AppSettings.tsx b/apps/client/src/features/app-settings/AppSettings.tsx
index 28c0098f13..beefc05f7a 100644
--- a/apps/client/src/features/app-settings/AppSettings.tsx
+++ b/apps/client/src/features/app-settings/AppSettings.tsx
@@ -3,6 +3,7 @@ import { ErrorBoundary } from '@sentry/react';
import { useKeyDown } from '../../common/hooks/useKeyDown';
import AboutPanel from './panel/about-panel/AboutPanel';
+import AutomationsPanel from './panel/automations-panel/AutomationsPanel';
import ClientControlPanel from './panel/client-control-panel/ClientControlPanel';
import FeatureSettingsPanel from './panel/feature-settings-panel/FeatureSettingsPanel';
import GeneralPanel from './panel/general-panel/GeneralPanel';
@@ -31,6 +32,7 @@ export default function AppSettings() {
{panel === 'feature_settings' && }
{panel === 'sources' && }
{panel === 'integrations' && }
+ {panel === 'automations' && }
{panel === 'client_control' && }
{panel === 'about' && }
{panel === 'network' && }
diff --git a/apps/client/src/features/app-settings/panel-utils/PanelUtils.tsx b/apps/client/src/features/app-settings/panel-utils/PanelUtils.tsx
index 4020d73d61..69be8a6e55 100644
--- a/apps/client/src/features/app-settings/panel-utils/PanelUtils.tsx
+++ b/apps/client/src/features/app-settings/panel-utils/PanelUtils.tsx
@@ -44,16 +44,15 @@ export function Card({ children, className, ...props }: { children: ReactNode }
}
export function Table({ className, children }: { className?: string; children: ReactNode }) {
- const classes = cx([style.table, className]);
return (
);
}
-export function ListGroup({ children }: { children: ReactNode }) {
- return ;
+export function ListGroup({ className, children }: { className?: string; children: ReactNode }) {
+ return ;
}
export function ListItem({ children }: { children: ReactNode }) {
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationCard.module.scss b/apps/client/src/features/app-settings/panel/automations-panel/AutomationCard.module.scss
new file mode 100644
index 0000000000..566552bbf6
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationCard.module.scss
@@ -0,0 +1,20 @@
+.cardCollapsed {
+ display: flex;
+ gap: 1rem;
+}
+
+.append {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ top: -0.75rem;
+ background-color: $gray-900;
+ left: 0;
+ left: 50%;
+ height: 2rem; // match button height
+ transform: translateX(-50%);
+ padding-inline: 1rem;
+ border-radius: 99px;
+ font-size: calc(1rem - 2px);
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationCard.tsx b/apps/client/src/features/app-settings/panel/automations-panel/AutomationCard.tsx
new file mode 100644
index 0000000000..441feddd0e
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationCard.tsx
@@ -0,0 +1,22 @@
+import { PropsWithChildren, ReactNode } from 'react';
+
+import { cx } from '../../../../common/utils/styleUtils';
+import * as Panel from '../../panel-utils/PanelUtils';
+
+import style from './AutomationCard.module.scss';
+
+interface AutomationCardProps {
+ append: ReactNode;
+ className?: string;
+}
+
+export default function AutomationCard(props: PropsWithChildren) {
+ const { append, className, children } = props;
+
+ return (
+
+ {children}
+ {append}
+
+ );
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationItem.module.scss b/apps/client/src/features/app-settings/panel/automations-panel/AutomationItem.module.scss
new file mode 100644
index 0000000000..b45c3c4f7e
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationItem.module.scss
@@ -0,0 +1,34 @@
+.cardItems {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.fullWidth {
+ flex: 1;
+ align-items: center;
+}
+
+.cardCollapsed {
+ background-color: $gray-1350;
+ display: flex;
+ justify-content: space-between;
+}
+
+.cardExpanded {
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+}
+
+.threeCols {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 1rem;
+}
+
+.filterRow{
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr auto;
+ gap: 1rem;
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationItem.tsx b/apps/client/src/features/app-settings/panel/automations-panel/AutomationItem.tsx
new file mode 100644
index 0000000000..9cd168671a
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationItem.tsx
@@ -0,0 +1,133 @@
+import { PropsWithChildren, useState } from 'react';
+import { Button, ButtonGroup, IconButton, Input, Select } from '@chakra-ui/react';
+import { IoAdd } from '@react-icons/all-files/io5/IoAdd';
+import { IoChevronDown } from '@react-icons/all-files/io5/IoChevronDown';
+import { IoTrash } from '@react-icons/all-files/io5/IoTrash';
+
+import AutomationCard from './AutomationCard';
+import { cycles } from './automationUtils';
+
+import style from './AutomationItem.module.scss';
+
+interface AutomationCardProps {
+ title: string;
+ trigger: string;
+}
+
+export default function AutomationItem(props: AutomationCardProps) {
+ const { title, trigger } = props;
+ const [expanded, setExpanded] = useState(false);
+
+ return (
+
+
+
+ }
+ aria-label='Edit entry'
+ onClick={() => setExpanded((prev) => !prev)}
+ />
+ }
+ color='#FA5656'
+ aria-label='Delete entry'
+ onClick={() => setExpanded((prev) => !prev)}
+ />
+
+ {expanded && }
+
+ );
+}
+
+function AutomationCardExpanded(props: PropsWithChildren) {
+ const { title, trigger } = props;
+ const [triggerRole, setTriggerRole] = useState('all');
+
+ return (
+ <>
+
+
+
+
+
+ If
+
+
+
+
+ match
+ >
+ }
+ >
+
+
+
+
+ }
+ aria-label='Delete entry'
+ onClick={() => undefined}
+ />
+
+ }
+ aria-label='Add entry'
+ onClick={() => undefined}
+ />
+
+
+
+
+
+
+
+
+ }
+ aria-label='Add entry'
+ onClick={() => undefined}
+ />
+
+ >
+ );
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationManagement.module.scss b/apps/client/src/features/app-settings/panel/automations-panel/AutomationManagement.module.scss
new file mode 100644
index 0000000000..2f9e33d1b7
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationManagement.module.scss
@@ -0,0 +1,5 @@
+.list {
+ display: flex;
+ flex-direction: column;
+ gap: 3rem;
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationManagement.tsx b/apps/client/src/features/app-settings/panel/automations-panel/AutomationManagement.tsx
new file mode 100644
index 0000000000..7d528e1aae
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationManagement.tsx
@@ -0,0 +1,69 @@
+import { Button } from '@chakra-ui/react';
+import { TimerLifeCycle } from 'ontime-types';
+
+import * as Panel from '../../panel-utils/PanelUtils';
+
+import AutomationItem from './AutomationItem';
+
+import style from './AutomationManagement.module.scss';
+
+const data = [
+ {
+ id: '1',
+ title: 'Automation 1',
+ trigger: TimerLifeCycle.onClock,
+ filterRule: 'all',
+ filter: [],
+ output: [],
+ },
+ {
+ id: '2',
+ title: 'Automation 1',
+ trigger: TimerLifeCycle.onClock,
+ filterRule: 'all',
+ filter: [],
+ output: [],
+ },
+ {
+ id: '3',
+ title: 'Automation 1',
+ trigger: TimerLifeCycle.onClock,
+ filterRule: 'all',
+ filter: [],
+ output: [],
+ },
+];
+
+export default function AutomationManagement() {
+ return (
+
+
+ Manage automations
+
+
+
+
+
+
+
+
+ undefined}
+ onKeyDown={() => console.log('prevent escapee')}
+ >
+
+
+ {data.map((automation) => {
+ return ;
+ })}
+
+
+
+ );
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationSettings.tsx b/apps/client/src/features/app-settings/panel/automations-panel/AutomationSettings.tsx
new file mode 100644
index 0000000000..e4aace642b
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationSettings.tsx
@@ -0,0 +1,114 @@
+import { Controller, useForm } from 'react-hook-form';
+import { Button, Input, Switch } from '@chakra-ui/react';
+
+import { isOnlyNumbers } from '../../../../common/utils/regex';
+import * as Panel from '../../panel-utils/PanelUtils';
+
+interface AutomationSettingsOptions {
+ enabledIn: boolean;
+ portIn: number;
+}
+
+const automationSettingsPlaceholder = {
+ enabledIn: false,
+ portIn: 8888,
+};
+
+const style = {
+ flex: 'flex',
+};
+export default function AutomationSettings() {
+ const {
+ control,
+ handleSubmit,
+ reset,
+ register,
+ setError,
+ formState: { errors, isSubmitting, isDirty, isValid },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: automationSettingsPlaceholder,
+ values: automationSettingsPlaceholder,
+ resetOptions: {
+ keepDirtyValues: true,
+ },
+ });
+
+ return (
+
+
+ Automation settings
+
+
+
+
+
+
+
+
+ undefined}
+ onKeyDown={() => console.log('prevent escapee')}
+ >
+
+ OSC Input
+ {errors?.root && {errors.root.message}}
+
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+
+ Automation
+ {errors?.root && {errors.root.message}}
+
+
+
+ (
+
+ )}
+ />
+
+
+
+
+ );
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/AutomationsPanel.tsx b/apps/client/src/features/app-settings/panel/automations-panel/AutomationsPanel.tsx
new file mode 100644
index 0000000000..f038628fb8
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/AutomationsPanel.tsx
@@ -0,0 +1,42 @@
+import { Alert, AlertDescription, AlertIcon } from '@chakra-ui/react';
+
+import ExternalLink from '../../../../common/components/external-link/ExternalLink';
+import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';
+import type { PanelBaseProps } from '../../panel-list/PanelList';
+import * as Panel from '../../panel-utils/PanelUtils';
+
+import AutomationManagement from './AutomationManagement';
+import AutomationSettings from './AutomationSettings';
+
+const integrationDocsUrl = 'https://docs.getontime.no/api/integrations/';
+
+export default function IntegrationsPanel({ location }: PanelBaseProps) {
+ const oscRef = useScrollIntoView('osc', location);
+ const httpRef = useScrollIntoView('http', location);
+
+ return (
+ <>
+ Automation
+
+
+
+
+ Integrations allow Ontime to receive commands or send its data to other systems in your workflow.
+
+ Currently supported protocols are OSC (Open Sound Control), HTTP and Websockets.
+ WebSockets are used for Ontime and cannot be configured independently.
+ See the docs
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/apps/client/src/features/app-settings/panel/automations-panel/automationUtils.ts b/apps/client/src/features/app-settings/panel/automations-panel/automationUtils.ts
new file mode 100644
index 0000000000..95a0b6f62b
--- /dev/null
+++ b/apps/client/src/features/app-settings/panel/automations-panel/automationUtils.ts
@@ -0,0 +1,29 @@
+import { TimerLifeCycle } from 'ontime-types';
+
+type CycleLabel = {
+ id: number;
+ label: string;
+ value: keyof typeof TimerLifeCycle;
+};
+
+export const cycles: CycleLabel[] = [
+ { id: 1, label: 'On Load', value: 'onLoad' },
+ { id: 2, label: 'On Start', value: 'onStart' },
+ { id: 3, label: 'On Pause', value: 'onPause' },
+ { id: 4, label: 'On Stop', value: 'onStop' },
+ { id: 5, label: 'Every second', value: 'onClock' },
+ { id: 5, label: 'On Timer Update', value: 'onUpdate' },
+ { id: 6, label: 'On Finish', value: 'onFinish' },
+ { id: 7, label: 'On Warning', value: 'onWarning' },
+ { id: 8, label: 'On Danger', value: 'onDanger' },
+];
+
+export const field = [
+ { id: 1, label: 'Cue', value: 'cue' },
+ { id: 2, label: 'Title', value: 'title' },
+ { id: 3, label: 'Note', value: 'note' },
+ { id: 4, label: 'Custom', value: 'cue' },
+ { id: 5, label: 'Cue', value: 'cue' },
+ { id: 6, label: 'Cue', value: 'cue' },
+ { id: 7, label: 'Cue', value: 'cue' },
+];
diff --git a/apps/client/src/features/app-settings/useAppSettingsMenu.tsx b/apps/client/src/features/app-settings/useAppSettingsMenu.tsx
index 7f87b4d2db..a277ace683 100644
--- a/apps/client/src/features/app-settings/useAppSettingsMenu.tsx
+++ b/apps/client/src/features/app-settings/useAppSettingsMenu.tsx
@@ -54,6 +54,14 @@ const staticOptions = [
{ id: 'integrations__http', label: 'HTTP settings' },
],
},
+ {
+ id: 'automations',
+ label: 'Automations',
+ secondary: [
+ { id: 'automations__settings', label: 'Automation settings' },
+ { id: 'automations__manage', label: 'Manage automations' },
+ ],
+ },
{
id: 'network',
label: 'Network',
diff --git a/apps/server/package.json b/apps/server/package.json
index 9b5a8a7e23..d9ea798361 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -8,19 +8,19 @@
"@googleapis/sheets": "^5.0.5",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
- "express": "^4.18.2",
- "express-static-gzip": "^2.1.7",
- "express-validator": "^7.0.1",
+ "express": "^4.21.1",
+ "express-static-gzip": "^2.2.0",
+ "express-validator": "^7.2.0",
"fast-equals": "^5.0.1",
"google-auth-library": "^9.4.2",
- "got": "^14.0.0",
+ "got": "^14.4.5",
"lowdb": "^7.0.1",
"multer": "^1.4.5-lts.1",
- "node-osc": "^9.0.2",
+ "node-osc": "^9.1.4",
"ontime-utils": "workspace:*",
"sanitize-filename": "^1.6.3",
"steno": "^4.0.2",
- "ws": "^8.13.0",
+ "ws": "^8.18.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
@@ -28,7 +28,7 @@
"@types/express": "^4.17.17",
"@types/multer": "^1.4.11",
"@types/node": "catalog:",
- "@types/node-osc": "^6.0.2",
+ "@types/node-osc": "^6.0.3",
"@types/websocket": "^1.0.5",
"@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "catalog:",
@@ -40,10 +40,10 @@
"prettier": "catalog:",
"server-timing": "^3.3.3",
"shx": "^0.3.4",
- "ts-essentials": "^9.4.1",
- "tsx": "^4.16.2",
+ "ts-essentials": "^10.0.3",
+ "tsx": "^4.19.2",
"typescript": "catalog:",
- "vitest": "^1.6.0"
+ "vitest": "^2.1.5"
},
"scripts": {
"addversion": "node -p \"'export const ONTIME_VERSION = ' + JSON.stringify(require('../../package.json').version) + ';'\" > src/ONTIME_VERSION.js",
diff --git a/apps/server/src/api-data/automation/__tests__/automation.service.test.ts b/apps/server/src/api-data/automation/__tests__/automation.service.test.ts
new file mode 100644
index 0000000000..94ac375684
--- /dev/null
+++ b/apps/server/src/api-data/automation/__tests__/automation.service.test.ts
@@ -0,0 +1,240 @@
+import { TimerLifeCycle } from 'ontime-types';
+
+import {
+ clearAutomations,
+ Automation,
+ addAutomations,
+ getAutomations,
+ deleteAutomation,
+ editAutomation,
+ OSCOutput,
+ HTTPOutput,
+ CompanionOutput,
+ triggerAction,
+} from '../automation.service.js';
+
+import * as oscClient from '../clients/osc.client.js';
+import * as httpClient from '../clients/http.client.js';
+import * as companionClient from '../clients/companion.client.js';
+
+// mock event store
+vi.mock('../../../stores/EventStore.js', () => ({
+ eventStore: {
+ poll: vi.fn(),
+ },
+}));
+
+describe('addAutomations()', () => {
+ beforeEach(() => {
+ clearAutomations();
+ });
+
+ it('should accept a list of valid automations', () => {
+ const testData: Automation[] = [
+ {
+ id: Math.random().toString(),
+ title: 'test',
+ trigger: TimerLifeCycle.onLoad,
+ filterRule: 'all',
+ filter: [],
+ output: [makeOSCAction(), makeHTTPAction(), makeCompanionAction()],
+ },
+ ];
+
+ const result = addAutomations(testData);
+ expect(result).toMatchObject(testData);
+ });
+});
+
+describe('removeAutomation()', () => {
+ beforeEach(() => {
+ clearAutomations();
+ addAutomations([
+ {
+ id: 'test-osc',
+ title: 'test-osc',
+ trigger: TimerLifeCycle.onLoad,
+ filterRule: 'all',
+ filter: [],
+ output: [],
+ },
+ {
+ id: 'test-http',
+ title: 'test-http',
+ trigger: TimerLifeCycle.onFinish,
+ filterRule: 'all',
+ filter: [],
+ output: [],
+ },
+ {
+ id: 'test-companion',
+ title: 'test-companion',
+ trigger: TimerLifeCycle.onStop,
+ filterRule: 'all',
+ filter: [],
+ output: [],
+ },
+ ]);
+ });
+
+ it('should remove an automation from the list', () => {
+ const automations = getAutomations();
+ expect(automations.length).toEqual(3);
+ expect(automations[0].id).toEqual('test-osc');
+ expect(automations[0].title).toEqual('test-osc');
+
+ const removed = deleteAutomation('test-osc');
+ expect(removed.length).toEqual(2);
+ expect(removed[0].id).not.toEqual('test-osc');
+ expect(removed[0].title).not.toEqual('test-osc');
+ });
+});
+
+describe('editAutomation()', () => {
+ beforeEach(() => {
+ clearAutomations();
+ addAutomations([
+ {
+ id: 'test-osc',
+ title: 'test-osc',
+ trigger: TimerLifeCycle.onLoad,
+ filterRule: 'any',
+ filter: [],
+ output: [],
+ },
+ {
+ id: 'test-http',
+ title: 'test-http',
+ trigger: TimerLifeCycle.onFinish,
+ filterRule: 'any',
+ filter: [],
+ output: [],
+ },
+ {
+ id: 'test-companion',
+ title: 'test-companion',
+ trigger: TimerLifeCycle.onStop,
+ filterRule: 'any',
+ filter: [],
+ output: [],
+ },
+ ]);
+ });
+
+ it('should edit the contents of an automation', () => {
+ const automations = getAutomations();
+ expect(automations[0].title).toEqual('test-osc');
+
+ const editedOSC = editAutomation('test-osc', {
+ id: 'test-osc',
+ title: 'edited-title',
+ trigger: TimerLifeCycle.onDanger,
+ filterRule: 'any',
+ filter: [],
+ output: [],
+ });
+
+ expect(editedOSC[0]).toMatchObject({
+ id: 'test-osc',
+ title: 'edited-title',
+ trigger: TimerLifeCycle.onDanger,
+ });
+ });
+});
+
+describe('triggerAction()', () => {
+ beforeEach(() => {
+ clearAutomations();
+ addAutomations([
+ {
+ id: 'test-osc',
+ title: 'test-osc',
+ trigger: TimerLifeCycle.onLoad,
+ filterRule: 'any',
+ filter: [],
+ output: [makeOSCAction()],
+ },
+ {
+ id: 'test-http',
+ title: 'test-http',
+ trigger: TimerLifeCycle.onFinish,
+ filterRule: 'any',
+ filter: [],
+ output: [makeOSCAction(), makeHTTPAction()],
+ },
+ {
+ id: 'test-companion',
+ title: 'test-companion',
+ trigger: TimerLifeCycle.onStop,
+ filterRule: 'any',
+ filter: [],
+ output: [makeCompanionAction(), makeCompanionAction()],
+ },
+ ]);
+ });
+ it('should trigger automations for a given action', () => {
+ const oscSpy = vi.spyOn(oscClient, 'emitOSC');
+ const httpSpy = vi.spyOn(httpClient, 'emitHTTP');
+ const companionSpy = vi.spyOn(companionClient, 'emitCompanion');
+
+ triggerAction(TimerLifeCycle.onLoad);
+ expect(oscSpy).toHaveBeenCalledTimes(1);
+ expect(httpSpy).not.toBeCalled();
+ expect(companionSpy).not.toBeCalled();
+ oscSpy.mockReset();
+ httpSpy.mockReset();
+ companionSpy.mockReset();
+
+ triggerAction(TimerLifeCycle.onStart);
+ expect(oscSpy).not.toBeCalled();
+ expect(httpSpy).not.toBeCalled();
+ expect(companionSpy).not.toBeCalled();
+ oscSpy.mockReset();
+ httpSpy.mockReset();
+ companionSpy.mockReset();
+
+ triggerAction(TimerLifeCycle.onFinish);
+ expect(oscSpy).toHaveBeenCalledTimes(1);
+ expect(httpSpy).toHaveBeenCalledTimes(1);
+ expect(companionSpy).not.toBeCalled();
+ oscSpy.mockReset();
+ httpSpy.mockReset();
+ companionSpy.mockReset();
+
+ triggerAction(TimerLifeCycle.onStop);
+ expect(oscSpy).not.toBeCalled();
+ expect(httpSpy).not.toBeCalled();
+ expect(companionSpy).toHaveBeenCalledTimes(2);
+ });
+});
+
+function makeOSCAction(action?: Partial): OSCOutput {
+ return {
+ type: 'osc',
+ targetIP: 'localhost',
+ targetPort: 3000,
+ address: 'test',
+ args: 'message',
+ ...action,
+ };
+}
+
+function makeHTTPAction(action?: Partial): HTTPOutput {
+ return {
+ type: 'http',
+ targetIP: 'localhost',
+ address: 'test',
+ ...action,
+ };
+}
+
+function makeCompanionAction(action?: Partial): CompanionOutput {
+ return {
+ type: 'companion',
+ targetIP: 'localhost',
+ address: 'test',
+ page: 1,
+ bank: 1,
+ ...action,
+ };
+}
diff --git a/apps/server/src/api-data/automation/automation.controller.ts b/apps/server/src/api-data/automation/automation.controller.ts
new file mode 100644
index 0000000000..226b54de8e
--- /dev/null
+++ b/apps/server/src/api-data/automation/automation.controller.ts
@@ -0,0 +1,55 @@
+import { getErrorMessage } from 'ontime-utils';
+import { ErrorResponse } from 'ontime-types';
+
+import type { Request, Response } from 'express';
+
+import * as automationService from './automation.service.js';
+import { Automation, AutomationOutput } from './automation.service.js';
+
+export function getAutomations(_req: Request, res: Response) {
+ res.json(automationService.getAutomations());
+}
+
+export function postAutomation(req: Request, res: Response) {
+ try {
+ const automation = req.body as Automation;
+ const allAutomations = automationService.addAutomations([automation]);
+ res.status(201).send(allAutomations);
+ } catch (error) {
+ const message = getErrorMessage(error);
+ res.status(400).send({ message });
+ }
+}
+
+export function putAutomation(req: Request, res: Response) {
+ try {
+ const automation = req.body as Automation;
+ const allAutomations = automationService.addAutomations([automation]);
+ res.status(201).send(allAutomations);
+ } catch (error) {
+ const message = getErrorMessage(error);
+ res.status(400).send({ message });
+ }
+}
+
+export function deleteAutomation(req: Request, res: Response) {
+ try {
+ const id = req.params.id;
+ const allAutomations = automationService.deleteAutomation(id);
+ res.status(204).send(allAutomations);
+ } catch (error) {
+ const message = getErrorMessage(error);
+ res.status(400).send({ message });
+ }
+}
+
+export function testAutomation(req: Request, res: Response) {
+ try {
+ const payload = req.body as AutomationOutput;
+ automationService.testOutput(payload);
+ res.status(200).send();
+ } catch (error) {
+ const message = getErrorMessage(error);
+ res.status(400).send({ message });
+ }
+}
diff --git a/apps/server/src/api-data/automation/automation.router.ts b/apps/server/src/api-data/automation/automation.router.ts
new file mode 100644
index 0000000000..9d6c2faf31
--- /dev/null
+++ b/apps/server/src/api-data/automation/automation.router.ts
@@ -0,0 +1,21 @@
+import express from 'express';
+
+import {
+ deleteAutomation,
+ getAutomations,
+ postAutomation,
+ putAutomation,
+ testAutomation,
+} from './automation.controller.js';
+import { paramContainsAutomationId, validateAutomation, validateTestPayload } from './automation.validation.js';
+
+export const router = express.Router();
+
+router.get('/', getAutomations);
+router.get('/test', validateTestPayload, testAutomation);
+
+router.post('/', validateAutomation, postAutomation);
+
+router.put('/:automationId', paramContainsAutomationId, putAutomation);
+
+router.delete('/:automationId', paramContainsAutomationId, deleteAutomation);
diff --git a/apps/server/src/api-data/automation/automation.service.ts b/apps/server/src/api-data/automation/automation.service.ts
new file mode 100644
index 0000000000..6ef41dedbe
--- /dev/null
+++ b/apps/server/src/api-data/automation/automation.service.ts
@@ -0,0 +1,179 @@
+import { RuntimeStore, TimerLifeCycle } from 'ontime-types';
+
+import { eventStore } from '../../stores/EventStore.js';
+
+import { emitOSC } from './clients/osc.client.js';
+import { emitHTTP } from './clients/http.client.js';
+import { emitCompanion } from './clients/companion.client.js';
+
+export type FilterRule = 'all' | 'any';
+export type Automation = {
+ id: string;
+ title: string;
+ filterRule: FilterRule;
+ trigger: TimerLifeCycle;
+ filter: AutomationFilter[];
+ output: AutomationOutput[];
+};
+
+export type AutomationFilter = {
+ field: string; // this should be a key of a OntimeEvent + custom fields
+ operator: 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'contains';
+ value: string; // we use string but would coerce to the field value
+};
+
+export type AutomationOutput = OSCOutput | HTTPOutput | CompanionOutput;
+
+export type OSCOutput = {
+ type: 'osc';
+ targetIP: string;
+ targetPort: number;
+ address: string;
+ args: number | string;
+};
+
+export type HTTPOutput = {
+ type: 'http';
+ targetIP: string;
+ address: string;
+};
+
+export type CompanionOutput = {
+ type: 'companion';
+ targetIP: string;
+ address: string;
+ page: number;
+ bank: number;
+};
+
+let automations: Automation[] = [];
+
+export function clearAutomations(): Automation[] {
+ automations = [];
+ return automations;
+}
+
+export function getAutomations(): Automation[] {
+ return automations;
+}
+
+/**
+ * Receives a list of automation, which is parsed, validated and normalised
+ * @param automations
+ */
+export function addAutomations(newAutomations: Automation[]) {
+ automations.push(...newAutomations);
+ return automations;
+}
+
+/**
+ * Exposes a method for triggering actions based on a TimerLifeCycle event
+ */
+export function deleteAutomation(id: string) {
+ automations = automations.filter((automation) => automation.id !== id);
+ return automations;
+}
+
+/**
+ * Exposes a method for triggering actions based on a TimerLifeCycle event
+ */
+export function editAutomation(id: string, newAutomation: Automation) {
+ for (let i = 0; i < automations.length; i++) {
+ const automation = automations[i];
+ if (automation.id === id) {
+ automations[i] = newAutomation;
+ break;
+ }
+ }
+ return automations;
+}
+
+/**
+ * Exposes a method for triggering actions based on a TimerLifeCycle event
+ */
+export function triggerAction(event: TimerLifeCycle) {
+ const triggerAutomations = automations.filter((automation) => automation.trigger === event);
+ if (triggerAutomations.length === 0) {
+ return;
+ }
+
+ const state = eventStore.poll();
+ triggerAutomations.forEach((automation) => {
+ if (automation.output.length === 0) {
+ return;
+ }
+ const shouldSend = testConditions(automation.filter, automation.filterRule, state);
+ if (shouldSend) {
+ send(automation.output, state);
+ }
+ });
+}
+
+export function testOutput(payload: AutomationOutput) {
+ const state = eventStore.poll();
+ const success = send([payload], state);
+ if (!success) {
+ throw new Error('Failed to send output');
+ }
+}
+
+/**
+ * Checks whether the automation conditions are met
+ */
+export function testConditions(
+ filters: AutomationFilter[],
+ filterRule: FilterRule,
+ state: Partial,
+): boolean {
+ if (filters.length === 0) {
+ return true;
+ }
+
+ if (filterRule === 'all') {
+ return filters.every((filter) => evaluateCondition(filter));
+ }
+
+ return filters.some((filter) => evaluateCondition(filter));
+
+ function evaluateCondition(filter: AutomationFilter): boolean {
+ const { field, operator, value } = filter;
+ const fieldValue = state[field];
+
+ switch (operator) {
+ case 'equals':
+ return fieldValue === value;
+ case 'not_equals':
+ return fieldValue !== value;
+ case 'greater_than':
+ return fieldValue > value;
+ case 'less_than':
+ return fieldValue < value;
+ case 'contains':
+ return typeof fieldValue === 'string' && fieldValue.includes(value);
+ default:
+ return false;
+ }
+ }
+}
+
+/**
+ * Handles preparing and sending of the data
+ */
+function send(output: AutomationOutput[], _state: Partial): boolean {
+ output.forEach((payload) => {
+ if (payload.type === 'osc') {
+ emitOSC();
+ return true;
+ }
+ if (payload.type === 'http') {
+ emitHTTP();
+ return true;
+ }
+ if (payload.type === 'companion') {
+ emitCompanion();
+ return true;
+ }
+ return false;
+ });
+ return true;
+}
diff --git a/apps/server/src/api-data/automation/automation.utils.ts b/apps/server/src/api-data/automation/automation.utils.ts
new file mode 100644
index 0000000000..ee042d8dd9
--- /dev/null
+++ b/apps/server/src/api-data/automation/automation.utils.ts
@@ -0,0 +1,9 @@
+type FilterOperator = 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'contains';
+
+export function isFilterOperator(value: string): value is FilterOperator {
+ return ['equals', 'not_equals', 'greater_than', 'less_than', 'contains'].includes(value);
+}
+
+export function isFilterRule(value: string): value is 'all' | 'any' {
+ return value === 'all' || value === 'any';
+}
diff --git a/apps/server/src/api-data/automation/automation.validation.ts b/apps/server/src/api-data/automation/automation.validation.ts
new file mode 100644
index 0000000000..98b7d43fa3
--- /dev/null
+++ b/apps/server/src/api-data/automation/automation.validation.ts
@@ -0,0 +1,126 @@
+import { Request, Response, NextFunction } from 'express';
+import { body, param, validationResult } from 'express-validator';
+
+import * as assert from '../../utils/assert.js';
+
+import { isFilterOperator, isFilterRule } from './automation.utils.js';
+import type { Automation, AutomationFilter, AutomationOutput } from './automation.service.js';
+
+export const validateTestPayload = [
+ body('type').exists().isIn(['osc', 'http', 'companion']),
+
+ // validation for OSC message
+ body('targetIP').if(body('type').equals('osc')).isIP(),
+ body('targetPort').if(body('type').equals('osc')).isPort(),
+ body('address').if(body('type').equals('osc')).isString().trim(),
+ body('args').if(body('type').equals('osc')).isString().trim(),
+
+ // validation for HTTP message
+ body('targetIP').if(body('type').equals('http')).isIP(),
+ body('address').if(body('type').equals('http')).isString().trim(),
+
+ // validation for OSC message
+ body('targetIP').if(body('type').equals('companion')).isIP(),
+ body('address').if(body('type').equals('companion')).isString().trim(),
+ body('page').if(body('type').equals('companion')).isInt({ min: 0 }),
+ body('bank').if(body('type').equals('companion')).isInt({ min: 0 }),
+
+ (req: Request, res: Response, next: NextFunction) => {
+ const errors = validationResult(req);
+ if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
+ next();
+ },
+];
+
+export const validateAutomation = [
+ body().custom(parseAutomation),
+
+ (_req: Request, _res: Response, next: NextFunction) => {
+ next();
+ },
+];
+
+export const paramContainsAutomationId = [
+ param('automationId').exists(),
+
+ (req: Request, res: Response, next: NextFunction) => {
+ const errors = validationResult(req);
+ if (!errors.isEmpty()) return res.status(422).json({ errors: errors.array() });
+ next();
+ },
+];
+
+/**
+ * Parses and validates a potential automation entry
+ */
+export function parseAutomation(maybeAutomation: unknown): Automation {
+ assert.isObject(maybeAutomation);
+ assert.hasKeys(maybeAutomation, ['title', 'filterRule', 'filter', 'output']);
+
+ const { title, filterRule, filter, output } = maybeAutomation;
+ assert.isString(title);
+ assert.isString(filterRule);
+ if (!isFilterRule(filterRule)) {
+ throw new Error('Invalid automation');
+ }
+ assert.isArray(filter);
+ validateFilter(filter);
+
+ assert.isArray(output);
+ validateOutput(output);
+
+ return maybeAutomation as Automation;
+}
+
+function validateFilter(filter: Array): filter is AutomationFilter[] {
+ filter.forEach((condition) => {
+ assert.isObject(condition);
+
+ assert.hasKeys(condition, ['field', 'operator', 'value']);
+ const { field, operator, value } = condition;
+ assert.isString(field);
+ assert.isString(operator);
+ assert.isString(value);
+ !isFilterOperator(operator);
+
+ if (typeof value !== 'string' && typeof value !== 'number' && typeof value !== 'boolean') {
+ throw new Error('Invalid automation');
+ }
+ });
+ return true;
+}
+
+function validateOutput(output: Array): output is AutomationOutput[] {
+ output.forEach((payload) => {
+ assert.isObject(payload);
+ assert.hasKeys(payload, ['type']);
+ const { type } = payload;
+ assert.isString(type);
+
+ if (type === 'osc') {
+ assert.hasKeys(payload, ['targetIP', 'targetPort', 'address', 'args']);
+ const { targetIP, targetPort, address, args } = payload;
+ assert.isString(targetIP);
+ assert.isNumber(targetPort);
+ assert.isString(address);
+ if (typeof args !== 'string' && typeof args !== 'number') {
+ throw new Error('Invalid automation');
+ }
+ } else if (type === 'http') {
+ assert.hasKeys(payload, ['targetIP', 'address']);
+ const { targetIP, address } = payload;
+ assert.isString(targetIP);
+ assert.isString(address);
+ } else if (type === 'companion') {
+ assert.hasKeys(payload, ['targetIP', 'address', 'page', 'bank']);
+ const { targetIP, address, page, bank } = payload;
+ assert.isString(targetIP);
+ assert.isString(address);
+ assert.isNumber(page);
+ assert.isNumber(bank);
+ } else {
+ throw new Error('Invalid automation');
+ }
+ });
+ return true;
+}
diff --git a/apps/server/src/api-data/automation/clients/companion.client.ts b/apps/server/src/api-data/automation/clients/companion.client.ts
new file mode 100644
index 0000000000..cb1e03cd5f
--- /dev/null
+++ b/apps/server/src/api-data/automation/clients/companion.client.ts
@@ -0,0 +1,18 @@
+/**
+ * Expose possibility to trigger a companion button over the HTTP protocol
+ */
+export function emitCompanion() {
+ console.log('companion emit not implemented');
+ const payload = preparePayload();
+ emit(payload);
+}
+
+/** Parses the state and prepares payload to be emitted */
+function preparePayload() {
+ return;
+}
+
+/** Emits message over transport */
+function emit(_payload) {
+ return;
+}
diff --git a/apps/server/src/api-data/automation/clients/http.client.ts b/apps/server/src/api-data/automation/clients/http.client.ts
new file mode 100644
index 0000000000..6028f8bf31
--- /dev/null
+++ b/apps/server/src/api-data/automation/clients/http.client.ts
@@ -0,0 +1,18 @@
+/**
+ * Expose possibility to send a message using HTTP protocol
+ */
+export function emitHTTP() {
+ console.log('HTTP emit not implemented');
+ const payload = preparePayload();
+ emit(payload);
+}
+
+/** Parses the state and prepares payload to be emitted */
+function preparePayload() {
+ return;
+}
+
+/** Emits message over transport */
+function emit(_payload) {
+ return;
+}
diff --git a/apps/server/src/api-data/automation/clients/osc.client.ts b/apps/server/src/api-data/automation/clients/osc.client.ts
new file mode 100644
index 0000000000..b455b7d9e7
--- /dev/null
+++ b/apps/server/src/api-data/automation/clients/osc.client.ts
@@ -0,0 +1,18 @@
+/**
+ * Expose possibility to send a message using OSC protocol
+ */
+export function emitOSC() {
+ console.log('OSC emit not implemented');
+ const payload = preparePayload();
+ emit(payload);
+}
+
+/** Parses the state and prepares payload to be emitted */
+function preparePayload() {
+ return;
+}
+
+/** Emits message over transport */
+function emit(_payload) {
+ return;
+}
diff --git a/apps/server/src/utils/assert.ts b/apps/server/src/utils/assert.ts
index 47e68aa55e..1a9b9fb2e6 100644
--- a/apps/server/src/utils/assert.ts
+++ b/apps/server/src/utils/assert.ts
@@ -21,3 +21,20 @@ export function isObject(value: unknown): asserts value is object {
throw new Error(`Unexpected payload type: ${String(value)}`);
}
}
+
+export function isArray(value: unknown): asserts value is unknown[] {
+ if (!Array.isArray(value)) {
+ throw new Error(`Unexpected payload type: ${String(value)}`);
+ }
+}
+
+export function hasKeys(
+ value: T,
+ keys: K[],
+): asserts value is T & Record {
+ for (const key of keys) {
+ if (!(key in value)) {
+ throw new Error(`Key not found: ${String(key)}`);
+ }
+ }
+}
diff --git a/apps/spec/automations.md b/apps/spec/automations.md
new file mode 100644
index 0000000000..b1db7fcdf2
--- /dev/null
+++ b/apps/spec/automations.md
@@ -0,0 +1,49 @@
+# Automations
+
+The automation feature's purpose is to integrate ontime into users' workflows.
+Ontime has a large amount of production information, which users need considerable effort to maintain. We want to allow tools so that:
+
+- allow distribution of Ontime's and other production data
+- allow surfacing Ontime events
+- allow synchronizing with other tools
+
+## Previous
+Previous iterations imposed limitations on the number of integrations and target devices to evaluate performance concerns.
+
+The feature was not as used as we had hoped, and users often escalated the integration to tools like Companion.
+I believe this to be in part from a lack of clarity on the feature and the limitations imposed
+- Lack of explicit filtering logic made the process hard to reason
+- Users met limitations on target devices earlier than expected. We would want users to meet these limitations only when the project grew over a size where a show controller would be needed
+- Building the template strings was complex and poorly documented
+
+## Overview
+- The user should be able to create as many automations as they want
+- Automations are triggered by lifecycle events
+- Each automation should go through a user-defined filtering process
+- Each automation should be able to target multiple devices and multiple protocols
+- We leverage HTTP / OSC as the main protocols and add support for triggering Companion button presses
+- To allow easier debugging and "learn" workflows, users should be able to test a message before saving the automation
+- We should have inline documentation for the template strings
+
+## Implementation details
+- To simplify the usage of template strings, we will generate a list of template strings at runtime from the user project file
+- To allow easier implementation and extensions, we want to keep the automations separate from triggers
+
+```ts
+type Automation = {
+ id: AutomationId;
+ name: string;
+ filter: Filter[];
+ output: Output[];
+};
+
+type Trigger = {
+ id: string;
+ event: TimerLifecycle;
+ automations: AutomationId[];
+};
+
+```
+
+### Extension
+- Users have expressed a desire to have automation triggered by the lifecycle of a specific event. By keeping the trigger separate from the automation, we will allow this to be implemented in the future.
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2b2cff25ff..842e393dda 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -292,14 +292,14 @@ importers:
specifier: ^16.0.1
version: 16.0.3
express:
- specifier: ^4.18.2
- version: 4.18.2
+ specifier: ^4.21.1
+ version: 4.21.1
express-static-gzip:
- specifier: ^2.1.7
- version: 2.1.7
+ specifier: ^2.2.0
+ version: 2.2.0
express-validator:
- specifier: ^7.0.1
- version: 7.0.1
+ specifier: ^7.2.0
+ version: 7.2.0
fast-equals:
specifier: ^5.0.1
version: 5.0.1
@@ -307,8 +307,8 @@ importers:
specifier: ^9.4.2
version: 9.4.2
got:
- specifier: ^14.0.0
- version: 14.0.0
+ specifier: ^14.4.5
+ version: 14.4.5
lowdb:
specifier: ^7.0.1
version: 7.0.1
@@ -316,8 +316,8 @@ importers:
specifier: ^1.4.5-lts.1
version: 1.4.5-lts.1
node-osc:
- specifier: ^9.0.2
- version: 9.0.2
+ specifier: ^9.1.4
+ version: 9.1.4
ontime-utils:
specifier: workspace:*
version: link:../../packages/utils
@@ -328,8 +328,8 @@ importers:
specifier: ^4.0.2
version: 4.0.2
ws:
- specifier: ^8.13.0
- version: 8.13.0
+ specifier: ^8.18.0
+ version: 8.18.0
xlsx:
specifier: ^0.18.5
version: 0.18.5
@@ -347,8 +347,8 @@ importers:
specifier: 'catalog:'
version: 20.14.10
'@types/node-osc':
- specifier: ^6.0.2
- version: 6.0.2
+ specifier: ^6.0.3
+ version: 6.0.3
'@types/websocket':
specifier: ^1.0.5
version: 1.0.5
@@ -383,17 +383,17 @@ importers:
specifier: ^0.3.4
version: 0.3.4
ts-essentials:
- specifier: ^9.4.1
- version: 9.4.1(typescript@5.5.3)
+ specifier: ^10.0.3
+ version: 10.0.3(typescript@5.5.3)
tsx:
- specifier: ^4.16.2
- version: 4.16.2
+ specifier: ^4.19.2
+ version: 4.19.2
typescript:
specifier: 'catalog:'
version: 5.5.3
vitest:
- specifier: ^1.6.0
- version: 1.6.0(@types/node@20.14.10)(jsdom@21.1.0)(sass@1.57.1)
+ specifier: ^2.1.5
+ version: 2.1.5(@types/node@20.14.10)(jsdom@21.1.0)(sass@1.57.1)
packages/types:
devDependencies:
@@ -1192,9 +1192,9 @@ packages:
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.21.5':
- resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
- engines: {node: '>=12'}
+ '@esbuild/aix-ppc64@0.23.1':
+ resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
+ engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
@@ -1210,9 +1210,9 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.21.5':
- resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
- engines: {node: '>=12'}
+ '@esbuild/android-arm64@0.23.1':
+ resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [android]
@@ -1228,9 +1228,9 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.21.5':
- resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
- engines: {node: '>=12'}
+ '@esbuild/android-arm@0.23.1':
+ resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
+ engines: {node: '>=18'}
cpu: [arm]
os: [android]
@@ -1246,9 +1246,9 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.21.5':
- resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
- engines: {node: '>=12'}
+ '@esbuild/android-x64@0.23.1':
+ resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [android]
@@ -1264,9 +1264,9 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.21.5':
- resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
- engines: {node: '>=12'}
+ '@esbuild/darwin-arm64@0.23.1':
+ resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
@@ -1282,9 +1282,9 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.21.5':
- resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
- engines: {node: '>=12'}
+ '@esbuild/darwin-x64@0.23.1':
+ resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
@@ -1300,9 +1300,9 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.21.5':
- resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
- engines: {node: '>=12'}
+ '@esbuild/freebsd-arm64@0.23.1':
+ resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
@@ -1318,9 +1318,9 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.21.5':
- resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
- engines: {node: '>=12'}
+ '@esbuild/freebsd-x64@0.23.1':
+ resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
@@ -1336,9 +1336,9 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.21.5':
- resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
- engines: {node: '>=12'}
+ '@esbuild/linux-arm64@0.23.1':
+ resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
@@ -1354,9 +1354,9 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.21.5':
- resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
- engines: {node: '>=12'}
+ '@esbuild/linux-arm@0.23.1':
+ resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
+ engines: {node: '>=18'}
cpu: [arm]
os: [linux]
@@ -1372,9 +1372,9 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.21.5':
- resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
- engines: {node: '>=12'}
+ '@esbuild/linux-ia32@0.23.1':
+ resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
+ engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
@@ -1390,9 +1390,9 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.21.5':
- resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
- engines: {node: '>=12'}
+ '@esbuild/linux-loong64@0.23.1':
+ resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
+ engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
@@ -1408,9 +1408,9 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.21.5':
- resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
- engines: {node: '>=12'}
+ '@esbuild/linux-mips64el@0.23.1':
+ resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
+ engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
@@ -1426,9 +1426,9 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.21.5':
- resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
- engines: {node: '>=12'}
+ '@esbuild/linux-ppc64@0.23.1':
+ resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
+ engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
@@ -1444,9 +1444,9 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.21.5':
- resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
- engines: {node: '>=12'}
+ '@esbuild/linux-riscv64@0.23.1':
+ resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
+ engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
@@ -1462,9 +1462,9 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.21.5':
- resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
- engines: {node: '>=12'}
+ '@esbuild/linux-s390x@0.23.1':
+ resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
+ engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
@@ -1480,9 +1480,9 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.21.5':
- resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
- engines: {node: '>=12'}
+ '@esbuild/linux-x64@0.23.1':
+ resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [linux]
@@ -1498,12 +1498,18 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.21.5':
- resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
- engines: {node: '>=12'}
+ '@esbuild/netbsd-x64@0.23.1':
+ resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
+ '@esbuild/openbsd-arm64@0.23.1':
+ resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.19.10':
resolution: {integrity: sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==}
engines: {node: '>=12'}
@@ -1516,9 +1522,9 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.21.5':
- resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
- engines: {node: '>=12'}
+ '@esbuild/openbsd-x64@0.23.1':
+ resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
@@ -1534,9 +1540,9 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.21.5':
- resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
- engines: {node: '>=12'}
+ '@esbuild/sunos-x64@0.23.1':
+ resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
@@ -1552,9 +1558,9 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.21.5':
- resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
- engines: {node: '>=12'}
+ '@esbuild/win32-arm64@0.23.1':
+ resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
+ engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
@@ -1570,9 +1576,9 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.21.5':
- resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
- engines: {node: '>=12'}
+ '@esbuild/win32-ia32@0.23.1':
+ resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
+ engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
@@ -1588,9 +1594,9 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.21.5':
- resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
- engines: {node: '>=12'}
+ '@esbuild/win32-x64@0.23.1':
+ resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
+ engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -1665,6 +1671,9 @@ packages:
'@jridgewell/sourcemap-codec@1.4.15':
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
'@jridgewell/trace-mapping@0.3.20':
resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==}
@@ -1803,6 +1812,9 @@ packages:
cpu: [x64]
os: [win32]
+ '@sec-ant/readable-stream@0.4.1':
+ resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
+
'@sentry-internal/browser-utils@8.19.0':
resolution: {integrity: sha512-kM/2KlikKuBR63nFi2q7MGS3V9K9hakjvUknhr/jHZqDVfEuBKmp1ZlHFAdJtglKHHJy07gPj/XqDH7BbYh5yg==}
engines: {node: '>=14.18'}
@@ -1915,9 +1927,9 @@ packages:
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
- '@sindresorhus/is@6.1.0':
- resolution: {integrity: sha512-BuvU07zq3tQ/2SIgBsEuxKYDyDjC0n7Zir52bpHy2xnBbW81+po43aLFPLbeV3HRAheFbGud1qgcqSYfhtHMAg==}
- engines: {node: '>=16'}
+ '@sindresorhus/is@7.0.1':
+ resolution: {integrity: sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==}
+ engines: {node: '>=18'}
'@svgr/babel-plugin-add-jsx-attribute@8.0.0':
resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==}
@@ -2147,8 +2159,8 @@ packages:
'@types/multer@1.4.11':
resolution: {integrity: sha512-svK240gr6LVWvv3YGyhLlA+6LRRWA4mnGIU7RcNmgjBYFl6665wcXrRfxGp5tEPVHUNm5FMcmq7too9bxCwX/w==}
- '@types/node-osc@6.0.2':
- resolution: {integrity: sha512-/TxCH+NlDoI3hFA6b2O91dpnPAqBDkLb2HEIv5hMVdKnCiWTdJJv2sVnQdX38sBgnals8TjCQEGii+OcMVf2fg==}
+ '@types/node-osc@6.0.3':
+ resolution: {integrity: sha512-f0JUTDVAlk/mV9RH6jE6g/8Y7l+Mvi3f1x7xv0RG3VI1PktaXEd60mR+4plpMS9VbRovFoPsS7qaaIDhFXdaEw==}
'@types/node@20.14.10':
resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==}
@@ -2361,18 +2373,47 @@ packages:
'@vitest/expect@1.6.0':
resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
+ '@vitest/expect@2.1.5':
+ resolution: {integrity: sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==}
+
+ '@vitest/mocker@2.1.5':
+ resolution: {integrity: sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@2.1.5':
+ resolution: {integrity: sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==}
+
'@vitest/runner@1.6.0':
resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==}
+ '@vitest/runner@2.1.5':
+ resolution: {integrity: sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==}
+
'@vitest/snapshot@1.6.0':
resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==}
+ '@vitest/snapshot@2.1.5':
+ resolution: {integrity: sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==}
+
'@vitest/spy@1.6.0':
resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==}
+ '@vitest/spy@2.1.5':
+ resolution: {integrity: sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==}
+
'@vitest/utils@1.6.0':
resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==}
+ '@vitest/utils@2.1.5':
+ resolution: {integrity: sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==}
+
'@xmldom/xmldom@0.8.10':
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
engines: {node: '>=10.0.0'}
@@ -2519,6 +2560,10 @@ packages:
assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@@ -2582,8 +2627,8 @@ packages:
bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
- body-parser@1.20.1:
- resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
+ body-parser@1.20.3:
+ resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
boolean@3.2.0:
@@ -2647,9 +2692,9 @@ packages:
resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
engines: {node: '>=14.16'}
- cacheable-request@10.2.14:
- resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==}
- engines: {node: '>=14.16'}
+ cacheable-request@12.0.1:
+ resolution: {integrity: sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==}
+ engines: {node: '>=18'}
cacheable-request@7.0.4:
resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
@@ -2658,6 +2703,10 @@ packages:
call-bind@1.0.2:
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+ call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+ engines: {node: '>= 0.4'}
+
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -2677,6 +2726,10 @@ packages:
resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==}
engines: {node: '>=4'}
+ chai@5.1.2:
+ resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==}
+ engines: {node: '>=12'}
+
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@@ -2692,6 +2745,10 @@ packages:
check-error@1.0.3:
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+ check-error@2.1.1:
+ resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+ engines: {node: '>= 16'}
+
chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@@ -2786,10 +2843,6 @@ packages:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
- content-type@1.0.4:
- resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==}
- engines: {node: '>= 0.6'}
-
content-type@1.0.5:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
@@ -2803,8 +2856,8 @@ packages:
cookie-signature@1.0.6:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
- cookie@0.5.0:
- resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
+ cookie@0.7.1:
+ resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
engines: {node: '>= 0.6'}
copy-to-clipboard@3.3.3:
@@ -2904,6 +2957,15 @@ packages:
supports-color:
optional: true
+ debug@4.3.7:
+ resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
@@ -2915,6 +2977,10 @@ packages:
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
engines: {node: '>=6'}
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
deep-equal@2.2.0:
resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==}
@@ -2933,6 +2999,10 @@ packages:
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
engines: {node: '>= 0.4'}
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
define-properties@1.1.4:
resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==}
engines: {node: '>= 0.4'}
@@ -3057,6 +3127,10 @@ packages:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
@@ -3078,9 +3152,20 @@ packages:
resolution: {integrity: sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==}
engines: {node: '>= 0.4'}
+ es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
es-get-iterator@1.1.3:
resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+ es-module-lexer@1.5.4:
+ resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
+
es-set-tostringtag@2.0.1:
resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
engines: {node: '>= 0.4'}
@@ -3105,9 +3190,9 @@ packages:
engines: {node: '>=12'}
hasBin: true
- esbuild@0.21.5:
- resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
- engines: {node: '>=12'}
+ esbuild@0.23.1:
+ resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
+ engines: {node: '>=18'}
hasBin: true
escalade@3.1.1:
@@ -3270,19 +3355,23 @@ packages:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
+ expect-type@1.1.0:
+ resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
+ engines: {node: '>=12.0.0'}
+
expect@29.3.1:
resolution: {integrity: sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- express-static-gzip@2.1.7:
- resolution: {integrity: sha512-QOCZUC+lhPPCjIJKpQGu1Oa61Axg9Mq09Qvit8Of7kzpMuwDeMSqjjQteQS3OVw/GkENBoSBheuQDWPlngImvw==}
+ express-static-gzip@2.2.0:
+ resolution: {integrity: sha512-4ZQ0pHX0CAauxmzry2/8XFLM6aZA4NBvg9QezSlsEO1zLnl7vMFa48/WIcjzdfOiEUS4S1npPPKP2NHHYAp6qg==}
- express-validator@7.0.1:
- resolution: {integrity: sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==}
+ express-validator@7.2.0:
+ resolution: {integrity: sha512-I2ByKD8panjtr8Y05l21Wph9xk7kk64UMyvJCl/fFM/3CTJq8isXYPLeKW/aZBCdb/LYNv63PwhY8khw8VWocA==}
engines: {node: '>= 8.0.0'}
- express@4.18.2:
- resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
+ express@4.21.1:
+ resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==}
engines: {node: '>= 0.10.0'}
extend@3.0.2:
@@ -3337,8 +3426,8 @@ packages:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
- finalhandler@1.2.0:
- resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
+ finalhandler@1.3.1:
+ resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
engines: {node: '>= 0.8'}
find-root@1.1.0:
@@ -3481,6 +3570,10 @@ packages:
get-intrinsic@1.2.2:
resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
+ get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+ engines: {node: '>= 0.4'}
+
get-nonce@1.0.1:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
@@ -3489,14 +3582,14 @@ packages:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
- get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
-
get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
+ get-stream@9.0.1:
+ resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
+ engines: {node: '>=18'}
+
get-symbol-description@1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
@@ -3563,8 +3656,8 @@ packages:
resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
engines: {node: '>=10.19.0'}
- got@14.0.0:
- resolution: {integrity: sha512-X01vTgaX9SwaMq5DfImvS+3GMQFFs5HtrrlS9CuzUSzkxAf/tWGEyynuI+Qy7BjciMczZGjyVSmawYbP4eYhYA==}
+ got@14.4.5:
+ resolution: {integrity: sha512-sq+uET8TnNKRNnjEOPJzMcxeI0irT8BBNmf+GtZcJpmhYsQM1DSKmCROUjPWKsXZ5HzwD5Cf5/RV+QD9BSTxJg==}
engines: {node: '>=20'}
graceful-fs@4.2.11:
@@ -3591,6 +3684,9 @@ packages:
has-property-descriptors@1.0.1:
resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==}
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
engines: {node: '>= 0.4'}
@@ -3800,6 +3896,10 @@ packages:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ is-stream@4.0.1:
+ resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
+ engines: {node: '>=18'}
+
is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
@@ -3992,6 +4092,9 @@ packages:
loupe@2.3.7:
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ loupe@3.1.2:
+ resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
+
lowdb@7.0.1:
resolution: {integrity: sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw==}
engines: {node: '>=18'}
@@ -4026,6 +4129,9 @@ packages:
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
hasBin: true
+ magic-string@0.30.13:
+ resolution: {integrity: sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==}
+
magic-string@0.30.5:
resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==}
engines: {node: '>=12'}
@@ -4042,8 +4148,8 @@ packages:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
- merge-descriptors@1.0.1:
- resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+ merge-descriptors@1.0.3:
+ resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@@ -4200,9 +4306,9 @@ packages:
encoding:
optional: true
- node-osc@9.0.2:
- resolution: {integrity: sha512-q+VQL7DMWRL5+yvzRlWVig8BD9raotLs6onHU4e8MaFgxmYuIwcXhsvQeyUZFiKP6y/qGUXU6K0T99gVmISwmA==}
- engines: {node: ^18.17.0 || >=20.5.0}
+ node-osc@9.1.4:
+ resolution: {integrity: sha512-ChkdOHmy2Ay6egrGsL9C7u0RqBQ+VIHjw+lk6yd59TuyzmqbaosCo53E1lvjh1xM97c+ByBhyH6i2dHOiBa2bw==}
+ engines: {node: ^18.17.0 || ^20.5.0 || >=22.0.0}
node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
@@ -4215,8 +4321,8 @@ packages:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'}
- normalize-url@8.0.0:
- resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
+ normalize-url@8.0.1:
+ resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==}
engines: {node: '>=14.16'}
npm-run-path@5.1.0:
@@ -4233,6 +4339,10 @@ packages:
object-inspect@1.12.3:
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
+ object-inspect@1.13.3:
+ resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==}
+ engines: {node: '>= 0.4'}
+
object-is@1.1.5:
resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
engines: {node: '>= 0.4'}
@@ -4345,8 +4455,8 @@ packages:
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
engines: {node: '>=16 || 14 >=14.17'}
- path-to-regexp@0.1.7:
- resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+ path-to-regexp@0.1.10:
+ resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==}
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
@@ -4355,9 +4465,16 @@ packages:
pathe@1.1.1:
resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==}
+ pathe@1.1.2:
+ resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+
pathval@1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ pathval@2.0.0:
+ resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+ engines: {node: '>= 14.16'}
+
pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
@@ -4459,6 +4576,10 @@ packages:
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
engines: {node: '>=0.6'}
+ qs@6.13.0:
+ resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
+ engines: {node: '>=0.6'}
+
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
@@ -4476,8 +4597,8 @@ packages:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
- raw-body@2.5.1:
- resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
+ raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
engines: {node: '>= 0.8'}
react-clientside-effect@1.2.6:
@@ -4735,21 +4856,25 @@ packages:
engines: {node: '>=10'}
hasBin: true
- send@0.18.0:
- resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
+ send@0.19.0:
+ resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
engines: {node: '>= 0.8.0'}
serialize-error@7.0.1:
resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
engines: {node: '>=10'}
- serve-static@1.15.0:
- resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
+ serve-static@1.16.2:
+ resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
engines: {node: '>= 0.8.0'}
server-timing@3.3.3:
resolution: {integrity: sha512-TP0xWAca4oM8H/PSdeaGgp2qm+HrZ2cWCRcMXS2t500a7Wum/hSojlpTW43VZsIUSVNlKPFGDknH34IqF+mbBg==}
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
@@ -4774,6 +4899,10 @@ packages:
side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ side-channel@1.0.6:
+ resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+ engines: {node: '>= 0.4'}
+
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
@@ -4843,6 +4972,9 @@ packages:
std-env@3.6.0:
resolution: {integrity: sha512-aFZ19IgVmhdB2uX599ve2kE6BIE3YMnQ6Gp6BURhW/oIzpXGKr878TQfAQZn1+i0Flcc/UKUy1gOlcfaUBCryg==}
+ std-env@3.8.0:
+ resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
+
steno@4.0.2:
resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==}
engines: {node: '>=18'}
@@ -4945,14 +5077,32 @@ packages:
tinybench@2.5.1:
resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@0.3.1:
+ resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==}
+
tinypool@0.8.4:
resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==}
engines: {node: '>=14.0.0'}
+ tinypool@1.0.2:
+ resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@1.2.0:
+ resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
+ engines: {node: '>=14.0.0'}
+
tinyspy@2.2.0:
resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==}
engines: {node: '>=14.0.0'}
+ tinyspy@3.0.2:
+ resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
+ engines: {node: '>=14.0.0'}
+
tmp-promise@3.0.3:
resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
@@ -4995,10 +5145,10 @@ packages:
peerDependencies:
typescript: '>=4.2.0'
- ts-essentials@9.4.1:
- resolution: {integrity: sha512-oke0rI2EN9pzHsesdmrOrnqv1eQODmJpd/noJjwj2ZPC3Z4N2wbjrOEqnsEgmvlO2+4fBb0a794DCna2elEVIQ==}
+ ts-essentials@10.0.3:
+ resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==}
peerDependencies:
- typescript: '>=4.1.0'
+ typescript: '>=4.5.0'
peerDependenciesMeta:
typescript:
optional: true
@@ -5031,8 +5181,8 @@ packages:
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
- tsx@4.16.2:
- resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==}
+ tsx@4.19.2:
+ resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==}
engines: {node: '>=18.0.0'}
hasBin: true
@@ -5090,6 +5240,10 @@ packages:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
+ type-fest@4.27.1:
+ resolution: {integrity: sha512-3Ta7CyV6daqpwuGJMJKABaUChZZejpzysZkQg1//bLRg2wKQ4duwsg3MMIsHuElq58iDqizg4DBUmK8H8wExJg==}
+ engines: {node: '>=16'}
+
type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
@@ -5209,6 +5363,11 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
+ vite-node@2.1.5:
+ resolution: {integrity: sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
vite-plugin-compression2@0.12.0:
resolution: {integrity: sha512-9zdEF9xKVezETSF1l1bHoOk8LNoKIHB+DZVgSIGuGWaYupwFmsAGh0uwRcmK6rVHacxQRBECVYdtfc65DPDRfg==}
@@ -5278,6 +5437,31 @@ packages:
jsdom:
optional: true
+ vitest@2.1.5:
+ resolution: {integrity: sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 2.1.5
+ '@vitest/ui': 2.1.5
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
w3c-xmlserializer@4.0.0:
resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
engines: {node: '>=14'}
@@ -5339,6 +5523,11 @@ packages:
engines: {node: '>=8'}
hasBin: true
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
wmf@1.0.2:
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
engines: {node: '>=0.8'}
@@ -5370,6 +5559,18 @@ packages:
utf-8-validate:
optional: true
+ ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
+ 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
+
xlsx@0.18.5:
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
engines: {node: '>=0.8'}
@@ -6501,7 +6702,7 @@ snapshots:
'@esbuild/aix-ppc64@0.20.2':
optional: true
- '@esbuild/aix-ppc64@0.21.5':
+ '@esbuild/aix-ppc64@0.23.1':
optional: true
'@esbuild/android-arm64@0.19.10':
@@ -6510,7 +6711,7 @@ snapshots:
'@esbuild/android-arm64@0.20.2':
optional: true
- '@esbuild/android-arm64@0.21.5':
+ '@esbuild/android-arm64@0.23.1':
optional: true
'@esbuild/android-arm@0.19.10':
@@ -6519,7 +6720,7 @@ snapshots:
'@esbuild/android-arm@0.20.2':
optional: true
- '@esbuild/android-arm@0.21.5':
+ '@esbuild/android-arm@0.23.1':
optional: true
'@esbuild/android-x64@0.19.10':
@@ -6528,7 +6729,7 @@ snapshots:
'@esbuild/android-x64@0.20.2':
optional: true
- '@esbuild/android-x64@0.21.5':
+ '@esbuild/android-x64@0.23.1':
optional: true
'@esbuild/darwin-arm64@0.19.10':
@@ -6537,7 +6738,7 @@ snapshots:
'@esbuild/darwin-arm64@0.20.2':
optional: true
- '@esbuild/darwin-arm64@0.21.5':
+ '@esbuild/darwin-arm64@0.23.1':
optional: true
'@esbuild/darwin-x64@0.19.10':
@@ -6546,7 +6747,7 @@ snapshots:
'@esbuild/darwin-x64@0.20.2':
optional: true
- '@esbuild/darwin-x64@0.21.5':
+ '@esbuild/darwin-x64@0.23.1':
optional: true
'@esbuild/freebsd-arm64@0.19.10':
@@ -6555,7 +6756,7 @@ snapshots:
'@esbuild/freebsd-arm64@0.20.2':
optional: true
- '@esbuild/freebsd-arm64@0.21.5':
+ '@esbuild/freebsd-arm64@0.23.1':
optional: true
'@esbuild/freebsd-x64@0.19.10':
@@ -6564,7 +6765,7 @@ snapshots:
'@esbuild/freebsd-x64@0.20.2':
optional: true
- '@esbuild/freebsd-x64@0.21.5':
+ '@esbuild/freebsd-x64@0.23.1':
optional: true
'@esbuild/linux-arm64@0.19.10':
@@ -6573,7 +6774,7 @@ snapshots:
'@esbuild/linux-arm64@0.20.2':
optional: true
- '@esbuild/linux-arm64@0.21.5':
+ '@esbuild/linux-arm64@0.23.1':
optional: true
'@esbuild/linux-arm@0.19.10':
@@ -6582,7 +6783,7 @@ snapshots:
'@esbuild/linux-arm@0.20.2':
optional: true
- '@esbuild/linux-arm@0.21.5':
+ '@esbuild/linux-arm@0.23.1':
optional: true
'@esbuild/linux-ia32@0.19.10':
@@ -6591,7 +6792,7 @@ snapshots:
'@esbuild/linux-ia32@0.20.2':
optional: true
- '@esbuild/linux-ia32@0.21.5':
+ '@esbuild/linux-ia32@0.23.1':
optional: true
'@esbuild/linux-loong64@0.19.10':
@@ -6600,7 +6801,7 @@ snapshots:
'@esbuild/linux-loong64@0.20.2':
optional: true
- '@esbuild/linux-loong64@0.21.5':
+ '@esbuild/linux-loong64@0.23.1':
optional: true
'@esbuild/linux-mips64el@0.19.10':
@@ -6609,7 +6810,7 @@ snapshots:
'@esbuild/linux-mips64el@0.20.2':
optional: true
- '@esbuild/linux-mips64el@0.21.5':
+ '@esbuild/linux-mips64el@0.23.1':
optional: true
'@esbuild/linux-ppc64@0.19.10':
@@ -6618,7 +6819,7 @@ snapshots:
'@esbuild/linux-ppc64@0.20.2':
optional: true
- '@esbuild/linux-ppc64@0.21.5':
+ '@esbuild/linux-ppc64@0.23.1':
optional: true
'@esbuild/linux-riscv64@0.19.10':
@@ -6627,7 +6828,7 @@ snapshots:
'@esbuild/linux-riscv64@0.20.2':
optional: true
- '@esbuild/linux-riscv64@0.21.5':
+ '@esbuild/linux-riscv64@0.23.1':
optional: true
'@esbuild/linux-s390x@0.19.10':
@@ -6636,7 +6837,7 @@ snapshots:
'@esbuild/linux-s390x@0.20.2':
optional: true
- '@esbuild/linux-s390x@0.21.5':
+ '@esbuild/linux-s390x@0.23.1':
optional: true
'@esbuild/linux-x64@0.19.10':
@@ -6645,7 +6846,7 @@ snapshots:
'@esbuild/linux-x64@0.20.2':
optional: true
- '@esbuild/linux-x64@0.21.5':
+ '@esbuild/linux-x64@0.23.1':
optional: true
'@esbuild/netbsd-x64@0.19.10':
@@ -6654,7 +6855,10 @@ snapshots:
'@esbuild/netbsd-x64@0.20.2':
optional: true
- '@esbuild/netbsd-x64@0.21.5':
+ '@esbuild/netbsd-x64@0.23.1':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.23.1':
optional: true
'@esbuild/openbsd-x64@0.19.10':
@@ -6663,7 +6867,7 @@ snapshots:
'@esbuild/openbsd-x64@0.20.2':
optional: true
- '@esbuild/openbsd-x64@0.21.5':
+ '@esbuild/openbsd-x64@0.23.1':
optional: true
'@esbuild/sunos-x64@0.19.10':
@@ -6672,7 +6876,7 @@ snapshots:
'@esbuild/sunos-x64@0.20.2':
optional: true
- '@esbuild/sunos-x64@0.21.5':
+ '@esbuild/sunos-x64@0.23.1':
optional: true
'@esbuild/win32-arm64@0.19.10':
@@ -6681,7 +6885,7 @@ snapshots:
'@esbuild/win32-arm64@0.20.2':
optional: true
- '@esbuild/win32-arm64@0.21.5':
+ '@esbuild/win32-arm64@0.23.1':
optional: true
'@esbuild/win32-ia32@0.19.10':
@@ -6690,7 +6894,7 @@ snapshots:
'@esbuild/win32-ia32@0.20.2':
optional: true
- '@esbuild/win32-ia32@0.21.5':
+ '@esbuild/win32-ia32@0.23.1':
optional: true
'@esbuild/win32-x64@0.19.10':
@@ -6699,7 +6903,7 @@ snapshots:
'@esbuild/win32-x64@0.20.2':
optional: true
- '@esbuild/win32-x64@0.21.5':
+ '@esbuild/win32-x64@0.23.1':
optional: true
'@eslint-community/eslint-utils@4.4.0(eslint@8.56.0)':
@@ -6781,6 +6985,8 @@ snapshots:
'@jridgewell/sourcemap-codec@1.4.15': {}
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
'@jridgewell/trace-mapping@0.3.20':
dependencies:
'@jridgewell/resolve-uri': 3.1.1
@@ -6885,6 +7091,8 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.17.2':
optional: true
+ '@sec-ant/readable-stream@0.4.1': {}
+
'@sentry-internal/browser-utils@8.19.0':
dependencies:
'@sentry/core': 8.19.0
@@ -7017,7 +7225,7 @@ snapshots:
'@sindresorhus/is@4.6.0': {}
- '@sindresorhus/is@6.1.0': {}
+ '@sindresorhus/is@7.0.1': {}
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.23.6)':
dependencies:
@@ -7291,7 +7499,7 @@ snapshots:
dependencies:
'@types/express': 4.17.17
- '@types/node-osc@6.0.2':
+ '@types/node-osc@6.0.3':
dependencies:
'@types/node': 20.14.10
@@ -7587,22 +7795,56 @@ snapshots:
'@vitest/utils': 1.6.0
chai: 4.3.10
+ '@vitest/expect@2.1.5':
+ dependencies:
+ '@vitest/spy': 2.1.5
+ '@vitest/utils': 2.1.5
+ chai: 5.1.2
+ tinyrainbow: 1.2.0
+
+ '@vitest/mocker@2.1.5(vite@5.2.11(@types/node@20.14.10)(sass@1.57.1))':
+ dependencies:
+ '@vitest/spy': 2.1.5
+ estree-walker: 3.0.3
+ magic-string: 0.30.13
+ optionalDependencies:
+ vite: 5.2.11(@types/node@20.14.10)(sass@1.57.1)
+
+ '@vitest/pretty-format@2.1.5':
+ dependencies:
+ tinyrainbow: 1.2.0
+
'@vitest/runner@1.6.0':
dependencies:
'@vitest/utils': 1.6.0
p-limit: 5.0.0
pathe: 1.1.1
+ '@vitest/runner@2.1.5':
+ dependencies:
+ '@vitest/utils': 2.1.5
+ pathe: 1.1.2
+
'@vitest/snapshot@1.6.0':
dependencies:
magic-string: 0.30.5
pathe: 1.1.1
pretty-format: 29.7.0
+ '@vitest/snapshot@2.1.5':
+ dependencies:
+ '@vitest/pretty-format': 2.1.5
+ magic-string: 0.30.13
+ pathe: 1.1.2
+
'@vitest/spy@1.6.0':
dependencies:
tinyspy: 2.2.0
+ '@vitest/spy@2.1.5':
+ dependencies:
+ tinyspy: 3.0.2
+
'@vitest/utils@1.6.0':
dependencies:
diff-sequences: 29.6.3
@@ -7610,6 +7852,12 @@ snapshots:
loupe: 2.3.7
pretty-format: 29.7.0
+ '@vitest/utils@2.1.5':
+ dependencies:
+ '@vitest/pretty-format': 2.1.5
+ loupe: 3.1.2
+ tinyrainbow: 1.2.0
+
'@xmldom/xmldom@0.8.10': {}
'@zag-js/element-size@0.3.2': {}
@@ -7817,6 +8065,8 @@ snapshots:
assertion-error@1.1.0: {}
+ assertion-error@2.0.1: {}
+
astral-regex@2.0.0:
optional: true
@@ -7878,7 +8128,7 @@ snapshots:
bluebird@3.7.2: {}
- body-parser@1.20.1:
+ body-parser@1.20.3:
dependencies:
bytes: 3.1.2
content-type: 1.0.5
@@ -7888,8 +8138,8 @@ snapshots:
http-errors: 2.0.0
iconv-lite: 0.4.24
on-finished: 2.4.1
- qs: 6.11.0
- raw-body: 2.5.1
+ qs: 6.13.0
+ raw-body: 2.5.2
type-is: 1.6.18
unpipe: 1.0.0
transitivePeerDependencies:
@@ -7971,14 +8221,14 @@ snapshots:
cacheable-lookup@7.0.0: {}
- cacheable-request@10.2.14:
+ cacheable-request@12.0.1:
dependencies:
'@types/http-cache-semantics': 4.0.4
- get-stream: 6.0.1
+ get-stream: 9.0.1
http-cache-semantics: 4.1.1
keyv: 4.5.4
mimic-response: 4.0.0
- normalize-url: 8.0.0
+ normalize-url: 8.0.1
responselike: 3.0.0
cacheable-request@7.0.4:
@@ -7996,6 +8246,14 @@ snapshots:
function-bind: 1.1.2
get-intrinsic: 1.2.2
+ call-bind@1.0.7:
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ set-function-length: 1.2.2
+
callsites@3.1.0: {}
camelcase@6.3.0: {}
@@ -8017,6 +8275,14 @@ snapshots:
pathval: 1.1.1
type-detect: 4.0.8
+ chai@5.1.2:
+ dependencies:
+ assertion-error: 2.0.1
+ check-error: 2.1.1
+ deep-eql: 5.0.2
+ loupe: 3.1.2
+ pathval: 2.0.0
+
chalk@2.4.2:
dependencies:
ansi-styles: 3.2.1
@@ -8037,6 +8303,8 @@ snapshots:
dependencies:
get-func-name: 2.0.2
+ check-error@2.1.1: {}
+
chokidar@3.5.3:
dependencies:
anymatch: 3.1.3
@@ -8141,8 +8409,6 @@ snapshots:
dependencies:
safe-buffer: 5.2.1
- content-type@1.0.4: {}
-
content-type@1.0.5: {}
convert-source-map@1.9.0: {}
@@ -8151,7 +8417,7 @@ snapshots:
cookie-signature@1.0.6: {}
- cookie@0.5.0: {}
+ cookie@0.7.1: {}
copy-to-clipboard@3.3.3:
dependencies:
@@ -8245,6 +8511,10 @@ snapshots:
dependencies:
ms: 2.1.2
+ debug@4.3.7:
+ dependencies:
+ ms: 2.1.3
+
decimal.js@10.4.3: {}
decompress-response@6.0.0:
@@ -8255,6 +8525,8 @@ snapshots:
dependencies:
type-detect: 4.0.8
+ deep-eql@5.0.2: {}
+
deep-equal@2.2.0:
dependencies:
call-bind: 1.0.2
@@ -8287,6 +8559,12 @@ snapshots:
gopd: 1.0.1
has-property-descriptors: 1.0.1
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ gopd: 1.0.1
+
define-properties@1.1.4:
dependencies:
has-property-descriptors: 1.0.1
@@ -8440,6 +8718,8 @@ snapshots:
encodeurl@1.0.2: {}
+ encodeurl@2.0.0: {}
+
end-of-stream@1.4.4:
dependencies:
once: 1.4.0
@@ -8490,6 +8770,12 @@ snapshots:
unbox-primitive: 1.0.2
which-typed-array: 1.1.9
+ es-define-property@1.0.0:
+ dependencies:
+ get-intrinsic: 1.2.4
+
+ es-errors@1.3.0: {}
+
es-get-iterator@1.1.3:
dependencies:
call-bind: 1.0.2
@@ -8502,6 +8788,8 @@ snapshots:
isarray: 2.0.5
stop-iteration-iterator: 1.0.0
+ es-module-lexer@1.5.4: {}
+
es-set-tostringtag@2.0.1:
dependencies:
get-intrinsic: 1.2.2
@@ -8573,31 +8861,32 @@ snapshots:
'@esbuild/win32-ia32': 0.20.2
'@esbuild/win32-x64': 0.20.2
- esbuild@0.21.5:
+ esbuild@0.23.1:
optionalDependencies:
- '@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
+ '@esbuild/aix-ppc64': 0.23.1
+ '@esbuild/android-arm': 0.23.1
+ '@esbuild/android-arm64': 0.23.1
+ '@esbuild/android-x64': 0.23.1
+ '@esbuild/darwin-arm64': 0.23.1
+ '@esbuild/darwin-x64': 0.23.1
+ '@esbuild/freebsd-arm64': 0.23.1
+ '@esbuild/freebsd-x64': 0.23.1
+ '@esbuild/linux-arm': 0.23.1
+ '@esbuild/linux-arm64': 0.23.1
+ '@esbuild/linux-ia32': 0.23.1
+ '@esbuild/linux-loong64': 0.23.1
+ '@esbuild/linux-mips64el': 0.23.1
+ '@esbuild/linux-ppc64': 0.23.1
+ '@esbuild/linux-riscv64': 0.23.1
+ '@esbuild/linux-s390x': 0.23.1
+ '@esbuild/linux-x64': 0.23.1
+ '@esbuild/netbsd-x64': 0.23.1
+ '@esbuild/openbsd-arm64': 0.23.1
+ '@esbuild/openbsd-x64': 0.23.1
+ '@esbuild/sunos-x64': 0.23.1
+ '@esbuild/win32-arm64': 0.23.1
+ '@esbuild/win32-ia32': 0.23.1
+ '@esbuild/win32-x64': 0.23.1
escalade@3.1.1: {}
@@ -8787,6 +9076,8 @@ snapshots:
signal-exit: 4.1.0
strip-final-newline: 3.0.0
+ expect-type@1.1.0: {}
+
expect@29.3.1:
dependencies:
'@jest/expect-utils': 29.3.1
@@ -8795,45 +9086,46 @@ snapshots:
jest-message-util: 29.3.1
jest-util: 29.3.1
- express-static-gzip@2.1.7:
+ express-static-gzip@2.2.0:
dependencies:
- serve-static: 1.15.0
+ parseurl: 1.3.3
+ serve-static: 1.16.2
transitivePeerDependencies:
- supports-color
- express-validator@7.0.1:
+ express-validator@7.2.0:
dependencies:
lodash: 4.17.21
validator: 13.12.0
- express@4.18.2:
+ express@4.21.1:
dependencies:
accepts: 1.3.8
array-flatten: 1.1.1
- body-parser: 1.20.1
+ body-parser: 1.20.3
content-disposition: 0.5.4
- content-type: 1.0.4
- cookie: 0.5.0
+ content-type: 1.0.5
+ cookie: 0.7.1
cookie-signature: 1.0.6
debug: 2.6.9
depd: 2.0.0
- encodeurl: 1.0.2
+ encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
- finalhandler: 1.2.0
+ finalhandler: 1.3.1
fresh: 0.5.2
http-errors: 2.0.0
- merge-descriptors: 1.0.1
+ merge-descriptors: 1.0.3
methods: 1.1.2
on-finished: 2.4.1
parseurl: 1.3.3
- path-to-regexp: 0.1.7
+ path-to-regexp: 0.1.10
proxy-addr: 2.0.7
- qs: 6.11.0
+ qs: 6.13.0
range-parser: 1.2.1
safe-buffer: 5.2.1
- send: 0.18.0
- serve-static: 1.15.0
+ send: 0.19.0
+ serve-static: 1.16.2
setprototypeof: 1.2.0
statuses: 2.0.1
type-is: 1.6.18
@@ -8897,10 +9189,10 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
- finalhandler@1.2.0:
+ finalhandler@1.3.1:
dependencies:
debug: 2.6.9
- encodeurl: 1.0.2
+ encodeurl: 2.0.0
escape-html: 1.0.3
on-finished: 2.4.1
parseurl: 1.3.3
@@ -9043,16 +9335,27 @@ snapshots:
has-symbols: 1.0.3
hasown: 2.0.0
+ get-intrinsic@1.2.4:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ has-proto: 1.0.1
+ has-symbols: 1.0.3
+ hasown: 2.0.0
+
get-nonce@1.0.1: {}
get-stream@5.2.0:
dependencies:
pump: 3.0.0
- get-stream@6.0.1: {}
-
get-stream@8.0.1: {}
+ get-stream@9.0.1:
+ dependencies:
+ '@sec-ant/readable-stream': 0.4.1
+ is-stream: 4.0.1
+
get-symbol-description@1.0.0:
dependencies:
call-bind: 1.0.2
@@ -9167,19 +9470,19 @@ snapshots:
p-cancelable: 2.1.1
responselike: 2.0.1
- got@14.0.0:
+ got@14.4.5:
dependencies:
- '@sindresorhus/is': 6.1.0
+ '@sindresorhus/is': 7.0.1
'@szmarczak/http-timer': 5.0.1
cacheable-lookup: 7.0.0
- cacheable-request: 10.2.14
+ cacheable-request: 12.0.1
decompress-response: 6.0.0
form-data-encoder: 4.0.2
- get-stream: 8.0.1
http2-wrapper: 2.2.1
lowercase-keys: 3.0.0
p-cancelable: 4.0.1
responselike: 3.0.0
+ type-fest: 4.27.1
graceful-fs@4.2.11: {}
@@ -9203,6 +9506,10 @@ snapshots:
dependencies:
get-intrinsic: 1.2.2
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.0
+
has-proto@1.0.1: {}
has-symbols@1.0.3: {}
@@ -9404,6 +9711,8 @@ snapshots:
is-stream@3.0.0: {}
+ is-stream@4.0.1: {}
+
is-string@1.0.7:
dependencies:
has-tostringtag: 1.0.0
@@ -9636,6 +9945,8 @@ snapshots:
dependencies:
get-func-name: 2.0.2
+ loupe@3.1.2: {}
+
lowdb@7.0.1:
dependencies:
steno: 4.0.2
@@ -9662,6 +9973,10 @@ snapshots:
lz-string@1.5.0: {}
+ magic-string@0.30.13:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
magic-string@0.30.5:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
@@ -9677,7 +9992,7 @@ snapshots:
media-typer@0.3.0: {}
- merge-descriptors@1.0.1: {}
+ merge-descriptors@1.0.3: {}
merge-stream@2.0.0: {}
@@ -9798,7 +10113,7 @@ snapshots:
dependencies:
whatwg-url: 5.0.0
- node-osc@9.0.2:
+ node-osc@9.1.4:
dependencies:
osc-min: 1.1.2
@@ -9808,7 +10123,7 @@ snapshots:
normalize-url@6.1.0: {}
- normalize-url@8.0.0: {}
+ normalize-url@8.0.1: {}
npm-run-path@5.1.0:
dependencies:
@@ -9820,6 +10135,8 @@ snapshots:
object-inspect@1.12.3: {}
+ object-inspect@1.13.3: {}
+
object-is@1.1.5:
dependencies:
call-bind: 1.0.2
@@ -9941,14 +10258,18 @@ snapshots:
lru-cache: 10.1.0
minipass: 7.0.4
- path-to-regexp@0.1.7: {}
+ path-to-regexp@0.1.10: {}
path-type@4.0.0: {}
pathe@1.1.1: {}
+ pathe@1.1.2: {}
+
pathval@1.1.1: {}
+ pathval@2.0.0: {}
+
pend@1.2.0: {}
picocolors@1.0.0: {}
@@ -10048,6 +10369,10 @@ snapshots:
dependencies:
side-channel: 1.0.4
+ qs@6.13.0:
+ dependencies:
+ side-channel: 1.0.6
+
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
@@ -10058,7 +10383,7 @@ snapshots:
range-parser@1.2.1: {}
- raw-body@2.5.1:
+ raw-body@2.5.2:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
@@ -10344,7 +10669,7 @@ snapshots:
semver@7.6.2: {}
- send@0.18.0:
+ send@0.19.0:
dependencies:
debug: 2.6.9
depd: 2.0.0
@@ -10367,12 +10692,12 @@ snapshots:
type-fest: 0.13.1
optional: true
- serve-static@1.15.0:
+ serve-static@1.16.2:
dependencies:
- encodeurl: 1.0.2
+ encodeurl: 2.0.0
escape-html: 1.0.3
parseurl: 1.3.3
- send: 0.18.0
+ send: 0.19.0
transitivePeerDependencies:
- supports-color
@@ -10381,6 +10706,15 @@ snapshots:
minimist: 1.2.8
on-headers: 1.0.2
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+
setprototypeof@1.2.0: {}
shebang-command@2.0.0:
@@ -10406,6 +10740,13 @@ snapshots:
get-intrinsic: 1.2.2
object-inspect: 1.12.3
+ side-channel@1.0.6:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ object-inspect: 1.13.3
+
siginfo@2.0.0: {}
signal-exit@4.1.0: {}
@@ -10465,6 +10806,8 @@ snapshots:
std-env@3.6.0: {}
+ std-env@3.8.0: {}
+
steno@4.0.2: {}
stop-iteration-iterator@1.0.0:
@@ -10588,10 +10931,20 @@ snapshots:
tinybench@2.5.1: {}
+ tinybench@2.9.0: {}
+
+ tinyexec@0.3.1: {}
+
tinypool@0.8.4: {}
+ tinypool@1.0.2: {}
+
+ tinyrainbow@1.2.0: {}
+
tinyspy@2.2.0: {}
+ tinyspy@3.0.2: {}
+
tmp-promise@3.0.3:
dependencies:
tmp: 0.2.1
@@ -10631,7 +10984,7 @@ snapshots:
dependencies:
typescript: 5.5.3
- ts-essentials@9.4.1(typescript@5.5.3):
+ ts-essentials@10.0.3(typescript@5.5.3):
optionalDependencies:
typescript: 5.5.3
@@ -10652,9 +11005,9 @@ snapshots:
tslib: 1.14.1
typescript: 5.5.3
- tsx@4.16.2:
+ tsx@4.19.2:
dependencies:
- esbuild: 0.21.5
+ esbuild: 0.23.1
get-tsconfig: 4.7.5
optionalDependencies:
fsevents: 2.3.3
@@ -10701,6 +11054,8 @@ snapshots:
type-fest@0.20.2: {}
+ type-fest@4.27.1: {}
+
type-is@1.6.18:
dependencies:
media-typer: 0.3.0
@@ -10816,6 +11171,23 @@ snapshots:
- supports-color
- terser
+ vite-node@2.1.5(@types/node@20.14.10)(sass@1.57.1):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.3.7
+ es-module-lexer: 1.5.4
+ pathe: 1.1.2
+ vite: 5.2.11(@types/node@20.14.10)(sass@1.57.1)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
vite-plugin-compression2@0.12.0(rollup@4.17.2):
dependencies:
'@rollup/pluginutils': 5.1.0(rollup@4.17.2)
@@ -10889,6 +11261,41 @@ snapshots:
- supports-color
- terser
+ vitest@2.1.5(@types/node@20.14.10)(jsdom@21.1.0)(sass@1.57.1):
+ dependencies:
+ '@vitest/expect': 2.1.5
+ '@vitest/mocker': 2.1.5(vite@5.2.11(@types/node@20.14.10)(sass@1.57.1))
+ '@vitest/pretty-format': 2.1.5
+ '@vitest/runner': 2.1.5
+ '@vitest/snapshot': 2.1.5
+ '@vitest/spy': 2.1.5
+ '@vitest/utils': 2.1.5
+ chai: 5.1.2
+ debug: 4.3.7
+ expect-type: 1.1.0
+ magic-string: 0.30.13
+ pathe: 1.1.2
+ std-env: 3.8.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.1
+ tinypool: 1.0.2
+ tinyrainbow: 1.2.0
+ vite: 5.2.11(@types/node@20.14.10)(sass@1.57.1)
+ vite-node: 2.1.5(@types/node@20.14.10)(sass@1.57.1)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 20.14.10
+ jsdom: 21.1.0
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
w3c-xmlserializer@4.0.0:
dependencies:
xml-name-validator: 4.0.0
@@ -10962,6 +11369,11 @@ snapshots:
siginfo: 2.0.0
stackback: 0.0.2
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
wmf@1.0.2: {}
word-wrap@1.2.3: {}
@@ -10978,6 +11390,8 @@ snapshots:
ws@8.13.0: {}
+ ws@8.18.0: {}
+
xlsx@0.18.5:
dependencies:
adler-32: 1.3.1