diff --git a/.vscode/settings.json b/.vscode/settings.json index 20cf4bea0..264d3a778 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], ["twMerge\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], ["twJoin\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] - ] + ], + "prettier.requireConfig": true } \ No newline at end of file diff --git a/src/.prettierrc b/src/.prettierrc deleted file mode 100644 index 937209858..000000000 --- a/src/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "useTabs": true, - "singleQuote": true, - "jsxSingleQuote": false, - "trailingComma": "all", - "printWidth": 120, - "plugins": ["prettier-plugin-tailwindcss"] -} diff --git a/src/bin/ratos b/src/bin/ratos new file mode 100755 index 000000000..46085c916 --- /dev/null +++ b/src/bin/ratos @@ -0,0 +1,6 @@ +#!/bin/bash +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +RATOS_BIN_CWD=$(pwd) +export RATOS_BIN_CWD +pnpm run --silent -C "$SCRIPT_DIR"/.. cli "$@" +exit $? \ No newline at end of file diff --git a/src/cli/components/container.tsx b/src/cli/components/container.tsx new file mode 100644 index 000000000..460c23f84 --- /dev/null +++ b/src/cli/components/container.tsx @@ -0,0 +1,10 @@ +import { Box } from 'ink'; +import React from 'react'; + +export const Container: React.FC = (props) => { + return ( + + {props.children} + + ); +}; diff --git a/src/cli/components/status.tsx b/src/cli/components/status.tsx new file mode 100644 index 000000000..91ea81dea --- /dev/null +++ b/src/cli/components/status.tsx @@ -0,0 +1,37 @@ +import { Box, Text } from 'ink'; +import React from 'react'; + +interface APIResult { + result: 'success' | 'error'; + message: string; +} + +interface StatusProps { + results: APIResult | APIResult[]; +} + +export const Status: React.FC = (props) => { + const hasError = Array.isArray(props.results) + ? props.results.some((result) => result.result === 'error') + : props.results.result === 'error'; + const results = Array.isArray(props.results) ? props.results : [props.results]; + return ( + + {hasError ? Error! : Success!} + {results.map(({ message, result }) => ( + + {result === 'success' ? ( + + ✓{' '} + + ) : ( + + ✘{' '} + + )} + {message} + + ))} + + ); +}; diff --git a/src/cli/components/table.tsx b/src/cli/components/table.tsx new file mode 100644 index 000000000..305b52e68 --- /dev/null +++ b/src/cli/components/table.tsx @@ -0,0 +1,373 @@ +/** + * Adapted from https://github.com/maticzav/ink-table + */ + +import React from 'react'; +import { Box, Text } from 'ink'; +import { sha1 } from 'object-hash'; + +/* Table */ + +type Scalar = string | number | boolean | null | undefined; + +type ScalarDict = { + [key: string]: Scalar; +}; + +export type CellProps = React.PropsWithChildren<{ column: number }>; + +export type TableProps = { + /** + * List of values (rows). + */ + data: T[]; + /** + * Columns that we should display in the table. + */ + columns: (keyof T)[]; + /** + * Cell padding. + */ + padding: number; + /** + * Header component. + */ + header: (props: React.PropsWithChildren<{}>) => JSX.Element; + /** + * Component used to render a cell in the table. + */ + cell: (props: CellProps) => JSX.Element; + /** + * Component used to render the skeleton of the table. + */ + skeleton: (props: React.PropsWithChildren<{}>) => JSX.Element; +}; + +/* Table */ + +export class Table extends React.Component, 'data'> & Partial>> { + /* Config */ + + /** + * Merges provided configuration with defaults. + */ + getConfig(): TableProps { + return { + data: this.props.data, + columns: this.props.columns || this.getDataKeys(), + padding: this.props.padding || 1, + header: this.props.header || Header, + cell: this.props.cell || Cell, + skeleton: this.props.skeleton || Skeleton, + }; + } + + /** + * Gets all keyes used in data by traversing through the data. + */ + getDataKeys(): (keyof T)[] { + let keys = new Set(); + + // Collect all the keys. + for (const data of this.props.data) { + for (const key in data) { + keys.add(key); + } + } + + return Array.from(keys); + } + + /** + * Calculates the width of each column by finding + * the longest value in a cell of a particular column. + * + * Returns a list of column names and their widths. + */ + getColumns(): Column[] { + const { columns, padding } = this.getConfig(); + + const widths: Column[] = columns.map((key) => { + const header = String(key).length; + /* Get the width of each cell in the column */ + const data = this.props.data.map((data) => { + const value = data[key]; + + if (value == undefined || value == null) return 0; + return String(value).length; + }); + + const width = Math.max(...data, header) + padding * 2; + + /* Construct a cell */ + return { + column: key, + width: width, + key: String(key), + }; + }); + + return widths; + } + + /** + * Returns a (data) row representing the headings. + */ + getHeadings(): Partial { + const { columns } = this.getConfig(); + + const headings: Partial = columns.reduce((acc, column) => ({ ...acc, [column]: column }), {}); + + return headings; + } + + /* Rendering utilities */ + + // The top most line in the table. + header = row({ + cell: this.getConfig().skeleton, + padding: this.getConfig().padding, + skeleton: { + component: this.getConfig().skeleton, + // chars + line: '─', + left: '┌', + right: '┐', + cross: '┬', + }, + }); + + // The line with column names. + heading = row({ + cell: this.getConfig().header, + padding: this.getConfig().padding, + skeleton: { + component: this.getConfig().skeleton, + // chars + line: ' ', + left: '│', + right: '│', + cross: '│', + }, + }); + + // The line that separates rows. + separator = row({ + cell: this.getConfig().skeleton, + padding: this.getConfig().padding, + skeleton: { + component: this.getConfig().skeleton, + // chars + line: '─', + left: '├', + right: '┤', + cross: '┼', + }, + }); + + // The row with the data. + data = row({ + cell: this.getConfig().cell, + padding: this.getConfig().padding, + skeleton: { + component: this.getConfig().skeleton, + // chars + line: ' ', + left: '│', + right: '│', + cross: '│', + }, + }); + + // The bottom most line of the table. + footer = row({ + cell: this.getConfig().skeleton, + padding: this.getConfig().padding, + skeleton: { + component: this.getConfig().skeleton, + // chars + line: '─', + left: '└', + right: '┘', + cross: '┴', + }, + }); + + /* Render */ + + render() { + /* Data */ + const columns = this.getColumns(); + const headings = this.getHeadings(); + + /** + * Render the table line by line. + */ + return ( + + {/* Header */} + {this.header({ key: 'header', columns, data: {} })} + {this.heading({ key: 'heading', columns, data: headings })} + {/* Data */} + {this.props.data.map((row, index) => { + // Calculate the hash of the row based on its value and position + const key = `row-${sha1(row)}-${index}`; + + // Construct a row. + return ( + + {this.separator({ key: `separator-${key}`, columns, data: {} })} + {this.data({ key: `data-${key}`, columns, data: row })} + + ); + })} + {/* Footer */} + {this.footer({ key: 'footer', columns, data: {} })} + + ); + } +} + +/* Helper components */ + +type RowConfig = { + /** + * Component used to render cells. + */ + cell: (props: CellProps) => JSX.Element; + /** + * Tells the padding of each cell. + */ + padding: number; + /** + * Component used to render skeleton in the row. + */ + skeleton: { + component: (props: React.PropsWithChildren<{}>) => JSX.Element; + /** + * Characters used in skeleton. + * | | + * (left)-(line)-(cross)-(line)-(right) + * | | + */ + left: string; + right: string; + cross: string; + line: string; + }; +}; + +type RowProps = { + key: string; + data: Partial; + columns: Column[]; +}; + +type Column = { + key: string; + column: keyof T; + width: number; +}; + +/** + * Constructs a Row element from the configuration. + */ +function row(config: RowConfig): (props: RowProps) => JSX.Element { + /* This is a component builder. We return a function. */ + + const skeleton = config.skeleton; + + /* Row */ + const Row = (props: RowProps) => ( + + {/* Left */} + {skeleton.left} + {/* Data */} + {...intersperse( + (i) => { + const key = `${props.key}-hseparator-${i}`; + + // The horizontal separator. + return {skeleton.cross}; + }, + + // Values. + props.columns.map((column, colI) => { + // content + const value = props.data[column.column]; + + if (value == undefined || value == null) { + const key = `${props.key}-empty-${column.key}`; + + return ( + + {skeleton.line.repeat(column.width)} + + ); + } else { + const key = `${props.key}-cell-${column.key}`; + + // margins + const ml = config.padding; + const mr = column.width - String(value).length - config.padding; + + return ( + /* prettier-ignore */ + + {`${skeleton.line.repeat(ml)}${String(value)}${skeleton.line.repeat(mr)}`} + + ); + } + }), + )} + {/* Right */} + {skeleton.right} + + ); + return Row; +} + +/** + * Renders the header of a table. + */ +export function Header(props: React.PropsWithChildren<{}>) { + return ( + + {props.children} + + ); +} + +/** + * Renders a cell in the table. + */ +export function Cell(props: CellProps) { + return {props.children}; +} + +/** + * Redners the scaffold of the table. + */ +export function Skeleton(props: React.PropsWithChildren<{}>) { + return {props.children}; +} + +/* Utility functions */ + +/** + * Intersperses a list of elements with another element. + */ +function intersperse(intersperser: (index: number) => I, elements: T[]): (T | I)[] { + // Intersparse by reducing from left. + let interspersed: (T | I)[] = elements.reduce( + (acc, element, index) => { + // Only add element if it's the first one. + if (acc.length === 0) return [element]; + // Add the intersparser as well otherwise. + return [...acc, intersperser(index), element]; + }, + [] as (T | I)[], + ); + + return interspersed; +} diff --git a/src/cli/package.json b/src/cli/package.json new file mode 100644 index 000000000..bedb411a9 --- /dev/null +++ b/src/cli/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/src/cli/ratos.tsx b/src/cli/ratos.tsx new file mode 100755 index 000000000..fbe9a1444 --- /dev/null +++ b/src/cli/ratos.tsx @@ -0,0 +1,319 @@ +import * as commander from 'commander'; +import type { AppRouter } from '../server/routers/index.js'; +import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'; +import trpc from '../utils/trpc.js'; +import { realpath, stat } from 'fs/promises'; +import path from 'path'; +import React from 'react'; +import { Box, Text, render } from 'ink'; +import { Container } from './components/container.jsx'; +import { Status } from './components/status.jsx'; +import { Table } from './components/table.jsx'; +import { readPackageUp } from 'read-package-up'; + +interface APIResult { + result: 'success' | 'error'; + message: string; +} + +function renderError(str: string, options: { exitCode: number } = { exitCode: 1 }) { + render( + + + , + ); + process.exit(options.exitCode); +} + +function renderApiResults(results: APIResult[] | APIResult) { + render( + + + , + ); +} + +function errorColor(str: string) { + // Add ANSI escape codes to display text in red. + return `\x1b[31m${str}\x1b[0m` as const; +} + +const client = createTRPCProxyClient({ + links: [ + httpBatchLink({ + url: `${trpc.getBaseUrl()}/api/trpc`, + }), + ], +}); + +const getRealPath = async (p: string) => { + if (process.env.RATOS_BIN_CWD == null && program.getOptionValue('cwd') == null) { + renderError( + `--cwd was not passed and RATOS_BIN_CWD environment variable is not set. + Either the --cwd option or the RATOS_BIN_CWD environment variable is required to run this command.`, + { exitCode: 1 }, + ); + } + return await realpath(path.resolve(process.env.RATOS_BIN_CWD ?? program.getOptionValue('cwd'), p)); +}; + +const program = new commander.Command() + .name('RatOS CLI') + .version((await readPackageUp())?.packageJson.version ?? 'unknown') + .description('RatOS CLI for interacting with the RatOS Configurator') + .option('-cwd, --cwd ', 'Set the current working directory') + .configureOutput({ + outputError: (str, write) => write(errorColor(str)), + }) + .showSuggestionAfterError(true); + +const extensions = program + .command('extensions') + .description('Register, unregister or symlink extensions managed by the RatOS Configurator'); + +const registerExtensions = extensions + .command('register') + .description('Register an extension to be managed by the RatOS Configurator'); + +const unregisterExtensions = extensions + .command('unregister') + .description('Unregister an extension from the RatOS Configurator'); + +extensions + .command('list') + .description('List all registered extensions') + .action(async () => { + const klippyExtensions = (await client['klippy-extensions'].list.query()).map((ext) => ({ + ...ext, + isKinematics: ext.isKinematics ? '✓' : '✘', + })); + const moonrakerExtensions = await client['moonraker-extensions'].list.query(); + render( + + {klippyExtensions.length ? ( + + + {klippyExtensions.length} Registered Klipper Extensions{klippyExtensions.length ? ':' : ''} + + ( + + {props.children} + + )} + >
+
+ ) : null} + {moonrakerExtensions.length ? ( + + + {moonrakerExtensions.length} Registered Klipper Extensions{moonrakerExtensions.length ? ':' : ''} + + +
+
+ ) : null} +
, + ); + }); + +registerExtensions + .command('klipper') + .description('Register a Klipper extension to be managed by the RatOS Configurator') + .option('-k, --kinematics', 'Register as a kinematics extension') + .option('-e, --error-if-exists', 'Throw error if the extension already exists') + .argument('', 'Name of the extension') + .argument('', 'The extension itself') + .showHelpAfterError() + .action(async (extName, extFile, options) => { + let realPath = ''; + try { + realPath = await getRealPath(extFile); + if (!(await stat(realPath)).isFile() || !realPath.endsWith('.py')) { + return renderError(`${realPath} is not a python file`, { exitCode: 2 }); + } + } catch (e) { + return renderError(`Failed to get file name from ${extFile}`, { exitCode: 2 }); + } + const fileName = realPath.split(path.sep).pop(); + if (fileName == null) { + return renderError(`Failed to get file name from ${realPath}`, { exitCode: 2 }); + } + try { + await client['klippy-extensions'].register.mutate({ + json: { + extensionName: extName, + path: realPath.lastIndexOf(fileName) === -1 ? realPath : realPath.slice(0, realPath.lastIndexOf(fileName)), + fileName: fileName, + isKinematics: options.kinematics, + errorIfExists: options.errorIfExists, + }, + }); + } catch (e) { + if (e instanceof Error) { + return renderError(e.message, { exitCode: 2 }); + } + return renderError('Failed to register extension', { exitCode: 2 }); + } + + render( + + + , + ); + }); + +registerExtensions + .command('moonraker') + .description('Register a Moonraker extension to be managed by the RatOS Configurator') + .argument('', 'Name of the extension') + .argument('', 'The extension itself') + .showHelpAfterError() + .option('-e, --error-if-exists', 'Throw error if the extension already exists') + .action(async (extName, extFile, options) => { + let realPath = ''; + try { + realPath = await getRealPath(extFile); + if (!(await stat(realPath)).isFile() || !realPath.endsWith('.py')) { + return renderError(`${realPath} is not a python file`, { exitCode: 2 }); + } + } catch (e) { + return renderError(`Failed to get file name from ${extFile}`, { exitCode: 2 }); + } + const fileName = realPath.split(path.sep).pop(); + if (fileName == null) { + return renderError(`Failed to get file name from ${realPath}`, { exitCode: 2 }); + } + try { + await client['moonraker-extensions'].register.mutate({ + json: { + extensionName: extName, + path: realPath.lastIndexOf(fileName) === -1 ? realPath : realPath.slice(0, realPath.lastIndexOf(fileName)), + fileName: fileName, + errorIfExists: options.errorIfExists, + }, + }); + render( + + + , + ); + } catch (e) { + if (e instanceof Error) { + return renderError(e.message, { exitCode: 2 }); + } + return renderError('Failed to register extension', { exitCode: 2 }); + } + }); + +unregisterExtensions + .command('klipper') + .description('Unlink and unregister a Klipper extension managed by the RatOS Configurator') + .argument('', 'Name of the extension') + .showHelpAfterError() + .option('-k, --kinematics', 'Register as a kinematics extension') + .option('-e, --error-if-not-exists', "Throw error if the extension doesn't exist") + .action(async (extName, options) => { + try { + const result = await client['klippy-extensions'].unregister.mutate({ + extensionName: extName, + errorIfNotExists: options.errorIfExists, + }); + renderApiResults(result); + } catch (e) { + if (e instanceof Error) { + return renderError(e.message, { exitCode: 2 }); + } + return renderError('Failed to unregister extension', { exitCode: 2 }); + } + }); + +unregisterExtensions + .command('moonraker') + .description('Unlink and unregister a Moonraker extension managed by the RatOS Configurator') + .argument('', 'Name of the extension') + .showHelpAfterError() + .option('-e, --error-if-not-exists', "Throw error if the extension doesn't exist") + .action(async (extName, options) => { + try { + const result = await client['moonraker-extensions'].unregister.mutate({ + extensionName: extName, + errorIfNotExists: options.errorIfNotExists, + }); + renderApiResults(result); + } catch (e) { + if (e instanceof Error) { + return renderError(e.message, { exitCode: 2 }); + } + return renderError('Failed to unregister extension', { exitCode: 2 }); + } + }); + +extensions + .command('symlink') + .addArgument( + new commander.Argument('[type]', 'Type of the extension').default('all').choices(['all', 'klipper', 'moonraker']), + ) + .option('-e, --error-if-exists', 'Throw error and abort if an extension already exist') + .description('Symlink all registered extensions') + .action(async (type, options) => { + try { + if (type === 'klipper' || type === 'all') { + const klipperExtensions = await client['klippy-extensions'].symlink.mutate({ + errorIfExists: options.errorIfExists, + }); + renderApiResults(klipperExtensions.symlinkResults); + } + if (type === 'moonraker' || type === 'all') { + const moonrakerExtensions = await client['moonraker-extensions'].symlink.mutate({ + errorIfExists: options.errorIfExists, + }); + renderApiResults(moonrakerExtensions.symlinkResults); + } + } catch (e) { + if (e instanceof Error) { + return renderError(e.message, { exitCode: 2 }); + } + return renderError('Failed to symlink extensions', { exitCode: 2 }); + } + }); + +program + .command('regenerate_config') + .description('Regenerate the printer config') + .action(async () => { + const result = await client['printer'].regenerateConfiguration.mutate(); + result.map((file) => { + let action = + file.action === 'created' + ? 'Created' + : file.action === 'skipped' + ? 'Skipped' + : file.action === 'overwritten' + ? 'Updated' + : 'Failed to write'; + console.log(`${action} ${file.fileName}`); + }); + }); + +program.parseAsync(); diff --git a/src/cli/tsconfig.json b/src/cli/tsconfig.json new file mode 100644 index 000000000..6b8b3289b --- /dev/null +++ b/src/cli/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16", + "target": "esnext" + } +} diff --git a/src/components/common/actions-dropdown.tsx b/src/components/common/actions-dropdown.tsx index fe816679e..8b1c42bf6 100644 --- a/src/components/common/actions-dropdown.tsx +++ b/src/components/common/actions-dropdown.tsx @@ -84,11 +84,11 @@ export const ActionsDropdown = () => { dismissText: 'Please wait...', }); setIsSymlinkModalOpen(true); - symlinkExtensions.mutateAsync().then( + symlinkExtensions.mutateAsync({}).then( (value) => { setSymlinkModalContent({ title: 'Symlink Complete', - children:

') }} />, + children:

') }} />, dismissText: 'OK', }); }, diff --git a/src/package.json b/src/package.json index 77d391e3c..c372c3592 100644 --- a/src/package.json +++ b/src/package.json @@ -11,7 +11,19 @@ "test:config": "vitest configuration", "test:ci": "vitest --reporter=verbose --reporter=junit", "test:ci:config": "vitest configuration --reporter=verbose --reporter=junit", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "cli": "tsx --tsconfig ./tsconfig.json ./cli/ratos.tsx" + }, + "prettier": { + "useTabs": true, + "singleQuote": true, + "jsxSingleQuote": false, + "trailingComma": "all", + "printWidth": 120, + "plugins": [ + "/home/pi/work/RatOS-configurator/src/node_modules/.pnpm/prettier-plugin-tailwindcss@0.5.10_prettier@3.1.1/node_modules/prettier-plugin-tailwindcss/dist/index.mjs" + ], + "tailwindConfig": "./tailwind.config.js" }, "dependencies": { "@formkit/auto-animate": "^0.8.0", @@ -25,26 +37,33 @@ "@trpc/next": "10.44.1", "@trpc/react-query": "10.44.1", "@trpc/server": "10.44.1", - "@vitest/coverage-v8": "^1.1.1", "axios": "^0.26.1", - "babel-plugin-superjson-next": "^0.4.5", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", + "commander": "^11.1.0", "file-type": "^17.1.6", "glob": "^10.3.10", + "ink": "^4.4.1", + "ink-progress-bar": "^3.0.0", + "ink-spinner": "^5.0.0", + "ink-table": "^3.1.0", "next": "13.2.4", "next-superjson-plugin": "^0.5.6", "node-cache": "^5.1.2", + "object-hash": "^3.0.0", "pino": "^8.17.2", "pino-pretty": "^10.3.1", "react": "18.2.0", "react-dom": "18.2.0", "react-query": "^3.39.3", "react-use-websocket": "^4.5.0", + "read-package-up": "^11.0.0", "recoil": "^0.7.7", "recoil-sync": "^0.2.0", "superjson": "^1.12.2", "tailwind-merge": "^1.14.0", + "tsx": "^4.7.0", + "typescript": "5.3.3", "zod": "^3.20.2", "zod-refine": "^1.1.1" }, @@ -53,11 +72,14 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@total-typescript/ts-reset": "^0.5.1", - "@types/node": "16.11.12", + "@types/node": "18.x.x", + "@types/object-hash": "^3.0.6", "@types/react": "18.2.21", - "@typescript-eslint/parser": "^5.0.1", + "@typescript-eslint/parser": "^6.17.0", "@typescript-eslint/typescript-estree": "6.17.0", + "@vitest/coverage-v8": "^1.1.1", "autoprefixer": "^10.4.13", + "babel-plugin-superjson-next": "^0.4.5", "dotenv": "^16.3.1", "eslint": "^8.56.0", "eslint-config-next": "14.0.4", @@ -65,11 +87,11 @@ "eslint-plugin-unused-imports": "3", "jest-environment-jsdom": "^29.5.0", "postcss": "^8.4.21", - "prettier": "^2.5.1", + "prettier": "^3.1.1", + "prettier-eslint": "^16.2.0", "prettier-plugin-tailwindcss": "^0.5.10", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.4.0", - "typescript": "5.3.3", "vitest": "^1.1.1" } } diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index 3fcc6896d..f47fe650e 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -38,27 +38,36 @@ dependencies: '@trpc/server': specifier: 10.44.1 version: 10.44.1 - '@vitest/coverage-v8': - specifier: ^1.1.1 - version: 1.1.1(vitest@1.1.1) axios: specifier: ^0.26.1 version: 0.26.1 - babel-plugin-superjson-next: - specifier: ^0.4.5 - version: 0.4.5(next@13.2.4)(superjson@1.12.2) class-variance-authority: specifier: ^0.7.0 version: 0.7.0 clsx: specifier: ^1.2.1 version: 1.2.1 + commander: + specifier: ^11.1.0 + version: 11.1.0 file-type: specifier: ^17.1.6 version: 17.1.6 glob: specifier: ^10.3.10 version: 10.3.10 + ink: + specifier: ^4.4.1 + version: 4.4.1(@types/react@18.2.21)(react@18.2.0) + ink-progress-bar: + specifier: ^3.0.0 + version: 3.0.0 + ink-spinner: + specifier: ^5.0.0 + version: 5.0.0(ink@4.4.1)(react@18.2.0) + ink-table: + specifier: ^3.1.0 + version: 3.1.0(ink@4.4.1)(react@18.2.0) next: specifier: 13.2.4 version: 13.2.4(@babel/core@7.21.0)(react-dom@18.2.0)(react@18.2.0) @@ -68,6 +77,9 @@ dependencies: node-cache: specifier: ^5.1.2 version: 5.1.2 + object-hash: + specifier: ^3.0.0 + version: 3.0.0 pino: specifier: ^8.17.2 version: 8.17.2 @@ -86,6 +98,9 @@ dependencies: react-use-websocket: specifier: ^4.5.0 version: 4.5.0(react-dom@18.2.0)(react@18.2.0) + read-package-up: + specifier: ^11.0.0 + version: 11.0.0 recoil: specifier: ^0.7.7 version: 0.7.7(react-dom@18.2.0)(react@18.2.0) @@ -98,6 +113,12 @@ dependencies: tailwind-merge: specifier: ^1.14.0 version: 1.14.0 + tsx: + specifier: ^4.7.0 + version: 4.7.0 + typescript: + specifier: 5.3.3 + version: 5.3.3 zod: specifier: ^3.20.2 version: 3.20.2 @@ -119,20 +140,29 @@ devDependencies: specifier: ^0.5.1 version: 0.5.1 '@types/node': - specifier: 16.11.12 - version: 16.11.12 + specifier: 18.x.x + version: 18.19.4 + '@types/object-hash': + specifier: ^3.0.6 + version: 3.0.6 '@types/react': specifier: 18.2.21 version: 18.2.21 '@typescript-eslint/parser': - specifier: ^5.0.1 - version: 5.55.0(eslint@8.56.0)(typescript@5.3.3) + specifier: ^6.17.0 + version: 6.17.0(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/typescript-estree': specifier: 6.17.0 version: 6.17.0(typescript@5.3.3) + '@vitest/coverage-v8': + specifier: ^1.1.1 + version: 1.1.1(vitest@1.1.1) autoprefixer: specifier: ^10.4.13 version: 10.4.13(postcss@8.4.21) + babel-plugin-superjson-next: + specifier: ^0.4.5 + version: 0.4.5(next@13.2.4)(superjson@1.12.2) dotenv: specifier: ^16.3.1 version: 16.3.1 @@ -155,23 +185,23 @@ devDependencies: specifier: ^8.4.21 version: 8.4.21 prettier: - specifier: ^2.5.1 - version: 2.8.8 + specifier: ^3.1.1 + version: 3.1.1 + prettier-eslint: + specifier: ^16.2.0 + version: 16.2.0 prettier-plugin-tailwindcss: specifier: ^0.5.10 - version: 0.5.10(prettier@2.8.8) + version: 0.5.10(prettier@3.1.1) tailwind-scrollbar: specifier: ^3.0.5 version: 3.0.5(tailwindcss@3.4.0) tailwindcss: specifier: ^3.4.0 version: 3.4.0 - typescript: - specifier: 5.3.3 - version: 5.3.3 vitest: specifier: ^1.1.1 - version: 1.1.1(@types/node@16.11.12) + version: 1.1.1(@types/node@18.19.4) packages: @@ -184,6 +214,14 @@ packages: resolution: {integrity: sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==} dev: true + /@alcalzone/ansi-tokenize@0.1.3: + resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==} + engines: {node: '>=14.13.1'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -201,7 +239,7 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 - dev: false + dev: true /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} @@ -209,6 +247,14 @@ packages: dependencies: '@babel/highlight': 7.18.6 + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.23.4 + chalk: 2.4.2 + dev: false + /@babel/compat-data@7.21.0: resolution: {integrity: sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==} engines: {node: '>=6.9.0'} @@ -231,7 +277,7 @@ packages: debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.3 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -255,7 +301,7 @@ packages: '@babel/helper-validator-option': 7.21.0 browserslist: 4.21.5 lru-cache: 5.1.1 - semver: 6.3.0 + semver: 6.3.1 /@babel/helper-environment-visitor@7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} @@ -319,7 +365,7 @@ packages: /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} - dev: false + dev: true /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} @@ -328,7 +374,6 @@ packages: /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-option@7.21.0: resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} @@ -352,6 +397,15 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 + /@babel/highlight@7.23.4: + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: false + /@babel/parser@7.21.2: resolution: {integrity: sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==} engines: {node: '>=6.0.0'} @@ -365,7 +419,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.23.6 - dev: false + dev: true /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.21.0): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} @@ -557,11 +611,11 @@ packages: '@babel/helper-string-parser': 7.23.4 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - dev: false + dev: true /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: false + dev: true /@esbuild/aix-ppc64@0.19.11: resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} @@ -854,6 +908,7 @@ packages: /@istanbuljs/schema@0.1.3: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} + dev: true /@jest/environment@29.5.0: resolution: {integrity: sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==} @@ -861,7 +916,7 @@ packages: dependencies: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 16.11.12 + '@types/node': 18.19.4 jest-mock: 29.5.0 dev: true @@ -888,7 +943,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@sinonjs/fake-timers': 10.0.2 - '@types/node': 16.11.12 + '@types/node': 18.19.4 jest-message-util: 29.5.0 jest-mock: 29.5.0 jest-util: 29.5.0 @@ -918,6 +973,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@sinclair/typebox': 0.27.8 + dev: true /@jest/transform@29.5.0: resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} @@ -949,7 +1005,7 @@ packages: '@jest/schemas': 29.4.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 16.11.12 + '@types/node': 18.19.4 '@types/yargs': 17.0.22 chalk: 4.1.2 dev: true @@ -997,7 +1053,6 @@ packages: /@next/env@13.2.4: resolution: {integrity: sha512-+Mq3TtpkeeKFZanPturjcXt+KHfKYnLlX6jMLyCrmpq6OOs4i1GqBOAauSkii9QeKCMTYzGppar21JU57b/GEA==} - dev: false /@next/eslint-plugin-next@14.0.4: resolution: {integrity: sha512-U3qMNHmEZoVmHA0j/57nRfi3AscXNvkOnxDmle/69Jz/G0o/gWjXTDdlgILZdrxQ0Lw/jv2mPW8PGy0EGIHXhQ==} @@ -1011,7 +1066,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: false optional: true /@next/swc-android-arm64@13.2.4: @@ -1020,7 +1074,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: false optional: true /@next/swc-darwin-arm64@13.2.4: @@ -1029,7 +1082,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-darwin-x64@13.2.4: @@ -1038,7 +1090,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-freebsd-x64@13.2.4: @@ -1047,7 +1098,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm-gnueabihf@13.2.4: @@ -1056,7 +1106,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-gnu@13.2.4: @@ -1065,7 +1114,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-musl@13.2.4: @@ -1074,7 +1122,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-gnu@13.2.4: @@ -1083,7 +1130,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-musl@13.2.4: @@ -1092,7 +1138,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-win32-arm64-msvc@13.2.4: @@ -1101,7 +1146,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-ia32-msvc@13.2.4: @@ -1110,7 +1154,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-x64-msvc@13.2.4: @@ -1119,7 +1162,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@nodelib/fs.scandir@2.1.5: @@ -1168,6 +1210,7 @@ packages: cpu: [arm] os: [android] requiresBuild: true + dev: true optional: true /@rollup/rollup-android-arm64@4.9.2: @@ -1175,6 +1218,7 @@ packages: cpu: [arm64] os: [android] requiresBuild: true + dev: true optional: true /@rollup/rollup-darwin-arm64@4.9.2: @@ -1182,6 +1226,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: true optional: true /@rollup/rollup-darwin-x64@4.9.2: @@ -1189,6 +1234,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: true optional: true /@rollup/rollup-linux-arm-gnueabihf@4.9.2: @@ -1196,6 +1242,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: true optional: true /@rollup/rollup-linux-arm64-gnu@4.9.2: @@ -1203,6 +1250,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true /@rollup/rollup-linux-arm64-musl@4.9.2: @@ -1210,6 +1258,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true /@rollup/rollup-linux-riscv64-gnu@4.9.2: @@ -1217,6 +1266,7 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true + dev: true optional: true /@rollup/rollup-linux-x64-gnu@4.9.2: @@ -1224,6 +1274,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true /@rollup/rollup-linux-x64-musl@4.9.2: @@ -1231,6 +1282,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true /@rollup/rollup-win32-arm64-msvc@4.9.2: @@ -1238,6 +1290,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true + dev: true optional: true /@rollup/rollup-win32-ia32-msvc@4.9.2: @@ -1245,6 +1298,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true + dev: true optional: true /@rollup/rollup-win32-x64-msvc@4.9.2: @@ -1252,6 +1306,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: true optional: true /@rushstack/eslint-patch@1.6.1: @@ -1264,6 +1319,7 @@ packages: /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true /@sinonjs/commons@2.0.0: resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} @@ -1281,7 +1337,6 @@ packages: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} dependencies: tslib: 2.5.0 - dev: false /@tailwindcss/forms@0.5.7(tailwindcss@3.4.0): resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==} @@ -1433,11 +1488,12 @@ packages: /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 16.11.12 + '@types/node': 18.19.4 dev: true /@types/istanbul-lib-coverage@2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: true /@types/istanbul-lib-report@3.0.0: resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} @@ -1461,7 +1517,7 @@ packages: /@types/jsdom@20.0.1: resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} dependencies: - '@types/node': 16.11.12 + '@types/node': 18.19.4 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -1470,8 +1526,19 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/node@16.11.12: - resolution: {integrity: sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==} + /@types/node@18.19.4: + resolution: {integrity: sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/normalize-package-data@2.4.4: + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + dev: false + + /@types/object-hash@3.0.6: + resolution: {integrity: sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w==} + dev: true /@types/prettier@2.7.2: resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} @@ -1479,7 +1546,6 @@ packages: /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - dev: true /@types/react-dom@18.0.11: resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==} @@ -1493,11 +1559,9 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 csstype: 3.1.1 - dev: true /@types/scheduler@0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} - dev: true /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} @@ -1523,19 +1587,20 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/parser@5.55.0(eslint@8.56.0)(typescript@5.3.3): - resolution: {integrity: sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@6.17.0(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.55.0 - '@typescript-eslint/types': 5.55.0 - '@typescript-eslint/typescript-estree': 5.55.0(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.17.0 + '@typescript-eslint/types': 6.17.0 + '@typescript-eslint/typescript-estree': 6.17.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.17.0 debug: 4.3.4 eslint: 8.56.0 typescript: 5.3.3 @@ -1543,17 +1608,12 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager@5.55.0: - resolution: {integrity: sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@6.17.0: + resolution: {integrity: sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==} + engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 5.55.0 - '@typescript-eslint/visitor-keys': 5.55.0 - dev: true - - /@typescript-eslint/types@5.55.0: - resolution: {integrity: sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/types': 6.17.0 + '@typescript-eslint/visitor-keys': 6.17.0 dev: true /@typescript-eslint/types@6.17.0: @@ -1561,27 +1621,6 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@5.55.0(typescript@5.3.3): - resolution: {integrity: sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.55.0 - '@typescript-eslint/visitor-keys': 5.55.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.3.3) - typescript: 5.3.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree@6.17.0(typescript@5.3.3): resolution: {integrity: sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -1604,14 +1643,6 @@ packages: - supports-color dev: true - /@typescript-eslint/visitor-keys@5.55.0: - resolution: {integrity: sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.55.0 - eslint-visitor-keys: 3.4.3 - dev: true - /@typescript-eslint/visitor-keys@6.17.0: resolution: {integrity: sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==} engines: {node: ^16.0.0 || >=18.0.0} @@ -1642,10 +1673,10 @@ packages: std-env: 3.7.0 test-exclude: 6.0.0 v8-to-istanbul: 9.2.0 - vitest: 1.1.1(@types/node@16.11.12) + vitest: 1.1.1(@types/node@18.19.4) transitivePeerDependencies: - supports-color - dev: false + dev: true /@vitest/expect@1.1.1: resolution: {integrity: sha512-Qpw01C2Hyb3085jBkOJLQ7HRX0Ncnh2qV4p+xWmmhcIUlMykUF69zsnZ1vPmAjZpomw9+5tWEGOQ0GTfR8U+kA==} @@ -1653,6 +1684,7 @@ packages: '@vitest/spy': 1.1.1 '@vitest/utils': 1.1.1 chai: 4.3.10 + dev: true /@vitest/runner@1.1.1: resolution: {integrity: sha512-8HokyJo1SnSi3uPFKfWm/Oq1qDwLC4QDcVsqpXIXwsRPAg3gIDh8EbZ1ri8cmQkBxdOu62aOF9B4xcqJhvt4xQ==} @@ -1660,6 +1692,7 @@ packages: '@vitest/utils': 1.1.1 p-limit: 5.0.0 pathe: 1.1.1 + dev: true /@vitest/snapshot@1.1.1: resolution: {integrity: sha512-WnMHjv4VdHLbFGgCdVVvyRkRPnOKN75JJg+LLTdr6ah7YnL75W+7CTIMdzPEPzaDxA8r5yvSVlc1d8lH3yE28w==} @@ -1667,11 +1700,13 @@ packages: magic-string: 0.30.5 pathe: 1.1.1 pretty-format: 29.7.0 + dev: true /@vitest/spy@1.1.1: resolution: {integrity: sha512-hDU2KkOTfFp4WFFPWwHFauddwcKuGQ7gF6Un/ZZkCogoAiTMN7/7YKvUDbywPZZ754iCQGjdUmXN3t4k0jm1IQ==} dependencies: tinyspy: 2.2.0 + dev: true /@vitest/utils@1.1.1: resolution: {integrity: sha512-E9LedH093vST/JuBSyHLFMpxJKW3dLhe/flUSPFedoyj4wKiFX7Jm8gYLtOIiin59dgrssfmFv0BJ1u8P/LC/A==} @@ -1679,6 +1714,7 @@ packages: diff-sequences: 29.6.3 loupe: 2.3.7 pretty-format: 29.7.0 + dev: true /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} @@ -1714,11 +1750,13 @@ packages: /acorn-walk@8.3.1: resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==} engines: {node: '>=0.4.0'} + dev: true /acorn@8.11.3: resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} @@ -1744,6 +1782,18 @@ packages: uri-js: 4.4.1 dev: true + /ansi-escapes@6.2.0: + resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} + engines: {node: '>=14.16'} + dependencies: + type-fest: 3.13.1 + dev: false + + /ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1753,6 +1803,11 @@ packages: engines: {node: '>=12'} dev: false + /ansi-styles@2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1768,6 +1823,7 @@ packages: /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + dev: true /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} @@ -1903,6 +1959,7 @@ packages: /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} @@ -1929,6 +1986,11 @@ packages: engines: {node: '>=8.0.0'} dev: false + /auto-bind@5.0.1: + resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /autoprefixer@10.4.13(postcss@8.4.21): resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} engines: {node: ^10 || ^12 || >=14} @@ -1994,7 +2056,7 @@ packages: hoist-non-react-statics: 3.3.2 next: 13.2.4(@babel/core@7.21.0)(react-dom@18.2.0)(react@18.2.0) superjson: 1.12.2 - dev: false + dev: true /babel-preset-current-node-syntax@1.0.1(@babel/core@7.21.0): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} @@ -2032,6 +2094,10 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + /blacklist@1.1.4: + resolution: {integrity: sha512-DWdfwimA1WQxVC69Vs1Fy525NbYwisMSCdYQmW9zyzOByz9OB/tQwrKZ3T3pbTkuFjnkJFlJuyiDjPiXL5kzew==} + dev: false + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -2088,11 +2154,12 @@ packages: /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + dev: true /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 get-intrinsic: 1.2.0 dev: true @@ -2132,6 +2199,18 @@ packages: loupe: 2.3.6 pathval: 1.1.1 type-detect: 4.0.8 + dev: true + + /chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + dev: true /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -2157,10 +2236,16 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} dependencies: get-func-name: 2.0.2 + dev: true /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} @@ -2179,7 +2264,6 @@ packages: /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} - dev: true /class-variance-authority@0.7.0: resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} @@ -2187,9 +2271,33 @@ packages: clsx: 2.0.0 dev: false + /cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + dev: false + + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: false + + /cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + dev: false + + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: false + /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - dev: false /clone@2.1.2: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} @@ -2206,6 +2314,13 @@ packages: engines: {node: '>=6'} dev: false + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: false + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -2234,10 +2349,20 @@ packages: delayed-stream: 1.0.0 dev: true + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + /common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2246,13 +2371,18 @@ packages: /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false /copy-anything@3.0.3: resolution: {integrity: sha512-fpW2W/BqEzqPp29QS+MwwfisHCQZtiduTe/m8idFo0xbti9fIZ2WVhAsCv4ggFVH3AgCkVdpoOCtQC6gBrdhjw==} engines: {node: '>=12.13'} dependencies: is-what: 4.1.8 - dev: false /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} @@ -2288,7 +2418,6 @@ packages: /csstype@3.1.1: resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} - dev: true /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -2338,6 +2467,7 @@ packages: engines: {node: '>=6'} dependencies: type-detect: 4.0.8 + dev: true /deep-equal@2.2.0: resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==} @@ -2416,6 +2546,7 @@ packages: /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} @@ -2673,7 +2804,6 @@ packages: /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} - dev: true /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -2704,11 +2834,11 @@ packages: dependencies: '@next/eslint-plugin-next': 14.0.4 '@rushstack/eslint-patch': 1.6.1 - '@typescript-eslint/parser': 5.55.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3) eslint: 8.56.0 eslint-import-resolver-node: 0.3.7 eslint-import-resolver-typescript: 3.5.3(eslint-plugin-import@2.29.1)(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.55.0)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0) eslint-plugin-jsx-a11y: 6.7.1(eslint@8.56.0) eslint-plugin-react: 7.33.2(eslint@8.56.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.56.0) @@ -2748,7 +2878,7 @@ packages: debug: 4.3.4 enhanced-resolve: 5.12.0 eslint: 8.56.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.55.0)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0) get-tsconfig: 4.4.0 globby: 13.1.3 is-core-module: 2.13.1 @@ -2758,7 +2888,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.55.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -2779,7 +2909,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.55.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3) debug: 3.2.7 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 @@ -2788,7 +2918,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.55.0)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -2798,7 +2928,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.55.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3) array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 array.prototype.flat: 1.3.2 @@ -2807,7 +2937,7 @@ packages: doctrine: 2.1.0 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.55.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.5.3)(eslint@8.56.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -3023,6 +3153,7 @@ packages: onetime: 6.0.0 signal-exit: 4.1.0 strip-final-newline: 3.0.0 + dev: true /expect@29.5.0: resolution: {integrity: sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==} @@ -3103,6 +3234,11 @@ packages: dependencies: to-regex-range: 5.0.1 + /find-up-simple@1.0.0: + resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} + engines: {node: '>=18'} + dev: false + /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3178,10 +3314,6 @@ packages: requiresBuild: true optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true - /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -3215,11 +3347,12 @@ packages: /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + dev: true /get-intrinsic@1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 has: 1.0.3 has-symbols: 1.0.3 dev: true @@ -3241,6 +3374,7 @@ packages: /get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + dev: true /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} @@ -3254,6 +3388,12 @@ packages: resolution: {integrity: sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==} dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3376,6 +3516,13 @@ packages: resolution: {integrity: sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==} dev: false + /has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + dev: true + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true @@ -3387,6 +3534,7 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + dev: true /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} @@ -3415,7 +3563,7 @@ packages: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 dev: true /hasown@2.0.0: @@ -3432,6 +3580,12 @@ packages: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: react-is: 16.13.1 + + /hosted-git-info@7.0.1: + resolution: {integrity: sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==} + engines: {node: ^16.14.0 || >=18.0.0} + dependencies: + lru-cache: 10.0.1 dev: false /html-encoding-sniffer@3.0.0: @@ -3443,7 +3597,7 @@ packages: /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: false + dev: true /http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} @@ -3469,6 +3623,7 @@ packages: /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + dev: true /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -3504,6 +3659,16 @@ packages: engines: {node: '>=8'} dev: true + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: false + + /index-to-position@0.1.2: + resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} + engines: {node: '>=18'} + dev: false + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -3513,6 +3678,81 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ink-progress-bar@3.0.0: + resolution: {integrity: sha512-GzByB3uEofqjyWC3VmdhYpBq+kzszu5Nwt/NruTDWa7fbw1E6sx6U1n6Kcsfj9D3qwR17dtC5w9uFVMyRA5HZw==} + dependencies: + blacklist: 1.1.4 + prop-types: 15.8.1 + dev: false + + /ink-spinner@5.0.0(ink@4.4.1)(react@18.2.0): + resolution: {integrity: sha512-EYEasbEjkqLGyPOUc8hBJZNuC5GvXGMLu0w5gdTNskPc7Izc5vO3tdQEYnzvshucyGCBXc86ig0ujXPMWaQCdA==} + engines: {node: '>=14.16'} + peerDependencies: + ink: '>=4.0.0' + react: '>=18.0.0' + dependencies: + cli-spinners: 2.9.2 + ink: 4.4.1(@types/react@18.2.21)(react@18.2.0) + react: 18.2.0 + dev: false + + /ink-table@3.1.0(ink@4.4.1)(react@18.2.0): + resolution: {integrity: sha512-qxVb4DIaEaJryvF9uZGydnmP9Hkmas3DCKVpEcBYC0E4eJd3qNgNe+PZKuzgCERFe9LfAS1TNWxCr9+AU4v3YA==} + peerDependencies: + ink: '>=3.0.0' + react: '>=16.8.0' + dependencies: + ink: 4.4.1(@types/react@18.2.21)(react@18.2.0) + object-hash: 2.2.0 + react: 18.2.0 + dev: false + + /ink@4.4.1(@types/react@18.2.21)(react@18.2.0): + resolution: {integrity: sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==} + engines: {node: '>=14.16'} + peerDependencies: + '@types/react': '>=18.0.0' + react: '>=18.0.0' + react-devtools-core: ^4.19.1 + peerDependenciesMeta: + '@types/react': + optional: true + react-devtools-core: + optional: true + dependencies: + '@alcalzone/ansi-tokenize': 0.1.3 + '@types/react': 18.2.21 + ansi-escapes: 6.2.0 + auto-bind: 5.0.1 + chalk: 5.3.0 + cli-boxes: 3.0.0 + cli-cursor: 4.0.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + indent-string: 5.0.0 + is-ci: 3.0.1 + is-lower-case: 2.0.2 + is-upper-case: 2.0.2 + lodash: 4.17.21 + patch-console: 2.0.0 + react: 18.2.0 + react-reconciler: 0.29.0(react@18.2.0) + scheduler: 0.23.0 + signal-exit: 3.0.7 + slice-ansi: 6.0.0 + stack-utils: 2.0.6 + string-width: 5.1.2 + type-fest: 0.12.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + ws: 8.13.0 + yoga-wasm-web: 0.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} @@ -3570,6 +3810,13 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.8.0 + dev: false + /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: @@ -3603,6 +3850,11 @@ packages: engines: {node: '>=8'} dev: false + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: false + /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} @@ -3616,6 +3868,12 @@ packages: dependencies: is-extglob: 2.1.1 + /is-lower-case@2.0.2: + resolution: {integrity: sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==} + dependencies: + tslib: 2.5.0 + dev: false + /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} dev: true @@ -3666,6 +3924,7 @@ packages: /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} @@ -3699,6 +3958,12 @@ packages: which-typed-array: 1.1.13 dev: true + /is-upper-case@2.0.2: + resolution: {integrity: sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==} + dependencies: + tslib: 2.5.0 + dev: false + /is-weakmap@2.0.1: resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} dev: true @@ -3719,7 +3984,6 @@ packages: /is-what@4.1.8: resolution: {integrity: sha512-yq8gMao5upkPoGEU9LsB2P+K3Kt8Q3fQFCGyNCWOAnJAMzEXVV9drYb0TXr42TTliLLhKIBvulgAXgtLLnwzGA==} engines: {node: '>=12.13'} - dev: false /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} @@ -3743,7 +4007,7 @@ packages: /istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - dev: false + dev: true /istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} @@ -3753,7 +4017,7 @@ packages: '@babel/parser': 7.21.2 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -3765,7 +4029,7 @@ packages: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - dev: false + dev: true /istanbul-lib-source-maps@4.0.1: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} @@ -3776,7 +4040,7 @@ packages: source-map: 0.6.1 transitivePeerDependencies: - supports-color - dev: false + dev: true /istanbul-reports@3.1.6: resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} @@ -3784,7 +4048,7 @@ packages: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - dev: false + dev: true /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -3828,7 +4092,7 @@ packages: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 '@types/jsdom': 20.0.1 - '@types/node': 16.11.12 + '@types/node': 18.19.4 jest-mock: 29.5.0 jest-util: 29.5.0 jsdom: 20.0.3 @@ -3849,7 +4113,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@types/graceful-fs': 4.1.6 - '@types/node': 16.11.12 + '@types/node': 18.19.4 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.10 @@ -3892,7 +4156,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 16.11.12 + '@types/node': 18.19.4 jest-util: 29.5.0 dev: true @@ -3937,7 +4201,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 16.11.12 + '@types/node': 18.19.4 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.10 @@ -3948,7 +4212,7 @@ packages: resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 16.11.12 + '@types/node': 18.19.4 jest-util: 29.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -4053,6 +4317,7 @@ packages: /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true /jsx-ast-utils@3.3.3: resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} @@ -4101,6 +4366,7 @@ packages: dependencies: mlly: 1.4.2 pkg-types: 1.0.3 + dev: true /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} @@ -4123,6 +4389,18 @@ packages: /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + /loglevel-colored-level-prefix@1.0.0: + resolution: {integrity: sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==} + dependencies: + chalk: 1.1.3 + loglevel: 1.8.1 + dev: true + + /loglevel@1.8.1: + resolution: {integrity: sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==} + engines: {node: '>= 0.6.0'} + dev: true + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -4134,11 +4412,13 @@ packages: deprecated: Please upgrade to 2.3.7 which fixes GHSA-4q6p-r6v2-jvc5 dependencies: get-func-name: 2.0.2 + dev: true /loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} dependencies: get-func-name: 2.0.2 + dev: true /lru-cache@10.0.1: resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} @@ -4166,6 +4446,7 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + dev: true /magicast@0.3.2: resolution: {integrity: sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg==} @@ -4173,14 +4454,14 @@ packages: '@babel/parser': 7.23.6 '@babel/types': 7.23.6 source-map-js: 1.0.2 - dev: false + dev: true /make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} dependencies: semver: 7.5.4 - dev: false + dev: true /makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -4197,6 +4478,7 @@ packages: /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -4225,9 +4507,15 @@ packages: mime-db: 1.52.0 dev: true + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: false + /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + dev: true /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} @@ -4265,6 +4553,7 @@ packages: pathe: 1.1.1 pkg-types: 1.0.3 ufo: 1.3.2 + dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -4296,7 +4585,6 @@ packages: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -4363,7 +4651,6 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: false /node-cache@5.1.2: resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==} @@ -4379,6 +4666,16 @@ packages: /node-releases@2.0.9: resolution: {integrity: sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA==} + /normalize-package-data@6.0.0: + resolution: {integrity: sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==} + engines: {node: ^16.14.0 || >=18.0.0} + dependencies: + hosted-git-info: 7.0.1 + is-core-module: 2.13.1 + semver: 7.5.4 + validate-npm-package-license: 3.0.4 + dev: false + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -4400,6 +4697,7 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: path-key: 4.0.0 + dev: true /nwsapi@2.2.2: resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} @@ -4409,6 +4707,11 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + /object-hash@2.2.0: + resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} + engines: {node: '>= 6'} + dev: false + /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -4518,11 +4821,19 @@ packages: dependencies: wrappy: 1.0.2 + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: false + /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} dependencies: mimic-fn: 4.0.0 + dev: true /open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} @@ -4576,6 +4887,7 @@ packages: engines: {node: '>=18'} dependencies: yocto-queue: 1.0.0 + dev: true /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} @@ -4603,12 +4915,26 @@ packages: callsites: 3.1.0 dev: true + /parse-json@8.1.0: + resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} + engines: {node: '>=18'} + dependencies: + '@babel/code-frame': 7.23.5 + index-to-position: 0.1.2 + type-fest: 4.9.0 + dev: false + /parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} dependencies: entities: 4.4.0 dev: true + /patch-console@2.0.0: + resolution: {integrity: sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -4625,6 +4951,7 @@ packages: /path-key@4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + dev: true /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -4644,9 +4971,11 @@ packages: /pathe@1.1.1: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: true /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true /peek-readable@5.0.0: resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==} @@ -4729,6 +5058,7 @@ packages: jsonc-parser: 3.2.0 mlly: 1.4.2 pathe: 1.1.1 + dev: true /postcss-import@15.1.0(postcss@8.4.32): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} @@ -4792,7 +5122,6 @@ packages: nanoid: 3.3.6 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /postcss@8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} @@ -4821,7 +5150,27 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier-plugin-tailwindcss@0.5.10(prettier@2.8.8): + /prettier-eslint@16.2.0: + resolution: {integrity: sha512-GDTSKc62VaLceiaI/qMaKo2oco2CIWtbj4Zr6ckhbTgcBL/uR0d9jkMzh9OtBIT/Z7iBoCB4OHj/aJ5YuNgAuA==} + engines: {node: '>=16.10.0'} + dependencies: + '@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3) + common-tags: 1.8.2 + dlv: 1.1.3 + eslint: 8.56.0 + indent-string: 4.0.0 + lodash.merge: 4.6.2 + loglevel-colored-level-prefix: 1.0.0 + prettier: 3.1.1 + pretty-format: 29.7.0 + require-relative: 0.8.7 + typescript: 5.3.3 + vue-eslint-parser: 9.3.2(eslint@8.56.0) + transitivePeerDependencies: + - supports-color + dev: true + + /prettier-plugin-tailwindcss@0.5.10(prettier@3.1.1): resolution: {integrity: sha512-9UGSejqFxGG6brYjFfTYlJ8zs4L/lvZg1AngFfaC5Fs1otSskASv5IWKmjPu5MlABQUtTKtMArKyYr/hWpXSUg==} engines: {node: '>=14.21.3'} peerDependencies: @@ -4870,12 +5219,12 @@ packages: prettier-plugin-twig-melody: optional: true dependencies: - prettier: 2.8.8 + prettier: 3.1.1 dev: true - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} + /prettier@3.1.1: + resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} + engines: {node: '>=14'} hasBin: true dev: true @@ -4904,6 +5253,7 @@ packages: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.2.0 + dev: true /process-warning@3.0.0: resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} @@ -4920,7 +5270,6 @@ packages: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: true /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} @@ -4967,6 +5316,7 @@ packages: /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true /react-query@3.39.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==} @@ -4987,6 +5337,17 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-reconciler@0.29.0(react@18.2.0): + resolution: {integrity: sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + dev: false + /react-ssr-prepass@1.5.0(react@18.2.0): resolution: {integrity: sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==} peerDependencies: @@ -5016,6 +5377,26 @@ packages: dependencies: pify: 2.3.0 + /read-package-up@11.0.0: + resolution: {integrity: sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==} + engines: {node: '>=18'} + dependencies: + find-up-simple: 1.0.0 + read-pkg: 9.0.1 + type-fest: 4.9.0 + dev: false + + /read-pkg@9.0.1: + resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} + engines: {node: '>=18'} + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 6.0.0 + parse-json: 8.1.0 + type-fest: 4.9.0 + unicorn-magic: 0.1.0 + dev: false + /readable-stream@3.6.0: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} engines: {node: '>= 6'} @@ -5125,6 +5506,10 @@ packages: resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==} dev: false + /require-relative@0.8.7: + resolution: {integrity: sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==} + dev: true + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: true @@ -5139,6 +5524,10 @@ packages: engines: {node: '>=8'} dev: true + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: false + /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -5156,6 +5545,14 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: false + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -5185,6 +5582,7 @@ packages: '@rollup/rollup-win32-ia32-msvc': 4.9.2 '@rollup/rollup-win32-x64-msvc': 4.9.2 fsevents: 2.3.3 + dev: true /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -5241,11 +5639,11 @@ packages: /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true + dev: true /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - dev: true /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} @@ -5293,10 +5691,10 @@ packages: /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} @@ -5312,6 +5710,22 @@ packages: engines: {node: '>=12'} dev: true + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + + /slice-ansi@6.0.0: + resolution: {integrity: sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==} + engines: {node: '>=14.16'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + /sonic-boom@3.2.1: resolution: {integrity: sha512-iITeTHxy3B9FGu8aVdiDXUVAcHMF9Ss0cCsAOo2HfCrmVGT3/DT5oYaeu0M/YKZDlKTvChEyPq0zI9Hf33EX6A==} dependencies: @@ -5332,6 +5746,29 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} requiresBuild: true + dev: true + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.16 + dev: false + + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: false + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.16 + dev: false + + /spdx-license-ids@3.0.16: + resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} + dev: false /split2@4.1.0: resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} @@ -5347,13 +5784,14 @@ packages: engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 - dev: true /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true /std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + dev: true /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} @@ -5449,6 +5887,13 @@ packages: safe-buffer: 5.2.1 dev: false + /strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + dependencies: + ansi-regex: 2.1.1 + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -5470,6 +5915,7 @@ packages: /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + dev: true /strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} @@ -5486,6 +5932,7 @@ packages: resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} dependencies: acorn: 8.11.3 + dev: true /strtok3@7.0.0: resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==} @@ -5511,7 +5958,6 @@ packages: '@babel/core': 7.21.0 client-only: 0.0.1 react: 18.2.0 - dev: false /sucrase@3.34.0: resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} @@ -5531,7 +5977,11 @@ packages: engines: {node: '>=10'} dependencies: copy-anything: 3.0.3 - dev: false + + /supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + dev: true /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -5544,6 +5994,7 @@ packages: engines: {node: '>=8'} dependencies: has-flag: 4.0.0 + dev: true /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} @@ -5623,6 +6074,7 @@ packages: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 + dev: true /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -5654,14 +6106,17 @@ packages: /tinybench@2.5.1: resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} + dev: true /tinypool@0.8.1: resolution: {integrity: sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg==} engines: {node: '>=14.0.0'} + dev: true /tinyspy@2.2.0: resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} engines: {node: '>=14.0.0'} + dev: true /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -5728,22 +6183,19 @@ packages: strip-bom: 3.0.0 dev: true - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} - /tsutils@3.21.0(typescript@5.3.3): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - 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.7.0: + resolution: {integrity: sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==} + engines: {node: '>=18.0.0'} + hasBin: true dependencies: - tslib: 1.14.1 - typescript: 5.3.3 - dev: true + esbuild: 0.19.11 + get-tsconfig: 4.7.2 + optionalDependencies: + fsevents: 2.3.3 + dev: false /type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} @@ -5762,12 +6214,28 @@ packages: /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + dev: true + + /type-fest@0.12.0: + resolution: {integrity: sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==} + engines: {node: '>=10'} + dev: false /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} dev: true + /type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: false + + /type-fest@4.9.0: + resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==} + engines: {node: '>=16'} + dev: false + /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} engines: {node: '>= 0.4'} @@ -5810,10 +6278,10 @@ packages: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} hasBin: true - dev: true /ufo@1.3.2: resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} + dev: true /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -5824,6 +6292,15 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + dev: false + /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -5877,9 +6354,16 @@ packages: '@jridgewell/trace-mapping': 0.3.17 '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 2.0.0 + dev: true + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 dev: false - /vite-node@1.1.1(@types/node@16.11.12): + /vite-node@1.1.1(@types/node@18.19.4): resolution: {integrity: sha512-2bGE5w4jvym5v8llF6Gu1oBrmImoNSs4WmRVcavnG2me6+8UQntTqLiAMFyiAobp+ZXhj5ZFhI7SmLiFr/jrow==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -5888,7 +6372,7 @@ packages: debug: 4.3.4 pathe: 1.1.1 picocolors: 1.0.0 - vite: 5.0.10(@types/node@16.11.12) + vite: 5.0.10(@types/node@18.19.4) transitivePeerDependencies: - '@types/node' - less @@ -5898,8 +6382,9 @@ packages: - sugarss - supports-color - terser + dev: true - /vite@5.0.10(@types/node@16.11.12): + /vite@5.0.10(@types/node@18.19.4): resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -5927,14 +6412,15 @@ packages: terser: optional: true dependencies: - '@types/node': 16.11.12 + '@types/node': 18.19.4 esbuild: 0.19.11 postcss: 8.4.32 rollup: 4.9.2 optionalDependencies: fsevents: 2.3.3 + dev: true - /vitest@1.1.1(@types/node@16.11.12): + /vitest@1.1.1(@types/node@18.19.4): resolution: {integrity: sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -5959,7 +6445,7 @@ packages: jsdom: optional: true dependencies: - '@types/node': 16.11.12 + '@types/node': 18.19.4 '@vitest/expect': 1.1.1 '@vitest/runner': 1.1.1 '@vitest/snapshot': 1.1.1 @@ -5978,8 +6464,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.8.1 - vite: 5.0.10(@types/node@16.11.12) - vite-node: 1.1.1(@types/node@16.11.12) + vite: 5.0.10(@types/node@18.19.4) + vite-node: 1.1.1(@types/node@18.19.4) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -5989,6 +6475,25 @@ packages: - sugarss - supports-color - terser + dev: true + + /vue-eslint-parser@9.3.2(eslint@8.56.0): + resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.56.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + dev: true /w3c-xmlserializer@4.0.0: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} @@ -6102,6 +6607,14 @@ packages: dependencies: siginfo: 2.0.0 stackback: 0.0.2 + dev: true + + /widest-line@4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + dev: false /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} @@ -6148,7 +6661,6 @@ packages: optional: true utf-8-validate: optional: true - dev: true /xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} @@ -6177,6 +6689,11 @@ packages: /yocto-queue@1.0.0: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} + dev: true + + /yoga-wasm-web@0.3.3: + resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} + dev: false /zod-refine@1.1.1(@recoiljs/refine@0.1.1)(recoil-sync@0.2.0)(zod@3.20.2): resolution: {integrity: sha512-aTRboKHcE/jGZjh4WYaU7NRkrNJuLakpRIFTZKNXbAx1vlVb8jOQ4ERf41jECww31v38R9mC41cuKDXFPS//Cg==} diff --git a/src/scripts/common.sh b/src/scripts/common.sh index fdd3c0b19..d15125199 100755 --- a/src/scripts/common.sh +++ b/src/scripts/common.sh @@ -56,6 +56,19 @@ install_hooks() fi } +install_cli() +{ + report_status "Installing RatOS CLI" + sudo="" + if [ "$EUID" -ne 0 ] + then + sudo="sudo" + fi + if [ ! -L "/usr/local/bin/ratos" ]; then + $sudo ln -s "$SRC_DIR/bin/ratos" "/usr/local/bin/ratos" + fi +} + verify_users() { if ! id "pi" &>/dev/null; then @@ -67,10 +80,10 @@ verify_users() install_udev_rule() { report_status "Installing udev rule" - sudo="sudo" - if [ "$1" = "root" ] + sudo="" + if [ "$EUID" -ne 0 ] then - sudo="" + sudo="sudo" fi if [ ! -e /etc/udev/rules.d/97-ratos.rules ]; then $sudo ln -s "$SCRIPT_DIR/ratos.rules" /etc/udev/rules.d/97-ratos.rules @@ -79,10 +92,10 @@ install_udev_rule() ensure_sudo_command_whitelisting() { - sudo="sudo" - if [ "$1" = "root" ] + sudo="" + if [ "$EUID" -ne 0 ] then - sudo="" + sudo="sudo" fi report_status "Updating whitelisted commands" # Whitelist RatOS configurator git hook scripts diff --git a/src/scripts/setup.sh b/src/scripts/setup.sh index fab019b3b..1bbabaeee 100755 --- a/src/scripts/setup.sh +++ b/src/scripts/setup.sh @@ -94,4 +94,5 @@ install_logrotation pnpm_install disable_telemetry install_service -install_udev_rule "$USER" +install_udev_rule +install_cli diff --git a/src/scripts/update.sh b/src/scripts/update.sh index 7073e2b3a..c17520ade 100755 --- a/src/scripts/update.sh +++ b/src/scripts/update.sh @@ -18,3 +18,4 @@ ensure_sudo_command_whitelisting ensure_pnpm_installation pnpm_install install_udev_rule root +install_cli \ No newline at end of file diff --git a/src/server/helpers/extensions.ts b/src/server/helpers/extensions.ts new file mode 100644 index 000000000..8b00fe1c8 --- /dev/null +++ b/src/server/helpers/extensions.ts @@ -0,0 +1,143 @@ +import { existsSync } from 'fs'; +import { symlink, appendFile, unlink } from 'fs/promises'; +import path from 'path'; +import { z } from 'zod'; +import { serverSchema } from '../../env/schema.mjs'; +import { replaceInFileByLine, searchFileByLine } from './file-operations'; +import { TRPCError } from '@trpc/server'; + +const extension = z.object({ + fileName: z.string(), + path: z.string(), + extensionName: z.string(), +}); + +const options = z.object({ + errorIfExists: z.boolean().optional(), + errorIfNotExists: z.boolean().optional(), +}); + +export type Extension = z.infer; +export type Options = z.infer; + +interface SymlinkExtensionsProps { + extensions: T[]; + options?: Pick; + gitRepoPath: string; + relativePath: string | ((extension: T) => string); + saveExtensions: (extensions: T[]) => void; +} + +export const symlinkExtensions = async (props: SymlinkExtensionsProps) => { + const environment = serverSchema.parse(process.env); + const currentExtensions = props.extensions.slice(); + let cleanedUpExtensions: T[] = []; + if (currentExtensions.length === 0) { + return { report: 'No extensions registered, nothing to do.', cleanedUpExtensions, symlinkResults: [] }; + } + const gitExcludePath = path.resolve(path.join(props.gitRepoPath, '.git', 'info', 'exclude')); + const symlinkResults = await Promise.all( + currentExtensions.map(async (ext): Promise<{ result: 'success' | 'error'; message: string }> => { + if (existsSync(path.resolve(path.join(ext.path, ext.fileName)))) { + cleanedUpExtensions.push(ext); + const relativeDestination = path.join( + typeof props.relativePath === 'function' ? props.relativePath(ext) : props.relativePath, + ext.fileName, + ); + const destination = path.resolve(path.join(environment.MOONRAKER_DIR, relativeDestination)); + const excludeLine = new RegExp(`^${relativeDestination}$`); + const isExcluded = await searchFileByLine(gitExcludePath, excludeLine); + const symlinkExists = existsSync(destination); + try { + if (symlinkExists === false) { + await symlink(path.resolve(path.join(ext.path, ext.fileName)), destination); + } else if (props.options?.errorIfExists) { + throw new TRPCError({ + code: 'PRECONDITION_FAILED', + message: `Symlink for "${ext.fileName}" already exists.`, + }); + } + if (isExcluded === false) { + await appendFile(gitExcludePath, `${relativeDestination}\n`); + } + return { + result: 'success', + message: symlinkExists + ? `Symlink for "${ext.fileName}" already exists. Skipping.` + : `Symlink for "${ext.fileName}" created`, + }; + } catch (e) { + return { + result: 'error', + message: `Failed to create symlink for "${ext.fileName}"`, + }; + } + } else { + return { + result: 'error', + message: `Extension file "${ext.fileName}" does not exist in ${ext.path} and has been removed from the list of registered extensions`, + }; + } + }), + ); + if (cleanedUpExtensions.length !== currentExtensions.length) { + props.saveExtensions(cleanedUpExtensions); + } + const successCount = symlinkResults.filter((r) => r.result === 'success').length; + let report = `Symlinked ${successCount}/${symlinkResults.length} extension(s): \n`; + symlinkResults.forEach((r) => { + report += `${r.message} \n`; + }); + return { report, cleanedUpExtensions, symlinkResults }; +}; + +interface UnlinkExtensionProps> { + extension: T; + options?: Pick; + gitRepoPath: string; + relativePath: string | ((extension: T) => string); +} + +export const unlinkExtension = async ( + props: UnlinkExtensionProps, +): Promise<{ result: 'success' | 'error'; message: string }> => { + const ext = props.extension; + const relativeDestination = path.join( + typeof props.relativePath === 'function' ? props.relativePath(ext) : props.relativePath, + ext.fileName, + ); + const gitExcludePath = path.resolve(props.gitRepoPath, '.git', 'info', 'exclude'); + const destination = path.resolve(path.join(props.gitRepoPath, relativeDestination)); + if (existsSync(path.resolve(path.join(ext.path, ext.fileName)))) { + const excludeLine = new RegExp(`^${relativeDestination}$`); + // Remove extension from git exclude file + await replaceInFileByLine(gitExcludePath, excludeLine, null); + const symlinkExists = existsSync(destination); + try { + if (symlinkExists === true) { + await unlink(destination); + } else if (props.options?.errorIfNotExists) { + throw new TRPCError({ + code: 'PRECONDITION_FAILED', + message: `Symlink for "${ext.fileName}" doesn't exist.`, + }); + } + return { + result: 'success', + message: symlinkExists + ? `Symlink for "${ext.fileName}" has been removed.` + : `Symlink for "${ext.fileName}" doesn't exist. Skipping.`, + }; + } catch (e) { + return { + result: 'error', + message: `Failed to remove symlink for "${ext.fileName}"`, + }; + } + } else { + return { + result: 'success', + message: `Extension file "${ext.fileName}" does not exist in ${ext.path}. Nothing to do.`, + }; + } +}; diff --git a/src/server/helpers/file-operations.ts b/src/server/helpers/file-operations.ts index c16d787f9..0471cc62f 100644 --- a/src/server/helpers/file-operations.ts +++ b/src/server/helpers/file-operations.ts @@ -3,7 +3,7 @@ import { copyFile, unlink } from 'fs/promises'; import { EOL } from 'os'; import { createInterface } from 'readline'; -export const replaceInFileByLine = async (filePath: string, search: string | RegExp, replace: string) => { +export const replaceInFileByLine = async (filePath: string, search: string | RegExp, replace: string | null) => { if (!existsSync(filePath)) { throw new Error('Firmware config file does not exist: ' + filePath); } @@ -16,6 +16,9 @@ export const replaceInFileByLine = async (filePath: string, search: string | Reg }); for await (const line of rl) { + if (replace == null || line.match(search)) { + continue; + } writeStream.write(line.replace(search, replace) + EOL); } await new Promise((resolve, reject) => { diff --git a/src/server/routers/klippy-extensions.ts b/src/server/routers/klippy-extensions.ts index 04432721f..85c324f33 100644 --- a/src/server/routers/klippy-extensions.ts +++ b/src/server/routers/klippy-extensions.ts @@ -5,14 +5,14 @@ import { getLogger } from '../helpers/logger'; import { publicProcedure, router } from '../trpc'; import path from 'path'; import { serverSchema } from '../../env/schema.mjs'; -import { searchFileByLine } from '../helpers/file-operations'; -import { appendFile, symlink } from 'fs/promises'; +import { symlinkExtensions, unlinkExtension } from '../helpers/extensions'; const klippyExtension = z.object({ fileName: z.string(), path: z.string(), extensionName: z.string(), errorIfExists: z.boolean().optional(), + errorIfNotExists: z.boolean().optional(), isKinematics: z.boolean().optional(), }); const klippyExtensions = z.array(klippyExtension); @@ -41,105 +41,114 @@ const saveExtensions = (extensions: z.infer) => { writeFileSync(klippyExtensionsFile, JSON.stringify(extensions)); }; -export const symlinkKlippyExtensions = async () => { +export const symlinkKlippyExtensions = async (errorIfExists?: boolean) => { const environment = serverSchema.parse(process.env); const currentExtensions = getExtensions(); - if (currentExtensions.length === 0) { - return 'No extensions registered, nothing to do.'; - } - let cleanedUpExtensions: z.infer = []; - const gitExcludePath = path.resolve(path.join(environment.KLIPPER_DIR, '.git', 'info', 'exclude')); - const symlinkResults = await Promise.all( - currentExtensions.map(async (ext) => { - if (existsSync(path.resolve(path.join(ext.path, ext.fileName)))) { - const relativeDestination = ext.isKinematics - ? `klippy/kinematics/${ext.fileName}` - : `klippy/extras/${ext.fileName}`; - const destination = path.resolve(path.join(environment.KLIPPER_DIR, relativeDestination)); - cleanedUpExtensions.push(ext); - const excludeLine = new RegExp(`^${relativeDestination}$`); - const isExcluded = await searchFileByLine(gitExcludePath, excludeLine); - const symlinkExists = existsSync( - path.resolve(path.join(environment.MOONRAKER_DIR, 'moonraker/components', ext.fileName)), - ); - if (existsSync(destination)) { - return { - result: 'success', - message: `Symlink for "${ext.fileName}" already exists`, - }; - } - try { - if (symlinkExists === false) { - await symlink(path.resolve(path.join(ext.path, ext.fileName)), destination); - } - if (isExcluded === false) { - await appendFile(gitExcludePath, `${relativeDestination}\n`); - } - return { - result: 'success', - message: symlinkExists - ? `Symlink for "${ext.fileName}" already exists. Skipping.` - : `Symlink for "${ext.fileName}" created`, - }; - } catch (e) { - return { - result: 'error', - message: `Failed to create symlink for "${ext.fileName}"`, - }; - } - } else { - return { - result: 'error', - message: `Extension file "${ext.fileName}" does not exist in ${ext.path} and has been removed from the list of registered extensions`, - }; - } - }), - ); - if (cleanedUpExtensions.length !== currentExtensions.length) { - saveExtensions(cleanedUpExtensions); - } - const successCount = symlinkResults.filter((r) => r.result === 'success').length; - let report = `Symlinked ${successCount}/${symlinkResults.length} extension(s): \n`; - symlinkResults.forEach((r) => { - report += `${r.message} \n`; + return await symlinkExtensions({ + extensions: currentExtensions, + options: { + errorIfExists: errorIfExists, + }, + gitRepoPath: environment.KLIPPER_DIR, + relativePath, + saveExtensions, }); - return report; +}; + +const relativePath = (ext: z.infer) => { + return ext.isKinematics ? `klippy/kinematics` : `klippy/extras`; }; export const klippyExtensionsRouter = router({ register: publicProcedure.input(z.object({ json: klippyExtension })).mutation(async ({ input }) => { const currentExtensions = getExtensions(); - const { path: filePath, fileName, errorIfExists } = input.json; + const { path: filePath, fileName, errorIfExists, extensionName } = input.json; const extensionPath = path.join(filePath, fileName); if (!existsSync(extensionPath)) { - getLogger().error(`File "${extensionPath}" does not exist`); throw new TRPCError({ message: `File "${extensionPath}" does not exist`, code: 'PRECONDITION_FAILED', }); } if ( - currentExtensions.find((ext) => ext.fileName === fileName && !!ext.isKinematics === !!input.json.isKinematics) + currentExtensions.find( + (ext) => + ext.extensionName === extensionName || + (ext.fileName === fileName && !!ext.isKinematics === !!input.json.isKinematics), + ) ) { if (errorIfExists === true) { - getLogger().error( - `${ - input.json.isKinematics ? 'A kinematic' : 'An' - } extension with the fileName "${fileName}" is already registered`, - ); throw new TRPCError({ - message: `An extension with the fileName "${fileName}" is already registered`, + message: `${ + input.json.isKinematics ? 'A kinematic' : 'An' + } extension called "${extensionName}" with fileName "${fileName}" is already registered`, code: 'PRECONDITION_FAILED', }); } - getLogger().warn(`An extension with the fileName "${fileName}" is already registered, ignoring...`); + getLogger().warn( + `${ + input.json.isKinematics ? 'A kinematic' : 'An' + } extension called "${extensionName}" with the fileName "${fileName}" is already registered, ignoring...`, + ); return true; } currentExtensions.push(input.json); saveExtensions(currentExtensions); return true; }), - symlink: publicProcedure.mutation(symlinkKlippyExtensions), + unregister: publicProcedure + .input(z.object({ extensionName: z.string(), errorIfNotExists: z.boolean().optional() })) + .mutation(async ({ input }) => { + const currentExtensions = getExtensions(); + const { extensionName } = input; + const extensionIndex = currentExtensions.findIndex((ext) => ext.extensionName === extensionName); + if (extensionIndex === -1) { + if (input.errorIfNotExists === true) { + throw new TRPCError({ + message: `Extension with the name "${extensionName}" is not registered`, + code: 'PRECONDITION_FAILED', + }); + } + getLogger().warn(`Extension with the name "${extensionName}" is not registered, ignoring...`); + return { + result: 'success' as const, + message: `Extension file "${extensionName}" does not exist. Nothing to do.`, + }; + } + const ext = currentExtensions.splice(extensionIndex, 1); + if (ext.length !== 1) { + throw new Error('Failed to remove extension'); + } + const res = await unlinkExtension({ + extension: ext[0], + gitRepoPath: serverSchema.parse(process.env).KLIPPER_DIR, + relativePath, + }); + if (res.result === 'success') { + saveExtensions(currentExtensions); + } + return res; + }), + symlink: publicProcedure + .input( + z.object({ + errorIfExists: z.boolean().optional(), + }), + ) + .mutation(async ({ input }) => await symlinkKlippyExtensions(input.errorIfExists)), + unlink: publicProcedure.mutation(async () => { + const currentExtensions = getExtensions(); + return await Promise.all( + currentExtensions.map(async (ext) => { + const res = await unlinkExtension({ + extension: ext, + gitRepoPath: serverSchema.parse(process.env).KLIPPER_DIR, + relativePath, + }); + return res; + }), + ); + }), list: publicProcedure.output(klippyExtensions).query(async () => { return getExtensions(); }), diff --git a/src/server/routers/moonraker-extensions.ts b/src/server/routers/moonraker-extensions.ts index d67a42703..6c7f89bef 100644 --- a/src/server/routers/moonraker-extensions.ts +++ b/src/server/routers/moonraker-extensions.ts @@ -5,8 +5,7 @@ import { getLogger } from '../helpers/logger'; import { publicProcedure, router } from '../trpc'; import path from 'path'; import { serverSchema } from '../../env/schema.mjs'; -import { searchFileByLine } from '../helpers/file-operations'; -import { appendFile, symlink } from 'fs/promises'; +import { symlinkExtensions, unlinkExtension } from '../helpers/extensions'; const moonrakerExtension = z.object({ fileName: z.string(), @@ -40,62 +39,19 @@ const saveExtensions = (extensions: z.infer) => { writeFileSync(moonrakerExtensionsFile, JSON.stringify(extensions)); }; -export const symlinkMoonrakerExtensions = async () => { +export const symlinkMoonrakerExtensions = async (errorIfExists?: boolean) => { const environment = serverSchema.parse(process.env); const currentExtensions = getExtensions(); - if (currentExtensions.length === 0) { - return 'No extensions registered, nothing to do.'; - } - let cleanedUpExtensions: z.infer = []; - const gitExcludePath = path.resolve(path.join(environment.MOONRAKER_DIR, '.git', 'info', 'exclude')); - const symlinkResults = await Promise.all( - currentExtensions.map(async (ext) => { - if (existsSync(path.resolve(path.join(ext.path, ext.fileName)))) { - cleanedUpExtensions.push(ext); - const excludeLine = new RegExp(`^moonraker/components/${ext.fileName}$`); - const isExcluded = await searchFileByLine(gitExcludePath, excludeLine); - const symlinkExists = existsSync( - path.resolve(path.join(environment.MOONRAKER_DIR, 'moonraker/components', ext.fileName)), - ); - try { - if (symlinkExists === false) { - await symlink( - path.resolve(path.join(ext.path, ext.fileName)), - path.resolve(path.join(environment.MOONRAKER_DIR, 'moonraker/components', ext.fileName)), - ); - } - if (isExcluded === false) { - await appendFile(gitExcludePath, `moonraker/components/${ext.fileName}\n`); - } - return { - result: 'success', - message: symlinkExists - ? `Symlink for "${ext.fileName}" already exists. Skipping.` - : `Symlink for "${ext.fileName}" created`, - }; - } catch (e) { - return { - result: 'error', - message: `Failed to create symlink for "${ext.fileName}"`, - }; - } - } else { - return { - result: 'error', - message: `Extension file "${ext.fileName}" does not exist in ${ext.path} and has been removed from the list of registered extensions`, - }; - } - }), - ); - if (cleanedUpExtensions.length !== currentExtensions.length) { - saveExtensions(cleanedUpExtensions); - } - const successCount = symlinkResults.filter((r) => r.result === 'success').length; - let report = `Symlinked ${successCount}/${symlinkResults.length} extension(s): \n`; - symlinkResults.forEach((r) => { - report += `${r.message} \n`; + + return await symlinkExtensions({ + extensions: currentExtensions, + options: { + errorIfExists: errorIfExists, + }, + gitRepoPath: environment.MOONRAKER_DIR, + relativePath: () => `moonraker/components`, + saveExtensions, }); - return report; }; export const moonrakerExtensionsRouter = router({ @@ -125,7 +81,58 @@ export const moonrakerExtensionsRouter = router({ saveExtensions(currentExtensions); return true; }), - symlink: publicProcedure.mutation(symlinkMoonrakerExtensions), + symlink: publicProcedure + .input( + z.object({ + errorIfExists: z.boolean().optional(), + }), + ) + .mutation(async ({ input }) => await symlinkMoonrakerExtensions(input.errorIfExists)), + unlink: publicProcedure.mutation(async () => { + const currentExtensions = getExtensions(); + const environment = serverSchema.parse(process.env); + return await Promise.all( + currentExtensions.map(async (ext) => { + const res = await unlinkExtension({ + extension: ext, + gitRepoPath: environment.MOONRAKER_DIR, + relativePath: 'moonraker/components', + }); + return res; + }), + ); + }), + unregister: publicProcedure + .input(z.object({ extensionName: z.string(), errorIfNotExists: z.boolean().optional() })) + .mutation(async ({ input }) => { + const environment = serverSchema.parse(process.env); + const currentExtensions = getExtensions(); + const { extensionName } = input; + const extensionIndex = currentExtensions.findIndex((ext) => ext.extensionName === extensionName); + if (extensionIndex === -1) { + if (input.errorIfNotExists === true) { + throw new TRPCError({ + message: `Extension with the name "${extensionName}" is not registered`, + code: 'PRECONDITION_FAILED', + }); + } + getLogger().warn(`Extension with the name "${extensionName}" is not registered, ignoring...`); + return { result: 'success' as const, message: `Extension with the name "${extensionName}" is not registered` }; + } + const ext = currentExtensions.splice(extensionIndex, 1); + if (ext.length !== 1) { + throw new Error('Failed to remove extension'); + } + const res = await unlinkExtension({ + extension: ext[0], + gitRepoPath: environment.MOONRAKER_DIR, + relativePath: 'moonraker/components', + }); + if (res.result === 'success') { + saveExtensions(currentExtensions); + } + return res; + }), list: publicProcedure.output(moonrakerExtensions).query(async () => { return getExtensions(); }), diff --git a/src/server/routers/printer.ts b/src/server/routers/printer.ts index 073f8431d..1e174e8ac 100644 --- a/src/server/routers/printer.ts +++ b/src/server/routers/printer.ts @@ -106,7 +106,7 @@ export const getPrinters = async ( ...(JSON.parse(readFileSync(f).toString()) as {}), path: f.replace('printer-definition.json', ''), id: f.replace('/printer-definition.json', '').split('/').pop(), - } as z.infer), + } as z.infer), ) .filter(Boolean); @@ -238,7 +238,7 @@ export const deserializePartialPrinterConfiguration = async ( ? undefined : await Promise.all( config.toolheads.map(async (th) => await deserializePartialToolheadConfiguration(th, config, boards)), - ); + ); return PartialPrinterConfiguration.parse({ toolheads: toolheads, @@ -287,13 +287,13 @@ const getTimeStamp = () => { return `${yyyy}${mm}${dd}-${hh}${min}${sec}`; }; -const generateKlipperConfiguration = async ( +const generateKlipperConfiguration = async ( config: PrinterConfiguration, overwritePrinterCfg = false, overwriteExtras: boolean = false, - returnAsText: boolean = false, + returnAsText: T = false as T, noWrite: boolean = false, -) => { +): Promise => { const utils = await constructKlipperConfigUtils(config); const extrasGenerator = constructKlipperConfigExtrasGenerator(config, utils); const helper = await constructKlipperConfigHelpers(config, extrasGenerator, utils); @@ -376,6 +376,7 @@ const generateKlipperConfiguration = async ( if (returnAsText) { return renderedTemplate; } + return results; }; export const loadSerializedConfig = async (filePath: string) => { @@ -385,14 +386,18 @@ export const loadSerializedConfig = async (filePath: string) => { return config; }; -export const regenerateKlipperConfiguration = async (fromFile?: string, returnAsText?: boolean, noWrite?: boolean) => { +export const regenerateKlipperConfiguration = async ( + fromFile?: string, + returnAsText?: T, + noWrite?: boolean, +) => { const environment = serverSchema.parse(process.env); const filePath = fromFile ?? path.join(environment.RATOS_DATA_DIR, 'last-printer-settings.json'); if (!existsSync(filePath)) { throw new Error("Couldn't find printer settings file: " + filePath); } const config = await loadSerializedConfig(filePath); - return await generateKlipperConfiguration(config, noWrite, noWrite, returnAsText, noWrite); + return await generateKlipperConfiguration(config, noWrite, noWrite, returnAsText, noWrite); }; const getToolhead = async < @@ -568,7 +573,7 @@ export const printerRouter = router({ }; }), regenerateConfiguration: publicProcedure.mutation(async () => { - return await regenerateKlipperConfiguration(); + return await regenerateKlipperConfiguration(); }), saveConfiguration: publicProcedure .input( diff --git a/src/tsconfig.json b/src/tsconfig.json index af6b6c835..cc83d6fa3 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -20,6 +20,5 @@ } ] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "build/types/**/*.ts"], - "exclude": ["node_modules"] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "build/types/**/*.ts"] } diff --git a/src/tsconfig.vitest.json b/src/tsconfig.vitest.json index fb1c15463..25c4b9633 100644 --- a/src/tsconfig.vitest.json +++ b/src/tsconfig.vitest.json @@ -1,5 +1,5 @@ { - "extends": "./tsconfig.next.json", + "extends": "./tsconfig.json", "compilerOptions": { "jsx": "react", "types": ["vitest/globals"]